/*!
* 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;
}
}