Friday, December 30, 2011

Efficient component tree traversal in JSF

Everybody knows about findComponent() and invokeOnComponent() methods in JSF to find a component and doing something with it. The first method expects a special search expression and the second one component's clientId. They belong to UIComponent class, so that any UIComponent can acts as a start point in the view hierarchy. But what is about if we want to find many components at some start point in the view hierarchy which match certain conditions? We can apply getChildren() rekursive, but we wish us a convenient method for tree traversal. Tree traversal refers to the process of visiting each node in a component tree data structure. There is an efficient method in JSF accomplishing this task - visitTree()
public boolean visitTree(VisitContext context, VisitCallback callback)
context is an instance of VisitContext class that is used to hold state relating to performing a component tree visit. callback is an instance of VisitCallback whose visit method will be called for each node visited. Let's start with a practical example. Our task is to find and gather all components implementing EditableValueHolder. Such components implement resetValue() method which allows to reset component's submitted, locale values, etc. to an un-initialized state. Furthermore, another requirement is to skip sub-tree traversal for a component which should be not rendered (don't visit sub-components). In other words we want to find only editable components to be rendered. Assume, the start component calls target
UIComponent target = ...
It can be got in an action / event listener by event.getComponent() or somewhere else by findComponent().

We are ready now to create a special EditableValueHoldersVisitCallback in order to find all mentioned above sub-components and call visitTree on the target component with this callback. EditableValueHoldersVisitCallback gathers sub-components we want to reset.
EditableValueHoldersVisitCallback visitCallback = new EditableValueHoldersVisitCallback();
target.visitTree(VisitContext.createVisitContext(FacesContext.getCurrentInstance()), visitCallback);

// iterate over found sub-components and reset their values
List<EditableValueHolder> editableValueHolders = visitCallback.getEditableValueHolders();
for (EditableValueHolder editableValueHolder : editableValueHolders) {
    editableValueHolder.resetValue();
}
Callback looks like this one
public class EditableValueHoldersVisitCallback implements VisitCallback {

    private List<EditableValueHolder> editableValueHolders = new ArrayList<EditableValueHolder>();

    @Override
    public VisitResult visit(final VisitContext context, final UIComponent target) {
        if (!target.isRendered()) {
            return VisitResult.REJECT;
        }

        if (target instanceof EditableValueHolder) {
            editableValueHolders.add((EditableValueHolder) target);
        }

        return VisitResult.ACCEPT;
    }

    public List<EditableValueHolder> getEditableValueHolders() {
        return editableValueHolders;
    }
}
Result VisitResult.REJECT indicates that the tree visit should be continued, but should skip the current component's subtree (remember our requirement?). VisitResult.ACCEPT indicates that the tree visit should descend into current component's subtree. There is also VisitResult.COMPLETE as return value if the tree visit should be terminated.

Some components extending UINamingContainer override the behavior of visitTree(). For instance, UIData overrides this method to handle iteration correctly.

Tuesday, December 27, 2011

Maven plugin for web resource optimization - advanced settings

In the last post I have introduced a new Maven plugin resources-optimizer-maven-plugin. This post is about two advanced features. Aggregation tag has a sub-tag subDirMode. This is an aggregation per sub-folder. Assume, JavaScript / CSS files are grouped by sub-folders which represent software modules. Resources of each module can be optimized separately in an easy way. As output we would have aggregated files per sub-folder. Names of aggregated files are the same as their folder names where they are placed. Files are aggregated in the lexicographic order. The following pictures demonstrate this approach.

Original source files below sub-folder keyfilter:


Aggregated file in target below sub-folder keyfilter:


This can be achieved with the following resources set
<resourcesSet>
    <includes>
        ...
        <include>keyfilter/**</include>
        ...
    </includes>
    <aggregations>
        <aggregation>
            <inputDir>...</inputDir>
            <subDirMode>true</subDirMode>
        </aggregation>
    </aggregations>
</resourcesSet>
The second feature is a preparation of uncompressed resources. Sometimes you have to build / deliver compressed and uncompressed resources. In JSF you can use then uncompressed resources if ProjectStage is "Development". RichFaces has e.g. this handy feature. resources-optimizer-maven-plugin allows to define several aggregation tags, e.g. one for compressed and one for uncompressed resources. The following picture demonstrates this approach.

Two folders, for compressed (primefaces-extensions) and uncompressed (primefaces-extensions-uncompressed) resources:


That can be achieved with this resources set
<resourcesSet>
    <includes>
        ...
    </includes>
    <aggregations>
        <aggregation>
            <inputDir>${resources.dir.compressed}</inputDir>
            ...
        </aggregation>
        <aggregation>
            <withoutCompress>true</withoutCompress>
            <inputDir>${resources.dir.uncompressed}</inputDir>
            ...
        </aggregation>
    </aggregations>
</resourcesSet>

<properties>
    <resources.dir.compressed>
        ${project.build.directory}/classes/META-INF/resources/primefaces-extensions
    </resources.dir.compressed>
    <resources.dir.uncompressed>
        ${project.build.directory}/classes/META-INF/resources/primefaces-extensions-uncompressed
    </resources.dir.uncompressed>
</properties>
Output directory for uncompressed resources should be created first. Put maven-resources-plugin with phase generate-resources in front of resources-optimizer-maven-plugin (phase prepare-package).
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-resources</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>${resources.dir.uncompressed}</outputDirectory>
                <resources>
                    <resource>
                        <directory>${project.basedir}/src/main/resources/META-INF/resources/primefaces-extensions</directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>
These were examples for an JAR project. The same is also valid for WAR (web) projects of course.

Monday, December 19, 2011

New Maven plugin for web resource optimization

Two months ago I released the first version of a new Maven plugin for web resource optimization. This plugin was created as a part of the PrimeFaces Extensions project. What is the PrimeFaces Extensions project? Thomas Andraschko and me have launched this young project with the aim of extending JSF library PrimeFaces. What does extending mean? We don't have "extends SomePrimeFacesComponent" in the code. It doesn't make sense to copy-&-paste or overwrite existing PrimeFaces code. PrimeFaces is a rapidly evolving component set and costs to maintain the entire code from release to release would be too high. Extending means, we use core functionality of PrimeFaces like core.js and CoreRenderer.java. Well. What for components and other stuff we have is not the topic of this post. This is a topic for next post(s). I just would like to appeal to everybody having JSF / PrimeFaces expert knowledge to contact us. Any help would be appreciated. We have great ideas and plans, but Thomas and me are full time worker and involving in various daily projects, so that time for PrimeFaces Extensions is very sparse. Even worse in my case. I can only work 15-20% for JSF in my daily work currently. So, everybody with experience in JSF / PrimeFaces can join this open source project.

Maven plugin for resource optimization can compress and merge JavaScript and CSS files very efficiently. It produces better results than all plugins I know. The new Maven plugin combines Google Closure Compiler (for JavaScript files) and YUI Compressor (for CSS files). The new plugin is highly configurable and allows some nice features which don't exist in other plugins. I would like to mention some highlights:
  • Flexible resource sets describing resources to be processed.
  • Settings for compilation and warning levels for Google Closure Compiler. Defaults are SIMPLE_OPTIMIZATIONS and QUIET.
  • Aggregation with or without compression.
  • Suffix for compressed / aggregated files if needed.
  • SubDirMode for files aggregation. Resources of each software module can be optimized separately in an easy way. It makes sense e.g. for component / widget development because you can say "merge files for component A to one big file and don't merge files for component B".
  • Possiblity to define a file to be prepended to the aggregated file.
  • Possiblity to build compressed and uncompressed resources at the same time. PrimeFaces community already asked about uncompressed resources for development stage. RichFaces and some other libs can deliver uncompressed resources if the ProjectStage is "Development". We have also done this for PrimeFaces Extensions by means of this plugin. A special JSF ResourceHandler can stream down uncompressed resources to the browser for the ProjectStage "Development". Never crypto-messages like "e is undefined" anymore!
I have tried to write a more or less comprehensive documentaion. Simple check it! We already use this plugin with success in 6-8 JAR and WAR projects. I have also drawn a comparison diagram for PrimeFaces: size in bytes without compression, with yuicompressor-maven-plugin and with our resources-optimizer-maven-plugin. And I have prepared a configuration for PrimeFaces to make changes easy. More details in the online documentation. We would be glad to see the resources-optimizer-maven-plugin in PrimeFaces! It's worth. This plugin is available in the Maven central repository. In the meantime I have released a new 0.2 version. Feedback is welcome. Thanks.

The next Maven plugin I'm planning to write is a CDK (component development kit) for PrimeFaces components (low prio, depends on free time). PrimeFaces has already one, but only for internal use. Futhermore, PrimeFaces's plugin doesn't generate component's source files under source folder (they are not under version control) and has an expensive configuration. The new CDK will be configurable via name conventions and avoid expensive configuration. The technique for that will be Java Emitter Templates (JET) from Eclipse Modeling Framework. Here is again - every help is appreciated. We have some code styles, so that our code is clean and optimized. But it's not a problem at all to follow them, even in a remote team. I'm convinced, the work in a distributed team can be very efficient.

Friday, December 16, 2011

Install Windows VHDs on Linux for testing websites with Internet Explorer

Need to test websites in multiple Internet Explorer versions under Linux / Mac OSX? No problem. Microsoft created free Windows Virtual PC VHDs with the purpose of allowing web designers to test websites in Internet Explorer 7-9. There is a script ievms simplifying the installation. But before you have to install the latest VirtualBox. You can do this e.g. via Package Manager (Ubuntu), Yast (OpenSuse) or via Linux terminal
 
sudo apt-get install virtualbox-4.1
 
The next step is the installation of VirtualBox Extension Pack. This is necessary for USB 2.0 devices, shared folders, better screen resolution, etc. The best way is to download and install the package for the VirtualBox Extension Pack manually.
 
wget http://download.virtualbox.org/virtualbox/4.1.6/Oracle_VM_VirtualBox_Extension_Pack-4.1.6-74713.vbox-extpack
VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-4.1.6-74713.vbox-extpack
 
Open VirtialBox tnen and go to File > Preferences > Extensions tab. Click there the "add" button and browse to the VirtualBox Extension Pack. Now you need to install curl (tool to transfer data from or to a server) and unrar (command-line applications for extracting RAR archives). In Ubuntu, install them using the command below.
 
sudo apt-get install curl unrar
 
To download and run the mentioned above script, use the following command in a terminal.
 
curl -s https://raw.github.com/xdissent/ievms/master/ievms.sh | bash
 
The above command will download Windows VHDs for IE7, IE8 and IE9. If you only need one specific Internet Explorer version, e.g. IE9, you can run:
 
curl -s https://raw.github.com/xdissent/ievms/master/ievms.sh | IEVMS_VERSIONS="9" bash
 
At this point, the download will start and it will take a while. The VHD archives are massive and can take hours to download. Each version is installed into a subdirectory of ~/.ievms/vhd/. At the end you can delete the downloaded archives (*.exe and *.rar files) below this folder if you want to free up some space. You are ready to test websites in IE7-IE9 now. The password for all VMs is "Password1". The picture below shows a VirtualBox with IE9.


The next picture shows that I set shared folders to exchange data between Windows 7 in VM and my Kubuntu 11.10 (Oneiric Ocelot).


You can start your web application on Linux. But how to access a running web application on Windows (VirtualBox)? Linux has a command tool ifconfig to configure, control and query TCP/IP network interface parameters. Open a terminal and type ifconfig. Find an IP address you Linux mashine is accessible from. I have e.g. 192.168.254.21 for wlan0 interface. You are able to call now
 
http://192.168.254.21:8080/...
 
in Interner Exloper on Windows. The IP address is like a localhost for your web application running on Linix. Remaning part behind this address is the same on both OS.

Wednesday, November 16, 2011

5 useful methods JSF developers should know

The aim of this post is a summary about some handy methods for JSF developers they can use in their day-to-day work. An utility class is a good place to put all methods together. I would call such class FacesAccessor. The first method is probably the most used one. It returns managed bean by the given name. The bean must be registered either per faces-config.xml or annotation. Injection is good, but sometimes if beans are rare called, it's not necessary to inject beans into each other.
public static Object getManagedBean(final String beanName) {
    FacesContext fc = FacesContext.getCurrentInstance();
    Object bean;
    
    try {
        ELContext elContext = fc.getELContext();
        bean = elContext.getELResolver().getValue(elContext, null, beanName);
    } catch (RuntimeException e) {
        throw new FacesException(e.getMessage(), e);
    }

    if (bean == null) {
        throw new FacesException("Managed bean with name '" + beanName
            + "' was not found. Check your faces-config.xml or @ManagedBean annotation.");
    }

    return bean;
}
Using:
@ManagedBean
public class PersonBean {
    ...
}

PersonBean personBean = (PersonBean)FacesAccessor.getManagedBean("personBean");

// do something with personBean
The second method is useful for JSF component developers and everyone who would like to evaluate the given value expression #{...} and sets the result to the given value.
public static void setValue2ValueExpression(final Object value, final String expression) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ELContext elContext = facesContext.getELContext();

    ValueExpression targetExpression = 
        facesContext.getApplication().getExpressionFactory().createValueExpression(elContext, expression, Object.class);
    targetExpression.setValue(elContext, value);
}
Using:
I personally use this method for the "log off functionality". After an user is logged off, he/she will see a special "logoff page". The "logoff page" uses user settings (e.g. theme, language, etc.) from a sesion scoped bean. But this session scoped bean doesn't exist more because the session was invalidated. What to do? Here is the code snippet from my logout method.
UserSettings userSettings = (UserSettings) FacesAccessor.getManagedBean("userSettings");

// invalidate session
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession) ec.getSession(false);
session.invalidate();

// create new session
((HttpServletRequest) ec.getRequest()).getSession(true);

// restore last used user settings because login / logout pages reference "userSettings"
FacesAccessor.setValue2ValueExpression(userSettings, "#{userSettings}");

// redirect to the specified logout page
ec.redirect(ec.getRequestContextPath() + "/views/logout.jsf");
The third method maps a variable to the given value expression #{...}. It uses javax.el.VariableMapper to assign the expression to the specified variable, so that any reference to that variable will be replaced by the expression in EL evaluations.
public static void mapVariable2ValueExpression(final String variable, final String expression) {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ELContext elContext = facesContext.getELContext();
    
    ValueExpression targetExpression =
        facesContext.getApplication().getExpressionFactory().createValueExpression(elContext, expression, Object.class);
    elContext.getVariableMapper().setVariable(variable, targetExpression);
}
Using:
Assume, "PersonBean" is a managed bean having "name" attribute and "PersonsBean" is a bean holding many instances of "PersonBean" (as array, collection or map). The following code allows to use "personBean" as a reference to a specific bean with "name" Oleg.
 
FacesAccessor.mapVariable2ValueExpression("personBean", "#{personsBean.person['Oleg']}");
 
In a facelets page, say so, personDetail.xhtml, we can write:
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
<ui:composition>
    ...
    <h:inputText value="#{personBean.name}"/>
    ...
</ui:composition>
</html>
Note, the reference "personBean" was set in Java. This mapping can be also used in facelets in declarative way via ui:include / ui:param.
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
    ...
    <ui:include src="personDetail.xhtml">
        <ui:param name="personBean" value="#{personsBean.person['Oleg']}"/>
    </ui:include>
    ...
</ui:composition>
</html>
The next two methods are used to create MethodExpression / MethodExpressionActionListener programmatically. They are handy if you use component binding via "binding" attribute or create some model classes in Java.
public static MethodExpression createMethodExpression(String valueExpression,
                                                      Class<?> expectedReturnType,
                                                      Class<?>[] expectedParamTypes) {
    MethodExpression methodExpression = null;
    try {
        FacesContext fc = FacesContext.getCurrentInstance();
        ExpressionFactory factory = fc.getApplication().getExpressionFactory();
        methodExpression = factory.
            createMethodExpression(fc.getELContext(), valueExpression, expectedReturnType, expectedParamTypes);
    } catch (Exception e) {
        throw new FacesException("Method expression '" + valueExpression + "' could not be created.");
    }
    
    return methodExpression;
}

public static MethodExpressionActionListener createMethodActionListener(String valueExpression,
                                                                        Class<?> expectedReturnType,
                                                                        Class<?>[] expectedParamTypes) {
    MethodExpressionActionListener actionListener = null;
    try {
        actionListener = new MethodExpressionActionListener(createMethodExpression(
            valueExpression, expectedReturnType, expectedParamTypes));
    } catch (Exception e) {
        throw new FacesException("Method expression for ActionListener '" + valueExpression
                          + "' could not be created.");
    }

    return actionListener;
}
Using:
In one of my projects I have created PrimeFaces MenuModel with menu items programmatically.
MenuItem mi = new MenuItem();
mi.setAjax(true);
mi.setValue(...);
mi.setProcess(...);
mi.setUpdate(...);
mi.setActionExpression(FacesAccessor.createMethodExpression(
    "#{navigationContext.setBreadcrumbSelection}", String.class, new Class[] {}));

UIParameter param = new UIParameter();
param.setId(...);
param.setName(...);
param.setValue(...);
mi.getChildren().add(param);
Do you have nice methods you want to share here? Tips / tricks are welcome.

Saturday, October 29, 2011

Fix for CSS opacity in Internet Explorer

How to set CSS opacity in Internet Explorer? It's easy for good browsers like Firefox, Google Chrome or new IE9:
opacity: 0.5;
For old Safary versions you probably also need
-khtml-opacity: 0.5;
For IE6, IE7 you can write
filter: alpha(opacity=50);
and for IE8
-ms-filter: "alpha(opacity=50)";
Saidly, but filter with opacity value in IE isn't enough. Element should be positioned, in order that opacity would work in IE. If the element doesn't have a position, there is a little trick in order to get it working. Add 'zoom: 1' to your CSS.
filter: alpha(opacity=50);        // IE6, IE7
-ms-filter: "alpha(opacity=50)"; // IE8
zoom: 1;
I have faced this problem with Schedule component in PrimeFaces. The button "today" is not disabled in IE7 for the current day although it has the jQuery UI style .ui-state-disabled. The fix would be
/* IE7 hack */
div.fc-button-today.ui-state-disabled {
    *zoom: 1;
}
* means the style is applied for IE7 only.

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);} 
}

