Yet another Java Developer.

JSF Developer living in Oklahoma City

Gallery

1236912526588.jpg 1239563215367.jpg IMGP0137.JPG IMGP0085.JPG

Currently browsing java

No Dialect mapping for JDBC type: -4

Yet another fun day with hibernate.
While working on ResourcePhaseListener for JSF attachment problem I run into following problem while trying to retrieve BLOB from MySQL db.

org.hibernate.MappingException: No Dialect mapping for JDBC type: -4 No Dialect mapping for JDBC type: -4

Here is the offending code:

SerializableBlob result= null;
Session hibSession=(Session) em.getDelegate();
result = (SerializableBlob)
hibSession.createSQLQuery("Select DATA from Table")
.addScalar("DATA", Hibernate.BLOB)
.uniqueResult();

Adding the mapping addScalar("DATA", Hibernate.BLOB) solved the problem.

Modulo based counters

Sometimes we need counters that wrap around at certain intervals ex:

1,2,3,1,2,3,1,2,3



One way of doing this would be to increment our ‘counter’ and then reset it when it reaches our number

int N = 3;
int counter = 0;
if (counter == N){
  counter = 0;
}
counter++;


But there are also couple other ways this same could be achieved.

Modulus

Using modulus operator ‘%’ we can divide the counter and get our wrapped value, where N is the value we will wrap at.

counter = (counter+1) % N;

Binary AND

This is almost this same approach as modulus but we are ‘AND’ing the counter with a power of 2. ex 1, 2, 4, 8, 16 … 2^n . Only problem here is that we have to AND with a power of 2.

counter = (counter+1) & 0x1;

produces 0,1,0,1,0,1

Test program

/**
 * Test program  for testing Modulus, Binary AND increments
 * @author greg
 *
 */
public class ModulePowerCounter {
 
	private static final int MAX_LOOP = 100000000;
	private static final int N = 2;
	private static final int POWER_OF_2 = 0x1;
 
	public static void main(String[] args) {
		long modTime = modulo();
		long counterTime = counter();
		long po2Time = powerOf2();		
 
		System.out.println(String.format("modTime = %s", modTime));
		System.out.println(String.format("counterTime = %s", counterTime));
		System.out.println(String.format("po2Time = %s", po2Time));
	}
 
	private static long powerOf2(){
		long start = System.currentTimeMillis();
		int counter = 0;
		for (int i = 0; i < MAX_LOOP; i++) {
			counter = (counter+1) & POWER_OF_2;
		}				
		return System.currentTimeMillis() - start;
	}
 
	private static long modulo(){
		long start = System.currentTimeMillis();
		int counter = 0;
		for (int i = 0; i < MAX_LOOP; i++) {
			counter = (counter+1) % N;
		}				
		return System.currentTimeMillis() - start;
	}
 
	private static long counter(){
		long start = System.currentTimeMillis();
		int counter = 0;
		for (int i = 0; i < MAX_LOOP; i++) {
			if(counter == N)counter = 0;
			counter++;
		}				
		return System.currentTimeMillis() - start;
	}
}

Performance

This is the fun part, so we have 3 different ways to achieve same thing but how do they perform.

Lets think about it, division is much more expensive than ‘addition and test’ which is more expensive than binary manipulation, our test program confirms our assumption.

modTime = 1258
counterTime = 449
po2Time = 108



As we see Power of 2 outperforms other methods by far, but its only for powers of 2, also our plain counter is almost 2.5 times faster than modulus as well. So why would we like to use modulus increments at all? Well in my opinion I think they provide a clean code and if used properly they are a great tool to know of.




Expanding Rich tree nodes programmatically

I have found two different methods for expanding nodes in Rich tree  from code, they both take  advantage of component binding and component state.

Tree Setup

<rich:tree 
	 value="#{ourbean.sampleTree}" 
	 binding="#{ourbean.sampleTreeBinding}"
 
	 var="node" 
	 nodeFace="simple" 
	 id="someid"
	 >
	 <rich:treeNode type="simple" >
		<h:outputText value="#{node}"/>        
	 </rich:treeNode>
</rich:tree>

Only thing to note here is the binding attribute that we setup in our backing bean.

	protected org.richfaces.component.UITree sampleTreeBinding;

for both solutions after we changed the sampleTree we need to update the binding with new value whitch is
value="#{ourbean.sampleTree}"

// Make sure that we set the new TreeModel on current binding
sampleTreeBinding.setValue(sampleTree);

