Monday, October 21, 2013

Mule connector development pointers

This article will be helpful for the mule beginners.

ANNOTATIONS
  • Following are some annotation and its meaning
    • @Connector : To mark a class as a Connector.The following is a description of the attributes for this annotation:
      • name: The name of the connector. This is a simple string value which should not contain any spaces in it, it will be used to generate the namespace of the connector.
      • schemaVersion: The version of the generated schema. This usually should match Mule’s schema version, so for .3.1 use schemaVersion=”3.3.1″. Keep in mind that if you add or change methods marked as @Processors or add @Configurable fields the generated schema will change and you should bump the version to avoid compatibility issues.
      • friendlyName: This is the name of the connector and is meant to be used only in Studio. This name will appear as the module name in the palette. Contrary to the name parameter, this field can contain spaces.
      • Connector class
      • minMuleVersion: The minimum version of Mule that this connector supports. A check will be generated for runtime verification that the Mule version this connector is running on is the correct one.
    • @Configurable : To involve a field in configuration
    • Configurable Attribute
    • @Connect : To establish connection to the Service
      • ConnectionKey : annotated parameter is used as the key to the pool. Thus, the Connector can be invoked using a number of different credentials
      Connect method
    • @Start : An alternative to connect annotation.If you don’t want to exploit the connection pool facility you can use this.This will mean you can have a single instance per configuration.
      Start method
    • @Processor : To mark a method as an operation
      Documentation

    • @Disconnect :  Invoked when as part of the maintenance of the Connection Pool
      Disconnect and Validation Connection method
    • @ValidateConnection : Invoked before the invocation of an operatio

READING PROPERTY FILES

  • To read the property files keys you need to put the property file under the folder src/main/resources and then in the flow file you have to add an entry 
    • <context:property-placeholder location="fusionlive.properties"/>
    • xmlns:context="http://www.springframework.org/schema/context" 
  • You can read the attribute like ${host} in the flow file.

READING POST PARAM
  • To read the http POST parameter you have to have the following entry in the flow file.

Flow XML

COMPILATION COMMANDS

  • Connector Compilation : Go the the directory where the mule project is reside and run the following command to compile the connector. If the compilataion is success it will create a target folder under the mule project. This target folder intern have myconnector-1.0-javadoc.jar and UpdateSite.zip files which contains  the documentation and the connector to export. The first command will generate the document but there are some missing element. If you want to resove this you have to run the second command. Second command will generate the document in apidocs folder under the target folder and not in the myconnector-1.0-javadoc.jar file.

    • mvn3 clean package -Ddevkit.studio.package.skip=false -e

    • mvn3 javadoc:javadoc

  • Importing third party library : If you want to import the third party jar then you have to run the following commands

    •  mvn install:install-file -Dfile=/home/username/jdbc.jar -DgroupId=org.mule.modules -DartifactId=myconnector -Dversion=1.0 -Dpackaging=jar

    • mvn install:install-file -Dfile=/home/username/jdbc.jar -DgroupId=org.test -DartifactId=myconnector -Dversion=1.0 -Dpackaging=jar

DEPLOYING
  • Mule ESB / Mulesoft express deployment as Tomcat service

    • Download Mule standalone.
    • Unpack it in the server’s location of your desire. 
    • Place your zipped Mule application in the /mule-standalone/apps directory.
    • If you have any kind of connector .jar, place it in the /mule-standalone/lib/mule directory.
    • Now you’re ready to run your application, go to  /mule-standalone/bin and you can do ./mule
    • And stopping it using Crtl-C.
    • Or you can manipulate it as a daemon using instead mule start/stop/restart

Thursday, October 17, 2013

Mule Upload Example with custom connector

Following code shows how the upload can be done via mule custom connector.
  • Code for the custom upload connector :


import java.io.BufferedInputStream;
import java.io.IOException;
import org.mule.api.ConnectionException;
import org.mule.api.annotations.Configurable;
import org.mule.api.annotations.ConnectionIdentifier;
import org.mule.api.annotations.Connector;
import org.mule.api.annotations.Disconnect;
import org.mule.api.annotations.Processor;
import org.mule.api.annotations.ValidateConnection;
import org.mule.api.annotations.lifecycle.Start;
import org.mule.api.annotations.param.Payload;

/**
 * Upload Connector
 *
 * @author MuleSoft, Inc.
 */
