/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.pentaho.di.trans.steps.webservices;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.plugins.StepPluginType;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaBigNumber;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.trans.RowProducer;
import org.pentaho.di.trans.RowStepCollector;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransHopMeta;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.TransformationTestCase;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.steps.dummytrans.DummyTransMeta;
import org.pentaho.di.trans.steps.injector.InjectorMeta;
import org.pentaho.metastore.api.IMetaStore;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
/**
* User: Dzmitry Stsiapanau Date: 2/12/14 Time: 5:15 PM
*/
public class WebServiceTest extends TransformationTestCase {
private static final String WSDL =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<definitions xmlns=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
+ " xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:tns=\"http://webservices.daehosting"
+ ".com/temperature\" name=\"TemperatureConversions\" targetNamespace=\"http://webservices.daehosting"
+ ".com/temperature\">\n"
+ " <types>\n"
+ " <xs:schema elementFormDefault=\"qualified\" targetNamespace=\"http://webservices.daehosting"
+ ".com/temperature\">\n"
+ " <xs:element name=\"CelciusToFahrenheit\">\n"
+ " <xs:complexType>\n"
+ " <xs:sequence>\n"
+ " <xs:element name=\"nCelcius\" type=\"xs:decimal\"/>\n"
+ " </xs:sequence>\n"
+ " </xs:complexType>\n"
+ " </xs:element>\n"
+ " <xs:element name=\"CelciusToFahrenheitResponse\">\n"
+ " <xs:complexType>\n"
+ " <xs:sequence>\n"
+ " <xs:element name=\"CelciusToFahrenheitResult\" type=\"xs:decimal\"/>\n"
+ " </xs:sequence>\n"
+ " </xs:complexType>\n"
+ " </xs:element>\n"
+ " </xs:schema>\n"
+ " </types>\n"
+ " <message name=\"CelciusToFahrenheitSoapRequest\">\n"
+ " <part name=\"parameters\" element=\"tns:CelciusToFahrenheit\"/>\n"
+ " </message>\n"
+ " <message name=\"CelciusToFahrenheitSoapResponse\">\n"
+ " <part name=\"parameters\" element=\"tns:CelciusToFahrenheitResponse\"/>\n"
+ " </message>\n"
+ " <portType name=\"TemperatureConversionsSoapType\">\n"
+ " <operation name=\"CelciusToFahrenheit\">\n"
+ " <documentation>Converts a Celcius Temperature to a Fahrenheit value</documentation>\n"
+ " <input message=\"tns:CelciusToFahrenheitSoapRequest\"/>\n"
+ " <output message=\"tns:CelciusToFahrenheitSoapResponse\"/>\n"
+ " </operation>\n"
+ " </portType>\n"
+ " <binding name=\"TemperatureConversionsSoapBinding\" type=\"tns:TemperatureConversionsSoapType\">\n"
+ " <soap:binding style=\"document\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n"
+ " <operation name=\"CelciusToFahrenheit\">\n"
+ " <soap:operation soapAction=\"\" style=\"document\"/>\n"
+ " <input>\n"
+ " <soap:body use=\"literal\"/>\n"
+ " </input>\n"
+ " <output>\n"
+ " <soap:body use=\"literal\"/>\n"
+ " </output>\n"
+ " </operation>\n"
+ " </binding>\n"
+ " <service name=\"TemperatureConversions\">\n"
+ " <documentation>Visual DataFlex Web Service to convert temperature values between Celcius and "
+ "Fahrenheit</documentation>\n"
+ " <port name=\"TemperatureConversionsSoap\" binding=\"tns:TemperatureConversionsSoapBinding\">\n"
+ " <soap:address location=\"HTTP_LOCALHOST_PLACEHOLDERwso\"/>\n" + " </port>\n" + " </service>\n"
+ "</definitions>\n";
private static final String STEP_META =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ " <step>\n"
+ " <name>Get Celcius 2</name>\n"
+ " <type>WebServiceLookup</type>\n"
+ " <description/>\n"
+ " <distribute>Y</distribute>\n"
+ " <custom_distribution/>\n"
+ " <copies>1</copies>\n"
+ " <partitioning>\n"
+ " <method>none</method>\n"
+ " <schema_name/>\n"
+ " </partitioning>\n"
+ " <wsURL>http://localhost:9998/wsdl</wsURL>\n"
+ " <wsOperation>CelciusToFahrenheit</wsOperation>\n"
+ " <wsOperationRequest/>\n"
+ " <wsOperationNamespace>http://webservices.daehosting.com/"
+ "temperature</wsOperationNamespace>\n"
+ " <wsInFieldContainer/>\n" + " <wsInFieldArgument/>\n"
+ " <wsOutFieldContainer>CelciusToFahrenheitResult</wsOutFieldContainer>\n"
+ " <wsOutFieldArgument>CelciusToFahrenheitResult</wsOutFieldArgument>\n" + " <proxyHost/>\n"
+ " <proxyPort/>\n" + " <httpLogin/>\n" + " <httpPassword/>\n" + " <callStep>1</callStep>\n"
+ " <passingInputData>Y</passingInputData>\n" + " <compatible>Y</compatible>\n"
+ " <repeating_element/>\n" + " <reply_as_string>Y</reply_as_string>\n" + " <fieldsIn>\n"
+ " <field>\n" + " <name>integer_20</name>\n" + " <wsName>nCelcius</wsName>\n"
+ " <xsdType>decimal</xsdType>\n" + " </field>\n" + " </fieldsIn>\n" + " <fieldsOut>\n"
+ " <field>\n" + " <name>CelciusToFahrenheitResult</name>\n"
+ " <wsName>CelciusToFahrenheitResult</wsName>\n" + " <xsdType>decimal</xsdType>\n"
+ " </field>\n" + " </fieldsOut>\n" + " <cluster_schema/>\n"
+ " <remotesteps> <input> </input> <output> </output> </remotesteps> <GUI>\n"
+ " <xloc>779</xloc>\n" + " <yloc>231</yloc>\n" + " <draw>Y</draw>\n" + " </GUI>\n"
+ " </step>\n";
private static final String RESPONSE_BODY = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" + " <soap:Body>\n"
+ " <CelciusToFahrenheitResponse xmlns=\"http://webservices.daehosting.com/temperature\">\n"
+ " <CelciusToFahrenheitResult>decimal</CelciusToFahrenheitResult>\n"
+ " </CelciusToFahrenheitResponse>\n" + " </soap:Body>\n" + "</soap:Envelope>";
public static final String host = "localhost";
public static final int port = 9998;
public static final String HTTP_LOCALHOST_9998 = "http://localhost:9998/";
private static HttpServer httpServer;
public WebServiceTest() throws KettleException {
super();
}
@Override
public void setUp() throws Exception {
startHttpAnswer();
}
@Override
public void tearDown() throws Exception {
httpServer.stop( 0 );
}
public void testProcessRow() throws Exception {
KettleEnvironment.init();
//
// Create a new transformation...
//
TransMeta transMeta = new TransMeta();
transMeta.setName( "WebServiceTest" );
PluginRegistry registry = PluginRegistry.getInstance();
//
// create an injector step...
//
String injectorStepname = "injector step";
InjectorMeta im = new InjectorMeta();
// Set the information of the injector.
String injectorPid = registry.getPluginId( StepPluginType.class, im );
StepMeta injectorStep = new StepMeta( injectorPid, injectorStepname, im );
transMeta.addStep( injectorStep );
//
// Create a dummy step 1
//
String dummyStepname1 = "dummy step 1";
DummyTransMeta dm1 = new DummyTransMeta();
String dummyPid1 = registry.getPluginId( StepPluginType.class, dm1 );
StepMeta dummyStep1 = new StepMeta( dummyPid1, dummyStepname1, dm1 );
transMeta.addStep( dummyStep1 );
TransHopMeta hi = new TransHopMeta( injectorStep, dummyStep1 );
transMeta.addTransHop( hi );
//
// Create a String Cut step
//
String webServiceStepname = "web service step";
WebServiceMeta scm = new WebServiceMeta();
// scm.setUrl(HTTP_LOCALHOST_9998+ "wsdl");
// scm.setOperationName("CelciusToFahrenheit");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse( new InputSource( new java.io.StringReader( STEP_META ) ) );
scm.loadXML( doc.getFirstChild(), null, (IMetaStore) null );
String webServicePid = registry.getPluginId( StepPluginType.class, scm );
StepMeta webServiceStep = new StepMeta( webServicePid, webServiceStepname, scm );
transMeta.addStep( webServiceStep );
TransHopMeta hi2 = new TransHopMeta( dummyStep1, webServiceStep );
transMeta.addTransHop( hi2 );
//
// Create a dummy step 2
//
String dummyStepname2 = "dummy step 2";
DummyTransMeta dm2 = new DummyTransMeta();
String dummyPid2 = registry.getPluginId( StepPluginType.class, dm2 );
StepMeta dummyStep2 = new StepMeta( dummyPid2, dummyStepname2, dm2 );
transMeta.addStep( dummyStep2 );
TransHopMeta hi3 = new TransHopMeta( webServiceStep, dummyStep2 );
transMeta.addTransHop( hi3 );
// Now execute the transformation...
Trans trans = new Trans( transMeta );
trans.prepareExecution( null );
StepInterface si = trans.getStepInterface( dummyStepname1, 0 );
RowStepCollector dummyRc1 = new RowStepCollector();
si.addRowListener( dummyRc1 );
si = trans.getStepInterface( webServiceStepname, 0 );
RowStepCollector webServiceRc = new RowStepCollector();
si.addRowListener( webServiceRc );
RowProducer rp = trans.addRowProducer( injectorStepname, 0 );
trans.startThreads();
// add rows
List<RowMetaAndData> inputList = createData( createRowMetaInterface(), new Object[][] { new Object[] { 10 } } );
for ( RowMetaAndData rm : inputList ) {
rp.putRow( rm.getRowMeta(), rm.getData() );
}
rp.finished();
trans.waitUntilFinished();
List<RowMetaAndData> goldRows =
createData( createOutputRowMetaInterface(), new Object[][] { new Object[] { 10,
new BigDecimal( 20 ) } } );
List<RowMetaAndData> resultRows2 = webServiceRc.getRowsWritten();
assertEquals( goldRows, resultRows2 );
}
public RowMetaInterface createRowMetaInterface() {
return createRowMetaInterface( new ValueMetaString( "integer_20" ) );
}
public RowMetaInterface createOutputRowMetaInterface() {
return createRowMetaInterface( new ValueMetaString( "integer_20" ), new ValueMetaBigNumber(
"CelciusToFahrenheitResult" ) );
}
private static void startHttpAnswer() throws IOException {
httpServer = HttpServer.create( new InetSocketAddress( host, port ), 10 );
httpServer.createContext( "/wsdl", new HttpHandler() {
@Override
public void handle( HttpExchange httpExchange ) throws IOException {
String response = WSDL.replaceAll( "HTTP_LOCALHOST_PLACEHOLDER", HTTP_LOCALHOST_9998 );
byte[] bodyBytes = response.getBytes( "UTF-8" );
httpExchange.sendResponseHeaders( 200, bodyBytes.length );
httpExchange.getResponseBody().write( bodyBytes );
httpExchange.close();
}
} );
httpServer.createContext( "/wso", new HttpHandler() {
@Override
public void handle( HttpExchange httpExchange ) throws IOException {
String response = RESPONSE_BODY.replaceAll( "decimal", "20" );
byte[] bodyBytes = response.getBytes( "UTF-8" );
httpExchange.getResponseHeaders().add( "Content-Type", "text/xml; charset=utf-8" );
httpExchange.sendResponseHeaders( 200, bodyBytes.length );
httpExchange.getResponseBody().write( bodyBytes );
httpExchange.close();
}
} );
httpServer.start();
}
}