Solution 1 : Expanding all nodes

TreeState componentState = (TreeState) sampleTreeBinding.getComponentState();
try {
	componentState.expandAll(sampleTreeBinding);
} catch (IOException e) {
	e.printStackTrace();
}

This will expand all levels of the nodes.

Solution 2 : Expanding only nodes that meet our criteria

try {
	final TreeState state = (TreeState) sampleTreeBinding.getComponentState();
	sampleTreeBinding.walk(FacesContext.getCurrentInstance(), new DataVisitor(){
		@SuppressWarnings("unchecked")
		public void process(FacesContext context, Object rowKey, Object argument)
		throws IOException {
			TreeRowKey<Object> row = (TreeRowKey<Object>)rowKey;
			if(row.depth() == 1){
				state.expandNode(sampleTreeBinding, (TreeRowKey<Object>)rowKey);
			}
		}
	});
}
catch (IOException e) {
	e.printStackTrace();
}

Here we are only expanding nodes at depth 1 but it could be anything. Idea is that we are walking the tree
and checking if we are interested in the doing something with that node if so then we can modify it here.




I hope this helps.

How to read the files placed in WEB-INF from JSF

Reading files from WEB-INF in JSF

This no different than reading files from a Servlet except it involves a extra step of getting ServletContext from FacesContext


FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
ServletContext sc = (ServletContext)externalContext.getContext();
String sc.getRealPath("/WEB-INF/somefile.xml");

Here we are getting the path to the file but you could read it if you like.

UnsatisfiedLinkError: javaxpcomglue.dll: Can’t find dependent libraries

While playing around with JavaXPCOM I have run into couple issues. I am running on window 7 64 bit.

When trying to initialize my GRE (Gecko Runtime Environment) I got following exception

Exception in thread "main" java.lang.UnsatisfiedLinkError: D:\xulrunner-sdk\bin\javaxpcomglue.dll: Can't find dependent libraries
	at java.lang.ClassLoader$NativeLibrary.load(Native Method)
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1803)
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1699)
	at java.lang.Runtime.load0(Runtime.java:770)
	at java.lang.System.load(System.java:1003)
	at org.mozilla.xpcom.internal.JavaXPCOMMethods.registerJavaXPCOMMethods(JavaXPCOMMethods.java:57)
	at org.mozilla.xpcom.internal.MozillaImpl.initialize(MozillaImpl.java:48)
	at org.mozilla.xpcom.Mozilla.initialize(Mozilla.java:668)
	at SampleBroswer.init(SampleBroswer.java:69)
	at SampleBroswer.main(SampleBroswer.java:45)

What is strange on my other dev machine same configuration I don’t have this problem, very strange.

Problem is that the file mozcrt19.dll can’t be found. So what I did is that I copied that file from xulrunner-sdk\bin to my C:\Windows\SysWOW64 folder and that fixed the problem. Still little puzzled over why my other machine is not throwing this exception.

Preventing ViewExpiredException in JSF

When our page is idle for x amount of time the view will expire and throw javax.faces.application.ViewExpiredException to prevent this from happening
one solution is to create CustomViewHandler that extends ViewHandler
and override restoreView method all the other methods are being delegated to the Parent

import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
 
public class CustomViewHandler extends ViewHandler {
	private ViewHandler parent;
 
	public CustomViewHandler(ViewHandler parent) {
		//System.out.println("CustomViewHandler.CustomViewHandler():Parent View Handler:"+parent.getClass());
		this.parent = parent;
	}
 
    @Override public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
	/**
	 * {@link javax.faces.application.ViewExpiredException}. This happens only  when we try to logout from timed out pages.
	 */
	UIViewRoot root =null; 
	root = parent.restoreView(facesContext, viewId);
	if(root == null) {			
		root = createView(facesContext, viewId);
	}
	return root;
 }
 
 @Override
	public Locale calculateLocale(FacesContext facesContext) {
		return parent.calculateLocale(facesContext);
	}
 
	@Override
	public String calculateRenderKitId(FacesContext facesContext) {
		String renderKitId = parent.calculateRenderKitId(facesContext);
		//System.out.println("CustomViewHandler.calculateRenderKitId():RenderKitId: "+renderKitId);
		return renderKitId;
	}
 
	@Override
	public UIViewRoot createView(FacesContext facesContext, String viewId) {
		return parent.createView(facesContext, viewId);
	}
 
 
    @Override
	public String getActionURL(FacesContext facesContext, String actionId) {
		return parent.getActionURL(facesContext, actionId);
	}
 
	@Override
	public String getResourceURL(FacesContext facesContext, String resId) {
		return parent.getResourceURL(facesContext, resId);
	}
 
	@Override
	public void renderView(FacesContext facesContext, UIViewRoot viewId) throws IOException, FacesException {
		parent.renderView(facesContext, viewId);
 
	}
 
	@Override
	public void writeState(FacesContext facesContext) throws IOException {
		parent.writeState(facesContext);
	}
 
	public ViewHandler getParent() {
		return parent;
	}
 
}

