Wednesday, July 5, 2017

AS4 Messaging Standard

AS4 is a recent B2B messaging standard. It can exchange any type of payloads (XML, JSON, Binary, ect.) and also it supports sending multiple payloads in one AS4 message.

AS4 originates from ebXML (Electronic Business XML). AS4 Profile of ebMS 3.0 which is a conformance profile of AS4 defines the following 3 conformance profiles (CP) defining subsets of ebMS V3 options to be supported by an AS4 Message Service Handler (MSH).

  • AS4 ebHandler CP
  • AS4 Light Client CP
  • AS4 Minimal Client CP

AS4 Messaging Model


AS4 defines a Four-Corner-Model including the components involved in a message exchange. Following are the entities of this four-corner-model.

Message Producer: Business application which sends the message content to the sending Message Service Handler(MSH).

Sending Message Service Handler: Packages the message content and sends to the intended receiving MSH.

Receiving Message Service Handler: Receive the message from the sending MSH.

Message Consumer: The business application which receives the message content from receiving MSH.





The above-mentioned conformance profiles of AS4 Profile of ebMS 3.0 defines supported different subsets of AS4 profile options by an AS4 Message Service Handler.
  • The message sent from the producer to the sending MSH can be of any format agreed by those two entities.
  • Similarly, the messages exchanged between the receiving MSH and the consumer can be of any format.
  • AS4 defines the message format being exchanged between the sending MSH and receiving MSH.
  • Apart from that AS4 P-mode configuration files which reside in the MSHs instruct on how to handle AS4 messages.


AS4 Message Exchange Patters (MEPs)


In AS4, there are two message exchange patterns. 
  • One-way / Push
    • In one-way / push MEP, the sending MSH sends the AS4 user message containing payloads to the receiving MSH. The initiator is the sending MSH.
  • One-way / Pull
    • In one-way / pull MEP, the receiving MSH sends a pull request signal message to the sending MSH. Then the sending MSH sends the user message. The initiator in this MEP is the receiving MSH.

Image result for as4 one way pull


AS4 Minimal Client Profile

As per the specification AS4 minimal client profile applies only to one side of an MEP (acting as a “client” to the other party).

P-Mode configuration file for AS4 Minimal Client Profile



      push
      http://wso2.org/examples/agreement0
      http://www.oasis-open.org/committees/ebxml-msg/one-way
      http://www.oasis-open.org/committees/ebxml-msg/push
      
           org:wso2:example:company:A
           Sender
      
      
           org:wso2:example:company:B
           Receiver
      
      
           
http://localhost:8280/as4Test
1.2
Examples StoreMessage true true


Wednesday, May 24, 2017

ESB Message Flow

Sample proxy configuration


   
      
         
         
            
               


1. Go inside /samples/axis2Server  and start the simple axis2service :  ./axis2server.sh

2. To send a request to the above proxy, go inside /samples/axis2Client and run the command: ant stockquote -Daddurl=http://localhost:8280/services/TestProxy

So now let's analyze the message In-flow inside ESB.

Message In-Flow

ProxyServiceMessageReceiver is the entry point to Synapse.

Once a message is sent to a proxy service deployed in ESB, is will come to the,

org.apache.synapse.core.axis2.ProxyServiceMessageReceiver::receive()
Receive method here gets a org.apache.axis2.context.MessageContext object.

In the Axis2 level, it uses Axis2 MessageContext. In the mediation engine level, that is, in the Synapse level it needs to be converted to SynapseMessageContext. This is done by MessageContextCreatorForAxis2

Inside the org.apache.synapse.core.axis2.MessageContextCreatorForAxis2::getSynapseMessageContext() method it will get the SynapseConfiguration from AxisConfiguration and get the SynapseEnvironment from AxisConfiguration

Message mediation starts thereafter inside the org.apache.synapse.mediators.base.SequenceMediator::mediate() method. Inside this method, following method call will call to AbstractListMediator::mediate() method.

boolean result = super.mediate(synCtx);


Message mediation starts thereafter inside the org.apache.synapse.mediators.base.SequenceMediator::mediate() method. Inside this method, following method call will call to AbstractListMediator::mediate() method.

boolean result = super.mediate(synCtx);

AbstractListMediator::mediate() method iterate through all the mediators in the mediation flow and verify whether there are content aware mediators exist in the mediation flow. If there are any, it will call AbstractListMediator::buildMessage() in order to build the message.

if (sequenceContentAware && mediator.isContentAware() &&
          (!Boolean.TRUE.equals(synCtx.getProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED)))) {
          buildMessage(synCtx, synLog);
}

Finally when the SequenceMediator::mediate() method returns true to the ProxyMessageReceiver::receive(), it will send the message to the endpoint.

