Posts Tagged ‘JSF1.2

23
Oct
10

JSF Custom Components, Importing Resources

As the web development world moves to a more “component-based” approach we see more and more usage of Dojo, YUI, jQuery, extJS. These frameworks require css and js files be imported into the page before their components could be used. This page describes the process of creating a “<resources/>” tag that will do this work for you.

Background

The benefit of using “resource tag” is to allow “selective importing” of resources onto the page so you don’t flood the client’s browser with unnecessary JavaScript.

The way it will work is by allowing each JSF component tag to indicate what resources are necessary in their constructors. This information will be communicated to the “ResourceHolder” managed bean.

The “resources” tag will read the information in the “ResourceHolder” during the render phase and import only the JavaScript necessary to render the components.

Requirements

Getting Started

To demonstrate this concept we will add to the existing project described in my “Hello World Posting”. (see above)

If you have not done so already import the project into eclipse. It will make editing a lot easier.

mvn eclipse:clean eclipse:eclipse

Import the as “Existing Project into Workspace”.

Its easy to get lost on this page so here is a summary of what is being done:

  1. Create a request scope managed bean that holds a list of resources for the current request.
  2. Create a Component Class
  3. Create a Component Renderer – this component is responsible for iterating thru the list of resources in the managed bean and rendering only the necessary “script” or “style” tags for the components on the page.
  4. Create a Resource Tag Class
  5. Define the component in the faces config
  6. Define the ResourceTag in the TLD
  7. Modify the HtmlHelloWorld tag to require extJS css and js files
  8. Modify the JSP and insert the resource tag.
  9. Run the code in Jetty

Create the Resource Holder Impl Managed Bean

The ResourceHolder class is simply a collection of URL’s (Strings). The resourceHolder is passed to the page via a request scoped Managed Bean seen above.

src/main/java/org/extjsf/resource/ResourceHolderImpl.java

package org.extjsf.resource;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ResourceHolderImpl {
	private List<String> resources;
	
	public ResourceHolderImpl() {
		resources = new ArrayList<String>();
	}
	
	public void addResource(String resource) {
		if(!resources.contains(resource))
			resources.add(resource);
	}

	public Collection<String> getResources() {
		return resources;
	}
}

Insert the following towards the top of your faces-config.

src/main/webapp/WEB-INF/faces-config.xml

	<managed-bean>
		<managed-bean-name>myResourceHolder</managed-bean-name>
		<managed-bean-class>org.extjsf.resource.ResourceHolderImpl</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>

Create Resources Component Class

src/main/java/org/extjsf/component/resources/Resources.java

package org.extjsf.component.resources;

import javax.faces.component.UIComponentBase;

public class Resources extends UIComponentBase {
	public static final String COMPONENT_TYPE = "org.extjsf.component.Resources";
	public static final String COMPONENT_FAMILY = "org.extjsf.component";
	
	@Override
	public String getFamily() {
		return COMPONENT_FAMILY;
	}
}

Define the Component Renderer

src/main/java/org/extjsf/component/resources/ResourcesRenderer.java

package org.extjsf.component.resources;

import java.io.IOException;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

import org.extjsf.resource.ResourceHolderImpl;

public class ResourcesRenderer extends Renderer {
	@Override
	public void encodeEnd(FacesContext facesContext, UIComponent component)
			throws IOException {
		ResourceHolderImpl resourceQueue = getResourceHolder(facesContext);
		ResponseWriter writer = facesContext.getResponseWriter();
		Resources resources = (Resources) component;
		
		writer.write("\n");

		for(String resource : resourceQueue.getResources()) {
			if(resource.endsWith("css")) {
				renderCSSDependency(facesContext, resource);				
			}
			else if(resource.endsWith("js")){
				renderScriptDependency(facesContext, resource);				
			}
		}
		
		writer.write("\n");
	}
	
	// for now these scriptPath references are absolute urls
	protected void renderScriptDependency(FacesContext facesContext, String scriptPath) throws IOException{
		ResponseWriter writer = facesContext.getResponseWriter();
		writer.startElement("script", null);
		writer.writeAttribute("type", "text/javascript", null);
		writer.writeAttribute("src", scriptPath, null);
		writer.endElement("script");
		writer.write("\n");
	}
	
	// for now these cssPath references are absolute urls
	protected void renderCSSDependency(FacesContext facesContext, String cssPath) throws IOException{
		ResponseWriter writer = facesContext.getResponseWriter();
		writer.startElement("link", null);
		writer.writeAttribute("rel", "stylesheet", null);
		writer.writeAttribute("type", "text/css", null);
		writer.writeAttribute("href", cssPath, null);
		writer.endElement("link");
		writer.write("\n");
	}

	protected ResourceHolderImpl getResourceHolder(FacesContext facesContext) {
		ValueExpression ve = facesContext.getApplication()
				.getExpressionFactory().createValueExpression(
						facesContext.getELContext(),
						"#{myResourceHolder}", ResourceHolderImpl.class);

		return (ResourceHolderImpl) ve.getValue(facesContext.getELContext());
	}
}

Resources Tag Class

src/main/java/org/extjsf/component/resources/ResourcesTag.java

package org.extjsf.component.resources;

import javax.faces.webapp.UIComponentELTag;

import org.extjsf.component.resources.Resources;

public class ResourcesTag extends UIComponentELTag {

	public String getComponentType() {
		return Resources.COMPONENT_TYPE;
	}

