Tuesday, January 29, 2013

Java assist to the rescue

Java assist to the rescue We use XStream (http://xstream.codehaus.org/) for serializing objects to xml. Our basic structure is:

 
 
 
  
  
 

We create annotations on our objects for the XStream converter, which worked fine. The problem we faced was how to give a proper name for the “object” node in the xml. Since we needed objects for the converter, we created a class GlobalInfo that accepted a base class of GenericObject. Each scenario that needed to transform an object to the xml, we inherited the GenericObject that had an internal field by the name that we wanted, this way the standard serializer used the field name for the xml. For example:
 public class TempObject extends GenericObject {
 private MyObject myName;
}
This would create the following xml: I looked for a generic way to create the “myName” node. Using XStream the standard way was to use annotations. The problem is that during run time you cannot change the annotation values. To overcome this I used java assit. With java assit I could create the class “TempObject” by code during runtime and then I would have a generic way to create the xml node without creating multiple classes during the coding phase. The idea is to create a class during runtime, and then assign the filed myName with the object that needs to be serialized. The following example will create the class:
@SuppressWarnings({ "rawtypes", "unchecked" })
public static GenericObject generate(Object source, String objectFieldName) {
 try {
  ClassPool pool = ClassPool.getDefault();
  // create the class
  String generatedClassName = String.format("TempObject.%s", objectFieldName);
  Class clazz = classFactory.get(objectFieldName);
  if (clazz == null) {
   CtClass transClass = null;
   try {
    transClass = pool.get(generatedClassName);
   } catch (NotFoundException e) {

    transClass = pool.makeClass(generatedClassName);
    CtClass superClass = pool.get("a.b.c.GenericObject");
    transClass.setSuperclass(superClass);

    CtField field = CtField.make(
      String.format("private Object %s;", objectFieldName), transClass);
    transClass.addField(field);
    transClass.addMethod(CtNewMethod.make(
      String.format("public void setObject (Object obj) { this.%s=obj; }",
        objectFieldName), transClass));

    clazz = transClass.toClass();
    classFactory.put(objectFieldName, clazz);
   }
  }

  Object obj = clazz.newInstance();
  Class[] formalParams = new Class[] { Object.class };
  Method meth = clazz.getDeclaredMethod("setObject", formalParams);
  meth.invoke(obj, source);
  // PropertyUtils.setProperty(obj, "obj", source);
  return (GenericObject) obj;

 } catch (Exception e) {
  throw new RuntimeException(e);

 }
}

Wednesday, January 23, 2013

Java Web Service Client


Java Web Service Client

There are numerous ways to create web service clients in java. The simplest way is of course to create a proxy class from the wdsl (see http://sourceforge.net/projects/wsdl2javawizard/, http://axis.apache.org/axis2/java/core/tools/eclipse/wsdl2java-plugin.html).
There are times that this is fine usually when you need to support only one web service and it is static. The downside is that a web service is just a protocol for communication, and we have now coupled our code to this specific web service and its interface.

First level of abstraction: spring templates

Spring has a template class for multiple services. The class for this is: WebServiceTemplate. This class supports defaultUri if all your calls are to the same web service.
The simplest function of this class is:
boolean sendSourceAndReceiveToResult(String uri, Source requestPayload, WebServiceMessageCallback requestCallback, final Result responseResult);

Through this function you can send to any web service. You define the url and the xml payload for the service. Spring will add all the soap headers needed (except for the soap action – we will see this later on).

An example:

String url = "http://www.w3schools.com/webservices/tempconvert.asmx";
String xml =” <CelsiusToFahrenheit xmlns="http://tempuri.org/"> <Celsius>22</Celsius>
</CelsiusToFahrenheit>”;

StreamSource webServiceInput = new StreamSource(new StringReader(xmlDoc));
StringWriter finalResponseWriter = new StringWriter();

StreamResult webServiceOutput = new StreamResult(finalResponseWriter);
webServiceTemplate.sendSourceAndReceiveToResult(url, webServiceInput,
                           webServiceOutput);

If succeeded the result of the soap request is stored in the finalResponseWriter object.

The soap action needs to be added to the soap request, and cannot be automatically added. To add support for this there is the callback method. For example:

new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
// Please see the WSDL for more details.
 ((SoapMessage) message).setSoapAction(“http://tempuri.org/CelsiusToFahrenheit”);
}

A more generic approach can be added by the following function:
public boolean sendSourceAndReceiveToResult(String uri,
              Source requestPayload, final Result responseResult,
              final String soapAction) {

       return super.sendSourceAndReceiveToResult(uri, requestPayload,
              new WebServiceMessageCallback() {
                     public void doWithMessage(WebServiceMessage message) {
                           // Please see the WSDL for more details.
                           ((SoapMessage) message).setSoapAction(soapAction);
                     }
              }, responseResult);
}


The spring template will allow the beginning of decoupling. We do not create specific classes for the web service, and if the provider is changed the we can paramitize the web service properties to an ini file and the xml request to another class to generate per web service interface.

Second level of abstraction: spring integration

With the soap template we still need write an abstraction level to create the xml requests per web service client.  In addition if the web service needs to be changed with another protocol the code now needs to be redone. To get full decoupling model we will use spring integration. To fully understand spring integration see http://www.springsource.org/spring-integration.

To make the code as nice as possible as in the example above we want to create a class CelsiusToFahrenheit and have the option to send a request to a service to get the result. What needs to be done is to serialize the class to the specific service protocol. This abstraction can be done with spring integration.
First we will look at the code that sends the class to get the Celsius to Fahrenheit conversion.

CelsiusToFahrenheit cToF = new CelsiusToFahrenheit(22);
                          
MessagingTemplate messagingTemplate = new MessagingTemplate(celsiusToFahrenheit);
              Message<?> response = messagingTemplate.sendAndReceive(new GenericMessage<CelsiusToFahrenheit>(cToF));
CelsiusToFahrenheitResponse celsiusToFahrenheitResponse = (CelsiusToFahrenheitResponse)response.getPayload();

To accomplish this we need to convert the CelsiusToFahrenheit class to xml using jaxb. We then send the xml on the web service. The result of the web service is then unmarshalled from xml to the class CelsiusToFahrenheitResponse.

The spring integration for this is:

<bean id="c2fMarshallingTransformer"
       class="org.springframework.integration.xml.transformer.MarshallingTransformer">
       <constructor-arg>
              <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                     <property name="classesToBeBound">
                           <array>
                                  <value> CelsiusToFahrenheit
                                  </value>
                           </array>
                     </property>
              </bean>
       </constructor-arg>
       <constructor-arg>
              <bean
                     class="org.springframework.integration.xml.transformer.ResultToDocumentTransformer" />
       </constructor-arg>
</bean>

<bean id="c2fUnmarshallingTransformer"
       class="org.springframework.integration.xml.transformer.UnmarshallingTransformer">
       <constructor-arg>
              <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
                     <property name="classesToBeBound">
                           <array>
                                  <value>CelsiusToFahrenheitResponse
                                  </value>
                           </array>
                     </property>
              </bean>
       </constructor-arg>
</bean>


<int:channel id="celsiusToFahrenheit" />
<int:chain input-channel="celsiusToFahrenheit">
       <int:transformer ref="c2fMarshallingTransformer" />
       <ws:header-enricher>
              <ws:soap-action value="http://tempuri.org/CelsiusToFahrenheit" />
       </ws:header-enricher>
       <ws:outbound-gateway
              uri="http://www.w3schools.com/webservices/tempconvert.asmx">
       </ws:outbound-gateway>
       <int:transformer ref="c2fUnmarshallingTransformer" />
</int:chain>


Other issues with Soap Requests

Whether using spring integration or spring template there are issues with web services that need to be overcome.

SSL – with or without credentials

The first is to allow sending web services over ssl and might or might not include using user credentials. To do this spring has two implementations for the sending of the web service. One is HttpComponentsMessageSender. This implementation uses HttpClient as the underlying connection. The HttpClient has many features that we will use.
By using the url of https, the HttpComponentsMessageSender knows to send all requests via ssl. To use user credentials the following needs to be configured on the message sender object:


<bean id="messageSender"
       class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
       <property name="connectionTimeout" value="3000" />
       <property name="readTimeout" value="5000" />
       <property name="credentials">
              <bean class="org.apache.http.auth.UsernamePasswordCredentials">
                     <constructor-arg value="username:password" />
              </bean>
       </property>
</bean>


Timeout

To add timeout parameters we also use the HttpClient as above and will configure:
<bean id="messageSender"
       class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
       <property name="connectionTimeout" value="3000" />
       <property name="readTimeout" value="5000" />
</bean>


Retries

We will again use the built in options of the HttpClient.
HttpClient support retry by using the following interface:

public interface HttpRequestRetryHandler {
    boolean retryRequest(IOException exception, int executionCount, HttpContext context);
}

You can implement this in your own way if needed. There is a default retry handler: DefaultHttpRequestRetryHandler.
The default handler will retry 3 times if not succeeded. The default handler knows to distinguish between a failed connection (and will retry) to other failures that retry will not help (like UnknownHostException, ConnectException, SSLException, InterruptedIOException). In the case that the exception is not in the list above the default handler calls the function handleAsIdempotent to determine if it is a read only request.
In the case of web services all http requests are post, and the protocol does not notify if the request is read only or not. So we will add a new class SoapHttpRequestRetryHandler that will override the handleAsIdempotent and allow to configure in the xml file the read only soap actions.

public class SoapHttpRequestRetryHandler extends DefaultHttpRequestRetryHandler {

       private List<String> readOnlySoapActions = new LinkedList<String>();
      
       public SoapHttpRequestRetryHandler(int retryCount, boolean requestSentRetryEnabled, List<String> readOnlySoapActions){
              super(retryCount, requestSentRetryEnabled);
              this.readOnlySoapActions = readOnlySoapActions;
       }

      
       private String getSoapAction(HttpRequest request){
              return request.getFirstHeader("SOAPAction").getValue();
       }
      
       @Override
       protected boolean handleAsIdempotent(HttpRequest request) {
              if (readOnlySoapActions.indexOf(getSoapAction(request))!=-1)
                     return true;
              return super.handleAsIdempotent(request);
       }
      
}

Untrusted SSL Clients


In the case of a trusted site, spring soap template knows to use the sites certificate to encrypt all data. If the site is not trusted, then spring will raise an exception:
SunCertPathBuilderException: unable to find valid certification path to requested target.

In the case you do not want this, you need to register a new class SSLSocketFactory with the httpclient, and add the method:

public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
return true;
}

For example:

private static DefaultHttpClient trustEveryoneSslHttpClient() {
    try {
        SchemeRegistry registry = new SchemeRegistry();

        SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {

            public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
                // Oh, I am easy...
                return true;
            }

        }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        registry.register(new Scheme("https", 443, socketFactory));
        registry.register(new Scheme("http", 80, new PlainSocketFactory()));
       
        PoolingClientConnectionManager mgr = new PoolingClientConnectionManager(registry);
        DefaultHttpClient client = new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
        return client;
    } catch (GeneralSecurityException e) {
        throw new RuntimeException(e);
    }
}     