// if inSequence returns true, forward message to endpointif(inSequenceResult) {
    if (proxy.getTargetEndpoint() != null) {
        Endpoint endpoint = synCtx.getEndpoint(proxy.getTargetEndpoint());

        if (endpoint != null) {
            traceOrDebug(traceOn, "Forwarding message to the endpoint : "                + proxy.getTargetEndpoint());
            endpoint.send(synCtx);

        } else {
            handleException("Unable to find the endpoint specified : " +
                proxy.getTargetEndpoint(), synCtx);
        }

    } else if (proxy.getTargetInLineEndpoint() != null) {
        traceOrDebug(traceOn, "Forwarding the message to the anonymous " +
            "endpoint of the proxy service");
        proxy.getTargetInLineEndpoint().send(synCtx);
    }
}

Exit point from the synapse is org.apache.synapse.core.axis2.Axis2FlexibleMEPClient::send() method.

When a response is returned from the backend, ESB needs to send it back to the client. This message flow is called message Out-Flow. Let's analyze the message out-flow.

Message Out-Flow

In the response path, the entry point to Synapse is org.apache.synapse.core.axis2.SynapseCallbackReceiver::receive() method.

Inside this method, org.apache.synapse.core.axis2.SynapseCallbackReceiver::handleMessage() is called. This method will handle the response or error.

This will call
synapseOutMsgCtx.getEnvironment().injectMessage(synapseInMessageContext);
which will send the response message through the synapse mediation flow.

Thursday, January 7, 2016

How to use Analytics JavaScript (JS) API in a JavaScript Client

In this post I'm going to create a simple JavaScript Client and show you how to use WSO2 Data Analytics Server 3.0.0 JavaScript API within it.

You can download the WSO2 Data Analytics Server 3.0.0 from here.

Extract the downloaded wso2das-3.0.0.zip file and create a folder inside DAS_HOME/repository/deployment/server/webapps/, with the name analytics-client.

Inside the analytics-client, create a folder with the name js. We keep this folder to store the imported JavaScript files in our web app.

Copy the following files from DAS_HOME/repository/deployment/server/jaggeryapps/portal/js/ into the js folder you created earlier.
  • carbon-analytics.js  
  • jquery-1.10.2.js
Now create the index.html file with the following content inside the analytics-client folder.


 

  DAS JS Client
  
  

  

 
 
 

Analytics JS Client



Now, start the server. Go to DAS_HOME/bin and execute the command, ./wso2server.sh

To invoke your web app from the browser, give the following url.

https://localhost:9443/analytics-client/index.html

Since we have used console.log() to display JavaScript values, activate debugging in your browser with F12, and select "Console" in the debugger menu. 

You can try more JavaScript functions exposed in Analytics JS API referring to the Data Analytics Server documentation.

References :

[1] https://docs.wso2.com/display/DAS300/Analytics+JavaScript+%28JS%29+API
[2] http://www.w3schools.com/js/js_debugging.asp


Saturday, August 29, 2015

Create a simple server with current directory's content using Python SimpleHTTPServer

When using Linux in a network environment you may want to get some files in one computer to another. Python's SimpleHTTPServer is a great tool which can be used to serve the contents of the current directory from the command line.

You just need to go inside the relevant folder using command line and give the following command.
This will start a server in port 8000 in your machine which hosts the contents of the current folder.

python -m SimpleHTTPServer

Then you can download the files from another machine using the curl command as below.

curl http://:8000/file-name.extension > file-name.extension 

Here's another way of making the current directory an http server with ruby

ruby -run -e httpd -- --port=8000

[1] https://docs.python.org/2/library/simplehttpserver.html

Thursday, April 23, 2015

Download File or Java Serializable object with REST

In this post I'm going to tell how to export a file or Serialzable java object in the server using a REST api call.