	public String getRendererType() {
		return "org.extjsf.component.ResourcesRenderer";
	}
}

Define the Component in the faces-config.xml

Put the following xml after the component that is currently defined in the file.
src/main/webapp/WEB-INF/faces-config.xml

	<component>
		<component-type>org.extjsf.component.Resources</component-type>
		<component-class>org.extjsf.component.resources.Resources</component-class>
	</component>

Define the Renderer in the faces-config.xml

Put the following xml after the renderer that is currently defined in the file.

		<renderer>
			<component-family>org.extjsf.component</component-family>
			<renderer-type>org.extjsf.component.ResourcesRenderer</renderer-type>
			<renderer-class>org.extjsf.component.resources.ResourcesRenderer</renderer-class>
		</renderer>

Define the resources tag in the tag library descriptor

Insert the following into:
src/main/webapp/WEB-INF/htmlHelloWorld.tld

<tag>
	<name>resources</name>
	<tag-class>org.extjsf.component.resources.ResourcesTag</tag-class>
	<body-content>JSP</body-content>
</tag>

At this point the resources tag is defined to print resources that are required by each of the components.

HtmlHelloWorld

Next we will modify the HelloWorld Component Class to require the extJSF resources in the default constructor. This component will indicate that the extjs css and js files should be included by the resource renderer. It will store this information in the resourceHolder managed bean seen above.

Your HtmlHelloWorld should look like this…

src/main/java/org/extjsf/component/helloworld/HtmlHelloWorld.java

package org.extjsf.component.helloworld;
 
import javax.el.ValueExpression;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;

import org.extjsf.resource.ResourceHolderImpl;

 
public class HtmlHelloWorld extends UIComponentBase {
    public static final String COMPONENT_FAMILY = "org.extjsf.component";
 
    @Override
    public String getFamily() {
        return COMPONENT_FAMILY;
    }
    
	protected ResourceHolderImpl getResourceHolder() {
		FacesContext facesContext = getFacesContext();
		if (facesContext == null)
			return null;

		ValueExpression ve = facesContext.getApplication()
				.getExpressionFactory().createValueExpression(
						facesContext.getELContext(),
						"#{myResourceHolder}", ResourceHolderImpl.class);

		return (ResourceHolderImpl) ve.getValue(facesContext.getELContext());
	}
	
	public HtmlHelloWorld() {
		ResourceHolderImpl resourceHolder = getResourceHolder();

		if(resourceHolder != null) {
			// Note: In an actual production code you would create a resource
			// servlet and use relative url's. The way its done here is 
			// just for demonstration purposes only.
			resourceHolder.addResource("http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css");
			resourceHolder.addResource("http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base.js");
			resourceHolder.addResource("http://dev.sencha.com/deploy/ext-3.3.1/ext-all.js");
		}
	}
}

And Finally the JSP Page

Finally we create a JSP page that uses the “resources” tag…

src/main/webapp/examples/resources.jsp

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<%@ taglib prefix="e" uri="http://extjsf.org/components" %>
 
<f:view>
    <html>
    <head>
        <title>Resources JSF Example</title>        
		<e:resources/>        
	</head>
<body>
<e:helloworld/>
    </body>
    </html>
</f:view>

Run the example

Drop to the command line and “cd” to the project’s base folder (where the pom.xml file is).

Type the following command to start the jetty servlet engine.
mvn jetty:run
Navigate to: http://localhost:8080/examples/resources.jsf

View source on the page should show something like this…
src/main/webapp/examples/resources.jsp

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    <head>
        <title>Resources JSF Example</title>        
		
<link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css" />
<script type="text/javascript" src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all.js"></script>

        
	</head>
<body>
<div style="color: red">HelloWorld! from renderer.</div>
    </body>
    </html>

To demonstrate Dynamic Resources

To demonstrate that the inclusion of the resources is dynamic, just remove the helloWorld tag from the body of the jsp page. Hit refresh on your browser and you will see that the head of the page no longer includes the css and the javascript files.

To productionalize the code

The example above can be improved by introducing a “ResourceServlet” that is responsible for resolving the libraries via “relative” links. The Resource Servlet can be programmed to return the files from the classpath (within the jar) thus simplifying the deployment.

If you run into trouble

The code on this page has been tested and worked at the time of this writing. If its not working for you please make sure you double check each step to make sure nothing was missed. If you are still having trouble just write a small note about it below and I will try to help you out.

That’s all for now

23
Sep
10

JSF Custom Components Hello World

This page describes how to write a JSF Custom component to print “Hello World” to the page.

This is a demonstration on how to create JSF custom tags using the Sun’s JSF Reference Implementation. This page will lay a solid foundation on how to write custom components to wrap any library or tool kits available for web development into standard JSF components.

This is crazy but these are the steps involved in creating a new JSF Component.

New JSF Custom Component Checklist:

  1. Component Class – This is the Java class that represents the core logic of the component. This class can be coded to render itself or use the help of a the “Renderer” class.
  2. Component Renderer – Responsible for rendering the component on the page.
  3. Tag Class – This is class brings the “custom tag” concept onto the table. Custom Tag libraries were introduced with the JSP 1.1 specification back in December 1999. Today the JSF specification builds upon the custom tag library concept.
  4. Tag Library Descriptor – XML file necessary for the custom tag.
  5. Faces Context – XML file necessary for the custom component.

