Saturday, January 11, 2014

Capturing SOAP packets in Apache Chainsaw


The logs from the handler mentioned in JAXWS Handler : Example for logging request / response SOAP packets can be forwarded over a socket to an external listener or a tool like Apache Chainsaw. In order to forward these logs over a socket, a SocketAppender needs to be used. The following modifications needs to be done to SOAPRequestResponseSpitter class. Add the imports
import org.apache.log4j.Logger;
import org.apache.log4j.net.SocketAppender;
Add the static block
private static Logger LOGGER = Logger.getLogger(SOAPRequestResponseSpitter.class);

 static {
  SocketAppender socketAppender = new SocketAppender("localhost", 4560);
  socketAppender.setReconnectionDelay(10000); // 10 seconds

  LOGGER.addAppender(socketAppender);
  socketAppender.activateOptions();
 }
In the log(..) method, write the soap packet to this logger.
 private void log(SOAPMessageContext smc) {
  Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (outboundProperty.booleanValue()) {
   System.out.println("\nOutbound message:");
  } else {
   System.out.println("\nInbound message:");
  }

  SOAPMessage message = smc.getMessage();
  ByteArrayOutputStream boas = new ByteArrayOutputStream();
  try {
   message.writeTo(boas);
   LOGGER.info(boas.toString());
   System.out.println(boas.toString());
   System.out.println("");
  } catch (Exception e) {
   System.out.println("Exception in handler: " + e);
  }
 }
Note: Above mentioned may be the worst way to configure an appender. A configuration file like log4j.xml or log4j.properties should be used instead. I don't want to go into details of how to configure log4j hence using the simple approach above to avoid distracting from the main focus. Launch Apache Chainsaw and choose the second option, i.e.
    Let me use a simple Receive: SocketReceiver on port 4560 (Default SocketAppender port)
Once this setting is used, all the SOAP packets being intercepted by the handler will be displayed on a tab in the Chainsaw application. Apache Chainsaw & the SocketAppender is being used here to log SOAP packets only. This combination can be used to remotely view any log4j logs transmitted by the SocketAppender.

Tuesday, October 22, 2013

Searching multiple words in multiple files in eclipse

