001/**
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *  http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014
015package org.nuxeo.theme.jsf.facelets;
016
017import java.io.IOException;
018import java.net.URL;
019import java.util.ArrayList;
020import java.util.HashMap;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Map;
024
025import javax.el.ELException;
026import javax.el.VariableMapper;
027import javax.faces.FacesException;
028import javax.faces.component.UIComponent;
029import javax.faces.context.ExternalContext;
030import javax.faces.context.FacesContext;
031import javax.faces.view.facelets.FaceletContext;
032import javax.faces.view.facelets.FaceletException;
033import javax.faces.view.facelets.TagAttribute;
034import javax.faces.view.facelets.TagConfig;
035import javax.servlet.http.HttpServletRequest;
036
037import org.apache.commons.logging.Log;
038import org.apache.commons.logging.LogFactory;
039import org.nuxeo.ecm.platform.ui.web.util.BaseURL;
040import org.nuxeo.theme.ApplicationType;
041import org.nuxeo.theme.Manager;
042import org.nuxeo.theme.NegotiationDef;
043import org.nuxeo.theme.jsf.negotiation.JSFNegotiator;
044import org.nuxeo.theme.negotiation.NegotiationException;
045import org.nuxeo.theme.types.TypeFamily;
046
047import com.sun.faces.facelets.FaceletContextImplBase;
048import com.sun.faces.facelets.TemplateClient;
049import com.sun.faces.facelets.el.VariableMapperWrapper;
050import com.sun.faces.facelets.tag.TagHandlerImpl;
051import com.sun.faces.facelets.tag.ui.DefineHandler;
052import com.sun.faces.facelets.tag.ui.ParamHandler;
053
054/**
055 * @author Jacob Hookom
056 * @version $Id: CompositionHandler.java,v 1.15 2009/02/02 22:58:59 driscoll Exp $
057 */
058public final class CompositionHandler extends TagHandlerImpl implements TemplateClient {
059
060    private static final Log log = LogFactory.getLog(CompositionHandler.class);
061
062    public static final String Name = "theme";
063
064    protected final Map<String, DefineHandler> handlers;
065
066    protected final TagAttribute strategyAttribute;
067
068    protected final ParamHandler[] params;
069
070    static {
071        Manager.initializeProtocols();
072    }
073
074    /**
075     * @param config
076     */
077    public CompositionHandler(TagConfig config) {
078        super(config);
079
080        handlers = new HashMap<String, DefineHandler>();
081        Iterator<DefineHandler> itr = this.findNextByType(DefineHandler.class);
082        DefineHandler d = null;
083        while (itr.hasNext()) {
084            d = itr.next();
085            this.handlers.put(d.getName(), d);
086            log.debug(tag + " found Define[" + d.getName() + "]");
087        }
088        final List paramC = new ArrayList();
089        itr = this.findNextByType(ParamHandler.class);
090        while (itr.hasNext()) {
091            paramC.add(itr.next());
092        }
093        if (paramC.size() > 0) {
094            this.params = new ParamHandler[paramC.size()];
095            for (int i = 0; i < this.params.length; i++) {
096                this.params[i] = (ParamHandler) paramC.get(i);
097            }
098        } else {
099            this.params = null;
100        }
101
102        strategyAttribute = getAttribute("strategy");
103    }
104
105    /*
106     * (non-Javadoc)
107     * @see com.sun.facelets.FaceletHandler#apply(com.sun.facelets.FaceletContext, javax.faces.component.UIComponent)
108     */
109    @Override
110    public void apply(FaceletContext ctxObj, UIComponent parent) throws IOException, FacesException, FaceletException,
111            ELException {
112        FaceletContextImplBase ctx = (FaceletContextImplBase) ctxObj;
113
114        VariableMapper orig = ctx.getVariableMapper();
115        if (this.params != null) {
116            VariableMapper vm = new VariableMapperWrapper(orig);
117            ctx.setVariableMapper(vm);
118            for (int i = 0; i < this.params.length; i++) {
119                this.params[i].apply(ctx, parent);
120            }
121        }
122
123        ctx.extendClient(this);
124
125        try {
126            final FacesContext facesContext = ctx.getFacesContext();
127
128            // Get the negotiation strategy
129            final ExternalContext external = facesContext.getExternalContext();
130            final Map<String, Object> requestMap = external.getRequestMap();
131            final String root = external.getRequestContextPath();
132            final ApplicationType application = (ApplicationType) Manager.getTypeRegistry().lookup(
133                    TypeFamily.APPLICATION, root);
134            String strategy = null;
135            if (application != null) {
136                final NegotiationDef negotiation = application.getNegotiation();
137                if (negotiation != null) {
138                    requestMap.put("org.nuxeo.theme.default.theme", negotiation.getDefaultTheme());
139                    requestMap.put("org.nuxeo.theme.default.engine", negotiation.getDefaultEngine());
140                    requestMap.put("org.nuxeo.theme.default.perspective", negotiation.getDefaultPerspective());
141                    strategy = negotiation.getStrategy();
142                }
143            }
144            // override startegy if defined
145            if (strategyAttribute != null) {
146                strategy = strategyAttribute.getValue(ctx);
147            }
148            String contextPath = BaseURL.getContextPath();
149            if (strategy == null) {
150                log.error("Could not obtain the negotiation strategy for " + root);
151                external.redirect(contextPath + "/nxthemes/error/negotiationStrategyNotSet.faces");
152
153            } else {
154                try {
155                    final String spec = new JSFNegotiator(strategy, facesContext,
156                            (HttpServletRequest) external.getRequest()).getSpec();
157                    final URL themeUrl = new URL(spec);
158                    requestMap.put("org.nuxeo.theme.url", themeUrl);
159                    ctx.includeFacelet(parent, themeUrl);
160                } catch (NegotiationException e) {
161                    log.error("Could not get default negotiation settings.", e);
162                    external.redirect(contextPath + "/nxthemes/error/negotiationDefaultValuesNotSet.faces");
163                }
164            }
165
166        } finally {
167            ctx.popClient(this);
168            ctx.setVariableMapper(orig);
169        }
170
171    }
172
173    @Override
174    public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException, FacesException,
175            FaceletException, ELException {
176        if (name != null) {
177            if (this.handlers == null) {
178                return false;
179            }
180            DefineHandler handler = this.handlers.get(name);
181            if (handler != null) {
182                handler.applyDefinition(ctx, parent);
183                return true;
184            } else {
185                return false;
186            }
187        } else {
188            this.nextHandler.apply(ctx, parent);
189            return true;
190        }
191    }
192
193}