/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright 2005 - 2009 Pentaho Corporation. All rights reserved. * * * Created Sep 21, 2005 * @author wseyler */ package org.pentaho.platform.plugin.action.xmla; import java.io.StringWriter; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.xml.soap.Detail; import javax.xml.soap.DetailEntry; import javax.xml.soap.MessageFactory; import javax.xml.soap.MimeHeaders; import javax.xml.soap.Name; import javax.xml.soap.Node; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPConnection; import javax.xml.soap.SOAPConnectionFactory; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFault; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import org.apache.commons.logging.Log; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.commons.connection.memory.MemoryMetaData; import org.pentaho.commons.connection.memory.MemoryResultSet; import org.pentaho.platform.api.data.IDataComponent; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.plugin.action.messages.Messages; public abstract class XMLABaseComponent extends ComponentBase implements IDataComponent { private static final long serialVersionUID = 8405489984774339891L; private static final String MDD_URI = "urn:schemas-microsoft-com:xml-analysis:mddataset"; //$NON-NLS-1$ private static final String ROWS_URI = "urn:schemas-microsoft-com:xml-analysis:rowset"; //$NON-NLS-1$ private static final String XMLA_URI = "urn:schemas-microsoft-com:xml-analysis"; //$NON-NLS-1$ private static final String EXECUTE_ACTION = "\"urn:schemas-microsoft-com:xml-analysis:Execute\""; //$NON-NLS-1$ private static final String ENCODING_STYLE = "http://schemas.xmlsoap.org/soap/encoding/"; //$NON-NLS-1$ private static final String URI = "uri"; //$NON-NLS-1$ private static final String USER = "user-id"; //$NON-NLS-1$ private static final String PASSWORD = "password"; //$NON-NLS-1$ private static final String CATALOG = "catalog"; //$NON-NLS-1$ private static final String QUERY = "query"; //$NON-NLS-1$ private static final int AXIS_COLUMNS = 0; private static final int AXIS_ROWS = 1; private IPentahoResultSet rSet; private SOAPConnectionFactory scf = null; private MessageFactory mf = null; private URL url = null; private int provider = 0; private String dataSource = null; public static final int PROVIDER_MICROSOFT = 1; public static final int PROVIDER_SAP = 2; public static final int PROVIDER_MONDRIAN = 3; public static final int PROVIDER_ESSBASE = 4; @Override public abstract boolean validateSystemSettings(); public abstract String getResultOutputName(); @Override public abstract Log getLogger(); interface Rowhandler { void handleRow(SOAPElement eRow, SOAPEnvelope envelope); } public IPentahoResultSet getResultSet() { return rSet; } @Override protected boolean validateAction() { try { if (!isDefinedInput(XMLABaseComponent.URI)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0001_CONNECTION_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } if (!isDefinedInput(XMLABaseComponent.USER)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0002_USER_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } if (!isDefinedInput(XMLABaseComponent.PASSWORD)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0003_PASSWORD_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } if (!isDefinedInput(XMLABaseComponent.CATALOG)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0004_CATALOG_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } if (!isDefinedInput(XMLABaseComponent.QUERY)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0005_QUERY_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } String outputName = getResultOutputName(); if (outputName != null) { if (!getOutputNames().contains(outputName)) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0006_OUTPUT_NOT_SPECIFIED", getActionName())); //$NON-NLS-1$ return false; } } return true; } catch (Exception e) { error(Messages.getInstance().getErrorString("XMLABaseComponent.ERROR_0007_VALIDATION_FAILED", getActionName()), e); //$NON-NLS-1$ } return false; } @Override public void done() { } @Override protected boolean executeAction() { try { scf = SOAPConnectionFactory.newInstance(); mf = MessageFactory.newInstance(); } catch (UnsupportedOperationException e) { e.printStackTrace(); } catch (SOAPException e) { e.printStackTrace(); } String uri = this.getInputStringValue(XMLABaseComponent.URI); String user = this.getInputStringValue(XMLABaseComponent.USER); String password = this.getInputStringValue(XMLABaseComponent.PASSWORD); String catalog = this.getInputStringValue(XMLABaseComponent.CATALOG); String query = this.getInputStringValue(XMLABaseComponent.QUERY); buildURl(uri, user, password); try { setProviderAndDataSource(discoverDS()); return executeQuery(query, catalog); } catch (XMLAException e) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } private void buildURl(final String uri, final String user, final String password) { try { this.url = new URL(uri); } catch (MalformedURLException e) { e.printStackTrace(); } if ((user != null) && (user.length() > 0)) { String newUri = this.url.getProtocol() + "://" + user; //$NON-NLS-1$ if ((password != null) && (password.length() > 0)) { newUri += ":" + password; //$NON-NLS-1$ } newUri += "@" + this.url.getHost() + ":" + this.url.getPort() //$NON-NLS-1$ //$NON-NLS-2$ + this.url.getPath(); try { this.url = new URL(newUri); } catch (MalformedURLException e) { e.printStackTrace(); } } } /** * Execute query * * @param query - * MDX to be executed * @param catalog * @param handler * Callback handler * @throws XMLAException */ public boolean executeQuery(final String query, final String catalog) throws XMLAException { Object[][] columnHeaders = null; Object[][] rowHeaders = null; Object[][] data = null; int columnCount = 0; int rowCount = 0; SOAPConnection connection = null; SOAPMessage reply = null; try { connection = scf.createConnection(); SOAPMessage msg = mf.createMessage(); MimeHeaders mh = msg.getMimeHeaders(); mh.setHeader("SOAPAction", XMLABaseComponent.EXECUTE_ACTION); //$NON-NLS-1$ SOAPPart soapPart = msg.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); envelope.setEncodingStyle(XMLABaseComponent.ENCODING_STYLE); SOAPBody body = envelope.getBody(); Name nEx = envelope.createName("Execute", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eEx = body.addChildElement(nEx); eEx.setEncodingStyle(XMLABaseComponent.ENCODING_STYLE); // add the parameters // COMMAND parameter // <Command> // <Statement>select [Measures].members on Columns from // Sales</Statement> // </Command> Name nCom = envelope.createName("Command", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ SOAPElement eCommand = eEx.addChildElement(nCom); Name nSta = envelope.createName("Statement", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ SOAPElement eStatement = eCommand.addChildElement(nSta); eStatement.addTextNode(query); // <Properties> // <PropertyList> // <DataSourceInfo>Provider=MSOLAP;Data // Source=local</DataSourceInfo> // <Catalog>Foodmart 2000</Catalog> // <Format>Multidimensional</Format> // <AxisFormat>TupleFormat</AxisFormat> oder "ClusterFormat" // </PropertyList> // </Properties> Map paraList = new HashMap(); paraList.put("DataSourceInfo", dataSource); //$NON-NLS-1$ paraList.put("Catalog", catalog); //$NON-NLS-1$ paraList.put("Format", "Multidimensional"); //$NON-NLS-1$ //$NON-NLS-2$ paraList.put("AxisFormat", "TupleFormat"); //$NON-NLS-1$ //$NON-NLS-2$ addParameterList(envelope, eEx, "Properties", "PropertyList", paraList); //$NON-NLS-1$ //$NON-NLS-2$ msg.saveChanges(); debug("Request for Execute"); //$NON-NLS-1$ logSoapMsg(msg); // run the call reply = connection.call(msg, url); debug("Reply from Execute"); //$NON-NLS-1$ logSoapMsg(reply); // error check errorCheck(reply); // process the reply SOAPElement eRoot = findExecRoot(reply); // for each axis, get the positions (tuples) Name name = envelope.createName("Axes", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$ //$NON-NLS-2$ SOAPElement eAxes = selectSingleNode(eRoot, name); if (eAxes == null) { throw new XMLAException("Excecute result has no Axes element"); //$NON-NLS-1$ } name = envelope.createName("Axis", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$ //$NON-NLS-2$ Iterator itAxis = eAxes.getChildElements(name); AxisLoop: for (int iOrdinal = 0; itAxis.hasNext();) { SOAPElement eAxis = (SOAPElement) itAxis.next(); name = envelope.createName("name"); //$NON-NLS-1$ String axisName = eAxis.getAttributeValue(name); int axisOrdinal; if (axisName.equals("SlicerAxis")) { //$NON-NLS-1$ continue; } else { axisOrdinal = iOrdinal++; } name = envelope.createName("Tuples", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eTuples = selectSingleNode(eAxis, name); if (eTuples == null) { continue AxisLoop; // what else? } name = envelope.createName("Tuple", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ Iterator itTuple = eTuples.getChildElements(name); // loop over tuples int positionOrdinal = 0; while (itTuple.hasNext()) { // TupleLoop SOAPElement eTuple = (SOAPElement) itTuple.next(); if ((axisOrdinal == XMLABaseComponent.AXIS_COLUMNS) && (columnHeaders == null)) { columnCount = getChildCount(envelope, eTuples, "Tuple"); //$NON-NLS-1$ columnHeaders = new Object[getChildCount(envelope, eTuple, "Member")][columnCount]; //$NON-NLS-1$ } else if ((axisOrdinal == XMLABaseComponent.AXIS_ROWS) && (rowHeaders == null)) { rowCount = getChildCount(envelope, eTuples, "Tuple"); //$NON-NLS-1$ rowHeaders = new Object[rowCount][getChildCount(envelope, eTuple, "Member")]; //$NON-NLS-1$ } int index = 0; name = envelope.createName("Member", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ Iterator itMember = eTuple.getChildElements(name); while (itMember.hasNext()) {// MemberLoop SOAPElement eMem = (SOAPElement) itMember.next(); // loop over children nodes String caption = null; Iterator it = eMem.getChildElements(); InnerLoop: while (it.hasNext()) { Node n = (Node) it.next(); if (!(n instanceof SOAPElement)) { continue InnerLoop; } SOAPElement el = (SOAPElement) n; String enam = el.getElementName().getLocalName(); if (enam.equals("Caption")) { //$NON-NLS-1$ caption = el.getValue(); } } if (axisOrdinal == XMLABaseComponent.AXIS_COLUMNS) { columnHeaders[index][positionOrdinal] = caption; } else if (axisOrdinal == XMLABaseComponent.AXIS_ROWS) { rowHeaders[positionOrdinal][index] = caption; } ++index; } // MemberLoop ++positionOrdinal; } // TupleLoop } // AxisLoop data = new Object[rowCount][columnCount]; // loop over cells in result set name = envelope.createName("CellData", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eCellData = selectSingleNode(eRoot, name); name = envelope.createName("Cell", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ Iterator itSoapCell = eCellData.getChildElements(name); while (itSoapCell.hasNext()) { // CellLoop SOAPElement eCell = (SOAPElement) itSoapCell.next(); name = envelope.createName("CellOrdinal", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ String cellOrdinal = eCell.getAttributeValue(name); int ordinal = Integer.parseInt(cellOrdinal); name = envelope.createName("Value", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ Object value = selectSingleNode(eCell, name).getValue(); int rowLoc = ordinal / columnCount; int columnLoc = ordinal % columnCount; data[rowLoc][columnLoc] = value; } // CellLoop MemoryResultSet resultSet = new MemoryResultSet(); MemoryMetaData metaData = new MemoryMetaData(columnHeaders, rowHeaders); resultSet.setMetaData(metaData); for (Object[] element : data) { resultSet.addRow(element); } rSet = resultSet; if (resultSet != null) { if (getResultOutputName() != null) { setOutputValue(getResultOutputName(), resultSet); } return true; } return false; } catch (SOAPException se) { throw new XMLAException(se); } finally { if (connection != null) { try { connection.close(); } catch (SOAPException e) { // log and ignore error("?", e); //$NON-NLS-1$ } } } } private int getChildCount(final SOAPEnvelope envelope, final SOAPElement element, final String childName) throws SOAPException { Name name = envelope.createName(childName, "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$ Iterator iter = element.getChildElements(name); int value = 0; while (iter.hasNext()) { value++; iter.next(); } return value; } private void setProviderAndDataSource(final Map resMap) throws XMLAException { if ((resMap == null) || (resMap.size() == 0)) { error(Messages.getInstance().getString("XMLABaseComponent.ERROR_0008_NO_RESOURCE_MAP")); //$NON-NLS-1$ throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0008_NO_RESOURCE_MAP")); //$NON-NLS-1$ } String pstr = (String) resMap.get("ProviderName"); //$NON-NLS-1$ if (pstr == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0009_NO_PROVIDER_NAME")); //$NON-NLS-1$ } provider = determineProvider("Provider=" + pstr); //$NON-NLS-1$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0001_PROVIDER_ID") + provider); //$NON-NLS-1$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0002_DATASOURCE_NAME") + String.valueOf(resMap.get("DataSourceName"))); //$NON-NLS-1$ //$NON-NLS-2$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0003_DATASOURCE_INFO") + String.valueOf(resMap.get("DataSourceInfo"))); //$NON-NLS-1$ //$NON-NLS-2$ dataSource = (String) resMap.get("DataSourceInfo"); //$NON-NLS-1$ if ((dataSource == null) || (dataSource.length() < 1)) { dataSource = (String) resMap.get("DataSourceName"); //$NON-NLS-1$ } if (dataSource == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0010_NO_DATASOURCE_NAME")); //$NON-NLS-1$ } debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0004_DISCOVER_DATASOURCE_SET") + dataSource); //$NON-NLS-1$ } /** * retrieve data source properties * * @return Map of key/value strings * @see DataSourceBrowser */ public Map discoverDS() throws XMLAException { // Microsoft wants restrictions HashMap rHash = new HashMap(); HashMap pHash = new HashMap(); pHash.put("Content", "Data"); //$NON-NLS-1$ //$NON-NLS-2$ final Map resultMap = new HashMap(); Rowhandler rh = new Rowhandler() { public void handleRow(SOAPElement eRow, SOAPEnvelope envelope) { /* * <row><DataSourceName>SAP_BW</DataSourceName> * <DataSourceDescription>SAP BW Release 3.0A XML f. Analysis * Service</DataSourceDescription> * <URL>http://155.56.49.46:83/SAP/BW/XML/SOAP/XMLA</URL> * <DataSourceInfo>default</DataSourceInfo> <ProviderName>SAP * BW</ProviderName> <ProviderType>MDP</ProviderType> * <AuthenticationMode>Integrated</AuthenticationMode></row> */ Iterator it = eRow.getChildElements(); while (it.hasNext()) { Object o = it.next(); if (!(o instanceof SOAPElement)) { continue; // bypass text nodes } SOAPElement e = (SOAPElement) o; String name = e.getElementName().getLocalName(); String value = e.getValue(); resultMap.put(name, value); } } }; discover("DISCOVER_DATASOURCES", url, rHash, pHash, rh); //$NON-NLS-1$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0005_DISCOVER_DATASOURCE_FOUND") + resultMap.size()); //$NON-NLS-1$ return resultMap; } /** * discover * * @param request * @param discoverUrl * @param restrictions * @param properties * @param rh * @throws XMLAException */ private void discover(final String request, final URL discoverUrl, final Map restrictions, final Map properties, final Rowhandler rh) throws XMLAException { try { SOAPConnection connection = scf.createConnection(); SOAPMessage msg = mf.createMessage(); MimeHeaders mh = msg.getMimeHeaders(); mh.setHeader("SOAPAction", "\"urn:schemas-microsoft-com:xml-analysis:Discover\""); //$NON-NLS-1$ //$NON-NLS-2$ SOAPPart soapPart = msg.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance"); //$NON-NLS-1$//$NON-NLS-2$ envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema"); //$NON-NLS-1$ //$NON-NLS-2$ SOAPBody body = envelope.getBody(); Name nDiscover = envelope.createName("Discover", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eDiscover = body.addChildElement(nDiscover); eDiscover.setEncodingStyle(XMLABaseComponent.ENCODING_STYLE); Name nPara = envelope.createName("RequestType", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eRequestType = eDiscover.addChildElement(nPara); eRequestType.addTextNode(request); // add the parameters if (restrictions != null) { addParameterList(envelope, eDiscover, "Restrictions", "RestrictionList", restrictions); //$NON-NLS-1$ //$NON-NLS-2$ } addParameterList(envelope, eDiscover, "Properties", "PropertyList", properties); //$NON-NLS-1$//$NON-NLS-2$ msg.saveChanges(); debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0006_DISCOVER_REQUEST") + request); //$NON-NLS-1$ logSoapMsg(msg); // run the call SOAPMessage reply = connection.call(msg, discoverUrl); debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0007_DISCOVER_RESPONSE") + request); //$NON-NLS-1$ logSoapMsg(reply); errorCheck(reply); SOAPElement eRoot = findDiscoverRoot(reply); Name nRow = envelope.createName("row", "", XMLABaseComponent.ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$ Iterator itRow = eRoot.getChildElements(nRow); while (itRow.hasNext()) { // RowLoop SOAPElement eRow = (SOAPElement) itRow.next(); rh.handleRow(eRow, envelope); } // RowLoop connection.close(); } catch (UnsupportedOperationException e) { throw new XMLAException(e); } catch (SOAPException e) { throw new XMLAException(e); } } /** * add a list of Restrictions/Properties ... */ private void addParameterList(final SOAPEnvelope envelope, final SOAPElement eParent, final String typeName, final String listName, final Map params) throws SOAPException { Name nPara = envelope.createName(typeName, "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ SOAPElement eType = eParent.addChildElement(nPara); nPara = envelope.createName(listName, "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ SOAPElement eList = eType.addChildElement(nPara); if (params == null) { return; } Iterator it = params.keySet().iterator(); while (it.hasNext()) { String tag = (String) it.next(); String value = (String) params.get(tag); nPara = envelope.createName(tag, "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ SOAPElement eTag = eList.addChildElement(nPara); eTag.addTextNode(value); } } /** * locate "root" in ExecuteResponse */ private SOAPElement findExecRoot(final SOAPMessage reply) throws SOAPException, XMLAException { SOAPPart sp = reply.getSOAPPart(); SOAPEnvelope envelope = sp.getEnvelope(); SOAPBody body = envelope.getBody(); Name name; name = envelope.createName("ExecuteResponse", "m", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eResponse = selectSingleNode(body, name); if (eResponse == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0011_NO_EXECUTE_RESPONSE_ELEMENT")); //$NON-NLS-1$ } name = envelope.createName("return", "m", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eReturn = selectSingleNode(eResponse, name); name = envelope.createName("root", "", XMLABaseComponent.MDD_URI); //$NON-NLS-1$//$NON-NLS-2$ SOAPElement eRoot = selectSingleNode(eReturn, name); if (eRoot == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0012_NO_RESPONSE_ROOT_ELEMENT"));} //$NON-NLS-1$ return eRoot; } /** * locate "root" in DisoverResponse */ private SOAPElement findDiscoverRoot(final SOAPMessage reply) throws SOAPException, XMLAException { SOAPPart sp = reply.getSOAPPart(); SOAPEnvelope envelope = sp.getEnvelope(); SOAPBody body = envelope.getBody(); Name childName; SOAPElement eResponse = null; if (provider == 0) { // unknown provider - recognize by prefix of DiscoverResponse Iterator itBody = body.getChildElements(); while (itBody.hasNext()) { Node n = (Node) itBody.next(); if (!(n instanceof SOAPElement)) { continue; } Name name = ((SOAPElement) n).getElementName(); if (name.getLocalName().equals("DiscoverResponse")) { //$NON-NLS-1$ eResponse = (SOAPElement) n; provider = getProviderFromDiscoverResponse(envelope, eResponse); break; } } if (eResponse == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0013_NO_DISCOVER_RESPONSE")); //$NON-NLS-1$ } } else { if ((provider == XMLABaseComponent.PROVIDER_MICROSOFT) || (provider == XMLABaseComponent.PROVIDER_ESSBASE)) { // Microsoft // or // Essbase childName = envelope.createName("DiscoverResponse", "m", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ } else if ((provider == XMLABaseComponent.PROVIDER_SAP) || (provider == XMLABaseComponent.PROVIDER_MONDRIAN)) { // SAP // or // Mondrian childName = envelope.createName("DiscoverResponse", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ } else { throw new IllegalArgumentException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0014_NO_PROVIDER_SPEC")); //$NON-NLS-1$ } eResponse = selectSingleNode(body, childName); if (eResponse == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0015_NO_DISCOVER_RESPONSE_ELEMENT")); //$NON-NLS-1$ } } SOAPElement eReturn = getDiscoverReturn(envelope, eResponse); if (eReturn == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0016_NO_RESULT_RETURN_ELEMENT")); //$NON-NLS-1$ } SOAPElement eRoot = getDiscoverRoot(envelope, eReturn); if (eRoot == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0017_NO_RESULT_ROOT_ELEMENT")); //$NON-NLS-1$ } return eRoot; } /** * Find the Provider type in the DiscoverResponse * * @param n * @return * @throws XMLAException * @throws SOAPException */ private int getProviderFromDiscoverResponse(final SOAPEnvelope envelope, final SOAPElement e) throws XMLAException, SOAPException { Name name = e.getElementName(); if (!name.getLocalName().equals("DiscoverResponse")) { //$NON-NLS-1$ throw new XMLAException( Messages.getInstance().getString("XMLABaseComponent.ERROR_0018_NOT_A_DISCOVER_RESPONSE") + name.getLocalName()); //$NON-NLS-1$ } // Look for return/root/row/ProviderName SOAPElement walker = getDiscoverReturn(envelope, e); if (walker == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0019_NO_RESULT_DISCOVER_RESPONSE")); //$NON-NLS-1$ } walker = getDiscoverRoot(envelope, walker); if (walker == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0020_NO_RESULT_DISCOVER_RETURN_ROOT")); //$NON-NLS-1$ } walker = getDiscoverRow(envelope, walker); if (walker == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0021_NO_DISCOVER_RESPONSE_ROW")); //$NON-NLS-1$ } /* * Name nProviderName = envelope.createName("ProviderName", "", * ROWS_URI); SOAPElement eProviderName = selectSingleNode(e, * nProviderName); * * if (eProviderName == null) { throw new OlapException("Discover result * has no DiscoverResponse/return/root/row/ProviderName element"); } * value = eProviderName.getValue(); */ String value = null; Iterator it = walker.getChildElements(); while (it.hasNext()) { Object o = it.next(); if (!(o instanceof SOAPElement)) { continue; // bypass text nodes } SOAPElement e2 = (SOAPElement) o; String nameString = e2.getElementName().getLocalName(); if (nameString.equals("ProviderName")) { //$NON-NLS-1$ value = e2.getValue(); debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0008_FOUND_PROVIDER") + value); //$NON-NLS-1$ break; } } if ((value == null) || (value.trim().length() == 0)) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0022_NO_PROVIDER_NAME_ELEMENT")); //$NON-NLS-1$ } return determineProvider("Provider=" + value); //$NON-NLS-1$ } /** * Get provider id from String * * @param dataSourceString * @return provider id from OlapDiscoverer * @throws XMLAException */ private int determineProvider(final String dataSourceString) throws XMLAException { debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0009_DETERMINE_PROVIDER") + dataSourceString); //$NON-NLS-1$ if (dataSourceString == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0023_NO_DATASOURCE_GIVEN")); //$NON-NLS-1$ } String upperDSString = dataSourceString.toUpperCase(); if (!upperDSString.startsWith("PROVIDER=")) { //$NON-NLS-1$ throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0024_MALFORMED_DATASOURCE")); //$NON-NLS-1$ } if (upperDSString.startsWith("PROVIDER=SAP")) { //$NON-NLS-1$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0009_SAP_PROVIDER")); //$NON-NLS-1$ return XMLABaseComponent.PROVIDER_SAP; } else if (upperDSString.startsWith("PROVIDER=MONDRIAN")) { //$NON-NLS-1$ debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0010_MONDRIAN_PROVIDER")); //$NON-NLS-1$ return XMLABaseComponent.PROVIDER_MONDRIAN; } else if (upperDSString.startsWith("PROVIDER=MS")) { //$NON-NLS-1$ //not sure if this is needed? debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0011_MICROSOFT_PROVIDER")); //$NON-NLS-1$ return XMLABaseComponent.PROVIDER_MICROSOFT; } else if (upperDSString.startsWith("PROVIDER=MICROSOFT")) { //$NON-NLS-1$ // return value from MSAS: "Microsoft XML for Analysis" debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0011_MICROSOFT_PROVIDER")); //$NON-NLS-1$ return XMLABaseComponent.PROVIDER_MICROSOFT; // } else if (upperDSString.startsWith("PROVIDER=ESSBASE")) { //$NON-NLS-1$ // return value from MSAS: "Microsoft XML for Analysis" debug(Messages.getInstance().getString("XMLABaseComponent.DEBUG_0012_ESSBASE_PROVIDER")); //$NON-NLS-1$ return XMLABaseComponent.PROVIDER_ESSBASE; // } else { error(Messages.getInstance().getString("XMLABaseComponent.ERROR_0023_CANNOT_DETERMINE_PROVIDER") + dataSourceString); //$NON-NLS-1$ throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0024_UNSUPPORTED_PROVIDER")); //$NON-NLS-1$ } } private SOAPElement getDiscoverReturn(final SOAPEnvelope envelope, final SOAPElement e) throws XMLAException, SOAPException { Name nReturn; if ((provider == XMLABaseComponent.PROVIDER_MICROSOFT) || (provider == XMLABaseComponent.PROVIDER_ESSBASE)) { nReturn = envelope.createName("return", "m", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ } else { nReturn = envelope.createName("return", "", XMLABaseComponent.XMLA_URI); //$NON-NLS-1$ //$NON-NLS-2$ } SOAPElement eReturn = selectSingleNode(e, nReturn); if (eReturn == null) { // old Microsoft XMLA SDK 1.0 does not have "m" prefix - try nReturn = envelope.createName("return", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ eReturn = selectSingleNode(e, nReturn); if (eReturn == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0025_NO_RETURN_DISCOVER_ELEMENT")); //$NON-NLS-1$ } } return eReturn; } private SOAPElement getDiscoverRoot(final SOAPEnvelope envelope, final SOAPElement e) throws XMLAException, SOAPException { Name nRoot = envelope.createName("root", "", XMLABaseComponent.ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$ SOAPElement eRoot = selectSingleNode(e, nRoot); if (eRoot == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0026_NO_ROOT_DISCOVER_ELEMENT"));} //$NON-NLS-1$ return eRoot; } private SOAPElement getDiscoverRow(final SOAPEnvelope envelope, final SOAPElement e) throws XMLAException, SOAPException { Name nRow = envelope.createName("row", "", XMLABaseComponent.ROWS_URI); //$NON-NLS-1$ //$NON-NLS-2$ SOAPElement eRow = selectSingleNode(e, nRow); if (eRow == null) { throw new XMLAException(Messages.getInstance().getString("XMLABaseComponent.ERROR_0027_NO_DISCOVER_ROW_ELEMENT"));} //$NON-NLS-1$ return eRow; } // error check private void errorCheck(final SOAPMessage reply) throws SOAPException, XMLAException { String[] strings = new String[4]; if (soapFault(reply, strings)) { String faultString = "Soap Fault code=" + strings[0] + " fault string=" + strings[1] + " fault actor=" + strings[2]; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ if (strings[3] != null) { faultString += "\ndetail:" + strings[3]; //$NON-NLS-1$ } throw new XMLAException(faultString); } } /** * check SOAP reply for Error, return fault Code * * @param reply * the message to check * @param aReturn * ArrayList containing faultcode,faultstring,faultactor */ private boolean soapFault(final SOAPMessage reply, final String[] faults) throws SOAPException { SOAPPart sp = reply.getSOAPPart(); SOAPEnvelope envelope = sp.getEnvelope(); SOAPBody body = envelope.getBody(); if (!body.hasFault()) { return false; } SOAPFault fault = body.getFault(); faults[0] = fault.getFaultCode(); faults[1] = fault.getFaultString(); faults[2] = fault.getFaultActor(); // probably not neccessary with Microsoft; Detail detail = fault.getDetail(); if (detail == null) { return true; } String detailMsg = ""; //$NON-NLS-1$ Iterator it = detail.getDetailEntries(); for (; it.hasNext();) { DetailEntry det = (DetailEntry) it.next(); Iterator ita = det.getAllAttributes(); for (boolean cont = false; ita.hasNext(); cont = true) { Name name = (Name) ita.next(); if (cont) { detailMsg += "; "; //$NON-NLS-1$ } detailMsg += name.getLocalName(); detailMsg += " = "; //$NON-NLS-1$ detailMsg += det.getAttributeValue(name); } } faults[3] = detailMsg; return true; } /** * @param contextNode * @param childPath * @return */ private SOAPElement selectSingleNode(final SOAPElement contextNode, final Name childName) { Iterator it = contextNode.getChildElements(childName); if (it.hasNext()) { return (SOAPElement) it.next(); } return null; } /** * log the reply message */ private void logSoapMsg(final SOAPMessage msg) { try { Writer writer = new StringWriter(); TransformerFactory tFact = TransformerFactory.newInstance(); Transformer transformer = tFact.newTransformer(); Source src = msg.getSOAPPart().getContent(); StreamResult result = new StreamResult(writer); transformer.transform(src, result); debug(writer.toString()); } catch (Exception e) { // no big problen - just for debugging error("?", e); //$NON-NLS-1$ } } public void dispose() { } @Override public boolean init() { return true; } }