@Connector(name="uploadconnector", schemaVersion="1.0", 
friendlyName="UploadConnector", description="Upload Functioanlity")
public class UploadConnector {
 
private String connectionIdentifier  = null;
private boolean isConnected = false;
 
/**
 * Specifies to which server to connect.
 */
 @Configurable
 private String host = null;
 
/**
  * @return the connectionIdentifier
  */
  @ConnectionIdentifier
 public String getConnectionIdentifier() {
    return connectionIdentifier;
 }
 
/**
 * @param connectionIdentifier the connectionIdentifier to set
 */
 public void setConnectionIdentifier(String connectionIdentifier) {
    this.connectionIdentifier = connectionIdentifier;
 }
 
 
/**
 * @return the host
 */
 public String getHost() {
    return host;
 }


/**
 * @param host the host to set
 */
 public void setHost(String host) {
    this.host = host;
 }

/**
 * Connects to server.
 * 
 * @throws ConnectionException, IOException
 */
 @Start
 public synchronized void connect()
    throws ConnectionException, IOException {
 }

/**
 * Disconnect
 */
 @Disconnect
 public synchronized void disconnect() {
    this.isConnected = false;
 }

/**
 * Are we connected
 */
 @ValidateConnection
 public boolean isConnected() {
    return this.isConnected;
 }
/**
 * Uploads the document
 * 
 * {@sample.xml ../../
 * ../doc/UploadConnector.xml.sample upload:publishdocument}
 *
 * @param payload File dat in the fromat of BufferedInputStream.
 * @param fileName File name of the file to upload.
 * 
 * @throws IOException If there is any exception while connecting 
 *         to the server.
 */
 @Processor
 public void publishdocument(@Payload BufferedInputStream payload, 
     String fileName) throws IOException {

     fileName = getFileName(fileName);
     //TODO Proceed with your client library.
 }
    
    
/**
 * Parse the content-dispposition parameter and get the file name 
 * out of it.
 * 
 * @param fileName content disposition parameter.
 */
 private String getFileName(String fileName) {
     String fileNameFinal = null;
     if(fileName != null){
         String filenameSplit[] = fileName.split(";");
         for (String fn : filenameSplit) {
             //filename="YT.jpg"
             if(fn.contains("filename=")){
                 fileNameFinal = fn.substring("filename=".length() + 2, 
                                 fn.length()-1);
             }
         }
     }
     return fileNameFinal;
 }
}


  • Code in the UploadConnector.xml.sample file
  1. Name of the method 'publishdocument' must be same as the name in the documentation file. i.e. UploadConnector.xml.sample
  2. Parameter name fileName must be same as specified in the function in the connector.


<!-- BEGIN_INCLUDE(uploadconnector:publishdocument) -->
    <uploadconnector:publishdocument 
        fileName="#[message.inboundProperties['content-disposition']]" 
        config-ref="uploadconnector"/>
<!-- END_INCLUDE(uploadconnector:publishdocument) -->


  • Entry in the UploadConnector.mflow file.
  1. Need to specify the host and port property in the properties file. Otherwise one can hard code it.
  2. Path attribute 'publishdocument' must be same as specified in the HTML form bellow. i.e. http://localhost:8081/publishdocument



<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
  <service-overrides 
   messageFactory="org.mule.transport.http.HttpMultipartMuleMessageFactory" />
</http:connector>

<flow name="publishdocument" doc:name="publishdocument">

    <http:inbound-endpoint  connector-ref="httpConnector" 
        exchange-pattern="request-response"  host="${http.host}" 
        port="${http.port}" path="publishdocument" doc:name="HTTP"/>

    <fusionlive:publishdocument config-ref="uploadconnector" 
       fileName="#[message.inboundProperties['content-disposition']]" 
       doc:name="UploadCon"/>
</flow>



HTML Upload Form
  • Name of the file type element must be payload.
  • Method must be post and encrypt attribute must be 'multipart/form-data'


<html>
  <head>
    <title>UploadConnector</title>
  </head>
  <body>
    </br>
      Upload Form
      <form  action="http://localhost:8081/publishdocument" method="post" 
        enctype="multipart/form-data">
 <input type="file" name ="payload"/>
        <input type="submit" value="Upload" />
      </form>
  </body>
</html>

Tuesday, May 21, 2013

Integration with Dropbox including download and upload example.

Easy step to integrate the Drop Box with your applications.

1. Setting up the  dropbox account.

  1. Create a dropbox account https://www.dropbox.com/
  2. Login to the dropbox
  3. Change the current URL to https://www.dropbox.com/developers/apps/create
  4. Select app type as core and permission type as full dropbox.
  5. Here you can create a app where you get the app_key and app_secret
  6. This key will be used for the authentication.
