Saturday, April 19, 2014

Creating dynamic JSF Components

You can often read a question how to create dynamic JSF 2 components. That means a programmatically combining already existing components to a dynamic one - just like a puzzle. There are some advices on the internet which don't work reliable in all cases. In this article for instance, the author tried to use PostAddToViewEvent, but had some troubles, and ended up then with an implementation which doesn't consider component's changes on postback. I would like to show a simple and reliable way for creating dynamic JSF 2 components.

The main question is at which time, better to say JSF phase, the components should be created? I suggest to use PreRenderComponentEvent and add all components there. In this blog post, we will create a component called DynamicButtons. DynamicButtons consists of multiple dynamic buttons. Every dynamic button is an abstraction. It is either a PrimeFaces command button or menu item. It depends on component's configuration how a dynamic button should be rendered - as command button or as menu item. In short words, DynamicButtons is a component which shows X command buttons and a menu button with items if more than X dynamic buttons are available. Here is a picture.


The component's tag is d:dynamicButtons. Every single dynamic button is condigured by the tag d:dynamicButton which has the same attributes as p:commandButton and p:menuitem. Sure, not all attributes of p:commandButton and p:menuitem are equal - some attributes in the d:dynamicButton are not availbale for items in the menu button (e.g. widgetVar). The XHTML snippet to the picture above demonstrates the usage of some attributes.
<p:growl showSummary="true" showDetail="false" autoUpdate="true"/>
<p:messages id="msgs" showSummary="true" showDetail="false"/>

<p:notificationBar position="top" effect="slide" widgetVar="bar">
    <h:outputText value="..."/>
</p:notificationBar>

<d:dynamicButtons id="dynaButtons" labelMenuButton="More Actions" iconPosMenuButton="right"
                  positionMenuButton="#{dynamicButtonsController.posMenuButton}">
    <d:dynamicButton value="Show notification" type="button" onclick="PF('bar').show()"/>
    <d:dynamicButton value="Hide notification" type="button" onclick="PF('bar').hide()"/>
    <d:dynamicButton value="Create" icon="ui-icon-plus" process="@this"
                        action="#{dynamicButtonsController.someAction('Create')}"/>
    <d:dynamicButton value="Edit" icon="ui-icon-pencil" process="@this"
                        action="#{dynamicButtonsController.someAction('Edit')}"/>
    <d:dynamicButton value="Delete" icon="ui-icon-trash" process="@this"
                        action="#{dynamicButtonsController.someAction('Delete')}"/>
    <d:dynamicButton value="Save" icon="ui-icon-disk" process="@this"
                        action="#{dynamicButtonsController.someAction('Save')}"/>
    <d:dynamicButton value="Log Work" icon="ui-icon-script" global="false" process="@this" update="msgs"
                        ignoreAutoUpdate="true" actionListener="#{dynamicButtonsController.logWork}"/>
    <d:dynamicButton value="Attach File" icon="ui-icon-document" global="false"/>
    <d:dynamicButton value="Move" icon="ui-icon-arrowthick-1-e" global="false"/>
    <d:dynamicButton value="Clone" icon="ui-icon-copy" disabled="true"/>
    <d:dynamicButton value="Comment" icon="ui-icon-comment" title="This is the comment action"/>
    <d:dynamicButton value="Homepage" icon="ui-icon-home" title="Link to the homepage" ajax="false"
                        action="/views/home?faces-redirect=true"/>
</d:dynamicButtons>
The position of the menu button is configurable by the attribute positionMenuButton. positionMenuButton defines the start index of buttons rendered in a menu button as items vertically. A valid position begins with 1. Negative or 0 value means that no menu button is rendered (all buttons are rendered horizontally). The current position can be controlled by a bean.
@Named
@ViewScoped
public class DynamicButtonsController implements Serializable {
    
    private int posMenuButton = 7;