Thursday, October 6, 2011

Facelets with HTML5

After reading this post on StackOverflow I have decided to use HTML5 DOCTYPE in JSF. Why to write long DOCTYPE with DTD, (X)HTML, Transitional, etc. like this one
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      ... >
      
</html>
if we can write much simpler <!DOCTYPE html>?
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      ... >
      
</html>
Using HTML5 DOCTYPE doesn't have side effects with Facelets parser and works fine in all browsers expect of IE6 which will render pages in quirks mode. IE6 usage is decreasing last years and it's not supported by many JSF libraries (like PrimeFaces) anymore. So, it doesn't hurt. If you are using HTML5 specific elements (e.g. file upload in PrimeFaces) and the browser doesn't support them, fallbacks will be applied. HTML5 specific elements will be gracefully degraded to HTML4.

One small issue I had during my changes of DOCTYPE was the entity &nbsp; which I sometimes use for non-breaking space. The Facelets parser says
 
The entity "nbsp" was referenced, but not declared.
 
The solution is to replace &nbsp; by the character reference &#160; Also other entities like &copy; should be replaced by character references. Apart from that JSF components which I use in my web apps are okey so far.

Summary: Using of <!DOCTYPE html> in Facelets is highly recommended. It's simple and future-proof.

Thursday, September 29, 2011