Monday, January 14, 2013

REST WADL / Extending WadlGenerator in CXF




A problem in the world of wadl, is that the documentation level on the wadl level is not great.
An example:
<resource path="/agents">
                <method name="GET">
                                <request>
                                                <param name="externalAgentRef" style="query" type="xs:string"/>
                                </request>
                                <response>
                                                <representation mediaType="application/json"/>
                                </response>
                </method>
</resource>

In this example you can see that the default WadlGenerator will display all parameters in the input, but the output is defined as application/json. What we want is for the xml to describe the object that is serialized on the output.
Solution:
To do this we need do define a provider for the jaxrs:
<jaxrs:providers>
<bean class="...WadlGeneratorEx">
<property name="linkJsonToXmlSchema" value="true" />
</bean>                                 
</jaxrs:providers>

CXF does not have a standard interface for the Wadl generator, so you need to extend the current WadlGenerator (http://cxf.apache.org/javadoc/latest/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.html).
Since the class was not created properly for overriding methods, I copied to whole class to a new class with the inheritance of:
public class WadlGeneratorEx extends WadlGenerator implements RequestHandler
On the method: private void handleRepresentation, I added the following line:
sb.append(" classImpl=\"").append(type.getSimpleName()).append("\"");

The new output looks like:
<representation mediaType="application/json" classImpl="Agent"/>

You can now add any other xml attributes you need for documentation.


Thursday, December 27, 2012

Hibernate setMaxResults on join tables


The problem:
Let’s say I have a class: Author that has children of multiple books. I would like to retrieve the authors and books, but only want to retrieve the first 10 authors.
The hibernate api for this is to use the setMaxResults function.
The naïve thought would be that if I set the setMaxResults to 10, I will get 10 authors, but this is not true. Since all hibernate commands in the end are sql statements, what the setMaxResults does is to add a LIMIT/TOP (depending on the database) to the sql statement. What then happens is if you have a join in your query like we do, you will not get 10 authors, but actually you will get 10 books (maybe only 5 authors).

Solution, Option One:
The simple solution for this is to create two sql statements. One that will retrieve the first 10 authors id’s according to the criteria you want (including on the books). Then add the id’s to a basic search and fetch the books with the authors.

Solution, Option Two:
If you need to create the join and fetch already in the query stage, but you only want to retrieve the first 10 records that have unique authors. The next solution I propose for this is to use a cursor. Using a standard query will return all records from the db to the application. Using a cursor you can iterate over the records without bringing them all to the client. Cursors lock the db for more time, but give the option to iterate over the records without retrieving them all. To do this you call .scroll() on the query object or criteria and get a ScrollableResults object. If you are only iterating of the list use the ScrollMode.FORWARD_ONLY option to use less memory and speed the process.
Note: you need to make sure that your database supports this, since some databases like mysql fake it and bring the whole data to the client (http://stackoverflow.com/questions/2826319/using-hibernates-scrollableresults-to-slowly-read-90-million-records)

Pagination:
Some queries use a pagination scheme to get data. The standard way is to call setFirstResult.
In the first solution, you need to add the setFirstResult to the query on the id’s, and not the query with the fetch.
In the second solution this won’t work since we are back to the problem that we are counting the rows by ourselves so the setFirstResult won’t work either in hibernate query or scroll.

Dialect solution:
Currently solutions to this issue is on the dialect of the specific database. For example sql server has a row count feature where you can define the field that the sql will add the row count field (a column that has an integer of count according to another field- http://msdn.microsoft.com/en-us/library/ms186734.aspx). Then on this field you can use the standard hibernate setMaxResults and setFirstResult.



Wednesday, July 4, 2012

Java Hibernate & Proxy


One of the strenghts of  Hibernate is the option for lazy loading. This means that we do not actually load the object from the db, but hibernate creates a proxy object, and only when we actually need the object does it go to the database and get the information.
This helps on performance of the product, but can cause a lot of side effects.
The proxy class is not the actual class, but implemenets all the public methods of the real class and then delegates them to the real class when created.
Some times this is not good enought and you need the actual class and not the proxy.
After searching the internet i have found the following way to get from hibernate the actuall class and not the proxy.

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
        throw new 
           NullPointerException("Entity passed for initialization is null");
    }

    Hibernate.initialize(entity);
    if (entity instanceof HibernateProxy) {
        entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
                .getImplementation();
    }
    return entity;
}