0001: /*
0002: * Copyright 2006 Pentaho Corporation. All rights reserved.
0003: * This software was developed by Pentaho Corporation and is provided under the terms
0004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
0005: * this file except in compliance with the license. If you need a copy of the license,
0006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
0007: * BI Platform. The Initial Developer is Pentaho Corporation.
0008: *
0009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
0010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
0011: * the license for the specific language governing your rights and limitations.
0012: *
0013: * Created Sep 21, 2005
0014: * @author wseyler
0015: */
0016:
0017: package org.pentaho.plugin.xmla;
0018:
0019: import java.io.StringWriter;
0020: import java.io.Writer;
0021: import java.net.MalformedURLException;
0022: import java.net.URL;
0023: import java.util.HashMap;
0024: import java.util.Iterator;
0025: import java.util.Map;
0026:
0027: import javax.xml.soap.Detail;
0028: import javax.xml.soap.DetailEntry;
0029: import javax.xml.soap.MessageFactory;
0030: import javax.xml.soap.MimeHeaders;
0031: import javax.xml.soap.Name;
0032: import javax.xml.soap.Node;
0033: import javax.xml.soap.SOAPBody;
0034: import javax.xml.soap.SOAPConnection;
0035: import javax.xml.soap.SOAPConnectionFactory;
0036: import javax.xml.soap.SOAPElement;
0037: import javax.xml.soap.SOAPEnvelope;
0038: import javax.xml.soap.SOAPException;
0039: import javax.xml.soap.SOAPFault;
0040: import javax.xml.soap.SOAPMessage;
0041: import javax.xml.soap.SOAPPart;
0042: import javax.xml.transform.Source;
0043: import javax.xml.transform.Transformer;
0044: import javax.xml.transform.TransformerFactory;
0045: import javax.xml.transform.stream.StreamResult;
0046:
0047: import org.apache.commons.logging.Log;
0048: import org.pentaho.core.component.IDataComponent;
0049: import org.pentaho.commons.connection.IPentahoResultSet;
0050: import org.pentaho.commons.connection.memory.MemoryMetaData;
0051: import org.pentaho.commons.connection.memory.MemoryResultSet;
0052: import org.pentaho.messages.Messages;
0053: import org.pentaho.plugin.ComponentBase;
0054:
0055: public abstract class XMLABaseComponent extends ComponentBase implements
0056: IDataComponent {
0057:
0058: private static final String MDD_URI = "urn:schemas-microsoft-com:xml-analysis:mddataset"; //$NON-NLS-1$
0059:
0060: private static final String ROWS_URI = "urn:schemas-microsoft-com:xml-analysis:rowset"; //$NON-NLS-1$
0061:
0062: private static final String XMLA_URI = "urn:schemas-microsoft-com:xml-analysis"; //$NON-NLS-1$
0063:
0064: private static final String EXECUTE_ACTION = "\"urn:schemas-microsoft-com:xml-analysis:Execute\""; //$NON-NLS-1$
0065:
0066: private static final String ENCODING_STYLE = "http://schemas.xmlsoap.org/soap/encoding/"; //$NON-NLS-1$
0067:
0068: private static final String URI = "uri"; //$NON-NLS-1$
0069:
0070: private static final String USER = "user-id"; //$NON-NLS-1$
0071:
0072: private static final String PASSWORD = "password"; //$NON-NLS-1$
0073:
0074: private static final String CATALOG = "catalog"; //$NON-NLS-1$
0075:
0076: private static final String QUERY = "query"; //$NON-NLS-1$
0077:
0078: private static final int AXIS_COLUMNS = 0;
0079:
0080: private static final int AXIS_ROWS = 1;
0081:
0082: private IPentahoResultSet rSet;
0083:
0084: private SOAPConnectionFactory scf = null;
0085:
0086: private MessageFactory mf = null;
0087:
0088: private URL url = null;
0089:
0090: private int provider = 0;
0091:
0092: private String dataSource = null;
0093:
0094: public static final int PROVIDER_MICROSOFT = 1;
0095:
0096: public static final int PROVIDER_SAP = 2;
0097:
0098: public static final int PROVIDER_MONDRIAN = 3;
0099:
0100: public static final int PROVIDER_ESSBASE = 4;
0101:
0102: public abstract boolean validateSystemSettings();
0103:
0104: public abstract String getResultOutputName();
0105:
0106: public abstract Log getLogger();
0107:
0108: interface Rowhandler {
0109: void handleRow(SOAPElement eRow, SOAPEnvelope envelope);
0110: }
0111:
0112: public IPentahoResultSet getResultSet() {
0113: return rSet;
0114: }
0115:
0116: protected boolean validateAction() {
0117:
0118: try {
0119: if (!isDefinedInput(URI)) {
0120: error(Messages
0121: .getErrorString(
0122: "XMLABaseComponent.ERROR_0001_CONNECTION_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0123: return false;
0124: }
0125:
0126: if (!isDefinedInput(USER)) {
0127: error(Messages
0128: .getErrorString(
0129: "XMLABaseComponent.ERROR_0002_USER_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0130: return false;
0131: }
0132:
0133: if (!isDefinedInput(PASSWORD)) {
0134: error(Messages
0135: .getErrorString(
0136: "XMLABaseComponent.ERROR_0003_PASSWORD_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0137: return false;
0138: }
0139:
0140: if (!isDefinedInput(CATALOG)) {
0141: error(Messages
0142: .getErrorString(
0143: "XMLABaseComponent.ERROR_0004_CATALOG_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0144: return false;
0145: }
0146:
0147: if (!isDefinedInput(QUERY)) {
0148: error(Messages
0149: .getErrorString(
0150: "XMLABaseComponent.ERROR_0005_QUERY_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0151: return false;
0152: }
0153:
0154: String outputName = getResultOutputName();
0155: if (outputName != null) {
0156: if (!getOutputNames().contains(outputName)) {
0157: error(Messages
0158: .getErrorString(
0159: "XMLABaseComponent.ERROR_0006_OUTPUT_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$
0160: return false;
0161: }
0162: }
0163: return true;
0164: } catch (Exception e) {
0165: error(
0166: Messages
0167: .getErrorString(
0168: "XMLABaseComponent.ERROR_0007_VALIDATION_FAILED", getActionName()), e); //$NON-NLS-1$
0169: }
0170:
0171: return false;
0172: }
0173:
0174: public void done() {
0175: }
0176:
0177: protected boolean executeAction() {
0178: try {
0179: scf = SOAPConnectionFactory.newInstance();
0180: mf = MessageFactory.newInstance();
0181: } catch (UnsupportedOperationException e) {
0182: e.printStackTrace();
0183: } catch (SOAPException e) {
0184: e.printStackTrace();
0185: }
0186:
0187: String uri = this .getInputStringValue(URI);
0188: String user = this .getInputStringValue(USER);
0189: String password = this .getInputStringValue(PASSWORD);
0190: String catalog = this .getInputStringValue(CATALOG);
0191: String query = this .getInputStringValue(QUERY);
0192:
0193: buildURl(uri, user, password);
0194: try {
0195: setProviderAndDataSource(discoverDS());
0196: return executeQuery(query, catalog);
0197: } catch (XMLAException e) {
0198: // TODO Auto-generated catch block
0199: e.printStackTrace();
0200: }
0201:
0202: return false;
0203: }
0204:
0205: private void buildURl(String uri, String user, String password) {
0206: try {
0207: this .url = new URL(uri);
0208: } catch (MalformedURLException e) {
0209: e.printStackTrace();
0210: }
0211:
0212: if (user != null && user.length() > 0) {
0213: String newUri = this .url.getProtocol() + "://" + user; //$NON-NLS-1$
0214: if (password != null && password.length() > 0) {
0215: newUri += ":" + password; //$NON-NLS-1$
0216: }
0217: newUri += "@" + this .url.getHost() + ":" + this .url.getPort() //$NON-NLS-1$ //$NON-NLS-2$
0218: + this .url.getPath();
0219:
0220: try {
0221: this .url = new URL(newUri);
0222: } catch (MalformedURLException e) {
0223: e.printStackTrace();
0224: }
0225: }
0226: }
0227:
0228: /**
0229: * Execute query
0230: *
0231: * @param query -
0232: * MDX to be executed
0233: * @param catalog
0234: * @param handler
0235: * Callback handler
0236: * @throws XMLAException
0237: */
0238: public boolean executeQuery(String query, String catalog)
0239: throws XMLAException {
0240:
0241: Object[][] columnHeaders = null;
0242: Object[][] rowHeaders = null;
0243: Object[][] data = null;
0244:
0245: int columnCount = 0;
0246: int rowCount = 0;
0247:
0248: SOAPConnection connection = null;
0249: SOAPMessage reply = null;
0250:
0251: try {
0252: connection = scf.createConnection();
0253: SOAPMessage msg = mf.createMessage();
0254:
0255: MimeHeaders mh = msg.getMimeHeaders();
0256: mh.setHeader("SOAPAction", EXECUTE_ACTION); //$NON-NLS-1$
0257:
0258: SOAPPart soapPart = msg.getSOAPPart();
0259: SOAPEnvelope envelope = soapPart.getEnvelope();
0260: envelope.setEncodingStyle(ENCODING_STYLE);
0261:
0262: SOAPBody body = envelope.getBody();
0263: Name nEx = envelope.createName("Execute", "", XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$
0264:
0265: SOAPElement eEx = body.addChildElement(nEx);
0266: eEx.setEncodingStyle(ENCODING_STYLE);
0267:
0268: // add the parameters
0269:
0270: // COMMAND parameter
0271: // <Command>
0272: // <Statement>select [Measures].members on Columns from
0273: // Sales</Statement>
0274: // </Command>
0275: Name nCom = envelope.createName("Command", "", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0276: SOAPElement eCommand = eEx.addChildElement(nCom);
0277: Name nSta = envelope.createName("Statement", "", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0278: SOAPElement eStatement = eCommand.addChildElement(nSta);
0279: eStatement.addTextNode(query);
0280:
0281: // <Properties>
0282: // <PropertyList>
0283: // <DataSourceInfo>Provider=MSOLAP;Data
0284: // Source=local</DataSourceInfo>
0285: // <Catalog>Foodmart 2000</Catalog>
0286: // <Format>Multidimensional</Format>
0287: // <AxisFormat>TupleFormat</AxisFormat> oder "ClusterFormat"
0288: // </PropertyList>
0289: // </Properties>
0290: Map paraList = new HashMap();
0291: paraList.put("DataSourceInfo", dataSource); //$NON-NLS-1$
0292: paraList.put("Catalog", catalog); //$NON-NLS-1$
0293: paraList.put("Format", "Multidimensional"); //$NON-NLS-1$ //$NON-NLS-2$
0294: paraList.put("AxisFormat", "TupleFormat"); //$NON-NLS-1$ //$NON-NLS-2$
0295: addParameterList(envelope, eEx,
0296: "Properties", "PropertyList", paraList); //$NON-NLS-1$ //$NON-NLS-2$
0297:
0298: msg.saveChanges();
0299:
0300: debug("Request for Execute"); //$NON-NLS-1$
0301: logSoapMsg(msg);
0302:
0303: // run the call
0304: reply = connection.call(msg, url);
0305:
0306: debug("Reply from Execute"); //$NON-NLS-1$
0307: logSoapMsg(reply);
0308:
0309: // error check
0310: errorCheck(reply);
0311:
0312: // process the reply
0313: SOAPElement eRoot = findExecRoot(reply);
0314:
0315: // for each axis, get the positions (tuples)
0316: Name name = envelope.createName("Axes", "", MDD_URI); //$NON-NLS-1$ //$NON-NLS-2$
0317: SOAPElement eAxes = selectSingleNode(eRoot, name);
0318: if (eAxes == null)
0319: throw new XMLAException(
0320: "Excecute result has no Axes element"); //$NON-NLS-1$
0321:
0322: name = envelope.createName("Axis", "", MDD_URI); //$NON-NLS-1$ //$NON-NLS-2$
0323: Iterator itAxis = eAxes.getChildElements(name);
0324:
0325: AxisLoop: for (int iOrdinal = 0; itAxis.hasNext();) {
0326: SOAPElement eAxis = (SOAPElement) itAxis.next();
0327: name = envelope.createName("name"); //$NON-NLS-1$
0328: String axisName = eAxis.getAttributeValue(name);
0329: int axisOrdinal;
0330: if (axisName.equals("SlicerAxis")) { //$NON-NLS-1$
0331: continue;
0332: } else {
0333: axisOrdinal = iOrdinal++;
0334: }
0335:
0336: name = envelope.createName("Tuples", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0337: SOAPElement eTuples = selectSingleNode(eAxis, name);
0338: if (eTuples == null)
0339: continue AxisLoop; // what else?
0340:
0341: name = envelope.createName("Tuple", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0342: Iterator itTuple = eTuples.getChildElements(name);
0343:
0344: // loop over tuples
0345: int positionOrdinal = 0;
0346: while (itTuple.hasNext()) { // TupleLoop
0347:
0348: SOAPElement eTuple = (SOAPElement) itTuple.next();
0349:
0350: if (axisOrdinal == AXIS_COLUMNS
0351: && columnHeaders == null) {
0352: columnCount = getChildCount(envelope, eTuples,
0353: "Tuple"); //$NON-NLS-1$
0354: columnHeaders = new Object[getChildCount(
0355: envelope, eTuple, "Member")][columnCount]; //$NON-NLS-1$
0356: } else if (axisOrdinal == AXIS_ROWS
0357: && rowHeaders == null) {
0358: rowCount = getChildCount(envelope, eTuples,
0359: "Tuple"); //$NON-NLS-1$
0360: rowHeaders = new Object[rowCount][getChildCount(
0361: envelope, eTuple, "Member")]; //$NON-NLS-1$
0362: }
0363:
0364: int index = 0;
0365: name = envelope.createName("Member", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0366: Iterator itMember = eTuple.getChildElements(name);
0367: while (itMember.hasNext()) {// MemberLoop
0368: SOAPElement eMem = (SOAPElement) itMember
0369: .next();
0370: // loop over children nodes
0371: String caption = null;
0372: Iterator it = eMem.getChildElements();
0373: InnerLoop: while (it.hasNext()) {
0374: Node n = (Node) it.next();
0375: if (!(n instanceof SOAPElement))
0376: continue InnerLoop;
0377: SOAPElement el = (SOAPElement) n;
0378: String enam = el.getElementName()
0379: .getLocalName();
0380: if (enam.equals("Caption")) //$NON-NLS-1$
0381: caption = el.getValue();
0382: }
0383: if (axisOrdinal == AXIS_COLUMNS) {
0384: columnHeaders[index][positionOrdinal] = caption;
0385: } else if (axisOrdinal == AXIS_ROWS) {
0386: rowHeaders[positionOrdinal][index] = caption;
0387: }
0388: ++index;
0389: } // MemberLoop
0390:
0391: ++positionOrdinal;
0392: } // TupleLoop
0393: } // AxisLoop
0394:
0395: data = new Object[rowCount][columnCount];
0396: // loop over cells in result set
0397: name = envelope.createName("CellData", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0398: SOAPElement eCellData = selectSingleNode(eRoot, name);
0399: name = envelope.createName("Cell", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0400: Iterator itSoapCell = eCellData.getChildElements(name);
0401: while (itSoapCell.hasNext()) { // CellLoop
0402: SOAPElement eCell = (SOAPElement) itSoapCell.next();
0403: name = envelope.createName("CellOrdinal", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0404: String cellOrdinal = eCell.getAttributeValue(name);
0405: int ordinal = Integer.parseInt(cellOrdinal);
0406: name = envelope.createName("Value", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0407: Object value = selectSingleNode(eCell, name).getValue();
0408:
0409: int rowLoc = ordinal / columnCount;
0410: int columnLoc = ordinal % columnCount;
0411:
0412: data[rowLoc][columnLoc] = value;
0413: } // CellLoop
0414:
0415: MemoryResultSet resultSet = new MemoryResultSet();
0416: MemoryMetaData metaData = new MemoryMetaData(columnHeaders,
0417: rowHeaders);
0418: resultSet.setMetaData(metaData);
0419: for (int aRow = 0; aRow < data.length; aRow++) {
0420: resultSet.addRow(data[aRow]);
0421: }
0422: rSet = resultSet;
0423: if (resultSet != null) {
0424: if (getResultOutputName() != null) {
0425: setOutputValue(getResultOutputName(), resultSet);
0426: }
0427: return true;
0428: }
0429: return false;
0430:
0431: } catch (SOAPException se) {
0432: throw new XMLAException(se);
0433: } finally {
0434: if (connection != null)
0435: try {
0436: connection.close();
0437: } catch (SOAPException e) {
0438: // log and ignore
0439: error("?", e); //$NON-NLS-1$
0440: }
0441:
0442: }
0443:
0444: }
0445:
0446: private int getChildCount(SOAPEnvelope envelope,
0447: SOAPElement element, String childName) throws SOAPException {
0448: Name name = envelope.createName(childName, "", MDD_URI); //$NON-NLS-1$
0449: Iterator iter = element.getChildElements(name);
0450: int value = 0;
0451: while (iter.hasNext()) {
0452: value++;
0453: iter.next();
0454: }
0455: return value;
0456: }
0457:
0458: private void setProviderAndDataSource(Map resMap)
0459: throws XMLAException {
0460: if (resMap == null || resMap.size() == 0) {
0461: error(Messages
0462: .getString("XMLABaseComponent.ERROR_0008_NO_RESOURCE_MAP")); //$NON-NLS-1$
0463: throw new XMLAException(
0464: Messages
0465: .getString("XMLABaseComponent.ERROR_0008_NO_RESOURCE_MAP")); //$NON-NLS-1$
0466: }
0467:
0468: String pstr = (String) resMap.get("ProviderName"); //$NON-NLS-1$
0469:
0470: if (pstr == null) {
0471: throw new XMLAException(
0472: Messages
0473: .getString("XMLABaseComponent.ERROR_0009_NO_PROVIDER_NAME")); //$NON-NLS-1$
0474: }
0475:
0476: provider = determineProvider("Provider=" + pstr); //$NON-NLS-1$
0477:
0478: debug(Messages
0479: .getString("XMLABaseComponent.DEBUG_0001_PROVIDER_ID") + provider); //$NON-NLS-1$
0480:
0481: debug(Messages
0482: .getString("XMLABaseComponent.DEBUG_0002_DATASOURCE_NAME") + String.valueOf(resMap.get("DataSourceName"))); //$NON-NLS-1$ //$NON-NLS-2$
0483: debug(Messages
0484: .getString("XMLABaseComponent.DEBUG_0003_DATASOURCE_INFO") + String.valueOf(resMap.get("DataSourceInfo"))); //$NON-NLS-1$ //$NON-NLS-2$
0485:
0486: dataSource = (String) resMap.get("DataSourceInfo"); //$NON-NLS-1$
0487:
0488: if (dataSource == null || dataSource.length() < 1) {
0489: dataSource = (String) resMap.get("DataSourceName"); //$NON-NLS-1$
0490: }
0491:
0492: if (dataSource == null) {
0493: throw new XMLAException(
0494: Messages
0495: .getString("XMLABaseComponent.ERROR_0010_NO_DATASOURCE_NAME")); //$NON-NLS-1$
0496: }
0497:
0498: debug(Messages
0499: .getString("XMLABaseComponent.DEBUG_0004_DISCOVER_DATASOURCE_SET") + dataSource); //$NON-NLS-1$
0500:
0501: }
0502:
0503: /**
0504: * retrieve data source properties
0505: *
0506: * @return Map of key/value strings
0507: * @see DataSourceBrowser
0508: */
0509: public Map discoverDS() throws XMLAException {
0510: // Microsoft wants restrictions
0511: HashMap rHash = new HashMap();
0512:
0513: HashMap pHash = new HashMap();
0514: pHash.put("Content", "Data"); //$NON-NLS-1$ //$NON-NLS-2$
0515: final Map resultMap = new HashMap();
0516: Rowhandler rh = new Rowhandler() {
0517:
0518: public void handleRow(SOAPElement eRow,
0519: SOAPEnvelope envelope) {
0520:
0521: /*
0522: * <row><DataSourceName>SAP_BW</DataSourceName>
0523: * <DataSourceDescription>SAP BW Release 3.0A XML f. Analysis
0524: * Service</DataSourceDescription>
0525: * <URL>http://155.56.49.46:83/SAP/BW/XML/SOAP/XMLA</URL>
0526: * <DataSourceInfo>default</DataSourceInfo> <ProviderName>SAP
0527: * BW</ProviderName> <ProviderType>MDP</ProviderType>
0528: * <AuthenticationMode>Integrated</AuthenticationMode></row>
0529: */
0530: Iterator it = eRow.getChildElements();
0531: while (it.hasNext()) {
0532: Object o = it.next();
0533: if (!(o instanceof SOAPElement))
0534: continue; // bypass text nodes
0535: SOAPElement e = (SOAPElement) o;
0536: String name = e.getElementName().getLocalName();
0537: String value = e.getValue();
0538: resultMap.put(name, value);
0539: }
0540: }
0541: };
0542:
0543: discover("DISCOVER_DATASOURCES", url, rHash, pHash, rh); //$NON-NLS-1$
0544: debug(Messages
0545: .getString("XMLABaseComponent.DEBUG_0005_DISCOVER_DATASOURCE_FOUND") + resultMap.size()); //$NON-NLS-1$
0546: return resultMap;
0547:
0548: }
0549:
0550: /**
0551: * discover
0552: *
0553: * @param request
0554: * @param discoverUrl
0555: * @param restrictions
0556: * @param properties
0557: * @param rh
0558: * @throws XMLAException
0559: */
0560: private void discover(String request, URL discoverUrl,
0561: Map restrictions, Map properties, Rowhandler rh)
0562: throws XMLAException {
0563:
0564: try {
0565: SOAPConnection connection = scf.createConnection();
0566:
0567: SOAPMessage msg = mf.createMessage();
0568:
0569: MimeHeaders mh = msg.getMimeHeaders();
0570: mh
0571: .setHeader(
0572: "SOAPAction", "\"urn:schemas-microsoft-com:xml-analysis:Discover\""); //$NON-NLS-1$ //$NON-NLS-2$
0573:
0574: SOAPPart soapPart = msg.getSOAPPart();
0575: SOAPEnvelope envelope = soapPart.getEnvelope();
0576: envelope.addNamespaceDeclaration(
0577: "xsi", "http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$//$NON-NLS-2$
0578: envelope.addNamespaceDeclaration(
0579: "xsd", "http://www.w3.org/2001/XMLSchema"); //$NON-NLS-1$ //$NON-NLS-2$
0580: SOAPBody body = envelope.getBody();
0581: Name nDiscover = envelope.createName(
0582: "Discover", "", XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$
0583:
0584: SOAPElement eDiscover = body.addChildElement(nDiscover);
0585: eDiscover.setEncodingStyle(ENCODING_STYLE);
0586:
0587: Name nPara = envelope.createName(
0588: "RequestType", "", XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$
0589: SOAPElement eRequestType = eDiscover.addChildElement(nPara);
0590: eRequestType.addTextNode(request);
0591:
0592: // add the parameters
0593: if (restrictions != null) {
0594: addParameterList(envelope, eDiscover,
0595: "Restrictions", "RestrictionList", restrictions); //$NON-NLS-1$ //$NON-NLS-2$
0596: }
0597: addParameterList(envelope, eDiscover,
0598: "Properties", "PropertyList", properties); //$NON-NLS-1$//$NON-NLS-2$
0599:
0600: msg.saveChanges();
0601:
0602: debug(Messages
0603: .getString("XMLABaseComponent.DEBUG_0006_DISCOVER_REQUEST") + request); //$NON-NLS-1$
0604: logSoapMsg(msg);
0605:
0606: // run the call
0607: SOAPMessage reply = connection.call(msg, discoverUrl);
0608:
0609: debug(Messages
0610: .getString("XMLABaseComponent.DEBUG_0007_DISCOVER_RESPONSE") + request); //$NON-NLS-1$
0611: logSoapMsg(reply);
0612:
0613: errorCheck(reply);
0614:
0615: SOAPElement eRoot = findDiscoverRoot(reply);
0616:
0617: Name nRow = envelope.createName("row", "", ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$
0618: Iterator itRow = eRoot.getChildElements(nRow);
0619: while (itRow.hasNext()) { // RowLoop
0620:
0621: SOAPElement eRow = (SOAPElement) itRow.next();
0622: rh.handleRow(eRow, envelope);
0623:
0624: } // RowLoop
0625:
0626: connection.close();
0627: } catch (UnsupportedOperationException e) {
0628: throw new XMLAException(e);
0629: } catch (SOAPException e) {
0630: throw new XMLAException(e);
0631: }
0632:
0633: }
0634:
0635: /**
0636: * add a list of Restrictions/Properties ...
0637: */
0638: private void addParameterList(SOAPEnvelope envelope,
0639: SOAPElement eParent, String typeName, String listName,
0640: Map params) throws SOAPException {
0641: Name nPara = envelope.createName(typeName, "", XMLA_URI); //$NON-NLS-1$
0642: SOAPElement eType = eParent.addChildElement(nPara);
0643: nPara = envelope.createName(listName, "", XMLA_URI); //$NON-NLS-1$
0644: SOAPElement eList = eType.addChildElement(nPara);
0645: if (params == null)
0646: return;
0647: Iterator it = params.keySet().iterator();
0648: while (it.hasNext()) {
0649: String tag = (String) it.next();
0650: String value = (String) params.get(tag);
0651: nPara = envelope.createName(tag, "", XMLA_URI); //$NON-NLS-1$
0652: SOAPElement eTag = eList.addChildElement(nPara);
0653: eTag.addTextNode(value);
0654: }
0655: }
0656:
0657: /**
0658: * locate "root" in ExecuteResponse
0659: */
0660: private SOAPElement findExecRoot(SOAPMessage reply)
0661: throws SOAPException, XMLAException {
0662: SOAPPart sp = reply.getSOAPPart();
0663: SOAPEnvelope envelope = sp.getEnvelope();
0664: SOAPBody body = envelope.getBody();
0665:
0666: Name name;
0667: name = envelope.createName("ExecuteResponse", "m", XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$
0668: SOAPElement eResponse = selectSingleNode(body, name);
0669: if (eResponse == null) {
0670: throw new XMLAException(
0671: Messages
0672: .getString("XMLABaseComponent.ERROR_0011_NO_EXECUTE_RESPONSE_ELEMENT")); //$NON-NLS-1$
0673: }
0674:
0675: name = envelope.createName("return", "m", XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$
0676: SOAPElement eReturn = selectSingleNode(eResponse, name);
0677:
0678: name = envelope.createName("root", "", MDD_URI); //$NON-NLS-1$//$NON-NLS-2$
0679: SOAPElement eRoot = selectSingleNode(eReturn, name);
0680: if (eRoot == null) {
0681: throw new XMLAException(
0682: Messages
0683: .getString("XMLABaseComponent.ERROR_0012_NO_RESPONSE_ROOT_ELEMENT"));} //$NON-NLS-1$
0684: return eRoot;
0685: }
0686:
0687: /**
0688: * locate "root" in DisoverResponse
0689: */
0690: private SOAPElement findDiscoverRoot(SOAPMessage reply)
0691: throws SOAPException, XMLAException {
0692:
0693: SOAPPart sp = reply.getSOAPPart();
0694: SOAPEnvelope envelope = sp.getEnvelope();
0695: SOAPBody body = envelope.getBody();
0696: Name childName;
0697: SOAPElement eResponse = null;
0698: if (provider == 0) {
0699: // unknown provider - recognize by prefix of DiscoverResponse
0700: Iterator itBody = body.getChildElements();
0701: while (itBody.hasNext()) {
0702: Node n = (Node) itBody.next();
0703: if (!(n instanceof SOAPElement))
0704: continue;
0705: Name name = ((SOAPElement) n).getElementName();
0706: if (name.getLocalName().equals("DiscoverResponse")) { //$NON-NLS-1$
0707: eResponse = (SOAPElement) n;
0708: provider = getProviderFromDiscoverResponse(
0709: envelope, eResponse);
0710: break;
0711: }
0712: }
0713: if (eResponse == null) {
0714: throw new XMLAException(
0715: Messages
0716: .getString("XMLABaseComponent.ERROR_0013_NO_DISCOVER_RESPONSE")); //$NON-NLS-1$
0717: }
0718:
0719: } else {
0720: if (provider == PROVIDER_MICROSOFT
0721: || provider == PROVIDER_ESSBASE) { // Microsoft
0722: // or
0723: // Essbase
0724: childName = envelope.createName(
0725: "DiscoverResponse", "m", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0726: } else if (provider == PROVIDER_SAP
0727: || provider == PROVIDER_MONDRIAN) { // SAP
0728: // or
0729: // Mondrian
0730: childName = envelope.createName(
0731: "DiscoverResponse", "", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0732: } else {
0733: throw new IllegalArgumentException(
0734: Messages
0735: .getString("XMLABaseComponent.ERROR_0014_NO_PROVIDER_SPEC")); //$NON-NLS-1$
0736: }
0737: eResponse = selectSingleNode(body, childName);
0738: if (eResponse == null) {
0739: throw new XMLAException(
0740: Messages
0741: .getString("XMLABaseComponent.ERROR_0015_NO_DISCOVER_RESPONSE_ELEMENT")); //$NON-NLS-1$
0742: }
0743: }
0744:
0745: SOAPElement eReturn = getDiscoverReturn(envelope, eResponse);
0746: if (eReturn == null)
0747: throw new XMLAException(
0748: Messages
0749: .getString("XMLABaseComponent.ERROR_0016_NO_RESULT_RETURN_ELEMENT")); //$NON-NLS-1$
0750:
0751: SOAPElement eRoot = getDiscoverRoot(envelope, eReturn);
0752: if (eRoot == null)
0753: throw new XMLAException(
0754: Messages
0755: .getString("XMLABaseComponent.ERROR_0017_NO_RESULT_ROOT_ELEMENT")); //$NON-NLS-1$
0756: return eRoot;
0757: }
0758:
0759: /**
0760: * Find the Provider type in the DiscoverResponse
0761: *
0762: * @param n
0763: * @return
0764: * @throws XMLAException
0765: * @throws SOAPException
0766: */
0767: private int getProviderFromDiscoverResponse(SOAPEnvelope envelope,
0768: SOAPElement e) throws XMLAException, SOAPException {
0769: Name name = e.getElementName();
0770: if (!name.getLocalName().equals("DiscoverResponse")) { //$NON-NLS-1$
0771: throw new XMLAException(
0772: Messages
0773: .getString("XMLABaseComponent.ERROR_0018_NOT_A_DISCOVER_RESPONSE") + name.getLocalName()); //$NON-NLS-1$
0774: }
0775:
0776: // Look for return/root/row/ProviderName
0777:
0778: SOAPElement walker = getDiscoverReturn(envelope, e);
0779:
0780: if (walker == null) {
0781: throw new XMLAException(
0782: Messages
0783: .getString("XMLABaseComponent.ERROR_0019_NO_RESULT_DISCOVER_RESPONSE")); //$NON-NLS-1$
0784: }
0785:
0786: walker = getDiscoverRoot(envelope, walker);
0787:
0788: if (walker == null) {
0789: throw new XMLAException(
0790: Messages
0791: .getString("XMLABaseComponent.ERROR_0020_NO_RESULT_DISCOVER_RETURN_ROOT")); //$NON-NLS-1$
0792: }
0793:
0794: walker = getDiscoverRow(envelope, walker);
0795:
0796: if (walker == null) {
0797: throw new XMLAException(
0798: Messages
0799: .getString("XMLABaseComponent.ERROR_0021_NO_DISCOVER_RESPONSE_ROW")); //$NON-NLS-1$
0800: }
0801:
0802: /*
0803: * Name nProviderName = envelope.createName("ProviderName", "",
0804: * ROWS_URI); SOAPElement eProviderName = selectSingleNode(e,
0805: * nProviderName);
0806: *
0807: * if (eProviderName == null) { throw new OlapException("Discover result
0808: * has no DiscoverResponse/return/root/row/ProviderName element"); }
0809: * value = eProviderName.getValue();
0810: */
0811: String value = null;
0812: Iterator it = walker.getChildElements();
0813: while (it.hasNext()) {
0814: Object o = it.next();
0815: if (!(o instanceof SOAPElement))
0816: continue; // bypass text nodes
0817: SOAPElement e2 = (SOAPElement) o;
0818: String nameString = e2.getElementName().getLocalName();
0819: if (nameString.equals("ProviderName")) { //$NON-NLS-1$
0820: value = e2.getValue();
0821: debug(Messages
0822: .getString("XMLABaseComponent.DEBUG_0008_FOUND_PROVIDER") + value); //$NON-NLS-1$
0823: break;
0824: }
0825: }
0826:
0827: if (value == null || value.trim().length() == 0) {
0828: throw new XMLAException(
0829: Messages
0830: .getString("XMLABaseComponent.ERROR_0022_NO_PROVIDER_NAME_ELEMENT")); //$NON-NLS-1$
0831: }
0832:
0833: return determineProvider("Provider=" + value); //$NON-NLS-1$
0834: }
0835:
0836: /**
0837: * Get provider id from String
0838: *
0839: * @param dataSourceString
0840: * @return provider id from OlapDiscoverer
0841: * @throws XMLAException
0842: */
0843: private int determineProvider(String dataSourceString)
0844: throws XMLAException {
0845: debug(Messages
0846: .getString("XMLABaseComponent.DEBUG_0009_DETERMINE_PROVIDER") + dataSourceString); //$NON-NLS-1$
0847: if (dataSourceString == null) {
0848: throw new XMLAException(
0849: Messages
0850: .getString("XMLABaseComponent.ERROR_0023_NO_DATASOURCE_GIVEN")); //$NON-NLS-1$
0851: }
0852:
0853: String upperDSString = dataSourceString.toUpperCase();
0854: if (!upperDSString.startsWith("PROVIDER=")) { //$NON-NLS-1$
0855: throw new XMLAException(
0856: Messages
0857: .getString("XMLABaseComponent.ERROR_0024_MALFORMED_DATASOURCE")); //$NON-NLS-1$
0858: }
0859:
0860: if (upperDSString.startsWith("PROVIDER=SAP")) { //$NON-NLS-1$
0861: debug(Messages
0862: .getString("XMLABaseComponent.DEBUG_0009_SAP_PROVIDER")); //$NON-NLS-1$
0863: return PROVIDER_SAP;
0864: } else if (upperDSString.startsWith("PROVIDER=MONDRIAN")) { //$NON-NLS-1$
0865: debug(Messages
0866: .getString("XMLABaseComponent.DEBUG_0010_MONDRIAN_PROVIDER")); //$NON-NLS-1$
0867: return PROVIDER_MONDRIAN;
0868: } else if (upperDSString.startsWith("PROVIDER=MS")) { //$NON-NLS-1$ //not sure if this is needed?
0869: debug(Messages
0870: .getString("XMLABaseComponent.DEBUG_0011_MICROSOFT_PROVIDER")); //$NON-NLS-1$
0871: return PROVIDER_MICROSOFT;
0872: } else if (upperDSString.startsWith("PROVIDER=MICROSOFT")) { //$NON-NLS-1$ // return value from MSAS: "Microsoft XML for Analysis"
0873: debug(Messages
0874: .getString("XMLABaseComponent.DEBUG_0011_MICROSOFT_PROVIDER")); //$NON-NLS-1$
0875: return PROVIDER_MICROSOFT; //
0876: } else if (upperDSString.startsWith("PROVIDER=ESSBASE")) { //$NON-NLS-1$ // return value from MSAS: "Microsoft XML for Analysis"
0877: debug(Messages
0878: .getString("XMLABaseComponent.DEBUG_0012_ESSBASE_PROVIDER")); //$NON-NLS-1$
0879: return PROVIDER_ESSBASE; //
0880: } else {
0881: error(Messages
0882: .getString("XMLABaseComponent.ERROR_0023_CANNOT_DETERMINE_PROVIDER") + dataSourceString); //$NON-NLS-1$
0883: throw new XMLAException(
0884: Messages
0885: .getString("XMLABaseComponent.ERROR_0024_UNSUPPORTED_PROVIDER")); //$NON-NLS-1$
0886: }
0887:
0888: }
0889:
0890: private SOAPElement getDiscoverReturn(SOAPEnvelope envelope,
0891: SOAPElement e) throws XMLAException, SOAPException {
0892:
0893: Name nReturn;
0894: if (provider == PROVIDER_MICROSOFT
0895: || provider == PROVIDER_ESSBASE) {
0896: nReturn = envelope.createName("return", "m", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0897: } else {
0898: nReturn = envelope.createName("return", "", XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$
0899: }
0900: SOAPElement eReturn = selectSingleNode(e, nReturn);
0901: if (eReturn == null) {
0902: // old Microsoft XMLA SDK 1.0 does not have "m" prefix - try
0903: nReturn = envelope.createName("return", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0904: eReturn = selectSingleNode(e, nReturn);
0905: if (eReturn == null)
0906: throw new XMLAException(
0907: Messages
0908: .getString("XMLABaseComponent.ERROR_0025_NO_RETURN_DISCOVER_ELEMENT")); //$NON-NLS-1$
0909: }
0910: return eReturn;
0911: }
0912:
0913: private SOAPElement getDiscoverRoot(SOAPEnvelope envelope,
0914: SOAPElement e) throws XMLAException, SOAPException {
0915:
0916: Name nRoot = envelope.createName("root", "", ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$
0917: SOAPElement eRoot = selectSingleNode(e, nRoot);
0918: if (eRoot == null) {
0919: throw new XMLAException(
0920: Messages
0921: .getString("XMLABaseComponent.ERROR_0026_NO_ROOT_DISCOVER_ELEMENT"));} //$NON-NLS-1$
0922: return eRoot;
0923:
0924: }
0925:
0926: private SOAPElement getDiscoverRow(SOAPEnvelope envelope,
0927: SOAPElement e) throws XMLAException, SOAPException {
0928:
0929: Name nRow = envelope.createName("row", "", ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$
0930: SOAPElement eRow = selectSingleNode(e, nRow);
0931: if (eRow == null) {
0932: throw new XMLAException(
0933: Messages
0934: .getString("XMLABaseComponent.ERROR_0027_NO_DISCOVER_ROW_ELEMENT"));} //$NON-NLS-1$
0935: return eRow;
0936:
0937: }
0938:
0939: // error check
0940: private void errorCheck(SOAPMessage reply) throws SOAPException,
0941: XMLAException {
0942: String[] strings = new String[4];
0943: if (soapFault(reply, strings)) {
0944: String faultString = "Soap Fault code=" + strings[0] + " fault string=" + strings[1] + " fault actor=" + strings[2]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0945: if (strings[3] != null)
0946: faultString += "\ndetail:" + strings[3]; //$NON-NLS-1$
0947: throw new XMLAException(faultString);
0948: }
0949: }
0950:
0951: /**
0952: * check SOAP reply for Error, return fault Code
0953: *
0954: * @param reply
0955: * the message to check
0956: * @param aReturn
0957: * ArrayList containing faultcode,faultstring,faultactor
0958: */
0959: private boolean soapFault(SOAPMessage reply, String[] faults)
0960: throws SOAPException {
0961: SOAPPart sp = reply.getSOAPPart();
0962: SOAPEnvelope envelope = sp.getEnvelope();
0963: SOAPBody body = envelope.getBody();
0964: if (!body.hasFault())
0965: return false;
0966: SOAPFault fault = body.getFault();
0967:
0968: faults[0] = fault.getFaultCode();
0969: faults[1] = fault.getFaultString();
0970: faults[2] = fault.getFaultActor();
0971:
0972: // probably not neccessary with Microsoft;
0973: Detail detail = fault.getDetail();
0974: if (detail == null)
0975: return true;
0976: String detailMsg = ""; //$NON-NLS-1$
0977: Iterator it = detail.getDetailEntries();
0978: for (; it.hasNext();) {
0979: DetailEntry det = (DetailEntry) it.next();
0980: Iterator ita = det.getAllAttributes();
0981: for (boolean cont = false; ita.hasNext(); cont = true) {
0982: Name name = (Name) ita.next();
0983: if (cont) {
0984: detailMsg += "; "; //$NON-NLS-1$
0985: }
0986: detailMsg += name.getLocalName();
0987: detailMsg += " = "; //$NON-NLS-1$
0988: detailMsg += det.getAttributeValue(name);
0989: }
0990: }
0991: faults[3] = detailMsg;
0992:
0993: return true;
0994: }
0995:
0996: /**
0997: * @param contextNode
0998: * @param childPath
0999: * @return
1000: */
1001: private SOAPElement selectSingleNode(SOAPElement contextNode,
1002: Name childName) {
1003:
1004: Iterator it = contextNode.getChildElements(childName);
1005: if (it.hasNext()) {
1006: return (SOAPElement) it.next();
1007: }
1008: return null;
1009: }
1010:
1011: /**
1012: * log the reply message
1013: */
1014: private void logSoapMsg(SOAPMessage msg) {
1015: try {
1016: Writer writer = new StringWriter();
1017: TransformerFactory tFact = TransformerFactory.newInstance();
1018: Transformer transformer = tFact.newTransformer();
1019: Source src = msg.getSOAPPart().getContent();
1020: StreamResult result = new StreamResult(writer);
1021: transformer.transform(src, result);
1022: debug(writer.toString());
1023: } catch (Exception e) {
1024: // no big problen - just for debugging
1025: error("?", e); //$NON-NLS-1$
1026: }
1027: }
1028:
1029: public void dispose() {
1030: }
1031:
1032: public boolean init() {
1033: return true;
1034: }
1035: }
|