Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Sunday, April 5, 2015

A way to read properties with variable interpolation

Recently, I tried to define and read a global properties in an application server. The benefit of such property configured in the application server - it can be shared across all web applications that are deployed on this server. Every deployed application can read the same property which is configured just once at one place. What I tried to do was a system property with another system property in the value part. In the application server JBoss / WildFly, you can e.g. define a system property in the configuration file standalone.xml. I set the property exporting.service.config.file.
<system-properties>
    <property name="exporting.service.config.file" value="${jboss.server.config.dir}\exporting\exporting-service.properties"/>
</system-properties>
jboss.server.config.dir points to the base configuration directory in JBoss. This property is set automatically by JBoss. In this example, we have a so-called Variable Interpolation. The definition from the Wikipedia: "Variable interpolation (also variable substitution or variable expansion) is the process of evaluating a string literal containing one or more placeholders, yielding a result in which the placeholders are replaced with their corresponding values". Another example for placeholders ${...} in property value would be the following configuration:
application.name=My App
application.version=2.0
application.title=${application.name} ${application.version}
When we now try to get the system property from the first example with Java's System.getProperty(...)
 
String globalConfigFile = System.getProperty("exporting.service.config.file");
 
we will get the value ${jboss.server.config.dir}\exporting\exporting-service.properties. The placeholder ${jboss.server.config.dir} is not resolved. There are the same troubles in the second example as well.

What would be the simplest way to read properties with variable interpolation? Well, there is the Spring Framework with PlaceholderConfigurerSupport and so on. But it is an overhead to have such big framework as dependency. Is there a lightweight library? Yes, sure - Apache Commons Configuration. Apache Commons Configuration provides special prefix names for properties to evaluate them in a certain context. There are for instance:
  • sys: This prefix marks a variable to be a system property. Commons Configuration will search for a system property with the given name and replace the variable by its value.
  • const: The prefix indicates that a variable is to be interpreted as a constant member field of a class. The name of the variable must be fully qualified class name.
  • env: The prefix references OS-specific environment properties.
 Some examples from the documentation:
user.file = ${sys:user.home}/settings.xml
action.key = ${const:java.awt.event.KeyEvent.VK_CANCEL}
java.home = ${env:JAVA_HOME}
Now, I could add the needed dependency to my Maven project
<dependency>
    <groupId>commons-configuration</groupId>
    <artifactId>commons-configuration</artifactId>
    <version>1.10</version>
</dependency>
set the prefix sys: before jboss.server.config.dir
<system-properties>
    <property name="exporting.service.config.file" value="${sys:jboss.server.config.dir}\exporting\exporting-service.properties"/>
</system-properties>
and write the following code
import org.apache.commons.configuration.SystemConfiguration;

...

SystemConfiguration systemConfiguration = new SystemConfiguration();
String globalConfigFile = systemConfiguration.getString("exporting.service.config.file");
...
The String globalConfigFile on my notebook has the value C:\Development\Servers\jboss-as-7.1.1.Final\standalone\configuration\exporting\exporting-service.properties. The prefix sys: marks a variable to be a system property. Commons Configuration will search for a system property with the given name and replace the variable by its value. The complete code:
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.SystemConfiguration;

...

PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration();
SystemConfiguration systemConfiguration = new SystemConfiguration();
String globalConfigFile = systemConfiguration.getString("exporting.service.config.file");
if (globalConfigFile != null) {
    try {                
        propertiesConfiguration.setDelimiterParsingDisabled(true);                
        propertiesConfiguration.load(globalConfigFile);
    } catch (ConfigurationException e) {
        LOG.log(Level.INFO, "Cannot read global properties");
    }            
}
Any single property can be read e.g. as
propertiesConfiguration.getString("someKey")
propertiesConfiguration.getString("someKey", someDefaultValue)
propertiesConfiguration.getBoolean("someKey")
propertiesConfiguration.getBoolean("someKey", someDefaultValue)
propertiesConfiguration.getInteger("someKey")
propertiesConfiguration.getInteger("someKey", someDefaultValue)
usw. That's all. Let me know if you know another simple ways to read properties with variable interpolation.

Friday, April 3, 2015

Caching of web content with Spring's cache manager


I this post, I would like to show basics how to cache and manage the caching of web content with Spring's CacheManager, @Cacheable and JMX annotations. Imagine a web shop which fetches some content, such as header, footer, teasers, main navigation, from a remote WCMS (Web Content Management System). The fetching may e.g. happen via a REST service. Some content is rarely updated, so that it makes sense to cache it in the web application due to performance reasons.

Getting Started

First, we need a cache provider. A good cache provider would be EhCache. You need to add the EhCache as dependency to your project. You also need to configure ehcache.xml which describes, among other things, the cache name(s), where and how long the cached content is stored. Please refer to the documentation to learn how the ehcache.xml looks like. The central class of the EhCache is the net.sf.ehcache.CacheManager. With help of this class you can add or remove any objects to / from the cache and much more programmatically. Objects can be cached in memory, on the disk or somewhere else.

The Spring framework provides a CacheManager backed by the EhCache - org.springframework.cache.CacheManager. It also provides the @Cacheable annotation. From the documentation: "As the name implies, @Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name of the cache associated with the annotated method". We will use the JMX annotations as well. These are Spring's annotations @ManagedResource and @ManagedOperation. Why do we need those? We need them to be able to clear cache(s) via an JMX console. Why? Well, e.g. the underlying data have been changed, but the cache is not expired yet. The outdated data will be still read from the cache and not from the native source. The beans annotated with @ManagedResource will be exposed as JMX beans and methods annotated by @ManagedOperation can be executed via an JMX console. I recommend to use JMiniX as a simple JMX entry point. Embedding JMiniX in a webapp is done simply by declaring a servlet. Parametrized methods are supported as well, so that you can even input some real values for method's parameters and trigger the execution with these values.

How to do it...

Now we are ready to develop the first code. We need a service which communicates with a remote backend in order to fetch various contents from the WCMS. Let's show exemplary a basic code with one method fetchMainNavigation(). This method fetches the structure of the main navigation menu and converts the structure to a DTO object NavigationContainerDTO (model class for the menu). The whole business and technical logic is resided in the bean MainNavigationHandler. This logic is not important for this blog post. The method fetchMainNavigation() expects two parameters: locale (e.g. English or German) and variant (e.g. B2C or B2B shop).
@Component
public class WCMSServiceImpl extends BaseService implements WCMSService {
 
    // injection of Spring's CacheManager is needed for @Cacheable
    @Autowired
    private CacheManager cacheManager;
 
    @Autowired
    private MainNavigationHandler mainNavigationHandler;
 
    ...
 