Requirements

  • Maven 2 or later
  • JSF 1.2 or above
  • Java 5 or later

Start a new Maven Project

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

For the group id enter: org.extjsf
For the artifactId enter: jsfCustom

Answer the rest of the questions using defaults [Hit Enter].

cd to the project’s folder

Next we create the src/main/java folder since this is not done for us using the archetype.

on unix you type:

cd jsfCustom
mkdir -p src/main/java

Project Configuration File

Modify the pom.xml file. It should look like this…

vi pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.extjsf</groupId>
    <artifactId>extJSF</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>jsfTestWeb Maven Webapp</name>
    <url>http://extjsf.org</url>
    <dependencies>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>1.2_02</version>
            <scope>compile</scope> <!--use compile scope for testing with jetty-->
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>1.2-b19</version>
            <scope>compile</scope> <!--use compile scope for testing with jetty-->
        </dependency>
        <dependency>
            <groupId>commons-digester</groupId>
            <artifactId>commons-digester</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-jsp_2.1_spec</artifactId>
			<version>1.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
		<dependency>
		    <groupId>javax.el</groupId>
		    <artifactId>el-api</artifactId>
		    <version>1.0</version>
		    <scope>provided</scope>
		</dependency>        
    </dependencies>
    <build>
        <finalName>extJSFWeb</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <wtpapplicationxml>true</wtpapplicationxml>
                    <wtpversion>1.5</wtpversion>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                    <classpathContainers>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.web.container</classpathContainer>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.module.container</classpathContainer>
                    </classpathContainers>
                    <additionalProjectFacets>
                        <jst.web>2.5</jst.web>
                        <jst.jsf>1.2</jst.jsf>
                    </additionalProjectFacets>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

web.xml

This is boiler plate code. There are no references to the custom components.

We will start from a fresh web.xml file so delete the one that is there.
rm src/main/webapp/WEB-INF/web.xml

Edit the file using a text editor.
vi src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
  <display-name>Archetype Created Web Application</display-name>

  <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>

  <welcome-file-list>
    <welcome-file>index.jsf</welcome-file>
  </welcome-file-list>

</web-app>

Create the Component Class

As mentioned above this is the main class that represents the custom component. It can either render itself or have another class assigned to do the work of rendering. In this case all we are defining is the component family. This is the package we will use to place all the components in.

Create the directory if it does not exist
mkdir -p src/main/java/org/extjsf/component/helloworld

Edit the file using a text editor.
vi src/main/java/org/extjsf/component/helloworld/HtmlHelloWorld.java

package org.extjsf.component.helloworld;

import javax.faces.component.UIComponentBase;

public class HtmlHelloWorld extends UIComponentBase {
	public static final String COMPONENT_FAMILY = "org.extjsf.component";

	@Override
	public String getFamily() {
		return COMPONENT_FAMILY;
	}
}

Create the Component Renderer

This is where the actual rendering of the hello world message is done.
Edit the file using a text editor.
vi src/main/java/org/extjsf/component/helloworld/HelloWorldRenderer.java

package org.extjsf.component.helloworld;

import java.io.IOException;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

public class HelloWorldRenderer extends Renderer {
    @Override
    public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeAttribute("style", "color: red", null);
        writer.writeText("HelloWorld! from renderer.", null);
        writer.endElement("div");
    }
}

Create the Tag Class

This is the custom tag class that will allow the JSP to communicate with the JSF component. You can consider this to be a “hook” into the Java Server Pages API. Allows the JSP page developer to pass “parameters” as tag attributes to the JSF custom component.

The Custom Tag class “componentType” is used to lookup the JSF Component class using the faces-context.xml.
Edit the file using a text editor.
vi src/main/java/org/extjsf/component/helloworld/HtmlHelloWorldTag.java

package org.extjsf.component.helloworld;

import javax.faces.webapp.UIComponentTag;

public class HtmlHelloWorldTag extends UIComponentTag {
    @Override
    public String getComponentType() {
        return "HtmlHelloWorld";
    }
    public String getRendererType() {
        return "org.extjsf.component.HelloWorldRenderer";
    }
}

Create the Tag Library Descriptor

Edit the file using a text editor.
vi src/main/webapp/WEB-INF/htmlHelloWorld.tld

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-
jsptaglibrary_2_0.xsd"
	version="2.0">
<tlib-version>1.0</tlib-version>
<uri>http://extjsf.org/components</uri>

<tag>
	<description>Hello World Tag</description>
	<name>helloworld</name>
	<tag-class>org.extjsf.component.helloworld.HtmlHelloWorldTag</tag-class>
</tag>
</taglib>

Modify the faces-config.xml

Edit the file using a text editor.
vi src/main/webapp/WEB-INF/faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config 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-facesconfig_1_2.xsd"
              version="1.2">

<component>
	<component-type>HtmlHelloWorld</component-type>
	<component-class>org.extjsf.component.helloworld.HtmlHelloWorld</component-class>
</component>
<render-kit>
	<renderer>
		<component-family>org.extjsf.component</component-family>
		<renderer-type>org.extjsf.component.HelloWorldRenderer</renderer-type>
		<renderer-class>org.extjsf.component.helloworld.HelloWorldRenderer</renderer-class>
	</renderer>
</render-kit>

</faces-config>

Create the JSP Page

Create the examples directory
mkdir -p src/main/webapp/examples