Then you need to add it to your faces-config.xml

<view-handler>com.demo.CustomViewHandler</view-handler>

This will prevent you from getting ViewExpiredException’s

Use argument in EL expression

There is couple ways about doing that, you could use JBoss EL expression implementation they support method calls with parameters check out Seam, or use similar approach as @digitaljoel suggested.
This is what I created for that purpose, you can call static and static methods, not a great solution but it does the job.

    <c:if  test="#{t:call(null, '@Util.SecurityUtility', 'isPanelWorkbookEnabledForUser','')}">
          Hello Panel    
      </c:if>

@Util is just an alias to com.mycomp.util where

**Example 2**

    <c:if test="#{item != null and  t:call(item, 'java.lang.String', 'indexOf', t:params(t:param('flash-alert',''))) == 0}">                
        #{t:call(session, 'org.apache.catalina.session.StandardSessionFacade', 'removeAttribute', t:params(t:param(item,'')))}      
    </c:if>

t:call, t:params, t:param are function defined in project-taglib.xml as so

    	<function>
		<function-name>call</function-name>
		<function-class>util.Functions</function-class>
		<function-signature>java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])</function-signature>
	</function>
	<function>
		<function-name>param</function-name>
		<function-class>.util.Functions</function-class>
		<function-signature>java.lang.String param(java.lang.Object, java.lang.String)</function-signature>
	</function>	
 
	<function>
		<function-name>params</function-name>
		<function-class>util.Functions</function-class>
		<function-signature>java.lang.Object[] params(java.lang.String)</function-signature>
	</function>

Here is the implementation

    package mycompany.web.util;
 
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
 
import javax.el.MethodNotFoundException;
 
 
public class Functions {
 
	private  static HashMap<String, String> alliasMap;
	static{
		alliasMap=new HashMap<String, String>();
		alliasMap.put("@DateUtil", "com.americanbanksystems.compliance.util.DateUtil");
		//Match anything following the dot(.)
		alliasMap.put("@Util.*", "com.americanbanksystems.compliance.util");
 
		alliasMap.put("@Application.*", "com.americanbanksystems.compliance.application");
 
	}
 
 
 
 
	public static String param(Object obj, String cls) {	
		//make sure that passed in object is not null
		if(obj==null){
			obj="";
		}
 
		ByteArrayOutputStream baut=new ByteArrayOutputStream();
		XMLEncoder encoder=new XMLEncoder( baut );
		//Bug in the JDK
		//http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=c993c9a3160fd7de44075a2a1fa?bug_id=6525396
		if(obj instanceof java.sql.Timestamp){
			Date o = new Date(((java.sql.Timestamp)obj).getTime());
			obj=o;
		}		
		//Checking if this is possible 
		if(String.class.isAssignableFrom(obj.getClass())){
			//removed trailing +" " because it was causing indexOf return invalid value
			//Unknown side effects
			obj=FacesUtil.get(obj.toString());			
		}
			encoder.writeObject( obj );
		encoder.close();
		return new String(baut.toByteArray());
	}
 
	private static Object decode(String str){
		ByteArrayInputStream bais=new ByteArrayInputStream(str.getBytes());
		XMLDecoder decoder=new XMLDecoder(bais);
		return decoder.readObject();
	}
 