Atmosphere and JSF are good friends

Decision to write this long article was driven by PrimeFaces community. People have troubles to develop web applications with server push techniques. Even with Atmosphere - framework for building portable Comet and WebSocket based applications. Portable means it can run on Tomcat, JBoss, Jetty, GlassFish or any other application server which supports Servlet specification 2.5 or higher. If you want to be independent on underlying server and don't want to have headaches during implementation, use Atmosphere framework. It simplifies development and can be easy integrated into JSF or any other web frameworks (don't matter). I read Atmosphere doesn't play nice with JSF or similar. PrimeFaces had a special Athmosphere handler for JSF in 2.2.1. But that's all is not necessary. It doesn't matter what for a web framework you use - the intergration is the same. My intention is to show how to set up a bidirectional communication between client and server by using of Atmosphere. My open source project "Collaborative Online-Whiteboard" demonstrates that this approach works well for all three transport protocols - Long-Polling, Streaming and WebSocket. This is an academic web application built on top of the Raphaƫl / jQuery JavaScript libraries, Atmosphere framework and PrimeFaces. You can open two browser windows (browser should support WebSocket) and try to draw shapes, to input text, to paste image, icon, to remove, clone, move elements etc.


We need a little theory at first. For bidirectional communication we need to define a Topic at first (called sometimes "channel"). Users subscribe to the Topic and act as Subscribers to receive new data (called updates or messages as well). A subscriber acts at the same time as Publisher and can send data to all subscribers (broadcasting). Topic can be expressed by an unique URL - from the technical point of view. URL should be specified in such a manner that all bidirectional communication goes through AtmosphereServlet. JSF requests should go through FacesServlet. This is a very important decision and probably the reason why Atmosphere integration in various web frameworks like JSF and Struts sometimes fails. Bidirectional communication should be lightweight and doesn't run all JSF lifecycle phases! This can be achieved by proper servlet-mapping in web.xml. The picture below should demonstrate the architecture (example of my open source project).