From the client's perspective he is downloading a file.
If you want to enable downloading a file in the server you can do it in the following way.
    @GET
    @Path("/{modelName}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response exportFile(@PathParam("modelName") String modelName) {

        try {
            MLModelNew model = mlModelHandler.getModel(tenantId, userName, modelName);
            if(model != null) {
                String filePath = model.getStorageDirectory();
                File file = new File(filePath);
                return Response.ok(file).build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        } catch (MLModelHandlerException e) {
            logger.error(String.format(
                    "Error while retrieving model [name] %s. Cause: %s",
                    modelName, e.getMessage()));
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
        }
    }
There's another useful scenario of downloading a java serializable object as it is. This can be done by sending it as a stream. Here is how you can send a java object as a stream.
This example send an object type of MLModel as a stream.
    @GET
    @Path("/{modelName}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response exportModel(@PathParam("modelName") String modelName) {

        try {
            MLModelNew model = mlModelHandler.getModel(tenantId, userName, modelName);
            if(model != null) {
                final MLModel generateModel = mlModelHandler.retrieveModel(model.getId());
                StreamingOutput stream = new StreamingOutput() {
                    public void write(OutputStream outputStream) throws IOException {
                        ObjectOutputStream out = new ObjectOutputStream(outputStream);
                        out.writeObject(generateModel);
                    }
                };
                return Response.ok(stream).build();
            } else {
                return Response.status(Response.Status.NOT_FOUND).build();
            }
        } catch (Exception e) {
            logger.error(String.format(
                    "Error while retrieving model [name] %s. Cause: %s",
                    modelName, e.getMessage()));
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
        } 
    }
References :

[1] http://examples.javacodegeeks.com/enterprise-java/rest/jax-rs-download-file/
[2] http://stackoverflow.com/questions/10100936/file-downloading-in-restfull-web-services
[3] http://howtodoinjava.com/2013/05/10/resteasy-file-download-example/
[4] http://rest.elkstein.org/2008/02/using-rest-in-java.html
[5] http://java.dzone.com/articles/streaming-apis-json-vs-xml-and
[6] http://stackoverflow.com/questions/29640523/streaming-the-result-of-rest-api-from-twitter
[7] http://stackoverflow.com/questions/3496209/input-and-output-binary-streams-using-jersey
[8] http://stackoverflow.com/questions/23421967/jax-rs-send-serialized-objects
[9] https://developer.jboss.org/thread/174955
[10] http://www.ibm.com/developerworks/library/j-5things1/
[11] http://www.postseek.com/meta/8ee7d7c8a67ab5f555f0403d19d27dd9 -

Friday, April 17, 2015

Writing a Test Class with In-memory H2 Database

While I was implementing unit tests for one java component, I had a requirement to write @Before method inside which I needed to initialize a database. Further I had to create a DataSource using it and bind it to the InitialContext.

According to the requirement, the database had to be populated with some initial data.

This post is about how I've used an in-memory H2 database inside the test classes.

    public static final String DRIVER_CLASS = "org.h2.Driver"; 
    public static final String CONNECTION_URL = "jdbc:h2:mem:WSO2ML_DB"; 
    public static final String USERNAME = "wso2carbon";
    public static final String PASSWORD = "wso2carbon";

    @Before
    public void createTestDB() throws SQLException, URISyntaxException, 
                                      NamingException, ClassNotFoundException, FileNotFoundException {

        // Create data source
        JdbcDataSource ds = new JdbcDataSource();
        ds.setURL(CONNECTION_URL);
        ds.setUser(USERNAME);
        ds.setPassword(PASSWORD);

        // Create initial context
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
        System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");

        // Bind data source -> 
        // DataSource can be accessed by : (DataSource) initContext.lookup("jdbc/WSO2ML_DB");
        InitialContext ic = new InitialContext();
        ic.createSubcontext("jdbc");
        ic.bind("jdbc/WSO2ML_DB", ds);

        Class.forName(DRIVER_CLASS);
        Connection connection = DriverManager.getConnection("jdbc:h2:mem:WSO2ML_DB", USERNAME, PASSWORD);

        // TO dump -> SCRIPT TO '<path-to-directory>/ml-db-dump.sql'
        // TO populate DB -> RUNSCRIPT

        // Populate DB with the given DB-dump
        URL resource = TestDB.class.getResource("/ml-db-dump.sql");
        String filePath = new File(resource.toURI()).getAbsolutePath();
        RunScript.execute(connection, new FileReader(filePath));
    }


References :
[1] http://stackoverflow.com/questions/3461310/how-can-i-bind-a-datasource-to-an-initialcontext-for-junit-testing
[2] http://www.journaldev.com/2509/jdbc-datasource-example-oracle-mysql-and-apache-dbcp-tutorial
[3] http://java.dzone.com/articles/presentation-and-use-h2
[4] http://www.h2database.com/javadoc/org/h2/jdbcx/JdbcDataSource.html
[5] http://stackoverflow.com/questions/3256694/how-in-h2db-get-sql-dump-like-in-mysql
[6] http://h2database.com/html/grammar.html#runscript
[7] http://stackoverflow.com/questions/10675768/executing-script-file-in-h2-database

Tuesday, March 17, 2015

How to see the H2 database content in a WSO2 Product

Every WSO2 product comes with an embedded H2 database as the default database configuration. There can be times we need to see the content of this database.

In this post, I'm going to explain how to see this database content through the H2 console.

First you have to configure the following in the <product-home>/repository/conf/carbon.xml file.

        
        8082
        
 
Once the configuration done as above, start the server(wso2 product you want).

Then open a browser and goto "http://localhost:8082/". You can see the login page as follows.



You need to give the JDBC URL, username and password.

You can find the relevant JDBC URL in the <product-home>/repository/conf/datasources/master-datasources.xml

For example, in ML, it is given as follows;

    WSO2ML_DB
    The datasource used for Machine Learner database
    
        jdbc/WSO2ML_DB
    
    
        
            jdbc:h2:repository/database/WSO2ML_DB;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=60000
            wso2carbon
            wso2carbon
            org.h2.Driver
            50
            60000
            true
            SELECT 1
            30000
        
    

Copy the url given in the element. Here it is jdbc:h2:repository/database/WSO2ML_DB.

Give the username and password given in the and elements in the above configuration. (The default username and password comes with every wso2 product is admin, admin)

You will see the H2 console like this.



Note :

When you need to do some change in the database of a wso2 product and setup the server with that change, you have to run the startup script as follows.

./wso2server.sh -Dsetup

Note that, in order to apply the changes first you have to delete the contents in the directory <product-home>/repository/database. Then start the server with -Dsetup option.