	public static Object[] params(String str){
		// (?<=</java>)\s*(?=<?)
		String[] obj=str.split("(?<=</java>)\\s*(?=<?)");
		Object[] results=new Object[obj.length];
		for(int i=0;i<obj.length;i++){
			results[i]=decode(obj[i]);
		}
		return results;
	}
 
 
	@SuppressWarnings("unchecked")
	public static Object call(Object owningObject, String qualifiedClassname, String methodName, java.lang.Object... methodArguments) {
		if (null == methodName || methodName.equals("")) {
			throw new IllegalArgumentException("Method name can't be null or empty");
		}
		if (null == methodArguments) {
			methodArguments = new Object[0];
		}
 
		//Check for aliases 
		if(qualifiedClassname.indexOf("@")>-1){
			String subpackage=qualifiedClassname;
			String originalClass=qualifiedClassname;
			//Split at the dot
			boolean isPackageAllias=false;
			String[] sp=subpackage.split("\\.");	
			if(sp.length>1){
				subpackage=sp[0]+".*";
				isPackageAllias=true;
			}
			if(alliasMap.containsKey(subpackage)){
				String value = alliasMap.get(subpackage);
				if(isPackageAllias){
					qualifiedClassname=subpackage.replace(sp[0], value);
					qualifiedClassname=qualifiedClassname.replace(".*", originalClass.replace(sp[0],""));
				}else{
					qualifiedClassname=value;
				}
			}else{
				throw new IllegalArgumentException("Allias name '"+qualifiedClassname+"' not found");
			}
		}
		Class clazz;
		try {
			clazz = Class.forName(qualifiedClassname);
			//Find method by methodName,Argument Types
			Class[] argumentTypes=new Class[methodArguments.length];	
 
			for(int i=0;i<methodArguments.length;i++){
				argumentTypes[i]=methodArguments[i].getClass();
				//Check if the passed in method argument is a string and if its represented as unicode char				
				//if it is then convert it into a char and reassign to the original parameter
				//example 1:  \u0022 == "
				//example 2:  \u0027 == '
				// Reason for this functionality is that we can't pass " and ' from within t:call method
				if (argumentTypes[i] == String.class && methodArguments[i].toString().indexOf("\\u") > -1) {
					String arg = methodArguments[i].toString();
					arg = arg.substring(2, arg.length());
					try {
						int outchar = Integer.parseInt(arg, 16);
						if (Character.isDefined(outchar)) {
							methodArguments[i] = String.valueOf((char) outchar);
						}
					} catch (NumberFormatException nfe) {
						// Suppress error and continue assuming this is a regular string
					}
				}
			}
 
			Method methodToInvoke = null;
			try{
				methodToInvoke  = clazz.getMethod(methodName, argumentTypes);
			}catch(NoSuchMethodException nsm){//Find by method name/ argument count
				for (Method method : clazz.getMethods()) {
					if (method.getName().equals(methodName)  && method.getParameterTypes().length == methodArguments.length) {
						if (null == owningObject) {
							owningObject = clazz.newInstance();
						}
						methodToInvoke=method;
						break;
					}
				}
			}
 
			if(methodToInvoke!=null){								
				return methodToInvoke.invoke(owningObject, methodArguments);
			}else{
				throw new InstantiationException("method not found :" + methodName);	
			}
 
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return null;
	}
 
 
	public static void main(String[] arg) {
		// StringBuffer buff=new StringBuffer();
		// buff.append("Gregs init");
		// Functions.call(java.lang.Class<T>, T, java.lang.String, java.lang.String, java.lang.Object...)
		/*
		 * Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," Init ");
		 * Functions.call(StringBuffer.class, buff, "java.lang.StringBuffer","append"," greg ");
		 * System.out.println("output="+ buff);
		 */
 
		//#{t:call(null, ".util.DateUtil", "normalizeDate", t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object"))}
	//	c(call(null, "util.DateUtil", "normalizeDate", new Date()));
 
		//	#{t:parametize(editRiskActionPlan.riskActionPlan.completionDate,",","java.lang.Object")}
		//parametize((new Date()).toString(),",","java.lang.Object");
		Date a=new Date();
 
		Date b=new Date();
 
		String rawString=param((Date)b, Date.class.toString() );					
		//System.out.println(rawString);
 
		//Replaced=#{t:call("Gregs ' car", 'java.lang.String', 'replace', t:params( parameter ))}
 
		String paramA=param("\\u0027","");
		String paramB=param("\\u0022","");
		String params=paramA+paramB;
		String in="I need to ' have a replaced single quote with double";
		String out=(String)call(in, "java.lang.String", "replace", params(params));
 
		System.out.println(out);
 
 
		/*
		Object[] obj=params(rawString);
		for(Object o:obj){
			System.out.println(o);
		}
		//c(call(null, "@DateUtil", "normalizeDate", obj));
 
		*/
 
	}
 
}

I hope this helps, btw this was copied/pasted from my project so not sure if I missed anything.

Display all managed-beans in JSF at runtime

Sometimes we like to see whats going on under the hood of jsf application (Checkout my JSFConsole). One such task is being able to display all the registered managed-beans during runtime.
Here we can see all registered beans, including implicit object(cookie,header,param etc…)

Result

