Friday, January 29, 2016

Apache Camel - How to create a Datasource in Camel - OSGI Blueprint DSL? (6/250-2016)


  • Create a Fuse project (archtype contract first) and name it Datasource - this is the Datasource project which will be deployed independently
  • In the blueprint.xml add the code below
<cm:property-placeholder persistent-id="configuration" update-strategy="reload" />

  <bean id="dbcp" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
    <property name="url" value="${db.jdbc.url}"/>
    <property name="username" value="${db.jdbc.username}"/>
    <property name="password" value="${db.jdbc.password}"/>
  </bean>  

  <service interface="javax.sql.DataSource" ref="dbcp">
    <service-properties>
      <entry key="osgi.jndi.service.name" value="jdbc/DBDS"/>
      <entry key="datasource.name" value="DBDS"/>
    </service-properties>
  </service>

  • Configuration - this needs to be saved as configuration.cfg and places under <installs-dir>/etc
db.datasource=DBDS
db.jndi.datasource=jdbc/DBDS
db.jdbc.username=abcd
db.jdbc.password=abcd
db.jdbc.url=jdbc:db2://<ip-address>:<port>/<databasename>


  • Dependency to be added in pom.xml

<modelVersion>4.0.0</modelVersion>
<groupId>com.test.ds</groupId>
<artifactId>datasource</artifactId>
<name>DataSource</name>
<version>1.0.0-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
    <dependency>
 <groupId>commons-dbcp</groupId>
 <artifactId>commons-dbcp</artifactId>
 <version>1.4</version>
    </dependency>
</dependencies>

  • Once the Datasource project is ready the Datasource object can be used in beans across several projects
  • Create a new Fuse project - name it TestDB (archtype - contract first)
  • In the blueprint add the code below

<bean id="SomeBean" class="com.some.bean.SomeBean">
    <property name="dataSource">
        <reference filter="(datasource.name=DBDS)" interface="javax.sql.DataSource" />
    </property>
</bean>

  • the datasource name is registered as "DBDS" - and this is referred from the bean "SomeBean"

public class SomeBean{
        private DataSource dataSource = null;
 public DataSource getDataSource() {
  return dataSource;
 }
 public void setDataSource(DataSource dataSource) {
  this.dataSource = dataSource;
 }
 
 public String testDBConnection()
 {
  //in this bean u can access the datasource and get connection
  DataSource ds = getDataSource();
  if(ds != null)
  {
   Connection conn = ds.getConnection()
  }
 }
} 


  • Once the datasource is accessable from a bean - life is simple and we can do any kind of DB queries
  • While testing in JBoss Fuse - please install features mentioned below
    • osgi:install wrap:mvn:commons-dbcp/commons-dbcp/1.4




Wednesday, January 27, 2016

Apache Camel - What is a Dynamic Router EIP? (5/250 - 2016)

The Dynamic Router from the EIP patterns allows you to route messages while avoiding the dependency of the router on all possible destinations while maintaining its efficiency.

Dynamic router is similar to Routing Slip - the difference being
1. Routing Slip - the decision is made before hand
2. Dynamic Router (Dynamic Routing Slip) - the decision is based on the fly - Provide logic - using Java code/query Database /rules Engine  - to route msg to particular destination

Example:

Spring DSL


<bean id="myBean" class="xyz.DynamicRouterAnnotationBean"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="direct:start"/>
            <bean ref="myBean" method="route"/>
            <to uri="mock:result"/>
        </route>
        <route>
            <from uri="direct:a"/>
    <log message="in direct:a"/>
        </route>
        <route>
            <from uri="direct:b"/>
    <log message="in direct:b"/>
        </route>
        <route>
            <from uri="direct:c"/>
    <log message="in direct:c"/>
        </route>
        <route>
            <from uri="direct:d"/>
    <log message="in direct:c"/>
        </route>
</camelContext>

Java Bean

public class DynamicRouterAnnotationBean {
    @DynamicRouter
    public String route(String body, @Header(Exchange.SLIP_ENDPOINT) String previous) {
    System.out.println("**************route, body-"+body+", previous-"+previous);
        if (previous == null) {
            // 1st time
            return "direct://a";
        } else if ("direct://a".equals(previous)) {
            // 2nd time -
            return "direct://b";
        } else if ("direct://b".equals(previous)) {
            // 2nd time -
            return "direct://d,direct://c";
        } else if ("direct://c".equals(previous)) {
        // 3rd time - transform the message body using the simple language
            return "direct://d";
        } else if ("direct://d".equals(previous)) {
            // 3rd time - transform the message body using the simple language
            return "language://simple:Bye ${body}";
        } else {
            // no more, so return null to indicate end of dynamic router
            return null;
        }
    }
}
  • From the camel route "direct:start", we call the method "route" in the bean DynamicRouterAnnotationBean. 
  • The method "route" has an annotation @DynamicRouter which tells camel that this is not a regular java bean, but follows EIPs
  • the route method will then be invoked repeatedly until it returns "null"
  • you can return multiple endpoints using delimeter