For my use case I need messages in JSON format, but generally any data can be passed over bidirectional channel (XML, HTML). What is the Topic exactly? It depends on web application how you define the Topic. You can let user types it self (e.g. in chat applications) or make it predefined. In my application I equate Topic with Whiteboard-Id which is generated as UUID. Furthermore, I have introduced User-Id (= Publisher-Id) as well and called it Sender. Sender serves as identificator to filter Publisher out of all Subscribers. Publisher is normally not interested in self notification. I'm going to show using of Sender later. My Topic-URL follows this pattern
http://host:port/pubsub/{topic}/{sender}.topic
and looks like e.g. as
http://localhost:8080/pubsub/ea288b4c-f2d5-467f-8d6c-8d23d6ab5b11/e792f55e-2309-4770-9c48-de75354f395d.topic
I use Atmosphere with Jersey I think it's a better way than to write Atmosphere handlers or try to integrate MeteorServlet. Therefore, to start using of Atmosphere, you need a dependency to current Atmosphere and Jersey. Below is a dependency configuration for Maven users. Note: I cut logging off.
<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-jersey</artifactId>
    <version>0.8-SNAPSHOT</version>
    <exclusions>
        <exclusion>
            <groupId>org.atmosphere</groupId>
            <artifactId>atmosphere-ping</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-servlet_3.0_spec</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.2</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.6.2</version>
</dependency>
The next step is to add Atmosphere-jQuery plugin to the client side. This plugin can be downloaded from the Atmosphere's homepage. After placing jquery.atmosphere.js under webapp/resources/js you can include it with
<h:outputScript library="js" name="jquery.atmosphere.js" target="head"/>
Yes, I know that Atmosphere can load jquery.atmosphere.js from JAR file in classpath, but a manual include is better in JSF environment. Now we are able to subscribe to the Topic and communicate with the server on the client side. There are two calls: jQuery.atmosphere.subscribe() and jQuery.atmosphere.response.push(). To establish a bidirectional communication, you need to call subscribe(). You have to call this method just once when page has been loaded. After that the method push() is responsible for data publushing to all subsribers. In the mentioned above web application I have an JavaScript object WhiteboardDesigner which encapsulates the Atmosphere's subscribe() call in the method subscribePubSub().
// Subscribes to bidirectional channel.
// This method should be called once the web-application is ready to use.
this.subscribePubSub = function() {
  jQuery.atmosphere.subscribe(
    this.pubSubUrl,
    this.pubSubCallback,
    jQuery.atmosphere.request = {
      transport: this.pubSubTransport,
      maxRequest: 100000000
    });
    
    this.connectedEndpoint = jQuery.atmosphere.response;
}
The first parameter this.pubSubUrl is the shown above Topic-URL. The second parameter this.pubSubCallback is the callback function. The third parameter is the request configuration which keeps among other things transport protocol defined in this.pubSubTransport: "long-polling", "streaming" or "websocket". The last line assigns jQuery.atmosphere.response the variable this.connectedEndpoint which allows us data publishing via push(). So now when new data being received, the callback function this.pubSubUrl gets called. Inside of the callback we can extract received data from response object. You can get the idea how to handle broadcasted data from my example:
// Callback method defined in the subscribePubSub() method.
// This method is always called when new data (updates) are available on server side.
this.pubSubCallback = function(response) {
  if (response.transport != 'polling' &&
      response.state != 'connected' &&
      response.state != 'closed' && response.status == 200) {
      var data = response.responseBody;
      if (data.length > 0) {
        // convert to JavaScript object
        var jsData = JSON.parse(data);

       // get broadcasted data
        var action = jsData.action;
        var sentProps = (jsData.element != null ? jsData.element.properties : null);
        switch (action) {
          case "create" :
            ...
            break;
          case "update" :
            ...
            break;
          case "remove" :
            ...
            break;
          ... 
          default :
        }
        ...
      }
  }
}
To publish data over the Topic-URL you need to call this.connectedEndpoint.push(). this.connectedEndpoint is a defined above shortcut for jQuery.atmosphere.response. I call it in my example for created whiteboard elements as follows (just an example):
// Send changes to server when a new image was created.
this.sendChanges({
  "action": "create",
  "element": {
    "type": "Image",
    "properties": {
      "uuid": ...,
      "x": ...,
      "y": ...,
      "url": ...,
      "width": ...,
      "height": ...
    }
  }
});

// Send any changes on client side to the server.
this.sendChanges = function(jsObject) {
  // set timestamp
  var curDate = new Date();
  jsObject.timestamp = curDate.getTime() + curDate.getTimezoneOffset() * 60000;

  // set user
  jsObject.user = this.user;

  // set whiteboard Id
  jsObject.whiteboardId = this.whiteboardId;

  var outgoingMessage = JSON.stringify(jsObject);

  // send changes to all subscribed clients
  this.connectedEndpoint.push(this.pubSubUrl, null, jQuery.atmosphere.request = {data: 'message=' + outgoingMessage});
}
Passed JavaScript object jsObject is converted to JSON via JSON.stringify(jsObject) befor it's sending to the server.

What is necessary on the server side? Calls jQuery.atmosphere.subscribe() and jQuery.atmosphere.response.push() have to be caught on the server side. I use Jersey and its annotations to catch GET- / POST-requests for the certain Topic-URL in a declarative way. For that are responsible annotations @GET, @POST und @PATH. I have developed the class WhiteboardPubSub to catch the Topic-URL by means of @Path("/pubsub/{topic}/{sender}"). With @GET annotated method subscribe() catches the call jQuery.atmosphere.subscribe(). This method tells Atmosphere to suspend the current request until an event occurs. Topic (= Broadcaster) is also created in this method. Topic-String is extracted by the annotation @PathParam from the Topic-URL. You can imagine a Broadcaster as a queue. As soon as a new message lands in the queue all subscribers get notified (browsers which are connected with Topic get this message). With @POST annotated method publish() catches the call jQuery.atmosphere.response.push(). Client's data will be processed there and broadcasted to all subscribed connections. This occurs independent from the underlying transport protocol.
@Path("/pubsub/{topic}/{sender}")
@Produces("text/html;charset=ISO-8859-1")
public class WhiteboardPubSub
{
  private @PathParam("topic") Broadcaster topic;

  @GET
  public SuspendResponse<String> subscribe() {
    return new SuspendResponse.SuspendResponseBuilder<String>().
               broadcaster(topic).outputComments(true).build();
  }