     a4j
     a4jSkin
     ajaxContext
     ajaxHandler
     application
     applicationScope
     beeHive       --- My Managed bean
     cookie
     facesContext
     header
     headerValues
     initParam
     param
     paramValues
     request
     requestScope
     richSkin
     session
     sessionScope
     view

Source

/**
	 * Retrieve all registered beans for given {@link ScopeType}
	 * @param scopeType to search in
	 * @return List of beanNames
	 */
	public static List<String> getRegisteredBeans(ScopeType scopeType){
		FacesContext facesContext=FacesContext.getCurrentInstance();
		ApplicationAssociate application = ApplicationAssociate.getInstance(facesContext.getExternalContext());
		BeanManager  beanManager = application.getBeanManager();
		Map<String, BeanBuilder> beanMap=beanManager.getRegisteredBeans();
		Set<Entry<String, BeanBuilder>>beanEntries=beanMap.entrySet();
		List<String> registeredBeans=new ArrayList<String>();
		for(Entry<String, BeanBuilder> bean:beanEntries){
			String beanName=bean.getKey();
			if(!beanManager.isManaged(beanName)){
				continue;
			}			
			BeanBuilder builder=bean.getValue();
			Scope bScope=builder.getScope();
			if(scopeType==ScopeType.ALL || bScope.toString().equals(scopeType.toString())){
				registeredBeans.add(beanName+":"+bScope.toString());
			}
		}
 
		if(scopeType==ScopeType.ALL || scopeType==ScopeType.IMPLICIT){
			List<String> implicitList=getProperties(new ImplicitObjectELResolver(), null);
			for(String implicitBeanName:implicitList){
				registeredBeans.add(implicitBeanName+":"+ScopeType.IMPLICIT.toString());
			}
		}
 
		Collections.sort(registeredBeans);
		return registeredBeans;
	}

ScopeType is nothing more than an emun wrapper

 
/**
 * Scope type with additional properties for all/implicit
 * @author devil
 *
 */
public enum ScopeType {
	//Really not a scope but a marker
	ALL("all"),
	IMPLICIT("implicit"),
 
	REQUEST("request"),
	SESSION("session"),
	APPLICATION("application");
 
	String scope;
	ScopeType(String scope) {
		this.scope = scope;
	}
 