Output

**************route, body-Camel, previous-null
2016-01-27 11:17:14,910 [                     main] INFO  route2                         - in direct:a
**************route, body-Camel, previous-direct://a
2016-01-27 11:17:14,914 [                     main] INFO  route3                         - in direct:b
**************route, body-Camel, previous-direct://b
2016-01-27 11:17:14,925 [                     main] INFO  route5                         - in direct:d
2016-01-27 11:17:14,928 [                     main] INFO  route4                         - in direct:c
**************route, body-Camel, previous-direct://c
2016-01-27 11:17:14,930 [                     main] INFO  route5                         - in direct:d
**************route, body-Camel, previous-direct://d
**************route, body-Bye Camel, previous-language://simple:Bye%20$%7Bbody%7D



References:
http://camel.apache.org/dynamic-router.html
https://github.com/camelinaction/camelinaction

Apache Camel - What is a Routing Slip? (4/250 for 2016)

The Routing Slip from the EIP patterns allows you to route a message consecutively through a series of processing steps where the sequence of steps is not known at design time and can vary for each message.







References:

http://camel.apache.org/routing-slip.html

Monday, January 18, 2016

Jboss Fuse / Apache Camel - How to enable ws-security? (3/250 - 2016)


Dependencies to be added in pom.xml
<dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-bindings</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-policy</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-ws-security-common</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-ws-security-dom</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-ws-security-policy-stax</artifactId>
   <version>2.0.3</version>
  </dependency>
  <dependency>
   <groupId>org.apache.wss4j</groupId>
   <artifactId>wss4j-ws-security-stax</artifactId>
   <version>2.0.3</version>
  </dependency>


Features to be installed in Fuse:

features:install wss4j
features:install cxf-wssecurity


Update Bluerpint with the code place- 
  <http:conduit name="https://.*/.*">
  <http:tlsClientParameters disableCNCheck="true">
   <sec:trustManagers>
    <sec:keyStore type="JKS" file="etc/uatesb.jks" password="password" />
   </sec:trustManagers>
   <sec:keyManagers keyPassword="password">
    <sec:keyStore type="JKS" file="etc/uatesb.jks" password="password" />
   </sec:keyManagers>

   <sec:cipherSuitesFilter>
    <sec:include>.*_EXPORT_.*</sec:include>
    <sec:include>.*_EXPORT1024_.*</sec:include>
    <sec:include>.*_WITH_DES_.*</sec:include>
    <sec:include>.*_WITH_AES_.*</sec:include>
    <sec:include>.*_WITH_NULL_.*</sec:include>
    <sec:exclude>.*_DH_anon_.*</sec:exclude>
   </sec:cipherSuitesFilter>
  </http:tlsClientParameters>
  <http:client AutoRedirect="true" Connection="Keep-Alive" />
 </http:conduit>


Based on the requirement add Inbound / Outbound Interceptors within the consumer / producer endpoints.

<cxf:inInterceptors>
 <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
  <property name="properties">
   <map>
    <entry key="passwordType" value="PasswordText" />
    <entry key="action" value="UsernameToken" />
    <entry key="passwordCallbackRef">
     <bean class="com.dummy.handler.PasswordCallback">
      <property name="passwordMap">
       <map>
        <entry key="${datapower.user.id}" value="${datapower.user.password}" />
        <entry key="${esb.user.id}" value="${esb.user.password}" />
       </map>
      </property>
     </bean>
    </entry>
   </map>
  </property>
 </bean>
</cxf:inInterceptors>



<cxf:outInterceptors>
 <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
  <property name="properties">
   <map>
    <entry key="user" value="wesb" />
    <entry key="passwordCallbackRef">
    <bean id="passwordCallback" class="com.dummy.handler.PasswordCallback">
     <property name="passwordMap">
      <map>
       <entry key="${datapower.user.id}" value="${datapower.user.password}" />
       <entry key="${esb.user.id}" value="${esb.user.password}" />
      </map>
     </property>
    </bean>
    </entry>
    <entry key="action" value="UsernameToken Timestamp" />
    <entry key="passwordType" value="PasswordDigest" />
    <entry key="mustUnderstand" value="${secureEnable}" />
   </map>
  </property>
 </bean>
