xmlamediator.java

来自「数据仓库展示程序」· Java 代码 · 共 827 行 · 第 1/3 页

JAVA
827
字号
/*
// $Id: //open/mondrian/src/main/mondrian/xmla/XmlaMediator.java#19 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// (C) Copyright 2003-2005 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package mondrian.xmla;

import java.io.*;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import mondrian.olap.*;
import mondrian.rolap.RolapConnection;
import mondrian.util.SAXHandler;
import mondrian.util.SAXWriter;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.apache.log4j.Logger;

/**
 * An <code>XmlaMediator</code> responds to XML for Analysis requests.
 *
 * @author jhyde
 * @since 27 April, 2003
 * @version $Id: //open/mondrian/src/main/mondrian/xmla/XmlaMediator.java#19 $
 */
public class XmlaMediator {
    private static final boolean DRILLTHROUGH_EXTENDS_CONTEXT = true;

    private static final Logger LOGGER = Logger.getLogger(XmlaMediator.class);
    private static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
    private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
    private static final String XMLA_NS = "urn:schemas-microsoft-com:xml-analysis";
    private static final String XMLA_MDDATASET_NS = "urn:schemas-microsoft-com:xml-analysis:mddataset";
    private static final String XMLA_ROWSET_NS = "urn:schemas-microsoft-com:xml-analysis:rowset";
    static ThreadLocal threadServletContext = new ThreadLocal();
    static Map dataSourcesMap = new HashMap();

    /**
     * Please call this method before any usage of XmlaMediator.
     * @param dataSources
     */
    public static void initDataSourcesMap(DataSourcesConfig.DataSources dataSources) {
        Map map = new HashMap();
        for (int i = 0; i < dataSources.dataSources.length; i++) {
                        DataSourcesConfig.DataSource ds = dataSources.dataSources[i];
                        if (map.containsKey(ds.getDataSourceName())) {
                                throw Util.newError("duplicated data source name '" + ds.getDataSourceName() + "'");
                        }
                        map.put(ds.getDataSourceName(), ds);
                }
        dataSourcesMap = Collections.unmodifiableMap(map);
    }