    public void someAction(String button) {
        FacesContext ctx = FacesContext.getCurrentInstance();
        FacesMessage message = new FacesMessage("Action of the button '" + button + "' has been invoked");
        message.setSeverity(FacesMessage.SEVERITY_INFO);
        ctx.addMessage(null, message);
    }
    
    public void logWork(ActionEvent event) {
        FacesContext ctx = FacesContext.getCurrentInstance();
        FacesMessage message = new FacesMessage("Action listener for 'Log Work' has been invoked");
        message.setSeverity(FacesMessage.SEVERITY_INFO);
        ctx.addMessage(null, message);
    }

    public int getPosMenuButton() {
        return posMenuButton;
    }

    public void setPosMenuButton(int posMenuButton) {
        this.posMenuButton = posMenuButton;
    }
}
Let's create dynamic buttons. I will only show the code which is important to get the idea. First of all we need a TagHandler behind the d:dynamicButton. It's called DynamicButtonTagHandler. DynamicButtonTagHandler collects values of all attributes defined in the d:dynamicButton and buffers them in the data container object DynamicButtonHolder. The object DynamicButtonHolder is saved in the attributes map of the parent component DynamicButtons (component behind the d:dynamicButtons tag).
public class DynamicButtonTagHandler extends TagHandler {

    private final TagAttribute value;
    private final TagAttribute widgetVar;
    private final TagAttribute rendered;
    private final TagAttribute ajax;
    private final TagAttribute process;
 
    // other attributes
    ...
 
    private final TagAttribute action;
    private final TagAttribute actionListener;

    public DynamicButtonTagHandler(TagConfig config) {
        super(config);

        this.value = this.getAttribute("value");
        this.widgetVar = this.getAttribute("widgetVar");
        this.rendered = this.getAttribute("rendered");
        this.ajax = this.getAttribute("ajax");
        this.process = this.getAttribute("process");
  
        // handle other attributes
        ...
  
        this.action = this.getAttribute("action");
        this.actionListener = this.getAttribute("actionListener");
    }

    @Override
    public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
        if (!ComponentHandler.isNew(parent)) {
            return;
        }

        @SuppressWarnings("unchecked")
        List<DynamicButtonHolder> holders = (List<DynamicButtonHolder>) parent.getAttributes().get(
                DynamicButtons.DYNAMIC_BUTTON_ATTR_HOLDER);
        if (holders == null) {
            holders = new ArrayList<DynamicButtonHolder>();
            parent.getAttributes().put(DynamicButtons.DYNAMIC_BUTTON_ATTR_HOLDER, holders);
        }

        DynamicButtonHolder holder = new DynamicButtonHolder();

        if (value != null) {
            if (value.isLiteral()) {
                holder.setValue(value.getValue());
            } else {
                holder.setValue(value.getValueExpression(ctx, Object.class));
            }
        }

        if (widgetVar != null) {
            if (widgetVar.isLiteral()) {
                holder.setWidgetVar(widgetVar.getValue());
            } else {
                holder.setWidgetVar(widgetVar.getValueExpression(ctx, String.class));
            }
        }

        if (rendered != null) {
            if (rendered.isLiteral()) {
                holder.setRendered(Boolean.valueOf(rendered.getValue()));
            } else {
                holder.setRendered(rendered.getValueExpression(ctx, Boolean.class));
            }
        }

        if (ajax != null) {
            if (ajax.isLiteral()) {
                holder.setAjax(Boolean.valueOf(ajax.getValue()));
            } else {
                holder.setAjax(ajax.getValueExpression(ctx, Boolean.class));
            }
        }

        if (process != null) {
            if (process.isLiteral()) {
                holder.setProcess(process.getValue());
            } else {
                holder.setProcess(process.getValueExpression(ctx, String.class));
            }
        }

        // handle other values
        ...

        if (action != null) {
            holder.setActionExpression(action.getMethodExpression(ctx, String.class, new Class[]{}));
        }

        if (actionListener != null) {
            holder.setActionListener(new MethodExpressionActionListener(actionListener.getMethodExpression(
                    ctx, Void.class, new Class[]{ActionEvent.class})));
        }