    @Override
    @Cacheable(value = "wcms-mainnavigation",
                        key = "T(somepackage.wcms.WCMSBaseHandler).cacheKey(#root.methodName, #root.args[0], #root.args[1])")
    public NavigationContainerDTO fetchMainNavigation(Locale lang, String variant) {
        Object[] params = new Object[0];
        if (lang != null) {
            params = ArrayUtils.add(params, lang);
        }
        if (variant != null) {
            params = ArrayUtils.add(params, variant);
        }
 
        return mainNavigationHandler.get("fetchMainNavigation", params);
    }
}
The method is annotated with the Spring's annotation @Cacheable. That means, the returned object NavigationContainerDTO will be cached if it was not yet available in the cache. The next fetching will return the object from the cache until the cache gets expired. The caching occurs according to the settings in the ehcache.xml. Spring's CacheManager finds the EhCache provider automatically in the classpath. The value attribute in @Cacheable points to the cache name. The key attribute points to the key in the cache the object can be accessed by. Since caches are essentially key-value stores, each invocation of a cached method needs to be translated into a suitable key for the cache access. In a simple case, the key can be any static string. In the example, we need a dynamic key because the method has two parameters: locale and variant. Fortunately, Spring supports dynamic keys with SpEL expression (Spring EL expression). See the table "Cache SpEL available metadata" for more details. You can invoke any static method generating the key. Our expression T(somepackage.wcms.WCMSBaseHandler).cacheKey(#root.methodName, #root.args[0], #root.args[1]) means we call the static method cacheKey in the class WCMSBaseHandler with three parameters: the method name, first and second arguments (locale and variant respectively). This is our key generator.
public static String cacheKey(String method, Object... params) {
    StringBuilder sb = new StringBuilder();
    sb.append(method);

    if (params != null && params.length > 0) {
        for (Object param : params) {
            if (param != null) {
                sb.append("-");
                sb.append(param.toString());
            }
        }
    }

    return sb.toString();
}
Let's show how the handler class MainNavigationHandler looks like. This is just a simplified example from a real project.
@Component
@ManagedResource(objectName = "bean:name=WCMS-MainNavigation",
                                description = "Manages WCMS-Cache for the Main-Navigation")
public class MainNavigationHandler extends WCMSBaseHandler<NavigationContainerDTO, Navigation> {

    @Override
    NavigationContainerDTO retrieve(Objects... params) {
        // the logic for content retrieving and DTOs mapping is placed here
        ...
    }
 
    @ManagedOperation(description = "Delete WCMS-Cache")
    public void clearCache() {
        Cache cache = cacheManager.getCache("wcms-mainnavigation");
        if (cache != null) {
            cache.clear();
        }
    } 
}
The CacheManager is also available here thanks to the following injection in the WCMSBaseHandler.
@Autowired
private CacheManager cacheManager;
@ManagedResource is the Spring's JMX annotation, so that the beans are exported as JMX MBean and become visible in the JMX console. The method to be exported should be annotated with @ManagedOperation. This is the methode clearCache() which removes all content for the main navigation from the cache. "All content" means an object of type NavigationContainerDTO. The developed WCMS service can be now injected into a bean on the front-end side. I already blogged about how to build a multi-level menu with plain HTML and shown the code. This is exactly the main navigation from this service.

There is more...

The scanning of JMX annotations should be configured in a Spring's XML configuration file.
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
    <property name="server" ref="mbeanServer"/>
    <property name="assembler" ref="assembler"/>
    <property name="namingStrategy" ref="namingStrategy"/>
    <property name="autodetect" value="true"/>
</bean>
The JMX console of the JMiniX is reachable under the http(s)://:/mct/webshop/admin/jmx/ A click on the execute button of the clearCache() method triggers the cache clearing.

Sunday, March 30, 2014

Set up JSF environment for JUnit tests

JUnit tests often need mocked JSF / Servlet objects when you test JSF based web applications. Such objects can be FacesContext, ExternalContext, ApplicationContext, HttpRequest, HttpSession, etc. I already mentioned the MyFaces Test Framework in one of my outdated post. In this post, I would like to introduce a new simple and lightweight approach based on JUnit TestRule. The concept behind TestRule is similar to custom JUnit runners, but without restrictions (you can not use multiple runners, but you can use multiple TestRules). Let's go step by step to explain the idea. A class which implements the interface TestRule must implement the method
Statement apply(Statement base, Description description)
The first Statement parameter is a specific object which reprensents the method under the test from your test class. Such a test method can be invoked by base.evaluate(). You can place any custom code before and after the call base.evaluate(). A typically implementation follows this pattern
public Statement apply(final Statement base, Description description) {
    return new Statement() {
        @Override
        public void evaluate() throws Throwable {
            // do something before invoking the method to be tested
            ...
            try {
                base.evaluate();
            } finally {
                // do something after invoking the method to be tested
                ...
            }
        }
    };
}
In short words: the apply method allows to intercept the base call of every test method and put a custom code around. Your TestRule implementation, say MyRule, can be used in any test class with the @Rule annotation as follows:
@Rule
public TestRule myRule = new MyRule();
Note: The member variable should be public. Let's take more examples. There is a good introduction in this tutorial. The author demonstrates how to implement two TestRules: one for SpringContext to use @Autowired in test classes and one for Mockito to populate the mocks before each test. An excellent example! I allow me to repeat the usage example.
public class FooTest {

    @Rule
    public TestRule contextRule = new SpringContextRule(new String[]{"testContext.xml"}, this);

    @Rule
    public TestRule mockRule = new MockRule(this);

    @Autowired
    public String bar;

    @Mock
    public List baz;

    @Test
    public void testBar() throws Exception {
        assertEquals("bar", bar);
    }

    @Test
    public void testBaz() throws Exception {
        when(baz.size()).thenReturn(2);
        assertEquals(2, baz.size());
    }
}
This can not be achieved with two JUnit runners at once. E.g. you can not annotate a test class at the same time with @RunWith(Parameterized.class) and @RunWith(SpringJUnit4ClassRunner.class) or @RunWith(MockitoJUnitRunner.class).

But back to JSF. I want to show how to implement a TestRule for a simple and extensible JSF environment. First of all, we need a mock for FacesContext. We will implement it with Mockito - the most popular Java test framework. I have seen many different implementations, but in fact it is not difficult to implement a proper mock of FacesContext.
import javax.faces.context.FacesContext;

import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public abstract class FacesContextMocker extends FacesContext {

    private FacesContextMocker() {
    }

    private static final Release RELEASE = new Release();

    private static class Release implements Answer<Void> {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            setCurrentInstance(null);
            return null;
        }
    }

    public static FacesContext mockFacesContext() {
        FacesContext context = Mockito.mock(FacesContext.class);
        setCurrentInstance(context);
        Mockito.doAnswer(RELEASE).when(context).release();
        return context;
    }
}
For all PrimeFaces fan we will provide a similar mock for RequestContext.
import org.primefaces.context.RequestContext;

import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public abstract class RequestContextMocker extends RequestContext {

    private RequestContextMocker() {
    }

    private static final Release RELEASE = new Release();

    private static class Release implements Answer<Void> {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            setCurrentInstance(null);
            return null;
        }
    }

    public static RequestContext mockRequestContext() {
        RequestContext context = Mockito.mock(RequestContext.class);
        setCurrentInstance(context);
        Mockito.doAnswer(RELEASE).when(context).release();
        return context;
    }
}
Now, a minimal JSF / Servlet environment could be set up as follows
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.faces.application.Application;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.mockito.Mockito;
import org.primefaces.context.RequestContext;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class JsfMock implements TestRule {

    public FacesContext mockFacesContext;
    public RequestContext mockRequestContext;
    public UIViewRoot mockViewRoot;
    public Application mockApplication;
    public ExternalContext mockExternalContext;
    public HttpSession mockHttpSession;
    public HttpServletRequest mockHttpServletRequest;
    public HttpServletResponse mockHttpServletResponse;

    @Override
    public Statement apply(final Statement base, final Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                init();
                try {
                    base.evaluate();
                } finally {
                    mockFacesContext.release();
                    mockRequestContext.release();
                }
            }
        };
    }

    protected void init() {
        mockFacesContext = FacesContextMocker.mockFacesContext();
        mockRequestContext = RequestContextMocker.mockRequestContext();
        mockApplication = Mockito.mock(Application.class);
        mockViewRoot = Mockito.mock(UIViewRoot.class);
        mockExternalContext = Mockito.mock(ExternalContext.class);
        mockHttpServletRequest = Mockito.mock(HttpServletRequest.class);
        mockHttpServletResponse = Mockito.mock(HttpServletResponse.class);
        mockHttpSession = Mockito.mock(HttpSession.class);

        Mockito.when(mockFacesContext.getApplication()).thenReturn(mockApplication);
        Mockito.when(mockApplication.getSupportedLocales()).thenReturn(createLocales().iterator());

        Mockito.when(mockFacesContext.getViewRoot()).thenReturn(mockViewRoot);
        Mockito.when(mockViewRoot.getLocale()).thenReturn(new Locale("en"));

        Mockito.when(mockFacesContext.getExternalContext()).thenReturn(mockExternalContext);
        Mockito.when(mockExternalContext.getRequest()).thenReturn(mockHttpServletRequest);
        Mockito.when(mockHttpServletRequest.getSession()).thenReturn(mockHttpSession);

        Map<String, String> requestMap = new HashMap<String, String>();
        Mockito.when(mockExternalContext.getRequestParameterMap()).thenReturn(requestMap);        
    }

    private List<Locale> createLocales() {
        ArrayList<Locale> locales = new ArrayList<>();
        locales.add(new Locale("en"));
        locales.add(new Locale("de"));
        ...
        return locales;
    }
}
We mocked the most used JSF / Servlet objects, linked them with each other and provided mocks via public member variables, so that they can be extended in test classes if needed. Below is an usage example which also demonstrates how to extend the mocked objects for a particular test.
public class PaymentRequestFormTest {

