Seam Mail with JSF 2 / MyFaces

722 views Asked by At

is anyone running Seam Mail (Seam 2.3) with JSF 2 using the MyFaces 2.1.x implementation of JSF?

I can not get Seam Mail to work because Seam's org.jboss.seam.faces.renderer component can not be created. It has a class dependency to com.sun.faces.facelets.Facelet and this class does not exist in MyFaces.

@Scope(ScopeType.STATELESS)
@BypassInterceptors
@Name("org.jboss.seam.faces.renderer")
@AutoCreate
@Install(value = true, precedence = Install.BUILT_IN,
  classDependencies = "com.sun.faces.facelets.Facelet")
public class FaceletsRenderer extends Renderer {
    ...
}

So the following statement fails with an "@In attributes requires non-null value" exception.

@In(create = true)
private Renderer renderer;

What can I do? Should I also add jsf-api from the Mojarra implementation?!

Cheers Frank

1

There are 1 answers

0
Frank On

Ok I fixed it!

I just replaced the buggy Seam FaceletsRenderer by my own component:

@Scope(ScopeType.STATELESS)
@BypassInterceptors
@Name("org.jboss.seam.faces.renderer")
@AutoCreate
@Install(value = true, precedence = Install.APPLICATION)
// dependency to the evil Sun JSF class is removed:
// , classDependencies = "com.sun.faces.facelets.Facelet")
public class FaceletsRenderer extends Renderer {

    /**
     * Render the viewId, anything written to the JSF ResponseWriter is returned
     */
    @Override
    public String render(final String viewId) {
        // call our fixed RendererRequest class instead of the original one.
        de.jw.filesio.webapp.renderer.RendererRequest rendererRequest = new de.jw.filesio.webapp.renderer.RendererRequest(
                viewId);
        try {
            rendererRequest.run();
        } catch (IOException e) {
            throw new RuntimeException("error rendering " + viewId, e);
        }
        return rendererRequest.getOutput();
    }

}

The original RendererRequest class from Seam-Ui is coupled to Sun JSF was well, so you also have to replace it. It is only necessary to fix the method faceletForViewId(String). Here you go:

    /**
     * Get a Facelet for a URL
     */
    protected Facelet faceletForViewId(String viewId) throws IOException {
        URL url = ResourceLoader.instance().getResource(viewId);
        if (url == null) {
            throw new IllegalArgumentException("resource doesn't exist: " + viewId);
        }

        // OLD CODE tightly coupled to Sun JSF
        // return
        // ApplicationAssociate.getCurrentInstance().getFaceletFactory().getFacelet(url);

        // NEW CODE for MyFaces
        // see
        // http://stackoverflow.com/questions/15813582/how-to-programmatically-instantiate-a-composite-component-or-a-tag-component
        FaceletFactory ff = DefaultFaceletFactory.getInstance();
        if (ff == null) {
            FaceletViewDeclarationLanguage vdl = new FaceletViewDeclarationLanguage(facesContext);

            Method createCompiler = null;
            Method createFaceletFactory = null;
            try {
                createCompiler = FaceletViewDeclarationLanguage.class.getDeclaredMethod("createCompiler",
                        FacesContext.class);
                createFaceletFactory = FaceletViewDeclarationLanguage.class.getDeclaredMethod("createFaceletFactory",
                        FacesContext.class, org.apache.myfaces.view.facelets.compiler.Compiler.class);
                createCompiler.setAccessible(true);
                createFaceletFactory.setAccessible(true);
                org.apache.myfaces.view.facelets.compiler.Compiler compiler = (org.apache.myfaces.view.facelets.compiler.Compiler) createCompiler
                        .invoke(vdl, facesContext);
                ff = (FaceletFactory) createFaceletFactory.invoke(vdl, facesContext, compiler);
            } catch (Exception ex) {
                log.error("Error creating FaceletFactory.", ex);
            }

        }

        Facelet facelet = null;
        try {

            facelet = ff.getFacelet(url);

        } catch (Exception ex) {
            log.error("Error creating facelet for url " + url, ex);
        }

        log.debug("Successfully created facelet for " + url + ": " + facelet);

        return facelet;
    }

I hope this helps someone else facing my problem.