001/*
002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Jean-Marc Orliaguet, Chalmers
018 *
019 * $Id$
020 */
021
022package org.nuxeo.theme.jsf.component;
023
024import java.io.IOException;
025import java.io.StringWriter;
026import java.util.List;
027import java.util.Map;
028
029import javax.faces.component.UIComponent;
030import javax.faces.component.UIOutput;
031import javax.faces.component.UIViewRoot;
032import javax.faces.context.FacesContext;
033import javax.faces.context.ResponseWriter;
034import javax.faces.view.facelets.Facelet;
035
036import com.sun.faces.application.ApplicationAssociate;
037import com.sun.faces.facelets.impl.DefaultFaceletFactory;
038
039public class UIFragment extends UIOutput {
040
041    final String templateEngine = "jsf-facelets";
042
043    private String uid;
044
045    private String engine;
046
047    private String mode;
048
049    @Override
050    public void encodeAll(final FacesContext context) throws IOException {
051        Map<String, Object> attributes = getAttributes();
052        uid = (String) attributes.get("uid");
053        engine = (String) attributes.get("engine");
054        mode = (String) attributes.get("mode");
055
056        final ResponseWriter response = context.getResponseWriter();
057        final UIViewRoot oldViewRoot = context.getViewRoot();
058
059        // Create a string writer for rendering the view
060        final StringWriter stringWriter = new StringWriter();
061        context.setResponseWriter(response.cloneWithWriter(stringWriter));
062
063        // Set up a transient view root
064        final UIViewRoot viewRoot = new UIViewRoot();
065        viewRoot.setRendererType(oldViewRoot.getRendererType());
066        viewRoot.setRenderKitId(oldViewRoot.getRenderKitId());
067        viewRoot.setViewId(oldViewRoot.getViewId());
068        viewRoot.setLocale(oldViewRoot.getLocale());
069        context.setViewRoot(viewRoot);
070
071        // Render the view
072        final String faceletId = String.format("nxtheme://element/%s/%s/%s/%s", engine, mode, templateEngine, uid);
073        ApplicationAssociate associate = ApplicationAssociate.getCurrentInstance();
074        DefaultFaceletFactory faceletFactory = associate.getFaceletFactory();
075        final Facelet facelet = faceletFactory.getFacelet(context, faceletId);
076        facelet.apply(context, viewRoot);
077        renderChildren(context, viewRoot);
078
079        // Write the rendered view into the response
080        response.write(stringWriter.getBuffer().toString());
081
082        // Restore the response and the original view root
083        context.setResponseWriter(response);
084        context.setViewRoot(oldViewRoot);
085    }
086
087    @Override
088    public boolean isTransient() {
089        // The UIFragment component is created dynamically by the
090        // FragmentTag filter. It must be declared as transient otherwise it
091        // will not be handled correctly by Facelets.
092        return true;
093    }
094
095    private static void renderChildren(FacesContext context, UIComponent component) throws IOException {
096        List<UIComponent> children = component.getChildren();
097        for (Object child : children) {
098            renderChild(context, (UIComponent) child);
099        }
100    }
101
102    private static void renderChild(FacesContext context, UIComponent child) throws IOException {
103        if (child.isRendered()) {
104            child.encodeBegin(context);
105            if (child.getRendersChildren()) {
106                child.encodeChildren(context);
107            } else {
108                renderChildren(context, child);
109            }
110            child.encodeEnd(context);
111        }
112    }
113
114    // Component properties
115    public String getEngine() {
116        return engine;
117    }
118
119    public void setEngine(String engine) {
120        this.engine = engine;
121    }
122
123    public String getMode() {
124        return mode;
125    }
126
127    public void setMode(String mode) {
128        this.mode = mode;
129    }
130
131    public String getUid() {
132        return uid;
133    }
134
135    public void setUid(String uid) {
136        this.uid = uid;
137    }
138}