    private PaymentView paymentView;

    @Rule
    public JsfMock jsfMock = new JsfMock();

    @Before
    public void initialize() {
        paymentView = mock(PaymentView.class);
        ...
    }

    @Test
    public void toJson() {
        // Mock URL and context path
        StringBuffer requestURI = new StringBuffer("http://localhost:8080/webshop");
        Mockito.when(jsfMock.mockHttpServletRequest.getRequestURL()).thenReturn(requestURI);
        Mockito.when(jsfMock.mockHttpServletRequest.getContextPath()).thenReturn("/webshop");

        // Invoke toJson method
        String json = PaymentRequestForm.toJson(jsfMock.mockFacesContext, paymentView);

        // Verify
        ...
    }
}
Any feedbacks are welcome.

Sunday, August 18, 2013

Simple and lightweight pool implementation

Object pools are containers which contain a specified amount of objects. When an object is taken from the pool, it is not available in the pool until it is put back. Objects in the pool have a lifecycle: creation, validation, destroying, etc. A pool helps to manage available resources in a better way. There are many using examples. Especially in application servers there are data source pools, thread pools, etc. Pools should be used in cases such as
  • High-frequency using of the same objects
  • Objects are very big and consume much memory
  • Objects need much time for initialization
  • Objects use massive IO operations (Streams, Sockets, DB, etc.)
  • Objects are not thread-safe
When I looked for a pool implementation for one of my Java projects, I found that many people reference the Apache Commons Pool. Apache Commons Pool provides an object-pooling API. There are interfaces ObjectPool, ObjectPoolFactory, PoolableObjectFactory and many implementations. A pool provides methods addObject, borrowObject, invalidateObject, returnObject to add, take, remove and return back objects. PoolableObjectFactory defines the behavior of objects within a pool and provides various callbacks for pool's operations.

After looking into the implementation details I found that Apache Commons Pool is not a lightweight implementation which is an overhead for my purposes. Furthermore, it uses the old Java's keyword synchronized for a lot of methods which is not recommended for using. Java 5 introduced Executor framework for Java concurrency (multi-threading). The Executor framework is preferable here. I decided to implement a simple and lightweight pool which I would like to present here. It is only one Java class. I think it is enough if you don't need callbacks and other advanced stuff. I created a project easy-pool on GitHub.

The pool implementation is based on ConcurrentLinkedQueue from the java.util.concurrent package. ConcurrentLinkedQueue is a thread-safe queue based on linked nodes. This queue orders elements by FIFO principle (first-in-first-out). My implementation for a generic pool looks as follows
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public abstract class ObjectPool<T>
{
    private ConcurrentLinkedQueue<T> pool;

    private ScheduledExecutorService executorService;

    /**
     * Creates the pool.
     *
     * @param minIdle minimum number of objects residing in the pool
     */
    public ObjectPool(final int minIdle) {
        // initialize pool
        initialize(minIdle);
    }

    /**
     * Creates the pool.
     *
     * @param minIdle            minimum number of objects residing in the pool
     * @param maxIdle            maximum number of objects residing in the pool
     * @param validationInterval time in seconds for periodical checking of minIdle / maxIdle conditions in a separate thread.
     *                           When the number of objects is less than minIdle, missing instances will be created.
     *                           When the number of objects is greater than maxIdle, too many instances will be removed.
     */
    public ObjectPool(final int minIdle, final int maxIdle, final long validationInterval) {
        // initialize pool
        initialize(minIdle);

        // check pool conditions in a separate thread
        executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(new Runnable()
        {
            @Override
            public void run() {
                int size = pool.size();
                if (size < minIdle) {
                    int sizeToBeAdded = minIdle - size;
                    for (int i = 0; i < sizeToBeAdded; i++) {
                        pool.add(createObject());
                    }
                } else if (size > maxIdle) {
                    int sizeToBeRemoved = size - maxIdle;
                    for (int i = 0; i < sizeToBeRemoved; i++) {
                        pool.poll();
                    }
                }
            }
        }, validationInterval, validationInterval, TimeUnit.SECONDS);
    }

    /**
     * Gets the next free object from the pool. If the pool doesn't contain any objects,
     * a new object will be created and given to the caller of this method back.
     *
     * @return T borrowed object
     */
    public T borrowObject() {
        T object;
        if ((object = pool.poll()) == null) {
            object = createObject();
        }

        return object;
    }

    /**
     * Returns object back to the pool.
     *
     * @param object object to be returned
     */
    public void returnObject(T object) {
        if (object == null) {
            return;
        }

        this.pool.offer(object);
    }

    /**
     * Shutdown this pool.
     */
    public void shutdown() {
        if (executorService != null) {
            executorService.shutdown();
        }
    }

    /**
     * Creates a new object.
     *
     * @return T new object
     */
    protected abstract T createObject();

    private void initialize(final int minIdle) {
        pool = new ConcurrentLinkedQueue<T>();

        for (int i = 0; i < minIdle; i++) {
            pool.add(createObject());
        }
    }
}
The abstract class ObjectPool provides two main methods: borrowObject to get the next free object from the pool and returnObject to return the borrowed object back to the pool. If the pool doesn't contain any objects, a new object will be created and given back to the caller of the method borrowObject. The object creation happens in the method createObject. Any class which extends the abstract class ObjectPool only needs to implement this method and the pool is ready to use. As you can see I also utilizes ScheduledExecutorService from the java.util.concurrent package. What it is good for? You can specifies minimum and maximum number of objects residing in the pool. ScheduledExecutorService starts a special task in a separate thread and observes periodical in a specified time (parameter validationInterval) the minimum and maximum number of objects in the pool. When the number of objects is less than the minimum, missing instances will be created. When the number of objects is greater than the maximum, too many instances will be removed. This is sometimes useful for the balance of memory consuming objects in the pool and more.

Let's implement test classes to show using of a concrete pool. First, we need a class representing objects in the pool which simulates a time-consuming process. This class, called ExportingProcess, needs some time to be instantiated.
public class ExportingProcess {

    private String location;

    private long processNo = 0;

    public ExportingProcess(String location, long processNo) {
        this.location = location;
        this.processNo = processNo;

        // doing some time expensive calls / tasks
        // ...

        // for-loop is just for simulation
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
        }

        System.out.println("Object with process no. " + processNo + " was created");
    }

    public String getLocation() {
        return location;
    }

    public long getProcessNo() {
        return processNo;
    }
}
The second class implements the Runnable interface and simulates some task doing by a thread. In the run method, we borrow an instance of ExportingProcess and return it later back to the pool.
public class ExportingTask implements Runnable {

    private ObjectPool<ExportingProcess> pool;

    private int threadNo;

    public ExportingTask(ObjectPool<ExportingProcess> pool, int threadNo) {
        this.pool = pool;
        this.threadNo = threadNo;
    }