There are times when we have to search for the occurrences of multiple words in multiple files. In eclipse you can perform this search using File Search with regex expressions.

  • Open Search > File dialog.
  • In the Containing text: field enter (?<!^\s*(//|\*).*)(jack|jim)
  • Select the Regular expression check box and hit the search button.
The above steps shall parse thru all the files selected in the File name patterns section and list all the files with either jack or jim or both.

To understand the expression above, you can refer to http://www.eclipse.org/tptp/home/downloads/installguide/gla_42/ref/rregexp.html

Tuesday, May 21, 2013

Temporary environment variables precedence in Windows

The user environment variables always have precedence over the system environment variables for the process run by the particular user.

In relation to the temporary folders, the TMP environment variable has a precedence over the TEMP environment variable (legacy reasons dating to DOS). So to sum up the temporary folders environment variable precedence (top to bottom) for the currently logged in user is:
  • User %TMP%  (Highest precedence)
  • System %TMP%
  • User %TEMP%
  • System %TEMP% (Lowest precedence)
You can verify the precedence using:
  • Command prompts echo %ENVIRONMENT VARIABLE%
  • Java's [System.getProperty("java.io.tmpdir")]
  • C# [Path.GetTempPath()]

Thursday, March 21, 2013

JAXWS Handler injection using Spring

I'll try to keep this post less verbose and let the code speak for itself.

In order inject the handler using Spring, we need the below mentioned default handler resolver class and the configuration.

DefaultHandlerResolver
package handler;

import java.util.List;

import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;

@SuppressWarnings("rawtypes")
public class DefaultHandlerResolver implements HandlerResolver {
 private List<Handler> handlerList;

 public List<Handler> getHandlerChain(PortInfo portInfo) {
  return handlerList;
 }

 public void setHandlerList(List<Handler> handlerList) {
  this.handlerList = handlerList;
 }
}


applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

 <!-- Web Service custom properties (Timeouts in millis)  -->
 <util:map id="jaxwsCustomProperties">
  <entry key="com.sun.xml.ws.connect.timeout">
   <value type="java.lang.Integer">15000</value>
  </entry> 
  <entry key="com.sun.xml.ws.request.timeout">
   <value type="java.lang.Integer">15000</value>
  </entry>
 </util:map>

 <bean id="handlerResolver" class="handler.DefaultHandlerResolver">
  <property name="handlerList">
   <list>
    <bean class="handler.SOAPRequestResponseSpitter" />
   </list>
  </property>
 </bean>

 <bean id="calculatorServicePortType" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
  <property name="serviceInterface" value="service.Calculator" />
  <property name="wsdlDocumentUrl" value="CalculatorService.wsdl" />
  <property name="namespaceUri" value="http://service/" />
  <property name="serviceName" value="CalculatorService" />
  <property name="endpointAddress" value="http://localhost:7001/CalculatorServiceWebApp/CalculatorService" />
  <property name="customProperties" ref="jaxwsCustomProperties" />
  <property name="handlerResolver" ref="handlerResolver"/>
 </bean>
</beans>


Once the above files are ready, then run the following in the main method of your test class or JUnit:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
Calculator calculator = (Calculator) context.getBean("calculatorServicePortType");
System.out.println("Calculated result [" + calculator.add(2, 3) +"]");


The output should look like: Outbound message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Header/>
  <S:Body>
    <ns2:add xmlns:ns2="http://service/">
      <a>2</a>
      <b>3</b>
    </ns2:add>
  </S:Body>
</S:Envelope>
Inbound message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
 <S:Header/>
 <S:Body>
  <ns2:addResponse xmlns:ns2="http://service/">
   <return>5</return>
  </ns2:addResponse>
 </S:Body>
</S:Envelope>
Calculated result [5]

JAXWS Handler : Example for logging request / response SOAP packets

There are times when we want to see the request / response SOAP packets in our system console or log files. Instead of going for TCP monitor or other similiar tools, I though of writing a handler. The code below is quite popular and can be found in many other posts too.

Adding this handler is simple. Just pass the binding object of your Web Service client port into the static addToPort(...) method in this class.
package handler;

import java.io.ByteArrayOutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Binding;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPRequestResponseSpitter implements SOAPHandler<SOAPMessageContext> {

 @Override
 public boolean handleMessage(SOAPMessageContext context) {
  logToSystemOut(context);
  return true;
 }

 @Override
 public boolean handleFault(SOAPMessageContext context) {
  logToSystemOut(context);
  return true;
 }

 private void logToSystemOut(SOAPMessageContext smc) {
  Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  if (outboundProperty.booleanValue()) {
   System.out.println("\nOutbound message:");
  } else {
   System.out.println("\nInbound message:");
  }

  SOAPMessage message = smc.getMessage();
  try {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       message.writeTo(baos);
       System.out.println(baos.toString());
  } catch (Exception e) {
   System.out.println("Exception in handler: " + e);
  }
 }

 @Override
 public void close(MessageContext context) {
 }

 @Override
 public Set<QName> getHeaders() {
  return Collections.emptySet();
 }

 @SuppressWarnings("rawtypes")
 /**
  * This static method adds the handler to the provided port's binding object. 
  * 
  * @param binding - The binding object can be fetched by <code>((BindingProvider) port).getBinding()</code>
  */
 public static void addToPort(Binding binding) {
  List<Handler> handlerChain = binding.getHandlerChain();
  handlerChain.add(new SOAPRequestResponseSpitter());

  /*
   * Check List<Handler> javax.xml.ws.Binding.getHandlerChain() javadocs.
   * It states: Gets a copy of the handler chain for a protocol binding
   * instance. If the returned chain is modified a call to setHandlerChain
   * is required to configure the binding instance with the new chain.
   */
  binding.setHandlerChain(handlerChain);
 }
}


To inject this handler into the port using Spring, please refer to my other post JAXWS Handler injection using Spring

The handler gives you much control on how you want to log the packets. If you don't want to write a handler and just want to see the packets without making any changes to the application, you can use the below mentioned JVM argument in your server startup script and all the web service related tcp communication will be printed on the console.
  -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true

Thursday, December 22, 2011

Associating JSP Editor for the .xhtml extension in Eclipse

To use the eclipse JSP editor for editing .xhtml files (created for JSF), go to Window > Preferences > General > Content Type > Text > JSP and add *.xhtml in the File Associations section.
With this extension added, you shall be able to see the available tags & attribute listing for the JSF tags too.

Monday, May 16, 2011

Setting timeout for web service invocations using SII client generated using Weblogic 8.1 SP6 ANT task

Even though the 11g version of weblogic has been released, most of the big organizations continue to use BEA Weblogic 8.1 version (there are number of reasons and I won't get into details). Since we have been invoking some very busy web services and wanted to utilize the timeout mechanism to throw an exception on the client side so that the user may be requested to try at a later time rather than waiting for ever. Over a number of blogs I saw people suggesting the use of weblogic.webservice.rpc.timeoutsecs property and provide the timeout values in seconds. It didn't seem to work for me and so was the experience of many users using the webservice client generated by weblogic ant tasks and using the weblogic.jar and webservice.jar in classpath. After a number of google searches, I found out a person who had succesfully used the above mentioned property to get the timeout functionality working. The secret to this person's solution was, he had used a DII (i.e. used a self written client instead of the generated client). The sample DII client for a Calculator service with an add webmethod is as below:
      String NS_XSD = "http://www.w3.org/2001/XMLSchema";
      String targetNamespace = "http://www.bea.com/examples/Calculator";

      System.setProperty("javax.xml.rpc.ServiceFactory", "weblogic.webservice.core.rpc.ServiceFactoryImpl");
      System.setProperty("weblogic.webservice.verbose", "false");
      System.setProperty("weblogic.webservice.UseWebLogicURLStreamHandler", "true");

      ServiceFactory factory = ServiceFactory.newInstance();
      QName serviceName = new QName(targetNamespace, "CalculatorService");
      QName portName = new QName(targetNamespace, "CalculatorServicePort");
      QName operationName = new QName(targetNamespace, "add");
      Service service = factory.createService(serviceName);

      Call call = service.createCall();
      call.setOperationName(operationName);
      call.setPortTypeName(portName);
      call.setProperty(Call.OPERATION_STYLE_PROPERTY, "rpc");

      call.addParameter("intVal", new QName(NS_XSD, "int"), Integer.class, ParameterMode.IN);
      call.addParameter("intVal0", new QName(NS_XSD, "int"), Integer.class, ParameterMode.IN);
      call.setReturnType(new QName(NS_XSD, "int"), Integer.class);
      call.setTargetEndpointAddress("http://localhost:7001/CalculatorService/CalculatorService");
      ((weblogic.webservice.core.rpc.CallImpl) call).setProperty("weblogic.webservice.rpc.timeoutsecs", "5");
      System.out.println("Invoked DII :");
      System.out.println("Result : " + call.invoke(new Object[] { new Integer(a), new Integer(b) }));
Now comes the second problem, all the existing client code for a huge number of webservices are SII codes (generated by the ANT task in webservices.jar). Instead of converting all the client codes to DII, I had to find the solution using SII. Since the code is not provided by BEA, I decompiled the jar to understand what's going on under the hood and found something strange, the weblogic.webservice.rpc.timeoutsecs set as a system property was fetched inside the jared code (in webservices.jar) but was only used in the logic that handled https invocations (may be missed out looking at the right place or it was never there). In order to confirm my findings, I exposed the service over https and modified the client code with some additional properties (related to https invocations and nothing to do with web service in particular) and VOILA!!!! It worked :)

Inference: To use the timeout property for rpc calls when using client generated SII, the webservice should be exposed in https (can't change the code in the jars used by the client code to fix it as the code is not open source). Or write a DII (example given above). For SII invocation over https you need to use the below mentioned properties:
       
System.setProperty("weblogic.security.SSL.trustedCAKeyStore", "C:/bea/weblogic81/server/lib/DemoIdentity.jks");
System.setProperty("weblogic.webservice.client.ssl.strictcertchecking", "false");
System.setProperty("weblogic.webservice.rpc.timeoutsecs", "10");
For invocations over https you shall need jsafeFIPS.jar & webserviceclient+ssl.jar in classpath in addition to webservices.jar & weblogic.jar (you can find all of those in the weblogic's lib folder). The invocation may also ask for license files (don't know why), then even put the license.bea & license_scale_limited.bea in the classpath.

For Weblogic 9 versions, the property to be set has changed. More details can be found at http://download.oracle.com/docs/cd/E13222_01/wls/docs92/webserv/client.html. Those properties are:
((Stub)service_action)._setProperty("weblogic.wsee.transport.read.timeout", 5000); //values are in millis
((Stub)service_action)._setProperty("weblogic.wsee.transport.connection.timeout", 5000); //values are in millis
Similiar properties for Weblogic 10 can be found at http://docs.oracle.com/cd/E13222_01/wls/docs100/webserv/client.html I hope you found this post helpful.

Thursday, April 7, 2011

Stop waiting for the designer to create rounded corners !!!

How many times has it happened that you've been waiting for the designer to create and provide you with the rounded corners image? We usually use these images as background images for divs or a rounded corner table. Now this can be achieved by using pure CSS. Follow the link http://www.css3.info/preview/rounded-border/ for more details. These CSS styles work perfectly for firefox and chrome but can give some problems on IE.

Saturday, March 12, 2011

jQuery FlexGrid & Spring MVC 3

Recently I have been working on Spring MVC 3. There is inbuilt support for returning JSON data using @ResponseBody annotation. Just make sure that jackson-all-x.x.x.jar is on your classpath. I used jackson-all-1.7.4.jar.This works great.

I wanted to display the results in a tabular format with some basic sorting and paging functionality with AJAX. So I thought I will give a shot at jQuery. jQuery is such an amazing JavaScript library it makes this a lot easier when it comes to working with JavaScript or manipulating DOM.

I found this amazing jQuery plugin, FlexGrid. It was pretty much what I wanted. Though it does not support i18N or themed L&F, it did the job for me.

So I started integrating the pieces. jQuery FlexGrid expects the JSON data to be in a specific format:

   total: (no of rec)
   page : (page no)
   rows : [{id: idVal, cell: [ (col1 value) , (col2 value) ,.. ]},
           {id: idVal, cell: [ (col1 value) , (col2 value) ,.. ]}
          ]

But the data returned from the method with @ResponseBody annotation is in the following format:

   
{(col1 value) , (col2 value) ,..}

So I thought I might as well go ahead and modify my DAO's to return the data in the required format. But well, why should I modify my DAO's? Its after all a UI layer requirement. This is what I came up with.

Write a wrapper class that will hold the data required for FlexGrid and send this as a JSON response. Here's the wrapper class:

import java.io.Serializable;
import java.util.List;

/**
 * Wrapper class for JSON data to send to the client.
 * 
 * Currently we are using jQuery FlexGrid for displaying JSON data in table.
* * jQuery FlexGrid plug-in requires data to be in the below specified format. * * * total: (no of rec) * page : (page no) * rows : [{id: idVal, cell: [ (col1 value) , (col2 value) ,.. ]}, * {id: idVal, cell: [ (col1 value) , (col2 value) ,.. ]} * ] * * To keep the data service independent of this requirement as far as possible, * the id, cell format specifically ignored. we wrap the result from the data * service and further format the result using JavaScript as required. * * * @author Enterprise Integrals * * @version 1.0 * @see jQuery FlexGrid * * @param T generic data type for list of objects to be sent in the JSON response. */ public class JsonDataWrapper<T> implements Serializable { private static final long serialVersionUID = 1L; //current page private int page; //total number of records for the given entity. private long total; //list of records to be displayed. private List<T> rows; public JsonDataWrapper(int page, long total, List<T> rows) { this.page = page; this.total = total; this.rows = rows; } // getter setter }
Here is how it is used in Spring MVC 3
/**
* FlexGrid submits the following parameters
* page: current page
* rp: rows per page
* sortname: sorting done on which column:
* sortorder: sort order asc/desc
* query: search criteria if you are using search option
* qtype: search on which column in grid. this is again customizable.
* 
* These parameters can be used as filters in the DAO to get the data.
*
* By default the FlexGrid uses POST. You can change to GET.
* @param T the entity list to displayed in grid
*/
@RequestMapping(value="/some Path", method= RequestMethod.POST)
public @ResponseBody JsonDataWrapper<T> getRows(WebRequest request) {
 //get the current page posted from the grid.
 int page = Integer.parseInt(request.getParameter("page"));
 //get the list of objects to be displayed from the db calling the service
 //the total number of pages are dynamically calculated on the basis of the total number of rows in the table. get that.
 JsonDataWrapper<T> jdw = new JsonDataWrapper<T>(page, total rows, rows);
 return jdw;
}
But there is a catch here. The FlexGrid plugin again refuses to render the data. The reason is the List<T> rows is again a list of objects returned from the DAO layer. It does not format the data as required by FlexGrid plugin. How do we do that? So I decided lets not put this logic in our MVC implementation. Here is how the data is set on to the FlexGrid using JavaScript.

 
$("#flex1").flexigrid({
   // standard flexgrid configuration as per your need,
   preProcess: formatData
});

Note the preProcess definition. It pre processes the data before the grid is populated with the JSON data return from the server. You can inline the function that actually formats the data but I kept it separate. Here it goes:

function formatData(data) {
 var rows = Array();
 $.each(data.rows,function(i,row){
                //id can be mapped to any attribute of the return object in the list
  rows.push({id:row.val1, cell:[row.val1,row.val2]});
});
 
 return {
  total:data.total,
  page:data.page,
  rows:rows
 };     
}

Now the grid populated correctly. There are other grid plugins for jQuery but FlexGrid & jQGrid are the best. FlexGrid has lot less functionality as compared to jQGrid but I like it because its light. For advanced features you can have a look at jQGrid.

Sunday, February 20, 2011

PHP 5.3 Date Timezone issue

I was recently trying to setup PHP on my development machine. I downloaded the php-5.3.5-Win32-VC6-x86.zip for Windows and started to manually configure PHP (to get a feel. You can ofcourse use something like XAMPP to get started quickly.)

Then I quickly executed some PHP scripts and found everything was running fine. I dumped some of the PHP samples I had and played around until one started complaining

It is not safe to rely on the system's timezone settings.

Little researching solved the issue. PHP 5.3 requires you to set date.timezone in php.ini file

e.g. date.timezone = Asia/Calcutta

http://nl3.php.net/manual/en/timezones.php

Thursday, June 17, 2010

Which style of WSDL should I use?

A Web Services Description Language (WSDL) binding style can be RPC or document. The use can be encoded or literal. How do you determine which combination of style and use to use? The author describes the WSDL and SOAP messages for each combination to help you decide.

Which style of WSDL should I use?

Saturday, October 31, 2009

Java 5 EOSL

Java 5 has reached End Of Life. Most of the bigger organization in the service industry are still using Java 1.4 and are not willing to migrate as they anticipate migration issues and feel that its a risk and unjustifiable. Java 6 has been out for a long and its time to take advantage of the new features, especially the web services stack (JAX-WS). There are lot of performance improvements which might be one reason to migrate.

On a personal note migration is little to do with technical, but more often political.

http://java.sun.com/products/archive/eol.policy.html

Thursday, September 17, 2009

File Download issue with IE over HTTPS

I am currently working on a project where the user can download PDF, XLS and CSV files. These files are dynamically generated within the application and thrown out on the browser when the user clicks on a particular link. This was running like a charm till recently, we decided to move to HTTPS and it stopped working. We were getting a message saying

"The file could not be stored in cache."
"Internet Explorer was unable to open this site. The requested site is either unavailable or cannot be found. Please try again later."


After a little googling I found that it is a known issue with IE. Refer to the link below. http://support.microsoft.com/kb/815313 But installing a hotfix was out of question. So I went looking for a solution that could be handled through code and here is the solution that seems to work for us and the magic required to satisfy IE
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "max-age=0");

Wednesday, August 12, 2009

Two way SSL on Tomcat & JBoss

Continued from the previous post where I had put in steps to setup one way SSL. In this post i shall provide steps to enable client certificate authorization. Hence here we will see a situation where the client verifies the server cert and server verifies the client cert for validity and trust before a successful SSL handshake. The initial steps shall be the same as mentioned in my previous post and with an assumption that your one way SSL is already working. Now to enable the client authorization, we need to modify the server.xml as below:
<Connector 
  port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true"
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" 
  secure="true" SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" 
  clientAuth="true" truststoreFile="c:/certs/test_store" 
  truststorePass="password" sslProtocol="TLS"/>
Export a certificate from the client keystore (client_store in this example) and import it into the server's truststore (test_store in this example). In real world you probably would not import each client cert but a CA root cert and then sign each client cert with that one. The above mentioned way is only for testing purposes and get the feel of the process. Launch the server. No modifications are needed in the code on the client side. You can launch the client using:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/client_store -Djavax.net.ssl.trustStorePassword=password -Djavax.net.ssl.keyStore=c:/certs/client_store -Djavax.net.ssl.keyStorePassword=password HelloWorld
Additional Tips: 1)In order to get detailed debug statements for the SSL handshake between the server and the client you can use the vm argument -Djavax.net.debug=ssl,handshake on either side. 2)If you want to be able to access the site using your browser then you will have to have the client certificate in the Internet Options > Content > Certificates > Personal section. For this you will have to be using a PKCS12 keystore instead of a standard JKS keystore. Hence instead use the following steps to generate the keystore on the client side:
keytool -genkey -v -alias clientKey -keyalg RSA -storetype PKCS12 -keystore client.p12
The keypass and storepass needs to be the same. Like in the steps for client using JKS, even here you can use a similar command to export the cert
keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.cer
Rest instructions like importing this cert into server's keystore continue to be same. One important point to note is that since the server's cert cannot be imported into PKCS12 keystore on client side, you have to import it into a JKS truststore and the commandline to launch the program needs to be modified as:
c:\>java -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.keyStore=c:/certs/client.p12 -Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
In this case, the server's certificate has been imported into the cacerts truststore of type JKS. The PKCS12 keystore can be imported into the internet explorer at the above mentioned path. Now if you hit the URL using https, you shall be displayed a dialog box to select the cert you want to use for client authorization. Once you select it, the handshake process continues. Through out the example we have been making hits to a servlet (https://personal-PC:8443/SampleWebApp/HelloWorld). We can get the details of the client cert used to access this URL from an attribute in the request object.
X509Certificate certs[] = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
for (X509Certificate cert : certs) {
out.println(cert.getIssuerDN());
}

Tuesday, August 4, 2009

SSL on Tomcat, JBoss and command line client (continued)

I finished my previous post with the ending lines as So if you had used domain name in the cert CN, then use domain name or if it is machine name then use the machine name ; and if you don't do so you shall see error messages similiar to HTTPS hostname wrong: should be <personal-pc> where you had given your ip or localhost as the CN name while creating the keystore whereas referring the machine by its name (personal-pc in this case). If you go by the rules mentioned in previous post, it shall work i.e. using the same name in the URL to refer the machine you used as CN. What if you still want to be able to work with the different name (not the one similiar to the CN) or you want to use the IP in the URL when accessing the site? Well there is also a provision for this. You can write your own code to decide what needs to be done in such a situation by implementing the HostnameVerifier interface.
URL url = new URL("https://personal-PC:8443/SampleWebApp/HelloWorld");
URLConnection connection = url.openConnection();

if (connection instanceof HttpsURLConnection) {
    ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {

        public boolean verify(String hostname, SSLSession session) {
           //TODO: Logic controlling the verfication.
           return true;
        }
    });
}

BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//Rest of the IO code.
In the code above, I am just returning true for what ever comes in as host name, you shall write your logic here to handle the situation the way you like. With the above code in place, you will be able to use all valid names to refer your machine in the URL including computer name and localhost/127.0.0.1 (only for testing purposes).

Monday, August 3, 2009

SSL on Tomcat, JBoss and command line client

Talking about a secure website, the first thing that comes to mind is SSL. For almost all the sites today, we do encounter a section in the website where the address bar turns yellow with a lock indicating that the data being transfered is being encrypted. That section can be a login screen or a transaction screen etc. In this post i've tried to put some steps to achieve the goal of securing a HelloWorldServlet (not much useful but the technique for this or a complex one shall be same).
In order to start with the process of securing your site, we need a certificate. You shall be able to get a valid certificate from a Certification Authority like Thwate, Verisign and many more. Here I shall use a self-signed certificate but the process shall be quite similar for the ones from a Certification Authority (CA).
First of all we create a Keystore using the keytool available in a JRE installation. You can look for it in JDK\bin or JRE\bin directory.
keytool -genkey -alias rsatest -keyalg RSA -keystore test_store -validity 60
Keep in mind while creating the keystore that the answer to the first question i.e. What is your first and last name? should be either your domain address or machine name (It should be the name by which your machine shall be referred in URL when clients are making hits to it using an HttpsURLConnection). This is the CN (Common Name).
After answering a number of self explanatory questions and providing an appropriate password, you shall see a file names test_store in your present working directory folder.
In the next step, you can create a certificate that shall be required by the client application to communicate with this machine using SSL.
keytool -export -alias rsatest -file rsatest.cer -keystore test_store
After executing this command, you shall see a rsatest.cer file created.
In order to start tomcat in https mode in addition to its default http mode, we need to modify the server.xml in the TOMCAT_HOME\CONF folder.
Paste the snippet below in server.xml.
 <Connector port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" 
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" 
  SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" clientAuth="false" sslProtocol="TLS"/>
Replace the location of keystoreFile and the keystorePass with appropriate values.
In case of JBoss the process is quite similar to that of Tomcat. We need to edit JBOSS_HOME\server\default\deploy\jboss-web.deployer\server.xml instead and paste the below give snippet.
 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
     maxThreads="150" scheme="https" secure="true"
     clientAuth="false" strategy="ms"
     address="${jboss.bind.address}"
     keystoreFile="C:/certs/test_store"
     keystorePass="password"
     sslProtocol="TLS"/>
Which ever server you choose to modify, after you are done with saving the server.xml file start the server. You should be able to make hits to the server url with https protocol on an appropriate port (8443 in our case). Expect to see some warning like There is a problem with this website's security certificate. on IE or localhost:8443 uses an invalid security certificate. on firefox for the reasons explained very well on that screen. This happens as ours is a self-signed certificate and not issued by a trusted certificate authority that the machine or the browsers certificate stores posses. These self signed shall be good enough for internal use or testing but for internet use you should get the certs from a trusted certificate authority.
Well, we are ready with our server running in https mode. For example purposes I had developed a very simple HelloWorldServlet. I am able to access via https://localhost:8443/WebAppDemo/HelloWorldServlet
Before we write the client code, we need to get the cert that we generated earlier. As we are on the same machine, you can re-use the trust store (for practice purposes) but in real environment (on a different machine), you shall create a new trust store and import the cert into it using the command given below:
keytool -import -alias rsatest -file rsatest.cer -keystore cacerts
The same command is used to import any ROOT certificates or the certs provided by a website that you want to connect using your java program.
With the above command we created a new keystore and imported the certificate into it. The client code is very simple i.e. a usual HttpUrlConnection code. A small snippet from my test class HelloWorld.java is given below:
  URL url = new URL("https://localhost:8443/WebAppDemo/HelloWorldServlet");
  URLConnection connection = url.openConnection();
Rest code is simple IO reading from stream hence skipping it.
The important part is are the VM arguments. If you have written a stand alone application, you shall run it using the following command:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
One very important point is that in the URL the server machine should be refered by the name used in the CN while creating the keystore. So you need to use the domain name of the machine as the CN. It won't work otherwise. In my example using localhost is a bad practice but I feel you get the point and modify your codes according to the situation. The IP of the machine should not be used as a CN, so you have to use the domain name or the machine name as the CN for the cert. The same domain name or machine name (used in CN) should be used when accessing the URL or else you will encounter host name verification failure.

Monday, February 23, 2009

Executing the code while JVM shuts down

A number of times we have encountered a situation where we want a particular piece of code to be executed when our application is exiting. More necessarily we need such a mechanism when we have developed a server and want the code to be executed for any System.exit(0) call or a CTRL + C key combination on the console. A shutdown hook is the way out for this problem. Writing it is very simple. All the code we need to be executed should be written in a Thread and its object should be registered with the Runtime of the JVM. The code is as below.
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        System.out.println("Executing the code while closing down.");
    }
});
A detailed explanation of the above method is provided in the Javadocs for the Runtime class.