Edit the file using a text editor.
vi src/main/webapp/examples/helloWorld.jsp

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<%@ taglib prefix="e" uri="http://extjsf.org/components" %>

<f:view>
    <html>
    <head>
        <title>Hello World JSF Example</title>
</head>
    <body>
<e:helloworld/>
    </body>
    </html>
</f:view>

The following is how all these files are related:

  1. Servlet Container encounters a <e:helloworld/> tag and checks the tag library described by the “http://extjsf.org/components&#8221; tag library xml file.
  2. The tag library xml file indicates that the “org.extjsf.component.helloworld.HtmlHelloWorldTag” is responsible for handling the custom tag.
  3. The System inspects the HtmlHelloWorldTag and gets the component Type and RendererType.
  4. The System inspects the faces-config.xml reads that “HtmlHelloWorld” component type is handled by the “HtmlHelloWorld” component class, and rendered by the “HelloWorldRenderer”.
  5. The family that is specified in the component class is used to make a determination on what renderer family to use.

Run the application

Drop to the command line and navigate to the project’s base directory (location of the pom.xml file).

Execute the following command to test the web application using Jetty servlet engine.

mvn jetty:run

Navigate to: http://localhost:8080/examples/helloWorld.jsf

Next steps

Classic Form Components:

INPUT
	text
	password
	checkbox
	image
	hidden
	file
LABEL

Buttons
-------
http://developer.yahoo.com/yui/button/
INPUT
	radio
	submit 
	reset
	button
BUTTON
SELECT

TEXTAREA
--------
http://developer.yahoo.com/yui/editor/

PRIMEFACES
----------

Mobile Components
-----------------
Pages &amp; Dialogs
Toolbars
	Header
	Footer
	Nav Bars
	Persistant Footer Nav
	
Buttons
	Inline Buttons (more narrow)
	Grouped Buttons
Layout
	Column Grids
	Collapsible Content
	
Form Elements
	Text
	Text Area
	Search Input
	Flip Switch
	Slider
	checkbox
	Radio
	Select

Lists
	Nested List
	Numbered List
	Split Button List
	Formatted Content

Advanced functionality:
Making AJAX requests for JSON data, Sorting Hiding of grid columns, grouping, row expanding, type ahead combo boxes, validation, Editor grid panel, saving preferences in browser cookies and in the database, live search functionality.

That’s all for now.

More to come.

25
Aug
10

Removing JSF Managed Bean from the Session

This page describes the process of cleaning up the session after using a JSF managed bean.

Background

JSF managed beans can be request or session scoped. If they are session scoped then they must be cleaned up manually after the user has navigated off the page. Otherwise they will hang around until the session times out.

In order to do a clean up just execute the following when the user performs the last step on the page.

  1. Program a cleanup() method in the managed bean (see below)
  2. Have the cleanup() method called by the last step the user takes on the page.
  3. Setup a nav-rule that allows the user to navigate to a new page.
	public String cleanup() {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
		.getExternalContext().getSession(true);
		session.removeAttribute("page1MB");

		return "page2";
	}

The clean up method is called by a command button:

<h:commandButton value="cleanup" action="#{page1MB.cleanup}"/>

A nav rule that directs the user to another page:

	<navigation-rule>
		<from-view-id>/page1.jsp</from-view-id>
		<navigation-case>
			<from-outcome>page2</from-outcome>
			<to-view-id>/page2.jsp</to-view-id>
		</navigation-case>
	</navigation-rule>

Use a SnoopServlet to verify that the values have been removed:
https://numberformat.wordpress.com/2010/01/02/snoopservlet-example/

25
Aug
10

Using JSF to Display Table Data

This page describes the process of using JSF to manage data that appears in tables.

Below you see an example data table where each item has:

  1. A textbox where user can specify the quantity
  2. An edit button where they can select a basket
  3. Submit/add buttons that act on the whole collection of baskets.

Using DataTables

When you surface links to allow the user to select the current row object then bind with data table and use dataTable.rowData().

Steps to follow in order to use DataTables:

  • Create an HtmlDataTable attribute in your managed bean.
  • Create a List<GiftBasket> attribute that will hold the backing data
  • Create getter/setters for both attributes
  • In your <h:dataTable> element include a binding and value attributes that points to the htmlDataTable, and the backing List you added to the managed bean.

The Managed Bean is defined like this…

private List<GiftBasket> list = new ArrayList<GiftBasket>();
private HtmlDataTable dataTable;
    // getters setters omitted.

The dataTable is defined like this in the JSP. As you can see a “backing” list is still necessary to hold the table data.

<h:dataTable var="giftBasket" value="#{page1MB.list}" binding="#{page1MB.dataTable}">

The Action column is defined like this in the JSP.

<h:column>
    <f:facet name="header"><h:outputText value="Action"/></f:facet>
    <h:commandLink value="edit" action="#{page1MB.editBasket}"/>
</h:column>

The Add button is mapped to the following method. It populates the backing list with data.

	public String addAllGiftBaskets() {
		list = giftBasketDataManager.getAllGiftBaskets();
		return null; // stay on the same page
	}

As you can see the value attribute points to a standard ArrayList.

When you run the code the system should print “Edit basket called for: ” at the server console.

    public String editBasket() {
        GiftBasket basket = (GiftBasket)dataTable.getRowData();
        System.out.println("Edit basket called for: " + basket);
        return null;
    }

Using ListDataModel

