001/*
002 * (C) Copyright 2006-2007 Nuxeo SAS <http://nuxeo.com> and others
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Jean-Marc Orliaguet, Chalmers
011 *
012 * $Id$
013 */
014
015package org.nuxeo.theme.jsf.component;
016
017import java.io.IOException;
018import java.io.StringWriter;
019import java.util.List;
020import java.util.Map;
021
022import javax.faces.component.UIComponent;
023import javax.faces.component.UIOutput;
024import javax.faces.component.UIViewRoot;
025import javax.faces.context.FacesContext;
026import javax.faces.context.ResponseWriter;
027import javax.faces.view.facelets.Facelet;
028
029import com.sun.faces.application.ApplicationAssociate;
030import com.sun.faces.facelets.impl.DefaultFaceletFactory;
031
032public class UIFragment extends UIOutput {
033
034    final String templateEngine = "jsf-facelets";
035
036    private String uid;
037
038    private String engine;
039
040    private String mode;
041
042    @Override
043    public void encodeAll(final FacesContext context) throws IOException {
044        Map<String, Object> attributes = getAttributes();
045        uid = (String) attributes.get("uid");
046        engine = (String) attributes.get("engine");
047        mode = (String) attributes.get("mode");
048
049        final ResponseWriter response = context.getResponseWriter();
050        final UIViewRoot oldViewRoot = context.getViewRoot();
051
052        // Create a string writer for rendering the view
053        final StringWriter stringWriter = new StringWriter();
054        context.setResponseWriter(response.cloneWithWriter(stringWriter));
055
056        // Set up a transient view root
057        final UIViewRoot viewRoot = new UIViewRoot();
058        viewRoot.setRendererType(oldViewRoot.getRendererType());
059        viewRoot.setRenderKitId(oldViewRoot.getRenderKitId());
060        viewRoot.setViewId(oldViewRoot.getViewId());
061        viewRoot.setLocale(oldViewRoot.getLocale());
062        context.setViewRoot(viewRoot);
063
064        // Render the view
065        final String faceletId = String.format("nxtheme://element/%s/%s/%s/%s", engine, mode, templateEngine, uid);
066        ApplicationAssociate associate = ApplicationAssociate.getCurrentInstance();
067        DefaultFaceletFactory faceletFactory = associate.getFaceletFactory();
068        final Facelet facelet = faceletFactory.getFacelet(context, faceletId);
069        facelet.apply(context, viewRoot);
070        renderChildren(context, viewRoot);
071
072        // Write the rendered view into the response
073        response.write(stringWriter.getBuffer().toString());
074
075        // Restore the response and the original view root
076        context.setResponseWriter(response);
077        context.setViewRoot(oldViewRoot);
078    }
079
080    @Override
081    public boolean isTransient() {
082        // The UIFragment component is created dynamically by the
083        // FragmentTag filter. It must be declared as transient otherwise it
084        // will not be handled correctly by Facelets.
085        return true;
086    }
087
088    private static void renderChildren(FacesContext context, UIComponent component) throws IOException {
089        List<UIComponent> children = component.getChildren();
090        for (Object child : children) {
091            renderChild(context, (UIComponent) child);
092        }
093    }
094
095    private static void renderChild(FacesContext context, UIComponent child) throws IOException {
096        if (child.isRendered()) {
097            child.encodeBegin(context);
098            if (child.getRendersChildren()) {
099                child.encodeChildren(context);
100            } else {
101                renderChildren(context, child);
102            }
103            child.encodeEnd(context);
104        }
105    }
106
107    // Component properties
108    public String getEngine() {
109        return engine;
110    }
111
112    public void setEngine(String engine) {
113        this.engine = engine;
114    }
115
116    public String getMode() {
117        return mode;
118    }
119
120    public void setMode(String mode) {
121        this.mode = mode;
122    }
123
124    public String getUid() {
125        return uid;
126    }
127
128    public void setUid(String uid) {
129        this.uid = uid;
130    }
131}