    public void run() {
        // get an object from the pool
        ExportingProcess exportingProcess = pool.borrowObject();

        System.out.println("Thread " + threadNo + 
                ": Object with process no. " + exportingProcess.getProcessNo() + " was borrowed");

        // do something
        // ...

        // for-loop is just for simulation
        for (int i = 0; i < 100000; i++) {
        }

        // return ExportingProcess instance back to the pool
        pool.returnObject(exportingProcess);

        System.out.println("Thread " + threadNo + 
                ": Object with process no. " + exportingProcess.getProcessNo() + " was returned");
    }
}
Now, in the JUnit class TestObjectPool, we create a pool of objects of type ExportingProcess. This occurs by means of new ObjectPool<ExportingProcess>(4, 10, 5). Parameters are described in the comments below.
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class TestObjectPool
{
    private ObjectPool<ExportingProcess> pool;

    private AtomicLong processNo = new AtomicLong(0);

    @Before
    public void setUp() {
        // Create a pool of objects of type ExportingProcess. Parameters:
        // 1) Minimum number of special ExportingProcess instances residing in the pool = 4
        // 2) Maximum number of special ExportingProcess instances residing in the pool = 10
        // 3) Time in seconds for periodical checking of minIdle / maxIdle conditions in a separate thread = 5.
        //    When the number of ExportingProcess instances is less than minIdle, missing instances will be created.
        //    When the number of ExportingProcess instances is greater than maxIdle, too many instances will be removed.
        //    If the validation interval is negative, no periodical checking of minIdle / maxIdle conditions
        //    in a separate thread take place. These boundaries are ignored then.
        pool = new ObjectPool<ExportingProcess>(4, 10, 5)
        {
            protected ExportingProcess createObject() {
                // create a test object which takes some time for creation
                return new ExportingProcess("/home/temp/", processNo.incrementAndGet());
            }
        };
    }

    @After
    public void tearDown() {
        pool.shutdown();
    }

    @Test
    public void testObjectPool() {
        ExecutorService executor = Executors.newFixedThreadPool(8);

        // execute 8 tasks in separate threads
        executor.execute(new ExportingTask(pool, 1));
        executor.execute(new ExportingTask(pool, 2));
        executor.execute(new ExportingTask(pool, 3));
        executor.execute(new ExportingTask(pool, 4));
        executor.execute(new ExportingTask(pool, 5));
        executor.execute(new ExportingTask(pool, 6));
        executor.execute(new ExportingTask(pool, 7));
        executor.execute(new ExportingTask(pool, 8));

        executor.shutdown();
        try {
            executor.awaitTermination(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
A test output looks like
Object with process no. 1 was created
Object with process no. 2 was created
Object with process no. 3 was created
Object with process no. 4 was created
Thread 2: Object with process no. 2 was borrowed
Thread 1: Object with process no. 1 was borrowed
Thread 2: Object with process no. 2 was returned
Thread 3: Object with process no. 3 was borrowed
Thread 4: Object with process no. 4 was borrowed
Thread 1: Object with process no. 1 was returned
Thread 4: Object with process no. 4 was returned
Thread 8: Object with process no. 4 was borrowed
Thread 5: Object with process no. 1 was borrowed
Thread 7: Object with process no. 3 was borrowed
Thread 3: Object with process no. 3 was returned
Thread 6: Object with process no. 2 was borrowed
Thread 7: Object with process no. 3 was returned
Thread 5: Object with process no. 1 was returned
Thread 8: Object with process no. 4 was returned
Thread 6: Object with process no. 2 was returned
As can be seen, the first thread accessing the pool creates the minimum objects residing in the pool. Running this test class multiple times, we can discover that sometimes 4 objects get borrowed each after other and a new 5. object will be created in the pool. All test classes are available in the GitHub.

Friday, January 11, 2013

Access resources in Java archives with Virtual File System (cross-application sever solution)

During my work on a custom JSF library I was looking for a way how to read the metadata from composite components in order to create a nice self-documented library. Based on this great article from Ed Burns I implemented a nice documentation framework which extracts all metadata from the VDL. Main idea:
FacesContext fc = FacesContext.getCurrentInstance();
ViewDeclarationLanguage vdl = fc.getApplication().getViewHandler().getViewDeclarationLanguage(fc, "/views/home.xhtml");
Resource ccResource = fc.getApplication().getResourceHandler().createResource(resourceName, libraryName);
BeanInfo metadata = vdl.getComponentMetadata(context, ccResource);
PropertyDescriptor attributes[] = metadata.getPropertyDescriptors();
// read metadata for cc:attributes, cc:clientBehavior, cc:valueHolder, cc:actionSource, cc:facet
...
The createResource method above expects the resource name and library name to access the metadata of a composite component. The library name is known. Assume the composite components are placed in a JAR file under the folder /META-INF/resources/com/foo That means, the library name is com/foo. The problem is to get names of all resources below the com/foo. Resources are XHTML files as composite components. For instance, for this structure
/META-INF/resources/com/foo/mycomponent1.xhtml
/META-INF/resources/com/foo/mycomponent2.xhtml
the resource names would be mycomponent1.xhtml and mycomponent1.xhtml. Without file extensions, they are the same as tag names of composite components. Is there a simple and reliable way to read these names from a WAR archive? Yes, sure, there is a simple method to read resources located in one Java archive from another Java archive. JBoss has Virtual File System (VFS). A good documentation can be found here. Please don't confuse it with Apache Commons VFS. These are different things with perhaps the same goal. In JBoss 6 / 7 application servers, if we read JAR files from the classpath, URLs start with vfs (meaning virtual file system) and not with file as usually. So that JBoss VFS is very handy here because it is exactly for vfs handling. The implemented approach is also working with all other application servers. I tested successful:
  • JBoss 6 / 7
  • Jetty 8
  • GlassFish 3
  • Tomcat 7
  • WebLogic 12
The next method shows the approach. To get an URL for the interested JAR file, we need to know any Java class in this JAR file. This can be a marker interface or any other interface, abstract class as well. Obtained Class object can be passed into the method along with the library name.
public void extractMetadata(Class clazz, String libraryName) throws IOException, URISyntaxException {
  VirtualFile virtualFile;
  Closeable handle = null;
  URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
  String protocol = url.getProtocol();

  if ("vfs".equals(protocol)) {
    URLConnection conn = url.openConnection();
    virtualFile = (VirtualFile) conn.getContent();
  } else if ("file".equals(protocol)) {
    virtualFile = VFS.getChild(url.toURI());

    File archiveFile = virtualFile.getPhysicalFile();
    TempFileProvider provider = TempFileProvider.create("tmp", Executors.newScheduledThreadPool(2));
    handle = VFS.mountZip(archiveFile, virtualFile, provider);
  } else {
    throw new UnsupportedOperationException("Protocol " + protocol + " is not supported");
  }

  List<VirtualFile> files = virtualFile.getChild("/META-INF/resources/" + libraryName).getChildren();
  List<String> resourceNames = new ArrayList<String>(files.size());
  for (VirtualFile ccFile : files) {
    resourceNames.add(ccFile.getName());
  }

  if (handle != null) {
    handle.close();
  }

  FacesContext fc = FacesContext.getCurrentInstance();
  ViewDeclarationLanguage vdl = fc.getApplication().getViewHandler().getViewDeclarationLanguage(fc,
     "/views/home.xhtml");

  for (String resourceName : resourceNames) {
    Resource ccResource = fc.getApplication().getResourceHandler().createResource(resourceName, libraryName);
    BeanInfo metadata = vdl.getComponentMetadata(fc, ccResource);
  
    // extract metadata
    ...
  }
}
As I said, supporting of two URL protocols, vfs and file, was enough for me to get it working on all modern app. servers. The main goal of this method is collecting VirtualFile instances below a certain folder. VirtualFile allows to get other infos such as size, name, path, whether the object is a file or directory, etc. It allows to get children und provides many other traversal operations. For the file protocol, we have to mount the archive file in the Virtual File System (like in UNIX). Once mounted, the archive structure is accessible like a normal file system. The call virtualFile.getChild("/META-INF/resources/" + libraryName).getChildren() returns all children (VirtualFile instances) below our /META-INF/resources/com/foo/. We iterate through and collect resource (file) names.

Thursday, December 27, 2012

GET / POST with RESTful Client API

There are many stuff in the internet how to work with RESTful Client API. These are basics. But even though the subject seems to be trivial, there are hurdles, especially for beginners. In this post I will try to summurize my know-how how I did this in real projects. I usually use Jersey (reference implementation for building RESTful services). See e.g. my other post. In this post, I will call a real remote service from JSF beans. Let's write a session scoped bean RestClient.
package com.cc.metadata.jsf.controller.common;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

/**
 * This class encapsulates some basic REST client API.
 */
@ManagedBean
@SessionScoped
public class RestClient implements Serializable {

    private transient Client client;

    public String SERVICE_BASE_URI;

    @PostConstruct
    protected void initialize() {
        FacesContext fc = FacesContext.getCurrentInstance();
        SERVICE_BASE_URI = fc.getExternalContext().getInitParameter("metadata.serviceBaseURI");

        client = Client.create();
    }

    public WebResource getWebResource(String relativeUrl) {
        if (client == null) {
            initialize();
        }

        return client.resource(SERVICE_BASE_URI + relativeUrl);
    }

    public ClientResponse clientGetResponse(String relativeUrl) {
        WebResource webResource = client.resource(SERVICE_BASE_URI + relativeUrl);
        return webResource.accept("application/json").get(ClientResponse.class);
    }
}
In this class we got the service base URI which is specified (configured) in the web.xml.
<context-param>
   <param-name>metadata.serviceBaseURI</param-name>
   <param-value>http://somehost/metadata/</param-value>
</context-param>
Furthermore, we wrote two methods to receive remote resources. We intend to receive resources in JSON format and convert them to Java objects. The next bean demonstrates how to do this task for GET requests. The bean HistoryBean converts received JSON to a Document object by using GsonConverter. The last two classes will not be shown here (they don't matter). Document is a simple POJO and GsonConverter is a singleton instance which wraps Gson.
package com.cc.metadata.jsf.controller.history;

import com.cc.metadata.jsf.controller.common.RestClient;
import com.cc.metadata.jsf.util.GsonConverter;
import com.cc.metadata.model.Document;

import com.sun.jersey.api.client.ClientResponse;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

/**
 * Bean getting history of the last extracted documents.
 */
@ManagedBean
@ViewScoped
public class HistoryBean implements Serializable {

    @ManagedProperty(value = "#{restClient}")
    private RestClient restClient;

    private List<Document> documents;
    private String jsonHistory;

    public List<Document> getDocuments() {
        if (documents != null) {
            return documents;
        }

        ClientResponse response = restClient.clientGetResponse("history");

        if (response.getStatus() != 200) {
            throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
        }

        // get history as JSON
        jsonHistory = response.getEntity(String.class);

        // convert to Java array / list of Document instances
        Document[] docs = GsonConverter.getGson().fromJson(jsonHistory, Document[].class);
        documents = Arrays.asList(docs);

        return documents;
    }

    // getter / setter
 ...
}
The next bean demonstrates how to communicate with the remote service via POST. We intent to send the content of uploaded file. I use the PrimeFaces' FileUpload component, so that the content can be extracted as InputStream from the listener's parameter FileUploadEvent. This is not important here, you can also use any other web frameworks to get the file content (also as byte array). More important is to see how to deal with RESTful Client classes FormDataMultiPart and FormDataBodyPart.
package com.cc.metadata.jsf.controller.extract;

import com.cc.metadata.jsf.controller.common.RestClient;
import com.cc.metadata.jsf.util.GsonConverter;
import com.cc.metadata.model.Document;

import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;

import org.primefaces.event.FileUploadEvent;

import java.io.IOException;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import javax.ws.rs.core.MediaType;

/**
 * Bean for extracting document properties (metadata).
 */
@ManagedBean
@ViewScoped
public class ExtractBean implements Serializable {

    @ManagedProperty(value = "#{restClient}")
    private RestClient restClient;

    private String path;

    public void handleFileUpload(FileUploadEvent event) throws IOException {
        String fileName = event.getFile().getFileName();

        FormDataMultiPart fdmp = new FormDataMultiPart();
        FormDataBodyPart fdbp = new FormDataBodyPart(FormDataContentDisposition.name("file").fileName(fileName).build(),
                event.getFile().getInputstream(), MediaType.APPLICATION_OCTET_STREAM_TYPE);
        fdmp.bodyPart(fdbp);

        WebResource resource = restClient.getWebResource("extract");
        ClientResponse response = resource.accept("application/json").type(MediaType.MULTIPART_FORM_DATA).post(
                ClientResponse.class, fdmp);

        if (response.getStatus() != 200) {
            throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
        }

        // get extracted document as JSON
        String jsonExtract = response.getEntity(String.class);

        // convert to Document instance
        Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class);

        ...
    }

    // getter / setter
 ...
}
Last but not least, I would like to demonstrate how to send a GET request with any query string (URL parameters). The next method asks the remote service by URL which looks as http://somehost/metadata/extract?file=<some file path>
public void extractFile() {
 WebResource resource = restClient.getWebResource("extract");
 ClientResponse response = resource.queryParam("file", path).accept("application/json").get(
   ClientResponse.class);

 if (response.getStatus() != 200) {
  throw new RuntimeException("Failed service call: HTTP error code : " + response.getStatus());
 }

 // get extracted document as JSON
 String jsonExtract = response.getEntity(String.class);

 // convert to Document instance
 Document doc = GsonConverter.getGson().fromJson(jsonExtract, Document.class);

 ...
}

Friday, February 17, 2012

Advanced injection of Maven properties into Java application

In the last post I have shown how to inject Maven project informations into Java application. This topic describes the injection for more useful properties. Advantage: no needs to define then any project specific Java constants and change constants with each release. Current project infos already exist in pom.xml. In the PrimeFaces Extensions project we have defined some profile dependent properties like these
...
<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>${primefaces.core.version}</version>
</dependency> 
<dependency>
    <groupId>org.primefaces.extensions</groupId>
    <artifactId>primefaces-extensions</artifactId>
    <version>${pe.impl.version}</version>
</dependency>
...
<properties>
    <java.version.source>1.6</java.version.source>
    <java.version.target>1.6</java.version.target>
    <jetty.server.version>8.1.0.RC2</jetty.server.version>
    <pe.jsf.impl>mojarra</pe.jsf.impl>
    <pe.jsf.displayname>Mojarra</pe.jsf.displayname>
    <pe.jsf.group>com.sun.faces</pe.jsf.group>
    <pe.jsf.artifact>jsf</pe.jsf.artifact>
    <pe.jsf.version>2.1.6</pe.jsf.version>
    <pe.impl.version>0.3.0-SNAPSHOT</pe.impl.version>        
    <pe.webapp.filter>development</pe.webapp.filter>
    <pe.webapp.online>false</pe.webapp.online>
    <primefaces.core.version>3.1.1</primefaces.core.version>
    <primefaces.theme.version>1.0.3</primefaces.theme.version>
</properties>
And we also configured two Maven plugins which put more useful properties to Maven based applications.
<plugin>
    <groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
    <artifactId>maven-svn-revision-number-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <goals>
                <goal>revision</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <entries>
            <entry>
                <prefix>svn</prefix>
            </entry>
        </entries>
    </configuration>                    
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <version>1.0</version>
    <executions>
        <execution>
            <id>generate-timestamp</id>
            <phase>validate</phase>
            <goals>
                <goal>create-timestamp</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <format>{0,date,yyyy-MM-dd HH:mm}</format>
        <items>
            <item>timestamp</item>
        </items>
    </configuration>
</plugin>
Let's start now. Property file under src/main/resources is called now pe-showcase.properties and has again only one line (surprise).
 
application.properties=${project.properties}
 
This line gets resolved at build time as follows:
application.properties={pe.jsf.impl=mojarra, pe.jsf.group=com.sun.faces, timestamp=1329486964505, svn.committedRevision=928, svn.revision=928, primefaces.theme.version=1.0.3, pe.impl.version=0.3.0-SNAPSHOT, pe.jsf.displayname=Mojarra, jetty.server.version=8.1.0.RC2, svn.committedDate=2012-02-17 01:48:44 +0100 (Fri, 17 Feb 2012), pe.jsf.version=2.1.6, primefaces.core.version=3.1.1, ...}
The task is now to parse this resolved line in a Java application. A good entry point for parsing in JSF is an application scoped bean noted with eager=true.
@ApplicationScoped
@ManagedBean(eager = true)
public class TechnicalInfo {

    private static final Logger LOGGER = Logger.getLogger(TechnicalInfo.class.getName());

    private String primeFaces;
    private String primeFacesExt;
    private String jsfImpl;
    private String server;
    private String revision;
    private String buildTime;
    private boolean online = false;
    private boolean mojarra = true;

    @PostConstruct
    protected void initialize() {
        ResourceBundle rb;
        try {
            rb = ResourceBundle.getBundle("pe-showcase");

            String strAppProps = rb.getString("application.properties");
            int lastBrace = strAppProps.indexOf("}");
            strAppProps = strAppProps.substring(1, lastBrace);

            Map<String, String> appProperties = new HashMap<String, String>();
            String[] appProps = strAppProps.split("[\\s,]+");
            for (String appProp : appProps) {
                String[] keyValue = appProp.split("=");
                if (keyValue != null && keyValue.length > 1) {
                    appProperties.put(keyValue[0], keyValue[1]);
                }
            }

            primeFaces = "PrimeFaces: " + appProperties.get("primefaces.core.version");
            primeFacesExt = "PrimeFaces Extensions: " + appProperties.get("pe.impl.version");
            jsfImpl = "JSF-Impl.: " + appProperties.get("pe.jsf.displayname") + " " + appProperties.get("pe.jsf.version");
            server = "Server: Jetty " + appProperties.get("jetty.server.version");
            revision = "SVN-Revision: " + appProperties.get("svn.revision");

            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(Long.valueOf(appProperties.get("timestamp")));
            buildTime = "Build time: " + formatter.format(calendar.getTime());

            online = Boolean.valueOf(appProperties.get("pe.webapp.online"));
            mojarra = appProperties.get("pe.jsf.impl").contains("mojarra");
        } catch (MissingResourceException e) {
            LOGGER.warning("Resource bundle 'pe-showcase' was not found");
        }
    }

    ... getter ...

}
Access in JSF facelets:
<h:panelGrid columns="7" style="float: left;">
    <h:panelGroup styleClass="ui-icon ui-icon-info"/>
    <h:outputText value="#{technicalInfo.primeFaces},"/>
    <h:outputText value="#{technicalInfo.primeFacesExt},"/>
    <h:outputText value="#{technicalInfo.jsfImpl},"/>
    <h:outputText value="#{technicalInfo.server},"/>
    <h:outputText value="#{technicalInfo.revision},"/>
    <h:outputText value="#{technicalInfo.buildTime}"/>
</h:panelGrid>
And voilĆ . We have done this! Click on image to enlarge it.

Wednesday, February 15, 2012

Inject Maven project informations into Java application

Do you have a Maven project and would like to inject project informations from pom.xml into your application to avoid duplications? This is possible with resource filtering. This small guide will help you to achieve that. More funny advanced examples are coming soon in the next post. I have applied this approach for PrimeFaces Extensions project, so that all examples are related to this project.

Step 1. Create a property file under src/main/resources. In my case it's called primefaces-extensions.properties and consists of only one line.
 
application.version=${project.version}
 
Placeholder ${...} gets resolved at project build time. Maven also exposes other project properties like ${project.artifactId}, ${project.name}, etc. Please refer Maven properties guide. Not only Maven self exposes such properties. Various Maven plugins as buildnumber-maven-plugin and maven-svn-revision-number-plugin expose useful properties too.

Step 2. To get placeholders replaced you need to enable filtering in your pom.xml.
<build>
    <resources>
        <resource>src/main/resources</resource>
        <filtering>true</filtering>
    </resources>
    ...
</build>

Step 3. Access in Java is simple. I have created a singleton class VersionProvider for that (because I only have one placeholder for project version). Project version is cached after the first access.
public final class VersionProvider {

    private static final Logger LOGGER = Logger.getLogger(VersionProvider.class.getName());

    private static final VersionProvider INSTANCE = new VersionProvider();
    private String version;

    private VersionProvider() {
        ResourceBundle rb;
        try {
            rb = ResourceBundle.getBundle("primefaces-extensions");
            version = rb.getString("application.version");
        } catch (MissingResourceException e) {
            LOGGER.warning("Resource bundle 'primefaces-extensions' was not found or error while reading current version.");
        }
    }

    public static String getVersion() {
        return INSTANCE.version;
    }
}

Step 4. Using in any places is simple as well. Just call VersionProvider.getVersion(). For instance in the following JSF listener class
public class PostConstructApplicationEventListener implements SystemEventListener {

    private static final Logger LOGGER = Logger.getLogger(PostConstructApplicationEventListener.class.getName());

    @Override
    public boolean isListenerForSource(final Object source) {
        return true;
    }

    @Override
    public void processEvent(final SystemEvent event) {
        if (StringUtils.isNotBlank(VersionProvider.getVersion())) {
            LOGGER.log(Level.INFO, "Running on PrimeFaces Extensions {0}", VersionProvider.getVersion());
        }
    }
}
or in JSF resource handler
public class PrimeFacesExtensionsResource extends ResourceWrapper {

    private Resource wrapped;
    private String version;

    public PrimeFacesExtensionsResource(final Resource resource) {
        super();
        wrapped = resource;

        // get current version
        if (StringUtils.isNotBlank(VersionProvider.getVersion())) {
            version = "&v=" + VersionProvider.getVersion();
        } else {
            version = UUID.randomUUID().toString();
        }
    }

    @Override
    public String getRequestPath() {
        return super.getRequestPath() + version;
    }

    ...
}
With resource filtering you don't need to care about available current project infos in Java programs.

Friday, October 7, 2011

Draw masked images with Java 2D API and Jersey servlet

The task I had for one Struts web project was the dynamic image painting. You maybe know a small flag icon in MS Outlook which indicates message states. It can be red, green, etc. We needed the similar flag icon with configurable colors. The color is variable and thus unknown a priori - it can be set dynamically in backend and passed to front-end. I develop Struts web applications with JSF in mind. We can't use custom JSF resource handler in Struts, but we can use servlets. A HTTP servlet is able to catch GET requests causing by Struts or JSF image tags and render an image. All parameters should be passed in URL - they should be parts of URL. We need following parameters:
  • image format like "png" or "jpg"
  • file name of base image
  • file name of mask image
  • color (in HEX without leading "#" or "0x" signs)
An URL-example is
 
http://host:port/webappcontext/masked/png/flag/flag-mask/FF0000/mfile.imgdrawer
 
To save me pain for manually parsing of URL string and extraction of all parameters I have took Jersey - reference implementation for building RESTful Web services. Jersey's RESTful Web services are implemented as servlet which takes requests and does some actions according to URL structure. We just need to implement such actions. My action (and task) is image drawing / painting. That occurs by means of Java 2D API - a set of classes for advanced 2D graphics and imaging. Let me show the end result at first. Base image looks as follows


Mask image looks as follows

And now the magic is comming. I'm sending a GET request to draw a red flag (color FF0000) dynamically:


I'm sending a GET request to draw a green flag (color 00FF00):


Do you want to see a blue image? No problem, I can type as color 00ff.

You need four things to achieve that:

1. Dependencies to Jersey and Java 2D Graphics. Maven users can add these as follows:
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-server</artifactId>
    <version>... last version ...</version>
</dependency>
<dependency>
    <groupId>com.sun.media</groupId>
    <artifactId>jai_codec</artifactId>
    <version>... last version ...</version>
</dependency>
<dependency>
    <groupId>com.sun.media</groupId>
    <artifactId>jai_imageio</artifactId>
    <version>... last version ...</version>
</dependency>
2. Two image files in the web application. I have placed them under webapp/resources/themes/app/images/ and they are called in my case flag.png and flag-mask.png.

3. Configuration for Jersey servlet in web.xml. My configuration is
<servlet>
    <servlet-name>imagedrawer</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>ip.client.commons.web.servlet</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>imagedrawer</servlet-name>
    <url-pattern>*.imgdrawer</url-pattern>
</servlet-mapping>
Image-URL should be ended with imgdrawer to be able to handled by Jersey servlet. By the way, my FacesServlet is mapped to *.jsf and Struts ActionServlet to *.do. Init parameter com.sun.jersey.config.property.packages points to the Java package where the handler class is placed. Writing of handler class is the step 4.

4. Handler class which treats GET requests and draws / paints a new masked image by means of Java 2D API. The new image is a composition of two predefined images from the step 2. The mask gets painted and overlapped with the base image. The code is more or less documented, so that I omit any comments :-)
/**
 * Jersey annotated class for image drawing. Drawed images don't need to be cached server side because they are cached
 * proper on the client side. Set "expires" and "max-age" ensure client side caching.
 */
@Path("/")
@Produces("image/*")
@Singleton
public class ImageDrawer {
    @Context ServletContext context;

    /** directory for image files (can be done configurable if needed) */
    private String imageDir = "/resources/themes/app/images/";

    /**
     * Gets composed image consist of base and mask image.
     *
     * @param  format   format, e.g. "png", "jpg".
     * @param  basefile file name of base image without file extension
     * @param  maskfile file name of mask image without file extension
     * @param  hexcolor color in HEX without leading "#" or "0x" signs
     * @return Response new composed image
     * @throws WebApplicationException thrown exception, 404 or 500 status code.
    */
    @GET
    @Path("/masked/{format}/{basefile}/{maskfile}/{hexcolor}/{img}")
    public Response getImage(@PathParam("format") String format,
                             @PathParam("basefile") String basefile,
                             @PathParam("maskfile") String maskfile,
                             @PathParam("hexcolor") String hexcolor) {
        // check parameters
        if (format == null || basefile == null || maskfile == null || hexcolor == null) {
            throw new WebApplicationException(404);
        }

        // try to get images from web application
        InputStream is1 = context.getResourceAsStream(imageDir + basefile + "." + format);
        if (is1 == null) {
            throw new WebApplicationException(404);
        }

        InputStream is2 = context.getResourceAsStream(imageDir + maskfile + "." + format);
        if (is2 == null) {
            throw new WebApplicationException(404);
        }

        RenderedImage img1 = renderImage(is1);
        RenderedImage img2 = renderImage(is2);

        // convert HEX to RGB
        Color color = Color.decode("0x" + hexcolor);

        // draw the new image
        BufferedImage resImage = drawMaskedImage(img1, img2, color);

        byte[] resImageBytes = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            // use Apache IO
            ImageIO.write(resImage, format, baos);
            baos.flush();
            resImageBytes = baos.toByteArray();
        } catch (IOException e) {
            throw new WebApplicationException(500);
        } finally {
            try {
                baos.close();
            } catch (IOException e) {
                ;
            }
        }

        // cache in browser forever
        CacheControl cacheControl = new CacheControl();
        cacheControl.setMaxAge(Integer.MAX_VALUE);

        return Response.ok(resImageBytes, "image/" + format).cacheControl(cacheControl)
                       .expires(new Date(Long.MAX_VALUE)).build();
    }
 
    // Utilities (written not by me, copyright ©)

    private RenderedImage renderImage(InputStream in) {
        SeekableStream stream = createSeekableStream(in);
        boolean isImageIOAvailable = false;
        if (Thread.currentThread().getContextClassLoader().
            getResource("META-INF/services/javax.imageio.spi.ImageReaderSpi") != null) {
            isImageIOAvailable = true;
        }
        return JAI.create(isImageIOAvailable ? "ImageRead" : "stream", stream);
    }

    private BufferedImage drawMaskedImage(RenderedImage orig, RenderedImage mask, Color color) {
        BufferedImage overlay = manipulateImage(mask, null);
        return manipulateImage(orig, new ImageManipulator() {
            public void manipulate(final Graphics2D g2d) {
                float[] scaleFactors = new float[] {
                2f * (color.getRed() / 255f), 2f * (color.getGreen() / 255f),
                2f * (color.getBlue() / 255f), color.getAlpha() / 255f};
                float[] offsets = new float[] {0, 0, 0, 0};
                g2d.drawImage(overlay, new RescaleOp(scaleFactors, offsets, null), 0, 0);
            }
        });
    }

    private BufferedImage manipulateImage(RenderedImage orig, ImageManipulator manipulator) {
        BufferedImage image;
        boolean drawOriginal = false;
        ColorModel colorModel = orig.getColorModel();
        int colorSpaceType = colorModel.getColorSpace().getType();
        if (colorModel.getPixelSize() >= 4 && colorSpaceType != ColorSpace.TYPE_GRAY) {
            image = new RenderedImageAdapter(orig).getAsBufferedImage();
        } else if (colorSpaceType == ColorSpace.TYPE_GRAY) {
            image = new BufferedImage(orig.getWidth(), orig.getHeight(), BufferedImage.TYPE_INT_ARGB);
            drawOriginal = true;
        } else {
            image = new BufferedImage(orig.getWidth(), orig.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
            drawOriginal = true;
        }
   
        Graphics2D g2d = image.createGraphics();
        if (drawOriginal) {
            g2d.drawImage(new RenderedImageAdapter(orig).getAsBufferedImage(), 0, 0, null);
        }

        if (manipulator != null) {
            manipulator.manipulate(g2d);
        }
    
        return image;
    }

    private interface ImageManipulator {void manipulate(Graphics2D g2d);} 
}

Sunday, May 29, 2011

Testing client-server communication with Java Scripting API

I would like to share my best practice for client- and server-side testing with Java Scripting API introduced in Java SE 6. As example I want to test simultaneous JSON serialization / deserialization on both sides. I'm going to use json2 from Douglas Crockford on client-side and Gson on server-side. I want to utilize the class Circle from my previous post and write JUnit tests for its serialization / deserialization. At first we need to implement the same interface by Java and JavaScript. It's convenient to implement an Java interface by script functions or methods. By using interfaces we can avoid having to use the javax.script API in many places.

JsonProvide.java
public interface JsonProvider
{
    public Object fromJson(String json);

    public String toJson(Object object);
}
JsonProvider is an interface which is used later to access correspondent JavaScript methods.

jsonTest.js
var jsonProvider = new Object();

// produces an JavaScript object or array from an JSON text.
jsonProvider.fromJson = function(json) {
    var obj = JSON.parse(json);
    return makeTestable(obj);
};

// produces an JSON text from an JavaScript object or array
jsonProvider.toJson = function(object) {
    var obj = makeTestable(object);
    return JSON.stringify(obj);
};

function makeTestable(obj) {
    obj.getValue = function(property) {
        return this[property];
    };

    return obj;
}

// Test object
var circle = {
    uuid: "567e6162-3b6f-4ae2-a171-2470b63dff00",
    x: 10,
    y: 20,
    movedToFront: true,
    rotationDegree: 90,
    radius: 50,
    backgroundColor: "#FF0000",
    borderColor: "#DDDDDD",
    borderWidth: 1,
    borderStyle: "-",
    backgroundOpacity: 1.0,
    borderOpacity: 0.5,
    scaleFactor: 1.2
};
There are two methods fromJson / toJson and a helper function makeTestable in order to get any value of JavaScript objects from Java. The test object in JavaScript is called circle. The corresponding Java class is called Circle and has the same fields with getter / setter. We can write an JUnit test now.
import com.google.gson.Gson;
import com.googlecode.whiteboard.model.Circle;
import org.apache.commons.beanutils.PropertyUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class JsonTest
{
    private static Gson gson;
    private static ScriptEngine engine;
    private static JsonProvider jsonProvider;

    @BeforeClass
    public static void runBeforeClass() {
        // create Gson
        GsonBuilder gsonBilder = new GsonBuilder();
        gson = gsonBilder.serializeNulls().create();

        // create a script engine manager
        ScriptEngineManager factory = new ScriptEngineManager();
        // create JavaScript engine
        engine = factory.getEngineByName("JavaScript");

        try {
            // evaluate JavaScript code from the json2 library and the test file
            engine.eval(new java.io.FileReader("src/main/webapp/resources/js/json2-min.js"));
            engine.eval(new java.io.FileReader("src/test/resources/js/jsonTest.js"));

            // get an implementation instance of the interface JsonProvider from the JavaScript engine,
            // all interface's methods are implemented by script methods of JavaScript object jsonProvider
            Invocable inv = (Invocable) engine;
            jsonProvider = inv.getInterface(engine.get("jsonProvider"), JsonProvider.class);
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @AfterClass
    public static void runAfterClass() {
        gson = null;
        jsonProvider = null;
    }

    @Test
    public void JavaScript2Java() {
        // get JavaScript object
        Object circle1 = engine.get("circle");

        // client-side: make JSON text from JavaScript object
        String json = jsonProvider.toJson(circle1);

        // server-side: convert JSON text to Java object
        Circle circle2 = gson.fromJson(json, Circle.class);

        // compare two objects
        testEquivalence(circle2, circle1);
    }

    @Test
    public void Java2JavaScript() {
        // create Java object
        Circle circle1 = new Circle();
        circle1.setUuid(UUID.randomUUID().toString());
        circle1.setX(100);
        circle1.setY(100);
        circle1.setMovedToFront(false);
        circle1.setRotationDegree(0);
        circle1.setRadius(250);
        circle1.setBackgroundColor("#FFFFFF");
        circle1.setBorderColor("#000000");
        circle1.setBorderWidth(3);
        circle1.setBorderStyle(".");
        circle1.setBackgroundOpacity(0.2);
        circle1.setBorderOpacity(0.8);
        circle1.setScaleFactor(1.0);

        // server-side: convert Java object to JSON text
        String json = gson.toJson(circle1);

        // client-side: make JavaScript object from JSON text
        Object circle2 = jsonProvider.fromJson(json);

        // compare two objects
        testEquivalence(circle1, circle2);
    }

    @SuppressWarnings("unchecked")
    private void testEquivalence(Object obj1, Object obj2) {
        try {
            Map<String, Object> map = PropertyUtils.describe(obj1);
            Set<String> fields = map.keySet();
            Invocable inv = (Invocable) engine;

            for (String key : fields) {
                Object value1 = map.get(key);
                if (!key.equals("class")) {
                    Object value2 = inv.invokeMethod(obj2, "getValue", key);
                    if (value1 instanceof Number && !(value1 instanceof Double)) {
                        // JS number is always converted to Java double ==> only doubles can be compared,
                        // see http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html
                        value1 = new Double(value1.toString());
                    }

                    Assert.assertEquals("Value of property '" + key + "' was wrong converted", value2, value1);
                }
            }
        } catch (Exception e) {
            throw new IllegalStateException("Equivalence test of two objects failed!", e);
        }
    }
}
I create a Gson and a ScriptEngine instances in the method runBeforeClass() and load all needed scripts into the ScriptEngine. After that I get an implementation instance of the interface JsonProvider from the JavaScript engine. Now I'm able to call JavaScript methods from my JsonProvider implementation. There are two tests:

@Test public void JavaScript2Java()

I test here the use case if an JavaScript object (circle) gets converted to an JSON text, sent to the server and converted there to an Java object (Circle). The original JavaScript object and the result Java object are compared afterwards.

@Test public void Java2JavaScript()

I test here the use case if a created Java object (Circle) gets converted to an JSON text, sent to the client and converted there to an JavaScript object (circle). The objects are compared to ensure their equivalence.

You can also use "JavaScript to Java Communication" with Java Scripting API and access Java classes, objects and methods from JavaScript. Pretty cool.

Monday, May 16, 2011

JSON with GSON and abstract classes

I have switched to Google Gson after many years of using org.json library for supporting JSON data interchange format in Java. org.json is a lower-level library, so that you have to create JSONObject, JSONArray, JSONString, ... and do other low-level work. Gson simplifies this work. It provides simple toJson() and fromJson() methods to convert arbitrary Java objects to JSON and vice-versa, supports Java Generics, allows custom representations for objects, generates compact and readability JSON output and has many other goodies. I love it more and more. The using is simple. Assume, we have a class called Circle.
public class Circle {
    private int radius = 10;
    private String backgroundColor = "#FF0000";
    private String borderColor = "#000000";
    private double scaleFactor = 0.5;
    ...

    // getter / setter
}
Serialization (Java object --> JSON) can be done as follows:
Circle circle = new Circle();
Gson gson = new Gson();
String json = gson.toJson(circle); 
==> json is
{
    "radius": 10,
    "backgroundColor": "#FF0000",
    "borderColor": "#000000",
    "scaleFactor": 0.5,
    ...
}
Deserialization (JSON --> Java object) is just one line of code:
Circle circle2 = gson.fromJson(json, Circle.class);  
==> circle2 is the same as the circle above
Everything works like a charm. There is only one problem I have faced with abstract classes. Assume, we have an abstract class AbstractElement and many other classes extending this one
public abstract class AbstractElement {
    private String uuid;

    // getter / setter
}

public class Circle extends AbstractElement {
   ...
}

public class Rectangle extends AbstractElement {
   ...
}

public class Ellipse extends AbstractElement {
   ...
}
Assume now, we store all concrete classes in a list or a map parametrized with AbstractElement
public class Whiteboard
{
    private Map<String, AbstractElement> elements = 
            new LinkedHashMap<String, AbstractElement>();
    ...
}
The problem is that the concrete class is undisclosed during deserialization. It's unknown in the JSON representation of Whiteboard. How the right Java class should be instantiated from the JSON representation and put into the Map<String, AbstractElement> elements? I have nothing found in the documentation what would address this problem. It is obvious that we need to store a meta information in JSON representations about concrete classes. That's for sure. Gson allows you to register your own custom serializers and deserializers. That's a power feature of Gson. Sometimes default representation is not what you want. This is often the case e.g. when dealing with third-party library classes. There are enough examples of how to write custom serializers / deserializers. I'm going to create an adapter class implementing both interfaces JsonSerializer, JsonDeserializer and to register it for my abstract class AbstractElement.
GsonBuilder gsonBilder = new GsonBuilder();
gsonBilder.registerTypeAdapter(AbstractElement.class, new AbstractElementAdapter());
Gson gson = gsonBilder.create();
And here is AbstractElementAdapter:
package com.googlecode.whiteboard.json;

import com.google.gson.*;
import com.googlecode.whiteboard.model.base.AbstractElement;
import java.lang.reflect.Type;

public class AbstractElementAdapter implements JsonSerializer<AbstractElement>, JsonDeserializer<AbstractElement> {
    @Override
    public JsonElement serialize(AbstractElement src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject result = new JsonObject();
        result.add("type", new JsonPrimitive(src.getClass().getSimpleName()));
        result.add("properties", context.serialize(src, src.getClass()));

        return result;
    }

    @Override
    public AbstractElement deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        String type = jsonObject.get("type").getAsString();
        JsonElement element = jsonObject.get("properties");

        try {
            return context.deserialize(element, Class.forName("com.googlecode.whiteboard.model." + type));
        } catch (ClassNotFoundException cnfe) {
            throw new JsonParseException("Unknown element type: " + type, cnfe);
        }
    }
}
I add two JSON properties - one is "type" and the other is "properties". The first property holds a concrete implementation class (simple name) of the AbstractElement and the second one holds the serialized object itself. The JSON looks like
{
    "type": "Circle",
    "properties": {
        "radius": 10,
        "backgroundColor": "#FF0000",
        "borderColor": "#000000",
        "scaleFactor": 0.5,
        ...
    }
}
We benefit from the "type" property during deserialization. The concrete class can be instantiated now by Class.forName("com.googlecode.whiteboard.model." + type) where "com.googlecode.whiteboard.model." + type is a fully qualified class name. The following call
 
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException
 
from JsonDeserializationContext invokes default deserialization on the specified object and completes the job.

Sunday, March 20, 2011

Install Java 1.6 and Tomcat 6 under Ubuntu

I have installed Java und Tomcat on my VPS http://www.fractalsoft.net many times but never noted necessary steps. Here some helpful infos.

1) Issue following command to find out current jdk version in apt-get
apt-cache search jdk

2) Install java JRE with apt-get install
sudo apt-get install openjdk-6-jre

3) Set environment variable JAVA_HOME. Copy following statement and append to /etc/profile or .bashrc
export JAVA_HOME="/usr/lib/jvm/java-6-openjdk;"

4) Install Tomcat 6
sudo apt-get install tomcat6 tomcat6-admin tomcat6-common tomcat6-user tomcat6-docs tomcat6-examples