DataModels allow you to do what dataTables can do. Examples for ListDataModel or any other DataModel are rare on the internet. the following article describes some more information about the topic: http://forums.sun.com/thread.jspa?threadID=653909

The following example is based on the screen shot above.

The big difference when using ListDataModel is that you only need to specify the “value” attribute of the dataTable element. A binding to a HtmlDataTable attribute is not necessary.

<h:dataTable var="giftBasket" value="#page1MB.selectedGiftBasketDataModel}" >

In your Managed Bean you define the following attribute.

private ListDataModel selectedGiftBasketDataModel =
    new ListDataModel(new ArrayList<GiftBasket>());

To populate the table with data you click the add button and that executes the following code in the managed bean.

	public String addAllGiftBaskets() {
		List<GiftBasket> list = giftBasketDataManager.getAllGiftBaskets();
		selectedGiftBasketDataModel.setWrappedData(list);
		return null;
	}

To get a reference to the data for a single row that was selected just do the following:

	public String editBasket() {
		GiftBasket basket = (GiftBasket)selectedGiftBasketDataModel.getRowData();
		System.out.println("Edit basket called for: " + basket);
		return null; // stay on the same page
	}

To print data for all the rows, do the following.

	public String printResults() {
		List<GiftBasket> list = (List<GiftBasket>) selectedGiftBasketDataModel.getWrappedData();

		for(GiftBasket basket : list) {
			System.out.println(basket);
		}
		return null; // stay on the same page
	}

Complete JSP

This is the “ListDataModel” version of the JSP used in the above example:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Page 1</title>
<link rel="stylesheet" type="text/css" href="styles/style.css" />
</head>
<body>
<f:view>
<h:form id="myform">
<h:messages showDetail="#{true}" showSummary="#{false}" />
    <div id="left" style="margin-bottom: 20px;">
		The following is an example a user input form created from a database.
    </div>

	<h:dataTable var="giftBasket" value="#{page1MB.selectedGiftBasketDataModel}" >
		<h:column>
			<f:facet name="header"><h:outputText value="ID"/></f:facet>
			<h:outputText value="#{giftBasket.id}"/>
		</h:column>
		<h:column>
			<f:facet name="header"><h:outputText value="Gift Basket Type"/></f:facet>
			<h:outputText value="#{giftBasket.type}"/>
		</h:column>
		<h:column>
			<f:facet name="header"><h:outputText value="Quantity"/></f:facet>
			<h:inputText value="#{giftBasket.quantity}" size="4"/>
		</h:column>
		<h:column>
			<f:facet name="header"><h:outputText value="Action"/></f:facet>
			<h:commandLink value="edit" action="#{page1MB.editBasket}"/>
		</h:column>
	</h:dataTable>
	<h:commandButton value="submit" action="#{page1MB.printResults}"/>
	<h:commandButton value="add" action="#{page1MB.addAllGiftBaskets}"/>
</h:form>
</f:view>
</body>
</html>
14
May
10

Getting Apache Tomahawk to work in Websphere 6.1 and JSF 1.1

This page describes how to get Apache MyFaces Tomahawk to work with IBM Websphere 6.1 / JSF 1.1 / Servlet Specification 2.4 combo.

Requirements

  • Java 1.5
  • Maven 2
  • Eclipse or IBM RAD 7.5 Development Environment
  • Websphere Test Environment (understand how to create and deploy an Ear file)
  • Servlet 2.4, JSF 1.1 (Default in WAS 6.1)

Background

Websphere 6.1 Application server comes pre-installed with Sun’s Reference Implementation of JSF. Unless you change the Classloader policy of your application to PARENT_LAST it is difficult to get the myfaces-impl and myfaces-api to play nice with the JARS that come pre-installed. Also if you are converting an existing application, then changing the classloader policy can open up a new can of worms. Therefore it is just easier to use the JSF Implementation available by default on the Websphere App Server.

Note: The examples in this page do NOT use the “standard maven directory structure”.  The jsp and the WEB-INF files will be kept in the “WebContent” folder instead of “src/main/webapp”. This is on purpose since we want this project to work in RAD 7.5 development environment.

Project Setup

Create a blank project using Maven archetype. Open up the command prompt and navigate to an empty directory.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

groupId: com.test
artifactId: jsfTest

Answer the rest of the questions with defaults “Just hit the enter key”

Since we are not using the maven standard directory structure you need to add the “WebContent” and the “WebContent/WEB-INF” folders right under the project main directory. Once these folders are created then move the files from the “src/main/webapp” to “WebContent”.

Settings

The archetype will set up most of the directory structure and generate a blank web.xml file and a pom.xml. At this time open up the pom.xml file and modify it to the way you see it below.