        // add data
        holders.add(holder);
    }
}
Data container class DynamicButtonHolder looks simple.
public class DynamicButtonHolder {

    private Object value;
    private Object widgetVar;
    private Object rendered;
    private Object ajax;
    private Object process;
 
    // other attributes
    ...
 
    private MethodExpression actionExpression;
    private ActionListener actionListener;

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    public Object getWidgetVar() {
        return widgetVar;
    }

    public void setWidgetVar(Object widgetVar) {
        this.widgetVar = widgetVar;
    }

    public Object getRendered() {
        return rendered;
    }

    public void setRendered(Object rendered) {
        this.rendered = rendered;
    }

    public Object getAjax() {
        return ajax;
    }

    public void setAjax(Object ajax) {
        this.ajax = ajax;
    }

    public Object getProcess() {
        return process;
    }

    public void setProcess(Object process) {
        this.process = process;
    }

    // setter / getter for other attributes
    ...

    public MethodExpression getActionExpression() {
        return actionExpression;
    }

    public void setActionExpression(MethodExpression actionExpression) {
        this.actionExpression = actionExpression;
    }

    public ActionListener getActionListener() {
        return actionListener;
    }

    public void setActionListener(ActionListener actionListener) {
        this.actionListener = actionListener;
    }
}
The component class DynamicButtons extends HtmlPanelGroup and registers itself as a listener for PreRenderComponentEvent. Command buttons and menu items in the menu button (see positionMenuButton) are added dynamically to the panel group in the method processEvent(). It happens shortly before the rendering phase.
@FacesComponent(value = "examples.component.DynamicButtons")
@ListenerFor(systemEventClass = PreRenderComponentEvent.class)
public class DynamicButtons extends HtmlPanelGroup {

    private static final String OPTIMIZED_PACKAGE = "examples.component.";
    public static final String DYNAMIC_BUTTON_ATTR_HOLDER = "dynamicButtonAttrHolder";

    enum PropertyKeys {
        disabled,
        positionMenuButton,
        labelMenuButton,
        iconPosMenuButton
    }

    public DynamicButtons() {
        super();
    }

    public boolean isDisabled() {
        return (Boolean) getStateHelper().eval(PropertyKeys.disabled, false);
    }

    public void setDisabled(boolean disabled) {
        getStateHelper().put(PropertyKeys.disabled, disabled);
    }

    public Integer getPositionMenuButton() {
        return (Integer) getStateHelper().eval(PropertyKeys.positionMenuButton, 0);
    }

    public void setPositionMenuButton(Integer positionMenuButton) {
        getStateHelper().put(PropertyKeys.positionMenuButton, positionMenuButton);
    }

    public String getLabelMenuButton() {
        return (String) getStateHelper().eval(PropertyKeys.labelMenuButton, null);
    }

    public void setLabelMenuButton(String labelMenuButton) {
        getStateHelper().put(PropertyKeys.labelMenuButton, labelMenuButton);
    }

    public String getIconPosMenuButton() {
        return (String) getStateHelper().eval(PropertyKeys.iconPosMenuButton, "left");
    }

    public void setIconPosMenuButton(String iconPosMenuButton) {
        getStateHelper().put(PropertyKeys.iconPosMenuButton, iconPosMenuButton);
    }

    /**
     * {@inheritDoc}
     */
    public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
        super.processEvent(event);

        if (!(event instanceof PreRenderComponentEvent)) {
            return;
        }

