Tuesday, December 11, 2012

Consuming webMethods WSD in C#.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;


namespace TANFWorkSearch
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var ws = new TANFWorkSearchWSD.TANFWorkSearch();


            TANFWorkSearchWSD.WorkSearchOut wsInput = new TANFWorkSearchWSD.WorkSearchOut();


            DateTime dateTime = DateTime.Now;
            TANFWorkSearchWSD.SGData sgData = new TANFWorkSearchWSD.SGData();
            sgData.RequestEnvironment = TANFWorkSearchWSD.RequestEnvironment.C;
            sgData.RequestTimeStamp = dateTime;
            sgData.Caller = TANFWorkSearchWSD.Caller.C;
            sgData.ServiceVersion = "serviceVersionPlaceHolder";


            TANFWorkSearchWSD.BusinessData businessData = new TANFWorkSearchWSD.BusinessData();


            TANFWorkSearchWSD.Individual individual = new TANFWorkSearchWSD.Individual();
            double recID=12.30;
            individual.RecipientID = recID.ToString();
            individual.FirstName = "firstName";
            individual.LastName = "lastName";
            individual.MiddleInitial = "Middle";
            individual.DOB =dateTime;
            individual.SSN = "1234";
            individual.BeginDate = dateTime;
            individual.EndDate = dateTime;
            individual.UserID = "1234";
            individual.ParticipantID = "1234";


            ws.GetWorkSearchInfo(wsInput);


        }
    }
}

Search String in text file and return line number.

Inputs:
searchString
fileName

outputs:
exists
lineNum
error

Code:
IDataCursor pipelineCursor = pipeline.getCursor();
        String    searchString = IDataUtil.getString( pipelineCursor, "searchString" );
        String    fileName = IDataUtil.getString( pipelineCursor, "fileName" );
        pipelineCursor.destroy();
        
        File file=new File(fileName);    
        int lineNum = 0;
        
        try {
            Scanner in = new Scanner(new FileReader(file));
            
            while (in.hasNext()) {
            String inString = in.nextLine().toLowerCase();
            if( inString.indexOf( searchString ) >= 0) 
            {             
                IDataUtil.put( pipelineCursor, "lineNum", Integer.toString(lineNum));
                IDataUtil.put( pipelineCursor, "exists", "true");
                break;
            }
            else{
                IDataUtil.put( pipelineCursor, "exists", "false");
            }
            lineNum++;
            }            
        } catch (FileNotFoundException e) {        
            IDataUtil.put( pipelineCursor, "error", e.toString());
        }
        pipelineCursor.destroy();
Imports:

Code:
import java.io.FileReader;
import java.util.Scanner;
import java.io.File;

Split one large file to multiple small files based on break length - Large file handling.

Inputs:

fileName: Absolute File Name path to be split.
lineBreak: number of lines when the break needs to happen.
outFileNamePrefix: output file name prefix, absolute path.

Code:


IDataCursor pipelineCursor = pipeline.getCursor();
  String fileName = IDataUtil.getString( pipelineCursor, "fileName" );
  String lineBreak = IDataUtil.getString( pipelineCursor, "lineBreak" );
  String outFileNamePrefix = IDataUtil.getString( pipelineCursor, "outFileNamePrefix" );
  pipelineCursor.destroy();  
  
  int breakLenInt=Integer.parseInt(lineBreak);
  int count=0;
  int currentLineNumber=0;
  String line=null;
  
  FileInputStream inputStream;
  FileWriter fstream;
  
  try {
   inputStream = new FileInputStream(new File(fileName));
   InputStreamReader streamReader = new InputStreamReader(inputStream, "UTF-8");
   BufferedReader reader = new BufferedReader(streamReader);
   while ((line=reader.readLine())!=null){
    if(currentLineNumber<breakLenInt){
     String outFile=outFileNamePrefix+"_"+count+".txt";
  
     fstream = new FileWriter(outFile,true);
     BufferedWriter bw=new BufferedWriter(fstream);
  
     bw.write(line);
     bw.newLine();
     bw.close();
     
     currentLineNumber++;
    }
    else{
     breakLenInt=breakLenInt+Integer.parseInt(lineBreak);
     count++;
    }
   }
   reader.close();
   streamReader.close();
   IDataUtil.put( pipelineCursor, "result", "Success" );
  } catch (FileNotFoundException e) {
   IDataUtil.put( pipelineCursor, "result", e.toString() );
  } catch (UnsupportedEncodingException e) {
   IDataUtil.put( pipelineCursor, "result", e.toString() );
  } catch (IOException e) {
   IDataUtil.put( pipelineCursor, "result", e.toString() );
  }