Sunday, January 25, 2009

Remote debugging application on pocket pc running on j9

I assume that eclipse was used for the development of the application. Once the application is ready, It shall be copied over to the device that has j9 run time environment. The application can be deployed as a jar file or classes. In order to run the application, either command line needs to be used or we can create a link file with the following content:
255#"\Program Files\j9\bin\j9.exe" -jcl:ppro11  -cp "Test.jar" "trial.Test"
Assuming that the application is packed into a jar file and the trail.Test is the main class. Save the above file with a .lnk extension e.g. Test.lnk. Click on the Test.lnk file and see that the application launches properly.
Now in order to remote debug, check for the existence of j9dbg23.dll in your j9 bin directory. Modify the Test.lnk file to:
255#"\Program Files\j9\bin\j9w.exe" -jcl:ppro11 -debug:transport=dt_socket,server=y,address=4142 -cp "Test.jar" "trial.Test"
Once it is done, open the same project in eclipse.
  1. Open the Debug Configurations window (Run > Debug Configuration).
  2. Create a new Remote Java Application configuration and enter the details as follows:
  • Project -> Select your project.
  • Connection Type -> Standard (Socket Attach)
  • Connection Properties -> ip of the remote machine (pocket pc) and the debug port (4142 in our example case). This port is mentioned in the above created ".lnk" file, hence should be the same in this "Remote Java Application" debug configuration.
  • Run the application on the pocket pc by clicking on the Test.lnk file.
  • Click on the Debug button on the newly created "Remote Java Application" debug configuration.
