Tag: jsf

  • Rich modalpanel events not populating form values

    So here is a problem I was running into, I usually use rich:modalpanel just to display some data to the user, but the other day I needed to collect some input. After happily submitting my page all the submitted values were null, what the hell. After some research here are my conclusions on this problem.

    We need to put “form” elements inside the modalPanel in order for this to work, and make sure that the ui:insert in our template is not nested within out top form.

    Reason for this is because of where modalpanel is appended to the DOM, that is also a reason why we have a4j:form inside the panel.

    
    
     
    	 
    		
    	
    		
    			
    	   
     
         CONTENT HERE
     
      
       
    
    

    Using Facelets and JSF 1.2

  • 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

    
    	 
    		        
    	 
    
    

    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 row = (TreeRowKey)rowKey;
    			if(row.depth() == 1){
    				state.expandNode(sampleTreeBinding, (TreeRowKey)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.

  • 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

     		
    com.demo.CustomViewHandler
    

    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.

        
              Hello Panel    
          
    

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

    **Example 2**

                        
            #{t:call(session, 'org.apache.catalina.session.StandardSessionFacade', 'removeAttribute', t:params(t:param(item,'')))}      
        
    

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

        	
    		call
    		util.Functions
    		java.lang.Object call(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object[])
    	
    	
    		param
    		.util.Functions
    		java.lang.String param(java.lang.Object, java.lang.String)
    		
    	
    	
    		params
    		util.Functions
    		java.lang.Object[] params(java.lang.String)
    		
    

    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 alliasMap;
    	static{
    		alliasMap=new HashMap();
    		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){
    		// (?<=)\s*(?=)\\s*(?=-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 -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, 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 getRegisteredBeans(ScopeType scopeType){
    		FacesContext facesContext=FacesContext.getCurrentInstance();
    		ApplicationAssociate application = ApplicationAssociate.getInstance(facesContext.getExternalContext());
    		BeanManager  beanManager = application.getBeanManager();
    		Map beanMap=beanManager.getRegisteredBeans();
    		Set>beanEntries=beanMap.entrySet();
    		List registeredBeans=new ArrayList();
    		for(Entry 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 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;
    	}
    }
    
    
  • 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 resources=new HashMap();
    	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
    

    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.

      
      
    	
    	
    	
      
    

    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