Friday, April 20, 2012

Convert an XML Node in pipeline to String.

When dealing with content handlers the data will come in to the pipeline as an XML node object $contentStream. This code will help convert that xml node object to string and stream outputs.

Input: node, datatype: object
Output: outString, datatype: String & outStream, datatype: object

Import the below classes.


import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Node;


Code:


IDataCursor pipelineCursor = pipeline.getCursor();
        Node node = (Node) IDataUtil.get( pipelineCursor, "node" );
        pipelineCursor.destroy();
        
        StringWriter sw = new StringWriter();
            try {
                
              Transformer t = TransformerFactory.newInstance().newTransformer();
              t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
              t.setOutputProperty(OutputKeys.INDENT, "yes");
              t.transform(new DOMSource(node), new StreamResult(sw));
              // convert to string debug...........
              String x=sw.toString();
              IDataUtil.put( pipelineCursor, "outStr", x);
             
              InputStream outStream = new ByteArrayInputStream(x.getBytes("UTF-8"));
              IDataUtil.put( pipelineCursor, "outStream", outStream);
              
            } catch (TransformerException e) {              
              IDataUtil.put( pipelineCursor, "outStr", e);
          } catch (UnsupportedEncodingException e) {
              IDataUtil.put( pipelineCursor, "outStr", e);
            }


Monday, January 16, 2012

Web service aliases usage in webMethods

A web service alias can be used effectively to manage the endpoints and the credentials for a web service outside of the code. Using web service aliases will remove the need for code changes or property file changes while pointing the web services to different environments.

"A Web service endpoint alias represents the network address and, optionally, any
security credentials to be used with Web services. The network address properties can be
used to enable dynamic addressing for Web services. The security credentials can be used
to control both transport-level and message-level security for Web services."
- Administering_Integration_Server.pdf

As long as the WSDL context remains the same and only the endpoint or the port changes between different environments of the Consumer WSDL, the aliases can be used to re-point the web service from the IS Admin page with out a need for a deployment.


Steps for HTTP web service alias:

1. Create a consumer HTTP web service alias on the IS Admin page with the endpoint settings from the consumer WSDL.
2. Consume a WSDL on to the webMethods Developer and open the WSD. Click on the binders tab and select the binder.
3. In the properties pane click on the drop down for port alias and select the port alias created in step 1. If it does not show up then reload the package and try again.
4. Now save the consumer WSD and start calling the web service connector. The connection details for this WSD will be taken from the web service alias.

Steps for HTTP web service alias:

1. Create a Keystore alias and a key alias with the client certificate configured.
2. Create a HTTPS web service alias with the end point details from the WSDL. Use the keystore and key alias created in step1 while configuring the HTTPS alias.
3. Consume the WSDL on to the webMethods Developer and open the WSD. Click on the binders tab and select the binder.
4. In the properties pane click on the drop down for the port alias and select the port alias created in step 2. If it does not show up then reload the package and try again.
5. Now save the consumer WSD and start calling the web service connector. The connection details for thisWSD will be takem from the web service alias.

Note:


  • A HTTP web service alias will not show up as an available port alias for a HTTPS WSD and vice versa.
  • IS will interpret the WSDL as-is and generate a HTTP or HTTPS WSD based on the endpoint definition in the WSDL. If you want to generate a HTTPS WSD for a HTTP WSDL then edit the WSDL and change the address location to HTTPS.

For ex:

If the WSDL has an endpoint defined as below, IS will create a HTTP WSD.

