View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.view.facelets.tag.ui;
20  
21  import java.io.IOException;
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.logging.Level;
26  import java.util.logging.Logger;
27  
28  import javax.el.ELException;
29  import javax.faces.FacesException;
30  import javax.faces.application.StateManager;
31  import javax.faces.component.UIComponent;
32  import javax.faces.event.PhaseId;
33  import javax.faces.view.facelets.FaceletContext;
34  import javax.faces.view.facelets.FaceletException;
35  import javax.faces.view.facelets.TagAttribute;
36  import javax.faces.view.facelets.TagConfig;
37  import javax.faces.view.facelets.TagHandler;
38  
39  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
40  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
41  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
42  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
43  import org.apache.myfaces.view.facelets.TemplateClient;
44  import org.apache.myfaces.view.facelets.tag.ComponentContainerHandler;
45  import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
46  import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
47  
48  /**
49   * The decorate tag acts the same as a composition tag, but it will not trim 
50   * everything outside of it. This is useful in cases where you have a list of 
51   * items in a document, which you would like to be decorated or framed.
52   *  
53   * The sum of it all is that you can take any element in the document and decorate 
54   * it with some external logic as provided by the template.
55   * 
56   * TODO: REFACTOR - This class could easily use a common parent with CompositionHandler
57   * 
58   * @author Jacob Hookom
59   * @version $Id: DecorateHandler.java 1306698 2012-03-29 03:13:06Z lu4242 $
60   */
61  @JSFFaceletTag(name="ui:decorate")
62  public final class DecorateHandler extends TagHandler implements TemplateClient, ComponentContainerHandler
63  {
64  
65      //private static final Logger log = Logger.getLogger("facelets.tag.ui.decorate");
66      private static final Logger log = Logger.getLogger(DecorateHandler.class.getName());
67  
68      /**
69       * The resolvable URI of the template to use. The content within the decorate tag 
70       * will be used in populating the template specified.
71       */
72      @JSFFaceletAttribute(
73              name="template",
74              className="javax.el.ValueExpression",
75              deferredValueType="java.lang.String")
76      private final TagAttribute _template;
77  
78      private final Map<String, DefineHandler> _handlers;
79  
80      private final ParamHandler[] _params;
81  
82      /**
83       * @param config
84       */
85      public DecorateHandler(TagConfig config)
86      {
87          super(config);
88          _template = getRequiredAttribute("template");
89          _handlers = new HashMap<String, DefineHandler>();
90  
91          for (DefineHandler handler : TagHandlerUtils.findNextByType(nextHandler, DefineHandler.class))
92          {
93              _handlers.put(handler.getName(), handler);
94              if (log.isLoggable(Level.FINE))
95              {
96                  log.fine(tag + " found Define[" + handler.getName() + "]");
97              }
98          }
99  
100         Collection<ParamHandler> params = TagHandlerUtils.findNextByType(nextHandler, ParamHandler.class);
101         if (!params.isEmpty())
102         {
103             int i = 0;
104             _params = new ParamHandler[params.size()];
105             for (ParamHandler handler : params)
106             {
107                 _params[i++] = handler;
108             }
109         }
110         else
111         {
112             _params = null;
113         }
114     }
115 
116     /*
117      * (non-Javadoc)
118      * 
119      * @see javax.faces.view.facelets.FaceletHandler#apply(javax.faces.view.facelets.FaceletContext,
120      * javax.faces.component.UIComponent)
121      */
122     public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
123             ELException
124     {
125         //VariableMapper orig = ctx.getVariableMapper();
126         //if (_params != null)
127         //{
128         //    VariableMapper vm = new VariableMapperWrapper(orig);
129         //    ctx.setVariableMapper(vm);
130         //    for (int i = 0; i < _params.length; i++)
131         //    {
132         //        _params[i].apply(ctx, parent);
133         //    }
134         //}
135 
136         AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
137         actx.pushClient(this);
138 
139         if (_params != null)
140         {
141             //VariableMapper vm = new VariableMapperWrapper(orig);
142             //ctx.setVariableMapper(vm);
143             for (int i = 0; i < _params.length; i++)
144             {
145                 _params[i].apply(ctx, parent);
146             }
147         }
148 
149         FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
150         String path;
151         boolean markInitialState = false;
152         if (!_template.isLiteral())
153         {
154             String uniqueId = fcc.startComponentUniqueIdSection();
155             //path = getTemplateValue(actx, fcc, parent, uniqueId);
156             String restoredPath = (String) ComponentSupport.restoreInitialTagState(ctx, fcc, parent, uniqueId);
157             if (restoredPath != null)
158             {
159                 // If is not restore view phase, the path value should be
160                 // evaluated and if is not equals, trigger markInitialState stuff.
161                 if (!PhaseId.RESTORE_VIEW.equals(ctx.getFacesContext().getCurrentPhaseId()))
162                 {
163                     path = this._template.getValue(ctx);
164                     if (path == null || path.length() == 0)
165                     {
166                         return;
167                     }
168                     if (!path.equals(restoredPath))
169                     {
170                         markInitialState = true;
171                     }
172                 }
173                 else
174                 {
175                     path = restoredPath;
176                 }
177             }
178             else
179             {
180                 //No state restored, calculate path
181                 path = this._template.getValue(ctx);
182             }
183             ComponentSupport.saveInitialTagState(ctx, fcc, parent, uniqueId, path);
184         }
185         else
186         {
187             path = _template.getValue(ctx);
188         }
189         try
190         {
191             boolean oldMarkInitialState = false;
192             Boolean isBuildingInitialState = null;
193             if (markInitialState)
194             {
195                 //set markInitialState flag
196                 oldMarkInitialState = fcc.isMarkInitialState();
197                 fcc.setMarkInitialState(true);
198                 isBuildingInitialState = (Boolean) ctx.getFacesContext().getAttributes().put(
199                         "javax.faces.IS_BUILDING_INITIAL_STATE", Boolean.TRUE);
200             }
201             try
202             {
203                 ctx.includeFacelet(parent, path);
204             }
205             finally
206             {
207                 if (markInitialState)
208                 {
209                     //unset markInitialState flag
210                     if (isBuildingInitialState == null)
211                     {
212                         ctx.getFacesContext().getAttributes().remove(
213                                 "javax.faces.IS_BUILDING_INITIAL_STATE");
214                     }
215                     else
216                     {
217                         ctx.getFacesContext().getAttributes().put(
218                                 "javax.faces.IS_BUILDING_INITIAL_STATE", isBuildingInitialState);
219                     }
220                     fcc.setMarkInitialState(oldMarkInitialState);
221                 }
222             }
223         }
224         finally
225         {
226             //ctx.setVariableMapper(orig);
227             actx.popClient(this);
228         }
229         if (!_template.isLiteral())
230         {
231             fcc.endComponentUniqueIdSection();
232         }
233         if (!_template.isLiteral() && fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() &&
234             !fcc.isRefreshingTransientBuild())
235         {
236             //Mark the parent component to be saved and restored fully.
237             ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
238         }
239     }
240 
241     public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException, FacesException,
242             FaceletException, ELException
243     {
244         if (name != null)
245         {
246             DefineHandler handler = _handlers.get(name);
247             if (handler != null)
248             {
249                 handler.applyDefinition(ctx, parent);
250                 return true;
251             }
252             else
253             {
254                 return false;
255             }
256         }
257         else
258         {
259             this.nextHandler.apply(ctx, parent);
260             return true;
261         }
262     }
263 }