  @POST
  @Broadcast
  public String publish(@FormParam("message") String message,
                      @PathParam("sender") String sender,
                      @Context AtmosphereResource resource) {
    // find current sender in all suspended resources and
    // remove it from the notification
    Collection<AtmosphereResource<?, ?>> ars = topic.getAtmosphereResources();
    if (ars == null) {
      return "";
    }

    Set<AtmosphereResource<?, ?>> arsSubset = new HashSet<AtmosphereResource<?, ?>>();
    HttpServletRequest curReq = null;
    for (AtmosphereResource ar : ars) {
      Object req = ar.getRequest();
      if (req instanceof HttpServletRequest) {
        String pathInfo = ((HttpServletRequest)req).getPathInfo();
        String resSender = pathInfo.substring(pathInfo.lastIndexOf('/') + 1);
        if (!sender.equals(resSender)) {
          arsSubset.add(ar);
        } else {
          curReq = (HttpServletRequest) req;
        }
      }
    }

    if (curReq == null) {
      curReq = (HttpServletRequest) resource.getRequest();
    }

    // process current message (JSON) and create a new one (JSON) for subscribed clients
    String newMessage = WhiteboardUtils.updateWhiteboardFromJson(curReq, message);

    // broadcast subscribed clients except sender
    topic.broadcast(newMessage, arsSubset);

    return "";
  }
}
In my case the method publish() looks for sender (= publisher of this message) among all subscribers and removes it from the notification. It looks a little bit complicated. In simple case you can write
@POST
@Broadcast
public Broadcastable publish(@FormParam("message") String message) {
  return new Broadcastable(message, "", topic);
}
and that's all! The last step is the mentioned above configuration in web.xml. *.jsf requests should be mapped to FacesServlet and *.topic requests to AtmosphereServlet. AtmosphereServlet can be configured comprehensively. Important configuration parameter is com.sun.jersey.config.property.packages. With this parameter you can tell Jersey where the annotated class is located (in my case WhiteboardPubSub). In my example Jersey scans the directory com.googlecode.whiteboard.pubsub.
<!-- Faces Servlet -->
<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<!-- Atmosphere Servlet -->
<servlet>
  <description>AtmosphereServlet</description>
  <servlet-name>AtmosphereServlet</servlet-name>
  <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
    <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>com.googlecode.whiteboard.pubsub</param-value>
  </init-param>
  <init-param>
    <param-name>org.atmosphere.useWebSocket</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>org.atmosphere.useNative</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>org.atmosphere.cpr.WebSocketProcessor</param-name>
    <param-value>org.atmosphere.cpr.HttpServletRequestWebSocketProcessor</param-value>
  </init-param>
  <init-param>
    <param-name>org.atmosphere.cpr.broadcastFilterClasses</param-name>
    <param-value>org.atmosphere.client.JavascriptClientFilter</param-value>
  </init-param>
  <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>AtmosphereServlet</servlet-name>
  <url-pattern>*.topic</url-pattern>
</servlet-mapping>
Please check Atmosphere documentation and showcases for more information.

Summary: We have seen that few things are needed to establish the bidirectional comminication: Topic-URL, callback function for data receiving, subsribe() und push() methods on client side, an Jersey class on server side and configuration in web.xml to bind all parts together. JSF- und Atmosphere-requests should be treated separately. You maybe ask "but what is about the case if I need to access JSF stuff in Atmosphere-request?" For a simple case you can use this technique to access managed beans. If you want to have a fully access to all JSF stuff you should use this technique which allows accessing FacesContext somewhere from the outside.

P.S. Good news. Atmosphere's lead Jeanfrancois Arcand announced his intention to pursue the work on Atmosphere. He can invest more time now in his great framework.

Tuesday, September 27, 2011

Quick practical introduction to JSDoc (JsDoc Toolkit)

