2 Replies Latest reply on Mar 8, 2007 12:57 PM by Igor Shabalov

    G4jsf and Seam success

    Jason DeTiberus Newbie

      I was able to get G4jsf and Seam running with help from Rob Jellinghaus and a custom Phase Listener.

      The problem I was having was an IllegalStateException, specifically:

      Error call :Error send event to component: java.lang.IllegalStateException: No phase id bound to current thread (make sure you do not have two SeamPhaseListener instances installed)

      The problem ended up being with the interaction of the SeamPhaseListener and the GwtPhaseListener. I solved this by:

      1. Disabling the GwtPhaseListener in gwtjsf.jar/META-INF/faces-config.xml.
      2. Creating a custom phase listener that extends SeamPhaseListener and performs the same tasks as the GwtPhaseListener in addition to the SeamPhaseListener.
      3. Replacing the SeamPhaseListener with the custom phase listener in my project WEB-INF/faces-config.xml




        • 1. Re: G4jsf and Seam success
          Jason DeTiberus Newbie

          Accidentally hit Submit instead of Preview. Here is the custom phase listener:

          package gwtseamtest.seam;
          
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.OutputStream;
          import java.io.StringReader;
          import java.util.Collections;
          import java.util.Enumeration;
          import java.util.HashMap;
          import java.util.Map;
          import java.util.zip.GZIPOutputStream;
          
          import javax.faces.FacesException;
          import javax.faces.context.ExternalContext;
          import javax.faces.context.FacesContext;
          import javax.faces.event.PhaseEvent;
          import javax.servlet.Servlet;
          import javax.servlet.ServletConfig;
          import javax.servlet.ServletContext;
          import javax.servlet.ServletException;
          import javax.servlet.ServletRequest;
          import javax.servlet.ServletResponse;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import javax.xml.parsers.SAXParser;
          import javax.xml.parsers.SAXParserFactory;
          
          import org.ajax4jsf.gwt.client.ComponentEntryPoint;
          import org.ajax4jsf.gwt.server.GwtFacesServlet;
          import org.jboss.seam.contexts.Lifecycle;
          import org.jboss.seam.jsf.SeamPhaseListener;
          import org.jboss.seam.log.LogProvider;
          import org.jboss.seam.log.Logging;
          import org.xml.sax.Attributes;
          import org.xml.sax.InputSource;
          import org.xml.sax.SAXException;
          import org.xml.sax.helpers.DefaultHandler;
          
          /**
           * Manages the Seam and GWT contexts associated with a JSF request.
           *
           * @author Jason DeTiberus
           */
          public class GwtSeamPhaseListener extends SeamPhaseListener {
           private static final long serialVersionUID = 3962145500728890731L;
          
           private static final LogProvider log = Logging.getLogProvider(GwtSeamPhaseListener.class);
          
           public static final String GWT_RESOURCE_PREFIX = "gwt/";
           private static final int BUFFER_SIZE = 1024;
           static protected final long DEFAULT_EXPIRE = 1000L * 60L * 60L * 12L;// 12 Hours
           private Map<String,Servlet> serviceServlets = Collections.synchronizedMap(new HashMap<String,Servlet>());
           private Servlet _defaultSrviceServlet;
          
           /* WebModuleConfigHandler class Taken from GwtPhaseListener written by shura */
           private static final class WebModuleConfigHandler extends DefaultHandler {
           private String _servletClassName = null;
          
           /* (non-Javadoc)
           * @see org.xml.sax.helpers.DefaultHandler#resolveEntity(java.lang.String, java.lang.String)
           */
           public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
           // Dummy resolver - disable all entity references
           return new InputSource(new StringReader(""));
           }
          
           /* (non-Javadoc)
           * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
           */
           public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
           if ("servlet".equals(qName)) {
           _servletClassName = attributes.getValue("class");
           }
           }
          
           /**
           * @return Returns the servletClassName.
           */
           String getServletClassName() {
           return _servletClassName;
           }
           }
          
           /* getServletForModule() taken from GwtPhaseListener written by shura */
           private Servlet getServletForModule(FacesContext context, String moduleName) {
           // First - check for existing instances
           if (serviceServlets.containsKey(moduleName)) {
           log.debug("Found existing servlet for module "+moduleName);
           return (Servlet) serviceServlets.get(moduleName);
           }
           // Second -attempt to read module config and, if in contain servlet
           // definition -
           // create instance and store in Map
           String servletClass = getServletClassForModule(moduleName);
           if(null != servletClass){
           Servlet servlet = createServlet(context,servletClass);
           serviceServlets.put(moduleName,servlet);
           return servlet;
           }
           // last - return default service servlet
           Servlet defaultServiceServlet = getDefaultServiceServlet(context);
           serviceServlets.put(moduleName,defaultServiceServlet);
           return defaultServiceServlet;
           }
          
           /* getServletClassForModule() taken from GwtPhaseListener written by shura */
           private String getServletClassForModule(String moduleName) {
           ClassLoader classLoader = Thread.currentThread()
           .getContextClassLoader();
           String servletClassName = null;
           // for module foo.bar.Module config file will be placed at foo/bar/Module.gwt.xml
           String gwtModuleConfigPath = moduleName.replace('.','/')+".gwt.xml";
           InputStream stream = classLoader.getResourceAsStream(gwtModuleConfigPath);
           if(null != stream){
           // We have module confir to read - parce it for servlen name.
           SAXParserFactory parserFactory = SAXParserFactory.newInstance();
           try {
           SAXParser parser = parserFactory.newSAXParser();
           WebModuleConfigHandler handler = new WebModuleConfigHandler();
           parser.parse(stream,handler);
           servletClassName = handler.getServletClassName();
           } catch (Exception e) {
           log.debug("Exception in parsing web module config "+e.getMessage());
           }
           }
           return servletClassName;
           }
          
           /* createServlet() taken from GwtPhaseListener written by shura */
           private Servlet createServlet(FacesContext context, String className) {
           ClassLoader classLoader = Thread.currentThread()
           .getContextClassLoader();
           try {
           Class clazz = classLoader.loadClass(className);
           Servlet servlet = (Servlet) clazz.newInstance();
           final ServletContext servletContext = (ServletContext) context.getExternalContext()
           .getContext();
           servlet.init(new ServletConfig() {
          
           public String getServletName() {
           return "gwtFacesService";
           }
          
           public ServletContext getServletContext() {
           return servletContext;
           }
          
           public String getInitParameter(String arg0) {
           return null;
           }
          
           public Enumeration getInitParameterNames() {
           return null;
           }
           });
           return servlet;
           } catch (Exception e) {
           e.printStackTrace();
           throw new FacesException("Error to create gwt service servlet", e);
           }
           }
          
           /* getDefaultServiceServlet() taken from GwtPhaseListener written by shura */
           public Servlet getDefaultServiceServlet(FacesContext context) {
           if (_defaultSrviceServlet == null) {
           _defaultSrviceServlet = createServlet(context,
           GwtFacesServlet.class.getName());
           }
           return _defaultSrviceServlet;
           }
          
          
          
           @Override
           public void beforePhase(PhaseEvent event) {
           log.debug("before phase: " + event.getPhaseId());
           Lifecycle.setPhaseId(event.getPhaseId());
          
           /* The following code was taken from beforePhase() in GwtPhaseListener written by shura */
           FacesContext facesContext = event.getFacesContext();
           ExternalContext externalContext = facesContext.getExternalContext();
           String mime = "text/html";
           String resourceName = null;
           // assume that mapping have /faces/* prefix
           String pathInfo = externalContext
           .getRequestPathInfo();
          
           if (null != pathInfo ) {
           if(pathInfo.charAt(0) == '/'){
           pathInfo = pathInfo.substring(1);
           }
           if (pathInfo.startsWith(GWT_RESOURCE_PREFIX) ) {
           resourceName = pathInfo;
           if (pathInfo.endsWith(".js")) {
           mime = "text/javascript";
           } else if (pathInfo.endsWith(".xml")) {
           // xml with module cache entries
           mime = "text/xml";
           } else if (pathInfo.endsWith(".css")) {
           // xml with module cache entries
           mime = "text/css";
           } else if (pathInfo.endsWith(".gif")) {
           mime = "image/gif";
           } else if (pathInfo.endsWith(".jpg")
           || pathInfo.endsWith(".jpeg")) {
           mime = "image/jpeg";
           }
          
           try {
           HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
           ClassLoader loader = Thread.currentThread()
           .getContextClassLoader();
           InputStream in = loader.getResourceAsStream("META-INF/"
           + resourceName);
          
           if (null != in) {
           OutputStream out = response.getOutputStream();
           response.setContentType(mime);
           // Set cachimg/nocaching headers.
          
           if (resourceName.endsWith(".nocache.html")) {
           response.setHeader("Cache-control", "no-cache");
           response.setHeader("Cache-control", "no-store");
           response.setHeader("Pragma", "no-cache");
           response.setIntHeader("Expires", 0);
           } else if (resourceName.contains(".cache.")){
           // TODO - send notmodified if request contain If-Modified-Since
           // ?
           HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
           long ifModifiedSince = request
           .getDateHeader("If-Modified-Since");
           if (ifModifiedSince >= 0) {
           response.setStatus(304);// Not modified
           in.close();
           out.close();
           facesContext.responseComplete();
           return ;
           } else {
           response.setDateHeader("Expires", System
           .currentTimeMillis()
           + DEFAULT_EXPIRE);
           }
           }
           // Set output compression
           if(mime.contains("text") || mime.contains("xml")){
           String encoding = (String) externalContext.getRequestHeaderMap().get("Accept-Encoding");
           if(null != encoding && encoding.contains("gzip")){
           // TODO - use cache ?
           response.setHeader("Content-Encoding","gzip");
           out = new GZIPOutputStream(out,BUFFER_SIZE);
           }
           }
           byte[] buffer = new byte[BUFFER_SIZE];
           int buffersCount = -1;
           int length;
           for (length = in.read(buffer); length > 0; length = in
           .read(buffer)) {
           out.write(buffer, 0, length);
           buffersCount++;
           }
           // For cacheable resources, store size.
           // if(isCacheable()){
           // setContentLength(buffersCount*BUFFER_SIZE+length);
           // }
           in.close();
           out.flush();
           out.close();
           } else {
           response.sendError(404);
           }
           } catch (IOException e) {
           throw new FacesException("Error then send resource", e);
           } finally {
           facesContext.responseComplete();
           }
           }
           }
           /* End code by shura */
          
           // Call the SeamPhaseListener beforePhase()
           super.beforePhase(event);
          
           }
          
           @Override
           public void afterPhase(PhaseEvent event) {
           log.debug("after phase: " + event.getPhaseId());
          
           /* Following code taken from afterPhase() from GwtPhaseListener written by shura */
           FacesContext facesContext = event.getFacesContext();
           ExternalContext externalContext = facesContext.getExternalContext();
           String requestContentType = externalContext.getRequestContentType();
           Map requestParameterMap = externalContext.getRequestParameterMap();
           if (null != requestContentType
           && requestContentType.contains("text/plain")) {
           // GWT module name. Due to differences in browsers and containers, compare with ignore case.
           String module = (String) requestParameterMap.get(ComponentEntryPoint.GWT_MODULE_NAME_PARAMETER);
           Servlet servletForModule;
           if(null != module){
           servletForModule = getServletForModule(facesContext, module);
           } else {
           servletForModule = getDefaultServiceServlet(facesContext);
           }
           try {
           servletForModule.service((ServletRequest) externalContext
           .getRequest(), (ServletResponse) externalContext
           .getResponse());
           } catch (ServletException e) {
           log.info("Servlet exception in GWT service method "+e.getMessage());
           throw new FacesException(
           "Servlet exception in GWT service method", e);
           } catch (IOException e) {
           log.info("IO exception in GWT service method "+e.getMessage());
           throw new FacesException("IO exception in GWT service method",
           e);
           }
           facesContext.responseComplete();
           }
           /* end code by shura */
          
           super.afterPhase(event);
           }
          }
          
          


          • 2. Re: G4jsf and Seam success
            Igor Shabalov Apprentice

            Seems similar to the problem with Seam EL resolver, see

            http://jira.jboss.org/jira/browse/AJSF-6