	public String toString() {
		return scope;
	}
 
 
	/**
	 * Get Enum from value
	 * @param name
	 * @return
	 */
	public static ScopeType fromValue(String name) {
		name=name!=null?name.toUpperCase():"";
		for(ScopeType v:values()){
			if(v.name().equals(name)){
				return v;
			}
		}
		//By default return all scoped objects
		return ScopeType.ALL;
	}
}

TabWidget demo project

Sorry it took little longer than expected, run in some issues with cupcake (SDK 1.5)
I have attached a Demo project for all interested with  some screenshots and modified .project for TabWidget Project(fixes cupcake problem ref http://groups.google.com/group/android-developers/browse_thread/thread/5537ae10e4143240) if you use eclipse.

1. My env:
Eclipse Version: 3.4.2
Android SDK 1.5
Windows

2.After you import the TabWidgedDemo project you will probably need to fix your buildpath.
Make sure to add TabWidet as a reference to TabWidgedDemo.

3.In TabWidged project you will need to update the .project file otherwise you will get Verify error when deploying to the device.

If you have any questions let me know, I hope you enjoy the project, more improvements to come

Download tabwidgetdemo for eclipse

Serving resources using Resource PhaseListener

PhaseListener designed to serve resources like css, javascript, images, pdf etc.. from jar file

ResourcePhaseListener.java

All required files can be downloaded here.

package com.gregbugaj.jsfdump.console;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
 
import javax.activation.MimetypesFileTypeMap;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
 
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
 
import com.gregbugaj.jsfdump.util.JarUtil;
import com.gregbugaj.jsfdump.util.XMLUtil;
/**
 * Serve resources from jar file  back to the user by specifying resource name in resource-config.xml
 * 
 * This works with following syntax if faces servlet is *.jsf  /jsfdump/resource/script.js.jsf
 * or  /jsfdump/resource/script.js if faces servlet is *.*
 * 
 * @author devil
 *
 */
@SuppressWarnings("serial")
public class ResourcePhaseListener implements PhaseListener {
	//This is how the resource will be accessed ex /jsfdump/resource/script.js
	private static final String RESOURCE_PREFIX = "/jsfdump/resource/";
	//Location of where the js, img, css etc files reside inside the jar, we could also placed them in META-INF folder
	private static final String RESOURCE_PATH = "/com/gregbugaj/jsfdump/resources/";
 
	private static Map<String, String> resources=new HashMap<String,String>();
	private boolean isLoaded;
 
	@Override
	public void afterPhase(PhaseEvent event) {
		FacesContext facesContext=event.getFacesContext();
		String rootId=facesContext.getViewRoot().getViewId();
		//Clean up key
		String key=rootId.replace(RESOURCE_PREFIX, "");
		key=key.replace(".xhtml", "");
		key=key.replace(".jsf", "");
		if(!rootId.startsWith(RESOURCE_PREFIX)){
			return; 
		}
 
		//Lazy loading
		if(!isLoaded){
			isLoaded=initResources();
		}	
		String resourceName=resources.get(key);
		//Location of resources inside the jar file
		String fileName=RESOURCE_PATH+resourceName;
		InputStream resourceStream=JarUtil.getStreamFromJar(fileName);
		HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
		response.setCharacterEncoding("UTF-8");
		ServletOutputStream sos = null;
		try {
			sos = response.getOutputStream();
			if(resourceStream!=null){
				response.setStatus(HttpServletResponse.SC_OK);
				//Resolve mime type, required that we have activation.jar loaded
				//Additional mime types can be defined in /META-INF/mimes.types  {@link http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/activation/MimetypesFileTypeMap.html }
				String contentType = new MimetypesFileTypeMap().getContentType(fileName);
				response.setContentType(contentType);
				byte[] buffer= new byte[1024];
				for (int bytesRead = 0; (bytesRead = resourceStream.read(buffer, 0, buffer.length)) > 0;)
				{
					sos.write(buffer, 0, bytesRead);
				}
			}else{
				//Resource not found
				response.setStatus(HttpServletResponse.SC_NOT_FOUND);
				response.setContentType("text/html");
			}
			sos.flush();
			sos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		facesContext.responseComplete();
	}
 
	@Override
	public void beforePhase(PhaseEvent event) {
		//Do nothing
	}
 
	/**
	 * Load resource mapping from resource-config.xml
	 * @return true if we successfully loded resource
	 */
	private boolean initResources() {
		boolean retVal=true;
		InputStream stream=null;	
		try {
			stream=JarUtil.getStreamFromJar("/META-INF/resource-config.xml");
			Document document=XMLUtil.getXmlDocument(stream);
			NodeList resourceNodes=XMLUtil.extract("/resources/resource", document);
			for(int i=0;i<resourceNodes.getLength();i++){
				Node node=resourceNodes.item(i);
				String name=XMLUtil.attributeText(node, "name");
				String src=XMLUtil.attributeText(node, "src");
				//No forward slash in the resource name
				//ex js/scriptname.js not /js/script.js
				if(src.startsWith("/")){
					src=src.replaceFirst("/", "");
				}
				resources.put(name, src);
			}
		}  catch (IOException e) {
			retVal=false;
			e.printStackTrace();
		}
		catch (Exception e) {
			retVal=false;
			e.printStackTrace();
		}
		return retVal;
	}
 
	@Override
	public PhaseId getPhaseId() {
		return PhaseId.RESTORE_VIEW;
	}
}

resource-config.xml

This is where we define resources that we will be serving. One reasons we use xml configuration is to prevent security breaches.

  <?xml version="1.0" encoding="UTF-8"?>
  <resources>
	<resource name="proto.js" src="js/proto.js" />
	<resource name="logo.png" src="images/a.png" />
	<resource name="main.css" src="css/hello.css" />
  </resources>

Two common ways to access the resources are
If faces servlet is *.jsf /jsfdump/resource/script.js.jsf
Of /jsfdump/resource/script.js if faces servlet is *.*

META-INF/mime.types

This is where we add additional mime types, requires that we have activation.jar loaded More info

This file is not required but it helps, for example png files resolve to application/octet-stream rather than image/x-png

Examples

Sidebar3 : Please add some widgets here.