Documentation of JavaScript code is a very important part of software development and helps front-end developers to understand code of third-party libraries. There are really well documented libraries. One of them is Mojarra JavaScript documentation. Other libraries (and that's a common case) don't have JavaScript documentation at all or don't cover all their features, so that features stay undocumented (I hope PrimeFaces guys read this blog post :-)).

JSDoc is documentation generated for JavaScript code by means of JsDoc Toolkit. Documentation is not restricted to multi-page HTML, other formats are possible too. Look-&-feel can be fully customized by templates. In this quick introduction I use built-in templates and would like to show generated JSDoc on example of my open source project "Collaborative Online-Whiteboard". I use following tags in my example:

@fileOverview
This tag allows you to provide documentation for an entire file. It's often used with other tags @author and @version.
@class
This tag also allows you to add a description of the JavaScript class (if you write your code in OOP style).
@param
This tag allows you to document information about the parameters to a function, method or class (constructor)
@public
This tag allows you to document public methods or variables.
@private
This tag allows you to document private methods or variables.
@type
This tag allows you to document the type of value a variable refers to, or the type of value returned by a function.
@returns
This tag documents the value returned by a function or method. You can specify a type of the returned value in curly braces {...}.
@link
This tag allows you to create a HTML link to some other documented symbol (similar link in JavaDoc).

Let's document the JavaScript code! I have a class called WhiteboardDesigner which expects 5 parameters (to be passed to constructor) and has many public / private methods. The documented class looks like
/**
* @fileOverview
* @author <a href="mailto:ovaraksin@googlemail.com">Oleg Varaksin</a>
* @version 0.2
*/

/**
* Whiteboard designer class for element drawing.
* @class
* @param witeboardConfig whiteboard's configuration {@link WhiteboardConfig}
* @param whiteboardId whiteboard's id
* @param user user (user name) working with this whiteboard
* @param pubSubUrl URL for bidirectional communication
* @param pubSubTransport transport protocol "long-polling" | "streaming" | "websocket"
*/
WhiteboardDesigner = function(witeboardConfig, whiteboardId, user, pubSubUrl, pubSubTransport) {
    /**
     * Whiteboard's configuration {@link WhiteboardConfig}.
     * @public
     * @type WhiteboardConfig
     */
    this.config = witeboardConfig;
    /**
     * Whiteboard's id.
     * @public
     * @type uuid
     */    
    this.whiteboardId = whiteboardId;
    /**
     * User which works with this whiteboard.
     * @public
     * @type string
     */    
    this.user = user;
    /**
     * URL for bidirectional communication.
     * @public
     * @type string
     */    
    this.pubSubUrl = pubSubUrl;
    /**
     * Transport protocol "long-polling" | "streaming" | "websocket".
     * @public
     * @type string
     */    
    this.pubSubTransport = pubSubTransport;
    /**
     * Logging flag, true - logging is visible, false - otherwise.
     * @public
     * @type boolean
     */    
    this.logging = false;
    /**
     * Raphael's canvas.
     * @private
     * @type Raphael's paper
     */    
    var paper = Raphael(this.config.ids.whiteboard, whiteboard.width(), whiteboard.height());
    
    ...
    
    /** Draws image with default properties.
    * @public
    * @param inputUrl image URL.
    * @param width image width.
    * @param height image height.
    */    
    this.drawImage = function(inputUrl, width, height) {
        ...
    }
    
    /** Gets currently selected whiteboard element.
    * @public
    * @returns {Raphael's element} currently selected element
    */
    this.getSelectedObject = function() {
        ...
    }

    ...

    /** Outputs debug messages.
    * @private
    * @param msg message
    */
    var logDebug = function(msg) {
        ...
    }
}
How to generate a documentation now? I would like to show a quick and simple way. Download JsDoc Toolkit zip file at first. Extract it and go to the directory jsdoc-toolkit. Create there a new folder with any name which will contain your documented JavaScript files. I have created a folder called "whiteboard". Copy all JavaScript files into this folder. Open a DOS console or Linux terminal or whatever at jsdoc-toolkit and type
 
java -jar jsrun.jar app/run.js -a -p -t=templates/jsdoc ./<yours folder name>/*.*
 
In my case it's
 
java -jar jsrun.jar app/run.js -a -p -t=templates/jsdoc ./whiteboard/*.*
 
JsDoc Toolkit runs via the Mozilla JavaScript Engine "Rhino." Rhino is wrapped in a runner application called jsrun. Option -a says: include all functions, even undocumented ones. Option -p says: include symbols tagged as private, underscored and inner symbols (such symbols are not included per default). Option -t is required und used to point to templates for output formatting. Using of default build-in templates which are located under templates/jsdoc is satisfying in most cases.

After script running you will find generated files in the out folder. Entry file is index.html. Its location is .../jsdoc-toolkit/out/index.html You can see online here how does it look for my project. Have much fun!

Friday, September 16, 2011

Inheritance in Maven based web projects

Sometimes you want to define a base web project and reuse all web based stuff in all other web projects. This is not rare in big projects. The first thought coming in mind is inheritance. Is there any inheritance between web projects at all? Yes, in a manner of speaking. In Maven based projects there is a nice "overlay" feature for maven-war-plugin. You can point to the base WAR project in the overlay tag and the base project gets extracted bevor it's stuff will be extended or overwritten by inherited project. An example:
<plugin>
    <artifactId>maven-war-plugin</artifactId>
    ...
    <configuration>
        <overlays>
            <overlay>
                <groupId>ip.client</groupId>
                <artifactId>ip-theme-framework</artifactId>
                <classifier>webapp</classifier>
                <excludes>
                    <exclude>META-INF/**</exclude>
                    <exclude>WEB-INF/web.xml</exclude>
                    <exclude>WEB-INF/lib/**</exclude>
                    <exclude>WEB-INF/classes/**</exclude>
                </excludes>
            </overlay>
        </overlays>
    </configuration>
</plugin>
You have also to add a dependency in your inherited project for the base project, of course. Well, this feature works fine, but there is a problem with transitive dependencies. Dependencies defined in the base project are "invisible" for inherited projects. You can not use transitive dependencies, they aren't going to be inherited. And adding of all dependencies again in inherited projects is error-prone and causes some issues during release management. To solve this problem, we can set packaging of all web projects as jar. That's what we do in my company.
<packaging>jar</packaging>
With packaging jar you have still a WAR archive at the end, but Java sources are packed to one jar file which is placed by Maven below WEB-INF/lib inside of the WAR. WEB-INF/classes stays empty. Dependencies get now accepted. One thing to keep in mind: WAR projects with packaging jar should be specified twice as dependencies. Once without <type> and once with <type>war</type>. An example:
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
</dependency>
<dependency>
    <groupId>ip.client</groupId>
    <artifactId>ip-theme-framework</artifactId>
    <classifier>webapp</classifier>
    <type>war</type>
    <scope>runtime</scope>
</dependency>
The last be not least is the support in IDEs. JAR projects are not recognized as web projects in Eclipse, IntelliJ or somewhere else and you lose all goodies from your preferred IDE. A solution is simple and uses profiles. Define a property ${packaging.war} for a special profile (see my last post).
<profile>
    <id>ide</id>
    <properties>
        <packaging.war>war</packaging.war>
    </properties>
</profile>
write variable packaging.war in the packaging tag of your project
<packaging>${packaging.war}</packaging>
and let Maven run with this profile when creating IDE specific files:
mvn -Pide eclipse:eclipse
mvn -Pide idea:idea
...
Summary: Overlays help to reuse web projects. They also help to customize web projects by having one big core project and many small custom specific projects which only have specific CSS, Images (logos, ect.) and messages in property files. Custom specific Maven projects don't have Java classes - the aim is to overwrite / extend resources of core project and achieve a custom Look-&-Feel.

Wednesday, September 14, 2011

Filter web.xml with Maven

Maven (build manager for Java projects) has a feature called "filtering". As is generally known you can replace with Maven any variables defined with placeholders like ${my.variable}. Such variables can be placed in property files or any other resource files like CSS, JavaScript, (X)HTML. I normally place placeholders in web.xml and replace them by real values while Maven runs with a certain profile. My default Maven profile is e.g. "development". Another profile is "release". To build artefacts with "release" profile I run
mvn -Prelease clean install
Option -P is for profile you want to build software with. How to set up filtering of web.xml exactly? At first we need to create a directory "filter" under "src/main" and place two (or more) property files under "src/main/filter". In order to demonstrate filtering for two profiles I'm going to create development.properties and release.properties. So, our structure looks now as follows:


Let us define the content of development.properties as
jsf.faceletsRefreshPeriod=2
jsf.resourceUpdateCheckPeriod=2
and the content of release.properties as
jsf.faceletsRefreshPeriod=-1
jsf.resourceUpdateCheckPeriod=-1
The next step is to modify web.xml. web.xml gets two placeholders:
...
<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>${jsf.faceletsRefreshPeriod}</param-value>
</context-param>
<context-param>
    <param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
    <param-value>${jsf.resourceUpdateCheckPeriod}</param-value>
</context-param>
...
The last step is to modify pom.xml. Actually we don't need two profiles. Let us only define the "release" profile and assume default case without any profiles as "development".
<profiles>
    <profile>
        <id>release</id>
        <properties>
            <webapp.filter>release</webapp.filter>
        </properties>
    </profile>
</profiles>
Important thing is to define a property "webapp.filter" for "release" profile. For default case we have also to add this line to pom.xml (somewhere at the end):
<properties>
    <webapp.filter>development</webapp.filter>
</properties>
To make it working together with maven-war plugin (in this case) we need to activate filtering feature. That means, before WAR archive gets packed, placeholders in web.xml should be already replaced by real values from property files. This task is simple:
<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <executions>
        <execution>
            <id>war</id>
            <phase>package</phase>
            <goals>
                <goal>war</goal>
            </goals>
            <configuration>
                ...
                <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
                <filters>
                    <filter>${basedir}/src/main/filter/${webapp.filter}.properties</filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>
We leverages here the variable ${webapp.filter} which points to file name depends on currently active profile. That's all. You can now run builds with
// build for development
mvn clean install

// build for release
mvn -Prelease clean install
There is only one issue when using Jetty Maven plugin and let it runs with
mvn jetty:run
Jetty looks as default under source directory and scans src/main/webapp/WEB-INF/web.xml. But located there web.xml has placeholders. How to solve that? A solution is easy. This is a bonus part of this post. We can leverages overrideDescriptor tag and specify a XML file with our own parts of web.xml which overwrite the same parts in src/main/webapp/WEB-INF/web.xml when Jetty running.
<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <configuration>
        <webAppConfig>
            ...
            <overrideDescriptor>src/main/resources/overrideweb.xml</overrideDescriptor>
        </webAppConfig>
    </configuration>
</plugin>
The content of overrideweb.xml is (we normally need settings for default "development" profile when Jetty running)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <context-param>
        <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
        <param-value>2</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.injectionProvider</param-name>
        <param-value>com.sun.faces.vendor.WebContainerInjectionProvider</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.spi.AnnotationProvider</param-name>
        <param-value>com.sun.faces.config.AnnotationScanner</param-value>
    </context-param>
    
    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>
</web-app>
Happy filtering!

Wednesday, September 7, 2011

Useful Maven commandos

Everybody who uses Maven from console / terminal knows how sometimes difficult to remember all handy commandos using in day job. A small reference list should help.

Skip running tests for a particular project.
mvn clean install -Dmaven.test.skip=true
Continue build if it has been failed at certain point. Maybe you have many sub-projects and build your entire project from top to down. "-rf" parameters allow to continue maven running where you want after any build errors. Assume my current top directory where I let Maven run is D:\SVN and the build was broken at D:\SVN\eIP\CoreServer\DatastoreConnector. Following command let go on with the build and skip this not compilable or not testable sub-project.
mvn clean install -rf eIP\CoreServer\DatastoreConnector
Get source jar files (e.g. for Eclipse projects). Having source files in local repository allow to jump into this directly from your preferred IDE.
mvn eclipse:eclipse -DdownloadSources=true
or run
mvn dependency:sources
to download all source jars for a given project into local repository. The same for JavaDoc (if it's available).
mvn eclipse:eclipse -DdownloadJavadocs=true
Output project's dependency tree. I like that! You can see versions of all used artefacts.
mvn dependency:tree
Output is like this one
[INFO] ip.client:ip-jsftoolkit:jar:3.4.1-SNAPSHOT
[INFO] +- ip.client:ip-filter-security:jar:3.4.0:compile
[INFO] |  +- com.scalaris.commons:scalaris-commons-enterprise:jar:2.3.1-SNAPSHOT:compile
[INFO] |  |  +- com.scalaris.commons:scalaris-commons-lang:jar:2.3.0:compile
[INFO] |  |  +- org.apache.commons:commons-lang3:jar:3.0:compile
[INFO] |  |  \- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  +- ip.client:ip-client-commons:jar:3.4.0:compile
[INFO] |  |  +- ip.services:ip-core-services:jar:3.4.0:compile
[INFO] |  |  |  \- ip.datatransfer:ip-datatransfer-commons:jar:3.4.0:compile
..................................................
[INFO] |  +- commons-httpclient:commons-httpclient:jar:3.0.1:compile
[INFO] |  +- org.apache.commons:commons-jexl:jar:2.0:compile
[INFO] |  \- joda-time:joda-time:jar:1.6.2:compile
[INFO] +- javax.ejb:ejb:jar:3.0:provided
[INFO] +- javax.servlet:servlet-api:jar:2.5:provided
[INFO] \- com.scalaris.commons:scalaris-commons-test:jar:2.2.8-SNAPSHOT:test
[INFO]    +- jmock:jmock:jar:1.2.0:test
[INFO]    +- junit:junit:jar:3.8.2:test
Filter project's dependency tree in order to see only a specified dependency. The syntax for filter patterns is as follows: [groupId]:[artifactId]:[type]:[version]
mvn dependency:tree -Dincludes=com.sun.faces:jsf-impl
Display the effective pom of a project. The effective pom represents the current pom state for a project (incl. maven super pom and active profiles).
mvn help:effective-pom
Generate files needed for an IntelliJ IDEA project setup.
mvn idea:idea
This plugin has no way to determine the name of the JDK you are using. It uses by default the same JDK as output java -version. Using with defined JDK:
mvn idea:idea -DjdkName=1.5
Create a web project from scratch.
mvn archetype:create 
 -DarchetypeGroupId=org.apache.maven.archetypes 
 -DarchetypeArtifactId=maven-archetype-webapp 
 -DarchetypeVersion=1.0 
 -DgroupId=com.maventest 
 -DartifactId=mywebtest 
 -Dversion=1.0-SNAPSHOT
Deploy artefact in global repository (located e.g. in file://///xyz.abc.com/maven/repo-m2).
mvn deploy:deploy-file
 -DgroupId=com.maventest
 -DartifactId=mywebtest
 -Dversion=1.0-SNAPSHOT
 -Dpackaging=war
 -Dfile=mywebapp.jar
 -DrepositoryId=xyz-release 
 -Durl=file://///xyz.abc.com/maven/repo-m2
Check all the dependencies used in your project and display a list of those dependencies with newer versions available.
mvn versions:display-dependency-updates

...
[INFO] The following dependency updates are available:
[INFO]   org.apache.maven:maven-artifact ........................ 2.0 -> 2.0.9
[INFO]   org.apache.maven:maven-plugin-api ...................... 2.0 -> 2.0.9
[INFO]   org.apache.maven:maven-project ....................... 2.0.2 -> 2.0.9
[INFO]   org.codehaus.plexus:plexus-utils ....................... 1.1 -> 1.5.6
Check all the plugins and reports used in your project and display a list of those plugins with newer versions available.
mvn versions:display-plugin-updates

...
[INFO] The following plugin updates are available:
[INFO]   maven-deploy-plugin ...................................... 2.5 -> 2.7
[INFO]   maven-jar-plugin ..................................... 2.3.1 -> 2.3.2
[INFO]   maven-plugin-plugin ...................................... 2.7 -> 2.9
[INFO]   maven-resources-plugin ................................. 2.4.3 -> 2.5
Decompile Java classes in the maven central repository :-). Useful if source code isn't available. The trick is here.

Thursday, August 25, 2011

Combine jQuery Datepicker and Spinner for fast day incrementation / decrementation

Is it possible to add + / - buttons to jQuery UI Datepicker in order to increment / decrement days in a comfortable way? Yes, it's possible. I have done this task - see screenshot.


This is an extended PrimeFaces Calendar with added "dateSpinner" mode. I would like to omit JSF part and only show HTML / CSS / JavaScript part of such combined calendar. All what you need is to wrap the datepicker markup with a span element, add themable up / down arrows and use datepicker utility functions $.datepicker.formatDate(format, date, settings) and $.datepicker.parseDate(format, value, settings).

HTML
Original HTML with a calendar icon (called icon trigger in jQuery Datepicker) looks very simple
 
<input id="datepicker" class="hasDatepicker" type="text">
<img class="ui-datepicker-trigger" src="images/calendar.gif" alt="..." title="...">
 
You have to extend this as follows
<span id="datepickerWrapper" class="ui-ccalendar ui-widget ui-corner-all">
	<input id="datepicker" class="hasDatepicker" type="text">
	<img class="ui-datepicker-trigger" src="images/calendar.gif" alt="..." title="...">
	<a class="ui-ccalendar-button ui-ccalendar-up ui-corner-tr ui-button ui-widget ui-state-default ui-button-text-only">
		<span class="ui-button-text">
			<span class="ui-icon ui-icon-triangle-1-n"></span>
		</span>
	</a>
	<a class="ui-ccalendar-button ui-ccalendar-down ui-corner-br ui-button ui-widget ui-state-default ui-button-text-only">
		<span class="ui-button-text">
			<span class="ui-icon ui-icon-triangle-1-s"></span>
		</span>
	</a>
</span>

CSS
The most CSS classes above are jQuery UI classes. I marked own classes with ui-ccalendar. In the CSS part is very important to shift spinner's arrow buttons to left. I have shifted absolute positioned buttons with CSS statement right: 17px;. We achieve with this displacement that the calendar icon is visible.
.ui-ccalendar {
    display: inline-block;
    overflow: visible;
    padding: 0;
    position: relative;
    vertical-align: middle;
}

.ui-ccalendar-button {
    cursor: default;
    display: block;
    font-size: 0.5em;
    height: 50%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    position: absolute;
    right: 17px;
    text-align: center;
    vertical-align: middle;
    width: 16px;
    z-index: 100;
}

.ui-ccalendar .ui-icon {
    left: 0;
    margin-top: -8px;
    position: absolute;
    top: 50%;
}

.ui-ccalendar-up {
    top: 0;
}

.ui-ccalendar-down {
    bottom: 0;
}

.ui-ccalendar .ui-icon-triangle-1-s {
    background-position: -65px -16px;
}

.ui-ccalendar .ui-icon-triangle-1-n {
    margin-top: -9px;
}

JavaScript
In this part I use the mentioned above utility functions formatDate() / parseDate() and setDate() / getDate() API of Date object to increment / decrement a single day. Month and year boundaries are considered automatically and in- / decremented if necessary. In- / decrementation logic is bound to mousedown event on spinner buttons.
var datepickerInput = $('#datepicker');
datepickerInput.datepicker({dateFormat: 'yy-mm-dd', ... other configuration if needed ...});

$('#datepickerWrapper').children('.ui-ccalendar-button').mouseover(function() {
	$(this).addClass('ui-state-hover');
}).mouseout(function() {
	$(this).removeClass('ui-state-hover');
}).mouseup(function() {
	$(this).removeClass('ui-state-active');
}).mousedown(function() {
	var el = $(this);
	el.addClass('ui-state-active');
	try {
		// get configured date format
		var dateFormat = datepickerInput.datepicker("option", "dateFormat");

		// extract a date from a string value with a specified format
		var date = $.datepicker.parseDate(dateFormat, datepickerInput.val());
		if (el.hasClass('ui-ccalendar-up')) {
			// increment day
			date.setDate(date.getDate() + 1);
		} else {
			// decrement day
			date.setDate(date.getDate() - 1);
		}

		// format a date into a string value with a specified format
		var strDate = $.datepicker.formatDate(dateFormat, date);
		datepickerInput.val(strDate);
	} catch (err) {
		// ignore and nothing to do
	}
});
Important is here "dateFormat" option. Date format normally depends on user locale and should be passed from outside.

P.S. Just now I found a desktop example of such combined calendar too. So, you see, it's an useful and established widget :-).

Monday, August 22, 2011

GWT composite widgets vs. JSF composite components

I have started to learn GWT (Google Web Toolkit). I don't want to compare all features of both frameworks. I would like to pick just one feature. In GWT you can write autonomous and reusable composite widgets and apply them many times on one or several pages. GWT following say that's not really possible in JSF 2 because one composite component is normally linked with a managed bean. If you use the same composite component twice and change value(s) in one composite component, changed value(s) will be propogated through the bean to another component too. Is it really true?

Take an example. Assume, we have to write a composite widget / component consist of a label, an input field and a button which are aligned horizontally. The GWT solution could be looked like this one
public class CompositeExample implements EntryPoint
{
	private static class LabeledInput extends Composite {
		private Label label = new Label();
		private TextBox textBox = new TextBox();
		private Button button = new Button("Jump!", new ClickHandler() {
			public void onClick(ClickEvent event) {
				// do something
			}
		});

		public LabeledInput() {
			HorizontalPanel panel = new HorizontalPanel();
			panel.add(label);
			panel.add(textBox);
			panel.add(button);

			initWidget(panel);
		}
	}

	public void onModuleLoad() {
		LabeledInput labeledInput = new LabeledInput();
		RootPanel.get().add(labeledInput);
	}
}
I defined a class named LabeledInput which extends the class com.google.gwt.user.client.ui.Composite. The new composite widget LabeledInput is well reusable many times on any pages. No problems here. A corresponding JSF solution could be implemented in a file labeledInput.xhtml as follows
<html xmlns="http://www.w3.org/1999/xhtml"
	  xmlns:h="http://java.sun.com/jsf/html"
	  xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface>
	<cc:attribute name="model" required="true">
		<cc:attribute name="labelValue" required="true"/>
		<cc:attribute name="inputValue" required="true"/>
		<cc:attribute name="jump" required="true" method-signature="void f(javax.faces.event.ActionEvent)"/>
	</cc:attribute>
	<cc:actionSource name="jump"/>
</cc:interface>
<cc:implementation>
	<h:panelGrid columns="3">
		<h:outputLabel for="#{cc.clientId}:input" value="#{cc.attrs.model.labelValue}"/>
		<h:inputText id="input" value="#{cc.attrs.model.inputValue}"/>
		<h:commandButton value="Jump!" actionListener="#{cc.attrs.model.jump}"/>
	</h:panelGrid>
</cc:implementation>
</html>
cc:attribute "model" should point to a managed bean having attributes "labelValue", "inputValue" and method (actionListener) "jump". Using of this custom component is simple
<h:form>
	...
	<custom:labeledInput id="cli1" model="#{someBean}">
	...
</h:form>

<h:form>
	...
	<custom:labeledInput id="cli2" model="#{someBean}">
	...
</h:form>
There is a problem with this JSF solution. If you change the input value (field h:inputText) in the first component and submit the surrounding form, the new value is going to set into the bean "someBean". This bean is also used by the second component. That means, the second component gets the changed value what is not a desired behavior of course. But JSF is powerful enough to solve this problem. There is a possibility to mix JSF components written in Java with declarative code written in XHTML. We can write a class LabeledInput extending UINamingContainer (according to specification) for our composite component. This class encapsulates then all attributes and has the mentioned above actionListener method.
@FacesComponent("mypackage.LabeledInput")
public class LabeledInput extends UINamingContainer
{
	enum PropertyKeys {labelValue, inputValue, jump;}

    public Object getLabelValue() {
		return getStateHelper().eval(PropertyKeys.labelValue);
    }

    public void setLabelValue(Object labelValue) {
		getStateHelper().put(PropertyKeys.labelValue, labelValue);
    }

    public Object getInputValue() {
		return getStateHelper().eval(PropertyKeys.inputValue);
    }

    public void setInputValue(Object inputValue) {
		getStateHelper().put(PropertyKeys.inputValue, inputValue);
    }

	public void jump(ActionEvent e) {
		// do something
	}
}
Component class can be linked now with the XHTML part via "componentType" attribute in cc:interface. Important part to be changed looks then as follows
<cc:interface componentType="mypackage.LabeledInput">
	<cc:attribute name="labelValue"/>
	<cc:attribute name="inputValue"/>
	<cc:actionSource name="jump"/>
</cc:interface>
<cc:implementation>
	<h:panelGrid columns="3">
		<h:outputLabel for="#{cc.clientId}:input" value="#{cc.labelValue}"/>
		<h:inputText id="input" value="#{cc.inputValue}"/>
		<h:commandButton value="Jump!" actionListener="#{cc.jump}"/>
	</h:panelGrid>
</cc:implementation>
Managed bean is not needed to be passed by this way. Now we can speak about an autonomous and reusable composite component and write <custom:labeledInput> on a page as much as we want without any collisions.