<service name="CreditScoreWebService">
    <port name=" CreditScoreEndpointPort" binding="tns: CreditScoreServiceEndpointPortBinding">
      <soap:address location="http://test.google.com:5555/creditscore/ CreditScoreWebService"/>
    </port>
  </service>


If the same WSDL has an endpoint defined as below, IS will create a HTTPS WSD.

<service name="CreditScoreWebService">
    <port name=" CreditScoreEndpointPort" binding="tns: CreditScoreServiceEndpointPortBinding">
      <soap:address location="https://test.google.com:5555/creditscore/ CreditScoreWebService"/>
    </port>
  </service>


Enable SOAP Request/Response Logging

In webMethods while trouble shooting issues with third party web services integration can be done using the Flow service level logging, in order to capture the raw SOAP request at the server level the following extended settings need to be set to true.

watt.server.SoapRPC.debug
watt.server.SoapRPC.trace
watt.server.SoapRPC.verbose

Enabling these settings will capture the raw SOAP request and reponses at the IS level.

Steps:

1. Go to the extended settings on the IS Admin page.
2. Click the show and hide keys URL.
3. select the above mentioned three settings and click save.
4. After the options show up on the extended settings page, edit the settings to set to true to enable the SOAP logging or set to false to disable the logging.

Note:

Enabling this logging setting for a prolonged period of time is not recommended as this will flood the logs with all the SOAP request/responses happening on the server.

Consuming WSDL when schema's are not reachable

In this post i will discuss how to consume a WSDL which has references to remote schema's through URL references.

Most of the times the development boxes are not in the DMZ of the network because of various security reasons and this will make consuming third party vendor WSDL's hosted outside of the intranet a bit painful in webMethods. In order to over come this problem we can edit the WSDL locally by modifying the URL/URI locations to either include the XSD's in the WSDL or to give a file reference to the locally downloaded locations.

Steps:

1. Download the WSDL and the XSD's from the remote location from a box where you can access them.
2. Now copy all these files to the target package resources directory.
Ex ..\integrationserver\pacakgeName\resources
3. Open the WSDL in eclipse or an XML editor and remove the URL references to the XSD's to a file location using the "file://"

ex:
before the change:


  <xsd:import namespace="http://remote.service.functionality.pogeneration.google.com/" schemaLocation="POGenerationWebService_schema1.xsd" />


After the change:
 <xsd:import namespace="http://remote.service.functionality.pogeneration.google.com/" schemaLocation="file:///D:/SoftwareAG/IntegrationServer/packages/packageName/resources/POGenerationWebService_schema1.xsd"/>

or

 <xsd:import namespace="http://remote.service.functionality.pogeneration.google.com/" schemaLocation="file:///../POGenerationWebService_schema1.xsd"/>



4. Repeat for all the XSD references and validate the WSDL in eclipse.
5. If the WSDL is valid after the changes then go to Developer and consume the wsdl.

The reason for them being put in the resources directory is to make sure that all the artifacts are bundled in the same package and can be ported during the deployment.

Cons:

  • Maintaining a new version of the WSDL than the one from the client.
  • Maintaining the schemas up to date from the client.


MTOM implementation

In this post i will be discussing how to send email with MTOM attachments using webMethods services.

Steps:

1. Create a Flow service senderSvc which will get an image file and then convert it to a base64 encoded string. This is our harness service replicating the Data feeder.
2. Create a Flow service service B with the inputs fileName (String) and data (string with the base64Binary contentType set). The output is a success (string) flag. This will be the receiver service.
3. Create a producer WSD receiverWSD for the receiverSvc and set the property attachment enabeld to true.
4. Consume the receiver WSD and make a call to the connector in senderSvc.
5. post the data from senderSvc to be received by receiverSvc and then send to an email using the pub.client:smtp service.

senderSvc:

receiverSvc:



Sample email:




Friday, January 13, 2012

Setting up Designer

In this tutorial you will learn how to setup Designer for developement.

1. Click on the Window ->preferences->SoftwareAG->IntegrationServers.




2. Click Add and then add the IS that you want to connect to for the development.

3. click on verify server and if the test is successful then the configuration is complete.