Friday, August 27, 2010

Red Pineapple ?

Saw this at one of the hotels where I stayed. I saw a pineapple tree for the first time and that too a red colored one.

Monday, August 23, 2010

XML2PDF-Text as document watermark

This one is long due. Some time back I was working on a task that takes XML input, XSL stylesheet and runs Apache FOP processor to create a PDF document.
The PDF document should contain different sections like headers, footers, invoice lines (table) and a watermark. Each section may contain different blocks of data.
There were some different types of pages so I have developed a couple of XSL stylesheet to handle this. Please note that this was not a dynamic thing which can be used for any kind of XML2PDF conversion.

The main challenges I have faced with FOP.
1) For some reason, I had issues with my final PDF document layout. Even if everything thing looked fine, I had some overlap problems between lines. Finally figured out that was the problem with using Saxon Transformer Factory.
Setting the Xalan Transformer Factory as the default solved the problem.
System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");

 
2) Creating a dynamic watermark/banner.
i.e. I get some text data as part of the input document and I need to set this as PDF watermark.
Most of the APIs easily support images as watermarks but there's no direct support for using text content as watermark.
Luckily I found the solution for this by using Batik API to draw watermarks and integrated that in my stylesheet using "fo:instream-foreign-object" in FOP.
The below snippet shows the XSL code for this.

Here I wanted the watermark to be in the diagonal shape so I transformed the text, rotated it by 45degrees and did some final finishing. Here's a quick snapshot of the final outcome. You can see the 'Test Watermark' which is generated using the above XSL.

Monday, March 15, 2010

Windows file lock issue in eclipse - classloader problem

File lock issue in windows when using URLClassloader objects.

Brief overview of the problem:

In our eclipse application, we configure various services. Each service has its own property sheet (dialog). While launching a service dialog in eclipse platform, we create a custom URLClassloader objects using all its dependencies/ resources (jar files). Once this dialog is Finished/Closed the jar files still get locked up in windows platform and this caused problems.

Normally to handle such locks, we create a custom URLStreamHandlerFactory that implements java.net.URLStreamHandlerFactory where we create our own handlers for different protocols. Sample code is present in Listing 1.

This perfectly works for most of the cases but since my process is an eclipse process and eclipse is already setting its own URLStreamHandlerFactory I couldn't directly use the code in Listing 1 since URL.setURLStreamHandlerFactory(customFactory); has to be called only once in a jvm.


However, I tried some workarounds like using reflection to reset the URLStreamHandlerFactory and to specifically use the following URL constructor.
URL jarUrl = new URL("jar", "", -1, resourceFileUrl.toString()+ "!/");
Iam able to accomplish the task but later I discovered that this broke some other areas and I keep on getting NoClassDefFoundErrors even if the class is available in the classpath and loaded by the same classloader.

Finally Iam able to resolve this with a simple workaround which does 2 things - Setting the field defaultUseCaches in URLConnection class to false, using some utility code to close all Jar connections. The solution is posted below.

Solution that Worked:

1. There is a field defaultUseCaches in URLConnection class. This field has to be set to false when the application loads.

static {
    try{
        Field defaultUseCaches = URLConnection.class.getDeclaredField("defaultUseCaches");
        defaultUseCaches.setAccessible(true);
        defaultUseCaches.set(defaultUseCaches, false);
    } catch(Exception e){
        //do something
    }
}

Note: If this is set to false then setting useCaches to false is not required as in Listing 1.


2. Used an utility class to release all the resources held by URLClassloader when a service dialog is closed.
Used releaseLoader(URLClassLoader classLoader, List jarsClosed) method in sun.misc.ClassLoaderUtil to close the jarfiles. The source code is available here.

http://www.docjar.com/html/api/sun/misc/ClassLoaderUtil.java.html

The classloader problem was resolved after this.

Note: ClassLoaderUtil uses classes like URLClassPath which are restricted by default in eclipse.
To overcome this the following setting has to be changed in eclipse preferences.
Navigate to Preferences -> Java -> Compiler -> Errors and Warnings -> Deprecated and Restricted API and change the value of  Forbidden Reference to Warning.


Listing 1:
Lists the sample custom URLStreamHandlerFactory class and a simple JarHandler. Same code can be used in other handlers like FTP, File etc.
Note: This cannot be used for eclipse process. Works for normal java processes.

-------------------MyURLStreamHandlerFactory -------------------------
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.Hashtable;

public class MyURLStreamHandlerFactory implements URLStreamHandlerFactory {


private Hashtable handlers;
public MyURLStreamHandlerFactory() {
    handlers = new Hashtable();
}

public URLStreamHandler createURLStreamHandler(String protocol) {
    URLStreamHandler ush = (URLStreamHandler) handlers.get(protocol);
    if (ush == null) {
        if (protocol.equalsIgnoreCase("file")) {
            URLFileHandler fileHandler = new URLFileHandler();

            ush = fileHandler;
            handlers.put(protocol, fileHandler);
        } else if (protocol.equalsIgnoreCase("jar")) {
            URLJarHandler jarHandler = new URLJarHandler();
            ush = jarHandler;
            handlers.put(protocol, jarHandler);
        } else if (protocol.equalsIgnoreCase("ftp")) {
            URLFtpHandler ftpHandler = new URLFtpHandler();
            ush = ftpHandler;
            handlers.put(protocol, ftpHandler);
        } else if (protocol.equalsIgnoreCase("http")) {
            URLHttpHandler httpHandler = new URLHttpHandler();
            ush = httpHandler;
            handlers.put(protocol, httpHandler);
        } else if (protocol.equalsIgnoreCase("https")) {
            URLHttpsHandler httpsHandler = new URLHttpsHandler();
            ush = httpsHandler;
            handlers.put(protocol, httpsHandler);
        }
    }
return ush;
}


/**
* Clears the URLStream Handler(s) hash table.

*/
public void clear() {
    handlers.clear();
}


}

--------------------- MyURLStreamHandlerFactory --------------

------------------------- URLJarHandler---------------------------
import java.net.URLConnection;
import java.net.URL;
import java.io.IOException;


/**
* Jar URL Stream Handler . It has all the attributes of a URLStreamHandler for the 'jar' protocol.
* openConnection method overriden to prevent locking & caching of file on windows os.
*/
public class URLJarHandler extends sun.net.www.protocol.jar.Handler {

protected URLConnection openConnection(URL url) throws IOException {
    URLConnection u = super.openConnection(url);
    u.setUseCaches(false);//prevents locking&caching of file on windows by jvm.
    return u;
}
 }
-------------------------------URLJarHandler------------------