        // add components to this panel group
        addComponents();
    }

    private void addComponents() {
        if (!isRendered()) {
            return;
        }

        @SuppressWarnings("unchecked")
        List<DynamicButtonHolder> holders = (List<DynamicButtonHolder>) getAttributes().get(
                DynamicButtons.DYNAMIC_BUTTON_ATTR_HOLDER);
        if (holders == null) {
            return;
        }

        // first remove all children
        this.getChildren().clear();

        final FacesContext fc = FacesContext.getCurrentInstance();
        MenuButton menuButton = null;
        int posMenuButton = getPositionMenuButton();

        for (int i = 0; i < holders.size(); i++) {
            DynamicButtonHolder holder = holders.get(i);

            if (posMenuButton <= 0 || i < posMenuButton - 1) {
                // create single command button
                createCommandButton(fc, holder, i);
            } else {
                if (menuButton == null) {
                    // create menu button
                    menuButton = (MenuButton)fc.getApplication().createComponent(MenuButton.COMPONENT_TYPE);
                    menuButton.setId(this.getId() + "_mbutton");
                    menuButton.setDisabled(isDisabled());
                    menuButton.setIconPos(getIconPosMenuButton());
                    menuButton.setValue(getLabelMenuButton());
                    menuButton.setStyleClass("dynaMenuButton");

                    // add as child to this component
                    this.getChildren().add(menuButton);
                }

                // create menuitem for menu button
                createMenuitem(fc, menuButton, holder, i);
            }
        }
    }

    private void createCommandButton(FacesContext fc, DynamicButtonHolder holder, int i) {
        CommandButton commandButton = (CommandButton)fc.getApplication().createComponent(
                CommandButton.COMPONENT_TYPE);
        commandButton.setId(this.getId() + "_cbutton_" + i);
        commandButton.setStyleClass("dynaCommandButton");

        // add to the children
        this.getChildren().add(commandButton);

        ELContext ec = fc.getELContext();

        Object value = getValue(ec, holder);
        if (value != null) {
            commandButton.setValue(value);
        }

        String widgetVar = getWidgetVar(ec, holder);
        if (StringUtils.isNotBlank(widgetVar)) {
            commandButton.setWidgetVar(widgetVar);
        }

        Boolean rendered = isRendered(ec, holder);
        if (rendered != null) {
            commandButton.setRendered(rendered);
        }

        Boolean ajax = isAjax(ec, holder);
        if (ajax != null) {
            commandButton.setAjax(ajax);
        }

        String process = getProcess(ec, holder);
        if (StringUtils.isNotBlank(process)) {
            commandButton.setProcess(process);
        }

        // handle other attributes
        ...

        MethodExpression me = holder.getActionExpression();
        if (me != null) {
            commandButton.setActionExpression(me);
        }

        ActionListener actionListener = holder.getActionListener();
        if (actionListener != null) {
            commandButton.addActionListener(actionListener);
        }
    }

    private void createMenuitem(FacesContext fc, MenuButton menuButton, DynamicButtonHolder holder, int i) {
        UIMenuItem menuItem = (UIMenuItem)fc.getApplication().createComponent(UIMenuItem.COMPONENT_TYPE);
        menuItem.setId(this.getId() + "_menuitem_" + i);
        menuItem.setStyleClass("dynaMenuitem");

        // add to the children
        menuButton.getChildren().add(menuItem);

        ELContext ec = fc.getELContext();

        Object value = getValue(ec, holder);
        if (value != null) {
            menuItem.setValue(value);
        }

        Boolean rendered = isRendered(ec, holder);
        if (rendered != null) {
            menuItem.setRendered(rendered);
        }

        Boolean ajax = isAjax(ec, holder);
        if (ajax != null) {
            menuItem.setAjax(ajax);
        }

        String process = getProcess(ec, holder);
        if (StringUtils.isNotBlank(process)) {
            menuItem.setProcess(process);
        }

        // handle other attributes
        ...

        MethodExpression me = holder.getActionExpression();
        if (me != null) {
            menuItem.setActionExpression(me);
        }

        ActionListener actionListener = holder.getActionListener();
        if (actionListener != null) {
            menuItem.addActionListener(actionListener);
        }
    }

    private Object getValue(ELContext ec, DynamicButtonHolder holder) {
        Object value;
        Object objValue = holder.getValue();
        if (objValue instanceof ValueExpression) {
            value = ((ValueExpression) objValue).getValue(ec);
        } else {
            value = objValue;
        }

        return value;
    }

    private String getWidgetVar(ELContext ec, DynamicButtonHolder holder) {
        String widgetVar = null;
        Object objWidgetVar = holder.getWidgetVar();
        if (objWidgetVar instanceof ValueExpression) {
            widgetVar = (String) ((ValueExpression) objWidgetVar).getValue(ec);
        } else if (objWidgetVar instanceof String) {
            widgetVar = (String) objWidgetVar;
        }

        return widgetVar;
    }

    private Boolean isRendered(ELContext ec, DynamicButtonHolder holder) {
        Boolean rendered = null;
        Object objRendered = holder.getRendered();
        if (objRendered instanceof ValueExpression) {
            rendered = (Boolean) ((ValueExpression) objRendered).getValue(ec);
        } else if (objRendered instanceof Boolean) {
            rendered = (Boolean) objRendered;
        }

        return rendered;
    }

    private Boolean isAjax(ELContext ec, DynamicButtonHolder holder) {
        Boolean ajax = null;
        Object objAjax = holder.getAjax();
        if (objAjax instanceof ValueExpression) {
            ajax = (Boolean) ((ValueExpression) objAjax).getValue(ec);
        } else if (objAjax instanceof Boolean) {
            ajax = (Boolean) objAjax;
        }

        return ajax;
    }

    private String getProcess(ELContext ec, DynamicButtonHolder holder) {
        String process = null;
        Object objProcess = holder.getProcess();
        if (objProcess instanceof ValueExpression) {
            process = (String) ((ValueExpression) objProcess).getValue(ec);
        } else if (objProcess instanceof String) {
            process = (String) objProcess;
        }

        return process;
    }

    // get other values
    ...

    public void setAttribute(PropertyKeys property, Object value) {
        getStateHelper().put(property, value);

        // some magic code which is not relevant here
        ...
    }
}
DynamicButtons and DynamicButtonTagHandler should be registered in a *.taglib.xml file.
<tag>
    <description>
        <![CDATA[Dynamic buttons.]]>
    </description>
    <tag-name>dynamicButtons</tag-name>
    <component>
        <component-type>examples.component.DynamicButtons</component-type>
        <renderer-type>javax.faces.Group</renderer-type>
    </component>
    <attribute>
        <description>
            <![CDATA[Unique identifier of the component in a NamingContainer.]]>
        </description>
        <name>id</name>
        <required>false</required>
        <type>java.lang.String</type>
    </attribute>
    ...