Notice in the file below, the myfaces-impl and myfaces-api are in the “provided” scope. This means that the jars will be available during compile time but will NOT be included during runtime.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>jsfTest</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>jsfTest Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

	<dependency>
	    <groupId>org.apache.myfaces.tomahawk</groupId>
	    <artifactId>tomahawk</artifactId>
	    <version>1.1.9</version>
	</dependency>

	<dependency>
	    <groupId>org.apache.myfaces.core</groupId>
	    <artifactId>myfaces-api</artifactId>
	    <version>1.1.7</version>
	    <scope>provided</scope> <!--use compile scope for testing with jetty-->
	</dependency>

	<dependency>
	    <groupId>org.apache.myfaces.core</groupId>
	    <artifactId>myfaces-impl</artifactId>
	    <version>1.1.7</version>
	    <scope>provided</scope> <!--use compile scope for testing with jetty-->
	</dependency>

  </dependencies>
  <build>
    <finalName>testWebApp</finalName>
    <plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
            <source>1.5</source>
            <target>1.5</target>
        </configuration>
    </plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<configuration>
				  <webappDirectory>WebContent</webappDirectory>
					<webResources>
						<resource>
							<directory>WebContent</directory>
						</resource>
					</webResources>
					<outputDirectory>
						WebContent/WEB-INF/classes
					</outputDirectory>
					<warSourceDirectory>WebContent</warSourceDirectory>
					<warName>jsfTest</warName>
					<webXml>WebContent/WEB-INF/web.xml</webXml>
				</configuration>
			</plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-eclipse-plugin</artifactId>
        <configuration>
            <wtpapplicationxml>true</wtpapplicationxml>
            <wtpversion>1.5</wtpversion>
            <downloadSources>true</downloadSources>
            <downloadJavadocs>true</downloadJavadocs>
					<outputDirectory>
						WebContent/WEB-INF/classes
					</outputDirectory>
            <classpathContainers>
							<classpathContainer>
								org.eclipse.jst.server.core.container/com.ibm.ws.ast.st.runtime.runtimeTarget.v61/was.base.v61
							</classpathContainer>
							<classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/WebSphere v6.1 JRE</classpathContainer>
                <classpathContainer>org.eclipse.jst.j2ee.internal.web.container</classpathContainer>
                <classpathContainer>org.eclipse.jst.j2ee.internal.module.container</classpathContainer>
            </classpathContainers>
            <additionalProjectFacets>
                <jst.jsf>1.2</jst.jsf>
            </additionalProjectFacets>
        </configuration>
    </plugin>
		    <plugin>
		        <groupId>org.mortbay.jetty</groupId>
		        <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
		        <configuration>
		            <webAppSourceDirectory>WebContent</webAppSourceDirectory>
					<scanTargets>
						<scanTarget>WebContent/WEB-INF</scanTarget>
					</scanTargets>
		            <scanIntervalSeconds>2</scanIntervalSeconds>
		        </configuration>
		    </plugin>

    </plugins>
  </build>
</project>

WebContent/WEB-INF/web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="WebApp_ID"
	version="2.4"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Archetype Created Web Application</display-name>

	<filter>
	        <filter-name>MyFacesExtensionsFilter</filter-name>
	        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
	</filter>

	<!-- extension mapping for adding <script/>, <link/>, and other resource tags to JSF-pages  -->
	<filter-mapping>
	    <filter-name>MyFacesExtensionsFilter</filter-name>
	    <!-- servlet-name must match the name of your javax.faces.webapp.FacesServlet entry -->
	    <servlet-name>Faces Servlet</servlet-name>
	</filter-mapping>

	<!-- extension mapping for serving page-independent resources (javascript, stylesheets, images, etc.)  -->
	<filter-mapping>
	    <filter-name>MyFacesExtensionsFilter</filter-name>
	    <url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
	</filter-mapping>

    <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>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

WebContent/WEB-INF/faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE faces-config PUBLIC
    "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
    "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>

</faces-config>

WebContent/index2.jsp

<%@ page session="false" contentType="text/html;charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t" %>

<html>
<body>
<f:view>
    <h:form>
        <f:verbatim>
            <h1>Input Text Help</h1>
        </f:verbatim>
        <t:outputText value="hello tomahawk"/>

        <h:outputText value="Select helper text:"/>
        <t:inputTextHelp value="" id="i1" helpText="Hello World"/>
        <t:div/>
        <h:outputText value="Select helper text:"/>
        <t:inputTextHelp value="" id="i2" selectText="true" helpText="TT.MM.JJJJ"/>
    </h:form>
</f:view>
</body>
</html>

Generated Javascript in Websphere 6.1 (important)

This step is important don’t skip it.

The Apache Tomahawk framework generates javascript for some of the components. You need to enable the following setting in “Application servers > server1 > Web container > Custom Properties”
Set the custom property “com.ibm.ws.webcontainer.invokefilterscompatibility” = true

Also don’t forget to do the same thing when your program reaches QA or PROD environments.

Testing using Websphere Test Environment

In order to run a Dynamic Web Project in the Application server built into RAD just create an Enterprise Project and put the Web Project into the EAR. Deploy the ear just like any other project. Start the application server and navigate to http://localhost:9081/jsfTest/index2.jsf

Testing using Jetty

This application can also be tested using jetty servlet engine. You just need to make sure to change the two <scope>provided</scope> tags to <scope>compile</scope>

After changing the pom.xml file above just type “mvn jetty:run” on the command line and then navigate to http://localhost:8080/index2.jsf using your browser.

References

01
Feb
10

Display Google Map Using JSF

This page describes the process of creating a web application to display a google map using the Gmap4JSF tag library. All the Javascript code to display the map is generated by the JSF library.

Requirements

  • Maven – installed and configured

Generate a new project using maven
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp
groupId: com.test
artifactId: googleMapTest
choose defaults for the rest of the questions.

Generate the eclipse project
mvn eclipse:clean eclipse:eclipse

Import the project into eclipse