You are ready to debug your application buy putting break points in appropriate code locations. This scenario has been tested with j9 on a Windows CE 4.2 environment. Should be the same for Windows Mobile and Linux environment (you'll get an .so instead of a .dll in j9 distribution).
The debugger can similiarly be attached even using netbeans.

Saturday, December 6, 2008

Fullscreen of Fedora10 installed on Vista using VirtualBox

Installing Fedora10 on Windows Vista using Virtual Box was very straight forward. I used a live disk or the iso initially and once the virtual machine booted up, I used the option of install to hard disk to avoid using the iso or the Live CD. The complex issue was that the screen size is too small i.e. the highest available resolution was 800 x 600. My Vista is using 1280 x 800, hence the Fedora on Virtual Box looked very small. I was able to make it full screen by following certain steps mentioned as below:
  • Run the Virtual Machine installed using VirtualBox. Go to the Devices menu and select the "Install Guest Addons . . ." option. Reboot the machine.
  • When the virtual machine is shutdown, you should be able to see that in the settings "CD/DVD-ROM" section will be configured for the "VBoxGuestAdditions.iso".
  • On the Virtual Machine startup, you shall be able to see this iso mounted and have icon on the desktop.
  • Before these Addons can be installed certain dependencies like make, gcc, kernel-headers and kernel-devel needs to be installed. These can be done using the following commands:
      • #] yum install make
      • #] yum install gcc-c++
      • #] yum install kernel-headers
      • #] yum install kernel-devel
  • When the dependencies are installed, we proceed installing the addons
      • #] cd /media/VBOXADDITIONS_2.0.6-39755/
      • #] sh ./VBoxLinuxAdditions-x86.run
  • Reboot the Virtual Machine. Now fire the commands to get the Display in the System > Administration menu.
      • #] yum install system-config-display
  • Now you can open the System > Administration > Display window. In the Hardware tab, select the VBoxVideo drivers in the Video Card configuration. Press OK two times and reboot the machine.
  • On restart, again open the Display window. If the desired resolution is not being displayed then you have to manually modify the /etc/X11/xorg.conf file.
  • Open the /etc/X11/xorg.conf file . Modify the Section "Screen". You need to add the Modes.
  •       Section "Screen"
             Identifier "Screen0"
             Device     "Videocard0"
             Monitor    "Monitor0"
             DefaultDepth     24
             SubSection "Display"
                 Viewport   0 0
                 Depth     24
                 Modes "1024x768"
             EndSubSection
          EndSection
  • Reboot the machine. On restart, you shall see the Virtual Machine will start with the new resolution. To have full screen press the host + F keys. By default the host key for Virtual Box is Right Control key.

Tuesday, November 11, 2008

Checking network connection using Java

At times it is required to check whether the machine is still connected to network or not. One way to find it using JDK1.6 by using the code is as below.
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
    NetworkInterface nic = interfaces.nextElement();
    System.out.print("Interface Name : [" + nic.getDisplayName() + "]");
    System.out.println(", Is connected : [" + nic.isUp() + "]");
}
Additionally several new useful methods such as isLoopBack(), isPointToPoint() and many more have been added in JDK 1.6 release. Refer to the Javadocs for more information on NetworkInterface class in java.net package.