5) Change tomcat server to run on port 80 in
/var/lib/tomcat6/conf/server.xml (symbolic link) or etc/tomcat6/server.xml

7) Start tomcat server sudo /etc/init.d/tomcat6 start
Stop tomcat server sudo /etc/init.d/tomcat6 stop
Restart tomcat server sudo /etc/init.d/tomcat6 restart
Get tomcat server status sudo /etc/init.d/tomcat6 status

8) To enable admin web based features add the following lines to
/etc/tomcat6/tomcat-user.xml

<role rolename="manager"/>
<role rolename="admin"/>
<user name="admin" password="admin" roles="manager,admin"/>

Manager app http://www.fractalsoft.net/manager/html has now user / pwd = “admin”.

9) Adjust default Tomcat page below /var/lib/tomcat6/webapps/ROOT/index.html if nessesary.

Edit: If you get this exception
SEVERE: Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener
java.lang.ExceptionInInitializerError
...
Caused by: java.security.AccessControlException: access denied (java.util.PropertyPermission com.sun.aas.installRoot read) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:342)
...
and the deployte web application doesn't start, set TOMCAT6_SECURITY=no (instead of yes) in the file /etc/init.d/tomcat6. Restart your Tomcat after that (login via ssh username@hostname and call sudo /etc/init.d/tomcat6 restart). Thanks to this post from ICEFaces forum!