2. Java code.
  1. You will need following jar files to be in classpath.
    1. dropbox-client-1.5.3.jar, httpclient-4.0.jar, httpcore-4.0.jar, json-simple-1.1.jar and commons-logging-1.1.jar

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Scanner;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.DropboxAPI.DropboxInputStream;
import com.dropbox.client2.DropboxAPI.Entry;
import com.dropbox.client2.exception.DropboxException;
import com.dropbox.client2.session.AccessTokenPair;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.RequestTokenPair;
import com.dropbox.client2.session.WebAuthSession;
import com.dropbox.client2.session.Session.AccessType;

public class DropBoxAuthTest {

// App key & secret that Dropbox's developer website gives your app
// Key Received @ step 1.5
private static final String APP_KEY = "your_key";
// Secret Received @ step 1.5
private static final String APP_SECRET = "your_secret";
// Permission type created @ step 1.4
final static private AccessType ACCESS_TYPE = AccessType.DROPBOX;
private static DropboxAPI<WebAuthSession> mDBApi;

public static void main(String[] args) throws Exception {
  
// Initialize the goods/session
AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
WebAuthSession session = new WebAuthSession(appKeys, ACCESS_TYPE);
// Initialize DropboxAPI object
mDBApi = new DropboxAPI<WebAuthSession>(session);
// Get ready for user input
Scanner input = new Scanner(System.in);
// Open file that stores tokens, MUST exist as a blank file
File tokensFile = new File("TOKENS");
System.out.println("Enter 'a' to authenticate, or 'r' to reauthentication, 'd' to download, 'u' to  upload ");
String command = input.next();
if(command.equals("a")){
try {
// Present user with URL to allow app access to Dropbox account on
System.out.println("Please go to this URL and hit \"Allow\": " + DBApi.getSession().getAuthInfo().url);
AccessTokenPair tokenPair = mDBApi.getSession().getAccessTokenPair();
// Wait for user to Allow app in browser
System.out.println("Finished allowing?  Enter 'next' if so: ");
if(input.next().equals("next")){
RequestTokenPair tokens = new RequestTokenPair(tokenPair.key,tokenPair.secret);
mDBApi.getSession().retrieveWebAccessToken(tokens);
PrintWriter tokenWriter = new PrintWriter(tokensFile);
tokenWriter.println(session.getAccessTokenPair().key);
tokenWriter.println(session.getAccessTokenPair().secret);
tokenWriter.close();
System.out.println("Authentication Successful!");
}
} catch (DropboxException e) {
e.printStackTrace();
}
} else if(command.equals("r")){
// Initiate Scanner to read tokens from TOKEN file
Scanner tokenScanner = new Scanner(tokensFile);    
String ACCESS_TOKEN_KEY = tokenScanner.nextLine();    // Read key
String ACCESS_TOKEN_SECRET = tokenScanner.nextLine(); // Read secret
tokenScanner.close(); //Close Scanner
//Re-auth
AccessTokenPair reAuthTokens = new AccessTokenPair(ACCESS_TOKEN_KEY,ACCESS_TOKEN_SECRET);
mDBApi.getSession().setAccessTokenPair(reAuthTokens);
System.out.println("Re-authentication Sucessful!");
//Run test command
System.out.println("Hello there, " + mDBApi.accountInfo().displayName);
} else if(command.equals("d")){
// Initiate Scanner to read tokens from TOKEN file
Scanner tokenScanner = new Scanner(tokensFile);       
String ACCESS_TOKEN_KEY = tokenScanner.nextLine();    // Read key
String ACCESS_TOKEN_SECRET = tokenScanner.nextLine(); // Read secret
tokenScanner.close(); //Close Scanner
//Re-auth
AccessTokenPair reAuthTokens = new AccessTokenPair(ACCESS_TOKEN_KEY,ACCESS_TOKEN_SECRET);
mDBApi.getSession().setAccessTokenPair(reAuthTokens);
Entry entries = mDBApi.metadata("/", 20, null, true, null);
for (Entry e: entries.contents) {
if(!e.isDeleted){
if(e.isDir){
System.out.println("Folder ---> " + e.fileName() );
} else {
// this will download the root level files.
System.out.println("File ---->" + e.fileName());
DropboxInputStream inputStream = mDBApi.getFileStream(e.path,null);
OutputStream out=new FileOutputStream(e.fileName());
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
      out.close();
      inputStream.close();
      System.out.println("File is created....");
}
}
}
} else if(command.equals("u")){
// Initiate Scanner to read tokens from TOKEN file
Scanner tokenScanner = new Scanner(tokensFile);    
String ACCESS_TOKEN_KEY = tokenScanner.nextLine();    // Read key
String ACCESS_TOKEN_SECRET = tokenScanner.nextLine(); // Read secret
tokenScanner.close(); //Close Scanner
//Re-auth
AccessTokenPair reAuthTokens = new AccessTokenPair(ACCESS_TOKEN_KEY, ACCESS_TOKEN_SECRET);
mDBApi.getSession().setAccessTokenPair(reAuthTokens);
// put Pic1.jpg file in the current directory.
File f = new File("Pic2.jpg");
InputStream inputStream = new FileInputStream(f);
mDBApi.putFile("/Photos/", inputStream, f.length(), null, null);
inputStream.close();
}
}
}