Modify the pom.xml file.
My pom.xml looks like this…

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>googleMapTest</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>googleMapTest Maven Webapp</name>
  <url>http://maven.apache.org</url>

    <repositories>
        <repository>
            <id>googlecode.com</id>
            <url>http://gmaps4jsf.googlecode.com/svn/trunk/gmaps4jsf-repo</url>
        </repository>
    </repositories>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
        <dependency>
            <groupId>com.googlecode.gmaps4jsf</groupId>
            <artifactId>gmaps4jsf-core</artifactId>
            <version>1.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-api</artifactId>
            <version>1.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.myfaces.core</groupId>
            <artifactId>myfaces-impl</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
  </dependencies>
  <build>
    <finalName>googleMapTest</finalName>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                        <configuration>
                         <scanIntervalSeconds>2</scanIntervalSeconds>
                        </configuration>
            </plugin>
        </plugins>
  </build>
</project>

Regenerate the eclipse project and refresh.
mvn eclipse:clean eclipse:eclipse

src/main/webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <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>/faces/*</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

src/main/webapp/index.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Your Page Title</title>
<meta http-equiv="REFRESH" content="0;url=<c:url value='/faces/displayMap.jsp'/>"></HEAD>
<BODY>
Optional page text here.
</BODY>
</HTML>

src/main/webapp/displayMap.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://code.google.com/p/gmaps4jsf/" prefix="m"%>
<!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">
<head>
<title>Welcome to GMaps4JSF</title>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<script
	src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAxrVS1QxlpJHXxQ2Vxg2bJBQdkFK-tWRbPPQS4ACM1pq_e-PltxQXeyH20wQuqDaQ_6EM5UeGGVpnIw"
	type="text/javascript"></script>

</head>
<body onunload="GUnload()">
<f:view>
	<h:form id="form">
		<m:map width="600px" height="600px" latitude="37.4"
			longitude="-122">
			<m:marker latitude="37.4" longitude="-122" draggable="true"/>
			<m:htmlInformationWindow latitude="37.4" longitude="-122"
				htmlText="<B>Hello World</B>" />
		</m:map>
	</h:form>
</f:view>
</body>
</html>

Test the project in Jetty

mvn clean compile jetty:run

navigate to http://localhost:8080/

You should see a map with a popup that says hello world. Read the Gmap4JSF website for more detailed instructions on how to use the tag.

Reference

03
Jan
10

Using JSF to change Log4j Log Levels at Runtime

This page will show you how you can easily code a JSF form to inspect the current log4j logging levels and allow the user to change them at runtime. The changes take effect immediately. The complete implementation should take about 45 minutes.

Requirements

Configuration

Just add the following to the pom.xml file.

    <dependency>
    	<groupId>commons-logging</groupId>
    	<artifactId>commons-logging</artifactId>
    	<version>1.1</version>
    </dependency>
    <dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.15</version>
	<exclusions>
		<exclusion>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
		</exclusion>
		<exclusion>
			<groupId>javax.jms</groupId>
			<artifactId>jms</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jdmk</groupId>
			<artifactId>jmxtools</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.sun.jmx</groupId>
			<artifactId>jmxri</artifactId>
		</exclusion>
		<exclusion>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
		</exclusion>
	</exclusions>
</dependency>
	<dependency>
		<groupId>org.apache.myfaces.tomahawk</groupId>
		<artifactId>tomahawk</artifactId>
		<version>1.1.9</version>
	</dependency>

and regenerate the eclipse / idea project.

mvn eclipse:clean eclipse:eclipse

Refresh the eclipse project.

Put the following file into the

src/main/resources/log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<appender name="A1" class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %c - %m%n" />
		</layout>
	</appender>

	<root>
		<priority value="fatal" />
		<appender-ref ref="A1" />
	</root>
	<logger name="org.vtechfw">
		<level value="debug" />
		<appender-ref ref="A1" />
	</logger>
	<logger name="org.vtechfw.utils">
		<level value="trace" />
		<appender-ref ref="A1" />
	</logger>
</log4j:configuration>

Managed Logger

This is just a wrapper bean to help configure the loggers.

src/main/java/org/vtechfw/utils/logging/ManagedLogger.java

package org.vtechfw.utils.logging;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * Wrapper to the Log4j Logger to help configure the logging levels.
 */
public class ManagedLogger {
	private Logger logger;

	
	public ManagedLogger() {
		super();
	}

	public ManagedLogger(Logger logger) {
		super();
		this.logger = logger;
	}

	public void setLogger(Logger logger) {
		this.logger = logger;
	}

	public final String getName() {
		return logger.getName();
	}

	public Logger getLogger() {
		return logger;
	}
	public Level getLevel() {
		return logger.getEffectiveLevel();
	}
	public void setLevel(Level level) {
		if(level!=null) {			
			logger.setLevel(level);
		}
	}
}

Managed Bean

Create the following class in the src/main/java/org/vtechfw/utils/logging folder

Log4jManager.java

package org.vtechfw.utils.logging;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;

import javax.faces.component.html.HtmlDataTable;