</cxf:outInterceptors>



The PasswordCallback Impl

public class PasswordCallback implements CallbackHandler {

 private static Logger logger = Logger.getLogger(PasswordCallback.class);
 private Map<String, String> passwordMap;

 public Map<String, String> getPasswordMap() {
  return passwordMap;
 }

 public void setPasswordMap(Map<String, String> passwordMap) {
  this.passwordMap = passwordMap;
 }

 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
  WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
  if (pc.getIdentifier() != null && passwordMap != null) {
   if ("wesb".equals(pc.getIdentifier())) {
    try {
     pc.setPassword((DummyEncryptDecrypter.decrypt(passwordMap.get(pc.getIdentifier()))));
    } catch (DummyCipherException e) {

     e.printStackTrace();
     logger.error("Error in decrypt password for id " + pc.getIdentifier());
     throw new UnsupportedCallbackException(null, "Error in decrypt password for id " + pc.getIdentifier());
    }
   } else {
    pc.setPassword(passwordMap.get(pc.getIdentifier()));
   }
  }
 }
}



DummyEncryptDecrypter

public class DummyEncryptDecrypter {

 Cipher cipher;

 private final static String IV = "password12345678";
 private final static String AES_CBC = "AES/CBC/PKCS5Padding";
 
 private static Logger logger = Logger.getLogger(DummyEncryptDecrypter.class);
 
 static SecretKeySpec key = new SecretKeySpec(IV.getBytes(), "AES");

 /**
  * Decrypt
  * 
  * @param cipherText
  * @return
  * @throws DummyCipherException
  */
 public static  String decrypt(String cipherText) throws DummyCipherException  {
  if(cipherText==null){
   return "";
  }
  AlgorithmParameterSpec paramSpec = new IvParameterSpec(
    IV.getBytes());

  Cipher cipher = null;
  byte[] output = null;
  byte[] decrypted = null;
  try {
   cipher = Cipher.getInstance(AES_CBC);
   cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
   output = new BASE64Decoder().decodeBuffer(cipherText);
   decrypted = cipher.doFinal(output);
  } catch (Exception e) {
   logger.error("Exception while decrypt ");

   throw new DummyCipherException(e.getMessage(), e);
  }
  String palintText = new String(decrypted);
  return palintText;
 }

 /**
  * Encrypt
  * 
  * @param painText
  * @return
  * @throws DummyCipherException
  */
 public static String encrypt(String painText) throws DummyCipherException {

  if(painText==null){
   return "";
  }
  AlgorithmParameterSpec paramSpec = new IvParameterSpec(
    IV.getBytes());

  Cipher cipher = null;
  byte[] ecrypted = null;
  String output = null;

  try {
   cipher = Cipher.getInstance(AES_CBC);
   cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
   ecrypted = cipher.doFinal(painText.getBytes());
   output = new BASE64Encoder().encode(ecrypted);
  } catch (Exception e) {
   logger.error("Exception while encrypting the string "+e.getMessage());
   throw new DummyCipherException(e.getMessage(), e);
  } 
  return output;

 }
 
 public static void main(String arg[]) throws DummyCipherException{
  String s = "xxxxxxxxxx";
  System.out.println(new DummyEncryptDecrypter().decrypt(s));
  System.out.println(new DummyEncryptDecrypter().encrypt("password"));
 }
}


DummyCipherException 
public class DummyCipherException extends Exception {

 private static final long serialVersionUID = 1L;
 public DummyCipherException(String message) {
  super(message);
 }
 public DummyCipherException(String message, Exception e) {
  super(message, e);
 }
}

Configuration File
datapower.user.password=xxxx
datapower.user.id=xxxx
keystore.password=xxxx
secureEnable=false
esb.user.id=xxxx
esb.user.password=xxxx


Monday, January 11, 2016

Jboss Fuse Karaf Container - Could not start JMX connector server.



1. Goto <installDir>\etc
2. backup org.apache.karaf.management.cfg  
3. open org.apache.karaf.management.cfg 
4. change 0.0.0.0 to meaningfull IP like 127.0.0.1

Tuesday, January 5, 2016

Resolve Continious Start/Stop of application - Cleanup Fuse

Remove the files from the location below -

<fuse_install>\data\cache

Any features installed will have to re-installed.