/*! * 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 (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.action.xmla; 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; 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 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 java.util.Locale; 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( Locale.US ); 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; } }