import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class Log4jManager {
	// used for regular logging.
	protected Logger logger = Logger.getLogger(getClass());
	private Logger currentLogger;
	private String logLevel;
	private HtmlDataTable htmlDataTable;

	@SuppressWarnings("unchecked")
	public List<Logger> getLoggerList() {
		Enumeration<Logger> enumeration = LogManager.getCurrentLoggers();
		List<Logger> list = Collections.<Logger>list(enumeration);
		list.add(LogManager.getRootLogger());

		Collections.sort(list, new Comparator<Logger>() {

			@Override
			public int compare(Logger o1, Logger o2) {
				String o1Name = o1.getName();
				String o2Name = o2.getName();

				return o1Name.compareTo(o2Name);
			}
		});

		return list;
	}

	public List<ManagedLogger> getManagedLoggerList() {
		List<Logger> list = getLoggerList();
		List<ManagedLogger> managedLoggerList = new ArrayList<ManagedLogger>();
		for (Logger logger : list) {
			ManagedLogger e = new ManagedLogger(logger);
			managedLoggerList.add(e);
		}
		return managedLoggerList;
	}

	public Logger getRootLogger() {
		return LogManager.getRootLogger();
	}

	public void setCurrentLogger(Logger currentLogger) {
		this.currentLogger = currentLogger;
	}

	public Logger getCurrentLogger() {
		return currentLogger;
	}

	public void setHtmlDataTable(HtmlDataTable htmlDataTable) {
		this.htmlDataTable = htmlDataTable;
	}

	public HtmlDataTable getHtmlDataTable() {
		return htmlDataTable;
	}

	public String setLoggerLevel() {

		// find out the currently selected logger.
		currentLogger = (Logger)htmlDataTable.getRowData();
		Level level = Level.toLevel(logLevel);
		currentLogger.setLevel(level);
		return "refresh";
	}

	public void setLogLevel(String logLevel) {
		this.logLevel = logLevel;
	}

	public String getLogLevel() {
		return logLevel;
	}
}

Converter

The following class converts between the text representation of the Logger and the actual logger instance.

src/main/java/org/vtechfw/utils/logging/LevelConverter.java

package org.vtechfw.utils.logging;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

import org.apache.log4j.Level;

public class LevelConverter implements Converter {

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) throws ConverterException {
		Level level = null;

		if(value==null || "".equals(value)) {
			level = null;
		} else {
			level = Level.toLevel(value);
		}
		return level;
	}

	@Override
	public String getAsString(FacesContext context, UIComponent component,
			Object value) throws ConverterException {
		if(value instanceof String) {
			return (String)value;
		}
		if(value instanceof Level) {
			Level level = (Level) value;
			return level.toString();
		}
		return "parent";
	}

}

JSP file

This is where all the magic happens. Its a short file that hopefully is self explanatory.

src/main/webapp/log4jManager.jsp

<%@taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Log4j Management Console</title>
</head>
<body>
<f:view>
	<h:form id="levelconfigform">
	<h3>Log Level Configuration Util (Log4j)</h3>
		<t:dataTable border="1" value="#{log4jManager.managedLoggerList}" var="logger" binding="#{log4jManager.htmlDataTable}" sortable="true">
			<h:column id="column1">
				<f:facet name="header">
					<h:outputText value="Name"></h:outputText>
				</f:facet>
				<h:outputText value="#{logger.name}"></h:outputText>
			</h:column>
			<h:column id="column3">
				<f:facet name="header">
					<h:outputText value="Level"></h:outputText>
				</f:facet>
				<h:selectOneMenu id="logLevel" value="#{logger.level}" onchange="submit();">
					<f:selectItem itemLabel="ALL" itemValue="ALL"/>
					<f:selectItem itemLabel="TRACE" itemValue="TRACE"/>
					<f:selectItem itemLabel="DEBUG" itemValue="DEBUG"/>
					<f:selectItem itemLabel="INFO" itemValue="INFO"/>
					<f:selectItem itemLabel="WARN" itemValue="WARN"/>
					<f:selectItem itemLabel="ERROR" itemValue="ERROR"/>
					<f:selectItem itemLabel="FATAL" itemValue="FATAL"/>
					<f:selectItem itemLabel="OFF" itemValue="OFF"/>
				</h:selectOneMenu>
			</h:column>
		</t:dataTable>
	</h:form>
</f:view>
</body>
</html>

Faces Config File

I have a lot of junk in mine so I am not going to include the whole thing. Here are the important sections.

src/main/webapp/WEB-INF/faces-config.xml

	<converter>
		<display-name>Level Converter</display-name>
		<converter-for-class>org.apache.log4j.Level</converter-for-class>
		<converter-class>org.vtechfw.utils.logging.LevelConverter</converter-class>
	</converter>

	<managed-bean>
		<managed-bean-name>log4jManager</managed-bean-name>
		<managed-bean-class>org.vtechfw.utils.logging.Log4jManager</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>

	<navigation-rule>
	        <display-name>log4jManager</display-name>
		<from-view-id>/log4jManager.jsp</from-view-id>
		<navigation-case>
			<from-outcome>refresh</from-outcome>
			<to-view-id>/log4jManager.jsp</to-view-id>
		</navigation-case>
	</navigation-rule>

Running the project

Drop to the command line and type in the following:

mvn jetty:run

Using your browser navigate to the following URL:

http://localhost:8080/log4jManager.jsf

You will be presented with a table of loggers and their associated level. The table is sortable using the table headings. Using the drop down you can change the log level of each logger. The changes take effect immediately.

The only bug with this jsf component is that when you select a logging level using the drop down the logging level of the item adjacent to it changes. But it starts working as expected with the second attempt. Having figured out what the problem is. If you guys figure it out let me know by commenting below.

That’s all for now!




Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 78 other followers

July 2017
S M T W T F S
« Mar    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Blog Stats

  • 822,600 hits