3. Execution
  1. When you run the above code, in the console you will asked to prompt for the options like a, r, d and u. 
  2. For the very first time you have to type  'a'. After typing 'a'  you will get an URL. Copy the URL and paste in browser and click on the allow button.
  3. Once this process is done you can run the same program again and try different options like 'd', 'u' and 'r' as per you wish.
4) Documentation
  1. Java api documentation is provided in the following location.    https://www.dropbox.com/static/developers/dropbox-java-sdk-1.5-docs/allclasses-noframe.html


Friday, April 26, 2013

Java Security Warning : Block potentially unsafe components from being run?

Cause of the issue: 

Signed Java Web Start applications and applets that contain signed and unsigned components could potentially be unsafe unless the mixed code was intended by the application vendor. As of the Java SE 6 Update 19 release, when a program contains both signed and unsigned components, a warning dialog is raised. 

Solution : 

Trusted-Only Attribute

For applications and applets that do not require unsigned components, the Trusted-Only attribute should be used. No warning dialog will be displayed and an application or applet that loads a jar file containing this attribute will not load any untrusted classes or resources. This attribute prevents a signed application or applet from being re-purposed with unsigned components. You can specify Trusted-Only: true in the manifest file. For example:

Manifest-Version: 1.0
Trusted-Only: true
Created-By: 1.6.0-internal (Sun Microsystems Inc.)
All classes and resources in the application or applet must be signed and trusted.

Trusted-Library Attribute


For applications and applets that are designed to allow unsigned components, the Trusted-Library attribute should be used. No warning dialog will be displayed and an application or applet may load jar files containing untrusted classes or resources. This attribute prevents signed components in an application or applet from being re-purposed with unsigned components. You can specify Trusted-Library: true in the manifest file. For example:
Manifest-Version: 1.0
Trusted-Library: true
Created-By: 1.6.0-internal (Sun Microsystems Inc.)
All classes and resources in a jar file containing this manifest attribute must be signed and trusted.

To fix the popup you need to add and extra attribute called Trusted:Library : true  into the manifest file.

How to add attribute to manifest file: 

Basic command to create a jar file is : 

            jar cfm jar-file manifest-addition input-file(s) 

m  option indicates that you want to merge information from an existing file to the manifest file of the jar file you are creating.
manifest-addition is the name( or path and name) of the existing text file whose content in our case will be either  Trusted-Only: true or  Trusted-Library: true

After the jar is create you have to sign the jar with your certificates and cross check f the manifest files has the correct attributes.

Liveconnect call for Applet ID * is not allowed in this JVM instance


The fix is to change the MANIFEST.MF file to have a Trusted-Library:true instead of Trusted-Only :true.

MANIFIEST.MF File should have the following three line and code signing classes  :

Manifest-Version: 1.0
Trusted-Library: true
Created-By: 1.6.0_16 (Sun Microsystems Inc.)

Modifying the manifest file :

The basic command has this format:
jar cfm jar-file manifest-addition input-file(s)
Let's look at the options and arguments used in this command:
  • The c option indicates that you want to create a JAR file.
  • The m option indicates that you want to merge information from an existing file into the manifest file of the JAR file you're creating.
  • The f option indicates that you want the output to go to a file (the JAR file you're creating) rather than to standard output.
  • manifest-addition is the name (or path and name) of the existing text file whose contents you want to add to the contents of JAR file's manifest.
  • jar-file is the name that you want the resulting JAR file to have.
  • The input-file(s) argument is a space-separated list of one or more files that you want to be placed in your JAR file.
The m and f options must be in the same order as the corresponding arguments.

example : jar cvfm  Test.jar manifestTest.text Upload.java

and manifestTest.text will have the Trusted-Library: true line.