    /**
     * Processes a request.
     * @param request  XML request, for example, "<SOAP-ENV:Envelope ...>".
     * @param response Destination for response
     */
    public void process(String request, Writer response) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder documentBuilder;
        try {
            documentBuilder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw Util.newError(e, "Error processing '" + request + "'");
        }
        Document document;
        try {
            document = documentBuilder.parse(new InputSource(new StringReader(request)));
        } catch (SAXException e) {
            throw Util.newError(e, "Error processing '" + request + "'");
        } catch (IOException e) {
            throw Util.newError(e, "Error processing '" + request + "'");
        }
        Element documentElement = document.getDocumentElement();
        try {
            process(documentElement, new SAXHandler(new SAXWriter(response)));
        } catch (SAXException e) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Request " + request + " failed", e);
            }
        }
    }

    /**
     * Processes a request, specified as a &lt;Discover&gt; or &lt;Execute&gt;
     * {@link Element DOM element}, and writes the response as a set of SAX
     * events.
     * @param element &lt;Discover&gt; or &lt;Execute&gt;
     *   {@link Element DOM element}
     * @param saxHandler Object to write SAX events to
     */
    public void process(Element element, SAXHandler saxHandler) throws SAXException {
        saxHandler.startDocument();
        processEnvelope(element, saxHandler);
        saxHandler.endDocument();
    }

    private void processEnvelope(Element element, SAXHandler saxHandler) throws SAXException {
        String tagName = element.getLocalName();
        Util.assertTrue(tagName.equals("Envelope"));
        //final NodeList childNodes = element.getChildNodes();
        saxHandler.startElement("SOAP-ENV:Envelope", new String[] {
            "xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/",
             "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/",
        });
        saxHandler.startElement("SOAP-ENV:Body");
        processBody(firstElement(element, "Body"), saxHandler);
        saxHandler.endElement();
        saxHandler.endElement();
    }

    private void processBody(Element element, SAXHandler saxHandler) {
        String tagName = element.getLocalName();
        Util.assertTrue(tagName.equals("Body"));
        final NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            final Node node = childNodes.item(i);
            if (node instanceof Element) {
                processRequest((Element) node, saxHandler);
            }
        }
    }

    private void processRequest(Element element, SAXHandler saxHandler) {
        String tagName = element.getLocalName();
        if (tagName.equals("Discover")) {
            discover(element, saxHandler);
        } else if (tagName.equals("Execute")) {
            execute(element, saxHandler);
        } else {
            throw Util.newError("Element <" + tagName + "> not supported");
        }
    }

    private void execute(Element execute, SAXHandler saxHandler) {
        Element command = firstElement(execute, "Command");
        if (command == null) {
            throw Util.newError("<Command> parameter is required");
        }
        String statement = firstElementCDATA(command, "Statement");
        if (statement == null) {
            throw Util.newError("<Statement> parameter is required");
        }
        final Properties properties = getProperties(execute);

        boolean isDrillThrough = false;
        // No usage of Regex in 1.4
        String upperStatement = statement.toUpperCase();
        int dtOffset = upperStatement.indexOf("DRILLTHROUGH");
        int slOffset = upperStatement.indexOf("SELECT");
        if (dtOffset != -1 && dtOffset < slOffset) {
            String format = properties.getProperty(PropertyDefinition.Format.name);
            if ("Tabular".compareToIgnoreCase(format) == 0)
                isDrillThrough = true;
            else
                throw Util.newError("Must set property 'Format' to 'Tabular' for DrillThrough");
        }

        try {
                saxHandler.startElement("ExecuteResponse", new String[] {
                                "xmlns", XMLA_NS});
                saxHandler.startElement("return", new String[] {
                   "xmlns:xsi", XSI_NS,
                   "xmlns:xsd", XSD_NS,});
                saxHandler.startElement("root", new String[] {
                                "xmlns", isDrillThrough ? XMLA_ROWSET_NS : XMLA_MDDATASET_NS});
                saxHandler.startElement("xsd:schema", new String[] {
                                "xmlns:xsd", XSD_NS});
                        // todo: schema definition
                saxHandler.endElement();
                try {
                if (isDrillThrough) {
                    StringBuffer dtStatement = new StringBuffer();
                    dtStatement.append(statement.substring(0, dtOffset)); // formulas
                    dtStatement.append(statement.substring(dtOffset + "DRILLTHROUGH".length())); // select to end
                    executeDrillThroughQuery(dtStatement.toString(), properties).unparse(saxHandler);
                } else {
                    executeQuery(statement, properties).unparse(saxHandler);
                }
                } catch(RuntimeException re) { // MondrianException is subclass of RuntimeException
                    saxHandler.completeBeforeElement("root");
                reportXmlaError(saxHandler, re);
            } finally {
                        saxHandler.endElement();
                        saxHandler.endElement();
                        saxHandler.endElement();
                }
        } catch (SAXException e) {
                throw Util.newError(e, "Error while processing execute request");
        }
    }

    private TabularRowSet executeDrillThroughQuery(String statement, Properties properties) {
        final Connection connection = getConnection(properties);
        final Query query = connection.parseQuery(statement);
        final Result result = connection.execute(query);
        Cell dtCell = result.getCell(new int[] {0,0});

        if (!dtCell.canDrillThrough()) {
            throw Util.newError("Cannot do DillThrough operation on the cell");
        }

        String dtSql = dtCell.getDrillThroughSQL(DRILLTHROUGH_EXTENDS_CONTEXT);
        TabularRowSet rowset = null;
        java.sql.Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = ((RolapConnection)connection).getDataSource().getConnection();
            stmt = conn.createStatement();
            rs = stmt.executeQuery(dtSql);
            rowset = new TabularRowSet(rs);
        } catch (SQLException sqle) {
            Util.newError(sqle, "Error while executing DrillThrough sql '" + dtSql + "'");
        } finally {
            try {
                if (rs != null) rs.close();
            } catch (SQLException ignored){}
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException ignored){}
            try {
                if (conn != null && !conn.isClosed()) conn.close();
            } catch (SQLException ignored){}
        }

        return rowset;
    }

    static class TabularRowSet {
        private String[] header;
        private List rows;

        public TabularRowSet(ResultSet rs) throws SQLException {
            ResultSetMetaData md = rs.getMetaData();
            int columnCount = md.getColumnCount();

            // populate header
            header = new String[columnCount];
            for (int i = 0; i < columnCount; i++) {
                header[i] = md.getColumnName(i+1);
            }

            // populate data
            rows = new ArrayList();
            while(rs.next()) {
                Object[] row = new Object[columnCount];
                for (int i = 0; i < columnCount; i++) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?