</tag>

<tag>
    <description>
        <![CDATA[Holder for dynamic button's attributes.]]>
    </description>
    <tag-name>dynamicButton</tag-name>
    <handler-class>examples.taghandler.DynamicButtonTagHandler</handler-class>
    <attribute>
        <description><![CDATA[Label of the component.]]></description>
        <name>value</name>
        <required>false</required>
        <type>java.lang.Object</type>
    </attribute>
    ...
</tag>

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.

Wednesday, March 5, 2014

Learning Primefaces' Extensions Development

I'm glad to announce a new book Learning Primefaces' Extensions Development. The book is about various JSF components provided in the open source, community driven project PrimeFaces Extensions - an official project with additional components to the great PrimeFaces framework. PrimeFaces is a de-facto standard framework in the Java Web Development. There are already a couple of books about the PrimeFaces core: Cookbook, Started and Beginner's Guide.

What is the new book about? The book covers most important major features of the PrimeFaces Extensions. You will meet the additional JSF components, learn step-by-step how to use them in the PrimeFaces based rich JSF applications and get some ideas for writing your own components. This is a must for every JSF / PrimeFaces developer.

The book has been written by a team member of the PrimeFaces Extensions Sudheer Jonna. Thanks Sudheer for your contribution! I'm sure PrimeFaces users will be happy to hold the book in their hands.


Wednesday, January 1, 2014

PrimeFaces Extensions 1.2.1 was released with a new QRCode component

We are glad to announce the next release 1.2.1 of PrimeFaces Extensions (yes, 1.2.1 and not 1.2.0 due to some encountered issues in the newly released 1.2.0). This is a maintenance release which contains fixes for the components AjaxErrorHandler, FluidGrid, DynaForm, TimePicker, InputNumber and new features in Exporter (possibility to skip some components during export) and Waypoint (can be used now for horizontal scrolling as well).

Beside fixed issues (full list on GitHub) we added a new JSF component QRCode. QR Code is a two-dimensional barcode for multi-purpose using. Refer this article on Wikipedia if you don't know what it is.


The QR Code is generated completely on the client-side. Usage example:
<pe:qrCode renderMethod="canvas" 
           renderMode="2" 
           text="http://primefaces-extensions.github.io/"
           label="PF-Extensions"
           size="200"                 
           fillColor="7d767d"
           fontName="Ubuntu"
           fontColor="#01A9DB"
           ecLevel="H"                   
           radius="0.5"/>
Furthermore, the component library and the showcase were updated to fit JSF 2.2. The PrimeFaces team lead Çagatay Çivici has provided us his dedicated server for deployment. We would like to thank him for that! This is the same server the PrimeFaces showcase is running on. Please consider a new URL for our showcase. The old URLs are out of date (I've canceled my VPS). The showcase is running on Mojarra 2.2.x. But of course we test it on MyFaces as well.

The new release is available as usually in the Maven central repository. Have fun!

Edit: Çagatay Çivici told us that the demos including PrimeFaces showcase, labs and extensions crashed a couple of times, so that he had to undeploy the extensions' showcase. The current showcase is deployed to Amazon EC2 instance and is running on Tomcat 7 now. Thanks to our user sebargarcia.

Wednesday, December 11, 2013

Modular JSF applications

Everybody heard about portals which combine single web applications to a big one. A portal software works like mashups - content from several sources is picked up in a single service, mostly displayed in a single web page. A portal software also allows to change user settings, such as language or theme, across all single web applications (independent modules) embedded into the portal software. Furthermore, a single sign-on (SSO) is expected and it should work as well. That means, a single login permits an user to access all embedded web applications. It would be interesting to know if there is a simple and lightweight solution in the JEE world to develop modular JSF 2 applications, to gather and to present them in one portal-like web application automatically. Sure, there are OSGi and complex Portals Bridges providing support for JSR-168 or JSR-286 compliant Portlet development. But fortunately, JSF 2 already provides a simple possibility for that "under the hood". With less effort we can build a portal-like software. All what we need are JSF 2 and CDI - de-facto standard DI framework in the Java world.

The topic of this post is not new. You can find some discussions and ideas in the web. I would only mention here two links. The first one is the article "How-to: Modular Java EE Applications with CDI and PrettyFaces" in the ocpsoft's blog. The second one "Modular Web Apps with JSF2" was presented in the JBoss' wiki. The idea is to create JAR files containing single web applications and to supply them with a main WAR file. The WAR file bundles JARs during build process, e.g. via Maven dependencies. That means, JARs are located in the WAR under WEB-INF/lib/. XHTML files in JARs are placed below /META-INF/resources/ and will be fetched automatically by JSF 2. They are available to JSF as if they were in the /webapp/resources/ folder. You can e.g. include facelets from JARs with a quite common ui:include. This works like a charm. To be able to pick up generic informations about every JSF module at runtime, we also need empty CDI's beans.xml in JARs files. They are located as usually below the META-INF folder.

Now let's start with the coding. But first, let's define the project's structure. You can find a complete implemented example on the GitHub. This is just a proof of concept for a lightweight JSF 2 portal-like implementation with demo web apps (written with JSF 2.2). There are 5 sub-projects

jsftoolkit-jar Base framework providing interfaces and utilities for modular JSF applications.
modA-jar First web application (module A) which depends on jsftoolkit-jar.
modB-jar Second web application (module B) which depends on jsftoolkit-jar.
portal-jar Java part of the portal-like software. It also depends on jsftoolkit-jar.
portal-war Web part of the portal-like software. It aggregates all artefacts and is a deployable WAR.

The base framework (jsftoolkit-jar) has interfaces which should be implemented by every single module. The most important are
/**
 * Interface for modular JSF applications. This interface should be implemented by every module (JSF app.)
 * to allow a seamless integration into a "portal" software.
 */
public interface ModuleDescription {

    /**
     * Provides a human readable name of the module.
     *
     * @return String name of the module
     */
    String getName();

    /**
     * Provides a description of the module.
     *
     * @return String description
     */
    String getDescription();

    /**
     * Provides a module specific prefix. This is a folder below the context where all web pages and
     * resources are located.
     *
     * @return String prefix
     */
    String getPrefix();

    /**
     * Provides a name for a logo image, e.g. "images/logo.png" (used in h:graphicImage).
     *
     * @return String logo name
     */
    String getLogoName();

    /**
     * Provides a start (home) URL to be navigated for the module.
     *
     * @return String URL
     */
    String getUrl();
}

/**
 * Any JSF app. implementing this interface can participate in an unified message handling
 * when all keys and messages are merged to a map and available via "msgs" EL, e.g. as #{msgs['mykey']}.
 */
public interface MessagesProvider {

    /**
     * Returns all mesages (key, text) to the module this interface is implemented for.
     *
     * @param  locale current Locale or null
     * @return Map with message keys and message text.
     */
    Map<String, String> getMessages(Locale locale);
}
Possible implementations for the module A look like as follows:
/**
 * Module specific implementation of the {@link ModuleDescription}.
 */
@ApplicationScoped
@Named
public class ModADescription implements ModuleDescription, Serializable {

    @Inject
    private MessagesProxy msgs;

    @Override
    public String getName() {
        return msgs.get("a.modName");
    }

    @Override
    public String getDescription() {
        return msgs.get("a.modDesc");
    }

    @Override
    public String getPrefix() {
        return "moda";
    }

    @Override
    public String getLogoName() {
        return "images/logo.png";
    }

    @Override
    public String getUrl() {
        return "/moda/views/hello.jsf";
    }
}

/**
 * Module specific implementation of the {@link MessagesProvider}.
 */
@ApplicationScoped
@Named
public class ModAMessages implements MessagesProvider, Serializable {

    @Override
    public Map<String, String> getMessages(Locale locale) {
        return MessageUtils.getMessages(locale, "modA");
    }
}
The prefix of this module is moda. That means, web pages and resources are located under the folder META-INF/resources/moda/. That allows to avoid path collisions (identical paths) across all single web applications. The utility class MessageUtils (from the jsftoolkit-jar) is not exposed here. I will only show the class MessagesProxy. The class MessagesProxy is an application scoped bean giving an access to all available messages in a modular JSF web application. It can be used in Java as well as in XHTML because it implements the Map interface. All found available implementations of the MessagesProvider interface are injected by CDI automatically at runtime. We make use of Instance<MessagesProvider>.
@ApplicationScoped
@Named(value = "msgs")
public class MessagesProxy implements Map<String, String>, Serializable {

    @Inject
    private UserSettingsData userSettingsData;

    @Any
    @Inject
    private Instance<MessagesProvider> messagesProviders;

    /** all cached locale specific messages */
    private Map<Locale, Map<String, String>> msgs = new ConcurrentHashMap<Locale, Map<String, String>>();

    @Override
    public String get(Object key) {
        if (key == null) {
            return null;
        }

        Locale locale = userSettingsData.getLocale();
        Map<String, String> messages = msgs.get(locale);

        if (messages == null) {
            // no messages to current locale are available yet
            messages = new HashMap<String, String>();
            msgs.put(locale, messages);

            // load messages from JSF impl. first
            messages.putAll(MessageUtils.getMessages(locale, MessageUtils.FACES_MESSAGES));

            // load messages from providers in JARs
            for (MessagesProvider messagesProvider : messagesProviders) {
                messages.putAll(messagesProvider.getMessages(locale));
            }
        }

        return messages.get(key);
    }
    
    public String getText(String key) {
        return this.get(key);
    }
    
    public String getText(String key, Object... params) {
        String text = this.get(key);

        if ((text != null) && (params != null)) {
            text = MessageFormat.format(text, params);
        }

        return text;
    }

    public FacesMessage getMessage(FacesMessage.Severity severity, String key, Object... params) {
        String summary = this.get(key);
        String detail = this.get(key + "_detail");

        if ((summary != null) && (params != null)) {
            summary = MessageFormat.format(summary, params);
        }

        if ((detail != null) && (params != null)) {
            detail = MessageFormat.format(detail, params);
        }

        if (summary != null) {
            return new FacesMessage(severity, summary, ((detail != null) ? detail : StringUtils.EMPTY));
        }

        return new FacesMessage(severity, "???" + key + "???", ((detail != null) ? detail : StringUtils.EMPTY));
    }
    
    /////////////////////////////////////////////////////////
    // java.util.Map interface
    /////////////////////////////////////////////////////////

    public int size() {
        throw new UnsupportedOperationException();
    }

    // other methods ...
}
Well. But where the instances of the ModuleDescription are picked up? The logic is in the portal-jar. I use the same mechanism with CDI Instance. CDI will find out all available implementations of the ModuleDescription for us.
/**
 * Collects all available JSF modules.
 */
@ApplicationScoped
@Named
public class PortalModulesFinder implements ModulesFinder {

    @Any
    @Inject
    private Instance<ModuleDescription> moduleDescriptions;

    @Inject
    private MessagesProxy msgs;

    private List<FluidGridItem> modules;

    @Override
    public List<FluidGridItem> getModules() {
        if (modules != null) {
            return modules;
        }

        modules = new ArrayList<FluidGridItem>();

        for (ModuleDescription moduleDescription : moduleDescriptions) {
            modules.add(new FluidGridItem(moduleDescription));
        }

        // sort modules by names alphabetically
        Collections.sort(modules, ModuleDescriptionComparator.getInstance());

        return modules;
    }
}
We are equipped now for creating dynamic tiles in UI which represent entry points to the corresponding web modules.
<pe:fluidGrid id="fluidGrid" value="#{portalModulesFinder.modules}" var="modDesc"
              fitWidth="true" hasImages="true">
    <pe:fluidGridItem styleClass="ui-widget-header">
        <h:panelGrid columns="2" styleClass="modGridEntry" columnClasses="modLogo,modTxt">
            <p:commandLink process="@this" action="#{navigationContext.goToPortlet(modDesc)}">
                <h:graphicImage library="#{modDesc.prefix}" name="#{modDesc.logoName}"/>
            </p:commandLink>

            <h:panelGroup>
                <p:commandLink process="@this" action="#{navigationContext.goToPortlet(modDesc)}">
                    <h:outputText value="#{modDesc.name}" styleClass="linkToPortlet"/>
                </p:commandLink>

                <p/>
                <h:outputText value="#{modDesc.description}"/>
            </h:panelGroup>
        </h:panelGrid>
    </pe:fluidGridItem>
</pe:fluidGrid>
Tiles were created by the component pe:fluidGrid from PrimeFaces Extensions. They are responsive, means they get rearranged when resizing the browser window. The next picture demonstrates how the portal web app looks like after the starting up. It shows two modular demo apps found in the classpath. Every modular web app is displayed as a tile containing a logo, name and short description. Logos and names are clickable. A click redirects to the corresponsing single web app.

As you can see, on the portal's homepage you can switch the current language and the theme. The second picture shows what happens if the user clicks on the module A. The web app for the module A is shown. You can see the Back to Portal button, so a back navigation to the portal's homepage is possible.


Two notes at the end:
  1. It is possible to run every module as a standalone web application. We can check at runtime (again by means of CDI) if the module is within the "portal" or not and use different master templates. A hint is here.
  2. I didn't implement a login screen, but there is no issue with single sign-on because we only have one big application (one WAR). Everything is delivered there.