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$
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(DecorateHandler.class.getName());
66  
67      /**
68       * The resolvable URI of the template to use. The content within the decorate tag 
69       * will be used in populating the template specified.
70       */
71      @JSFFaceletAttribute(
72              name="template",
73              className="javax.el.ValueExpression",
74              deferredValueType="java.lang.String")
75      private final TagAttribute _template;
76  
77      private final Map<String, DefineHandler> _handlers;
78  
79      private final ParamHandler[] _params;
80  
81      /**
82       * @param config
83       */
84      public DecorateHandler(TagConfig config)
85      {
86          super(config);
87          _template = getRequiredAttribute("template");
88          _handlers = new HashMap<String, DefineHandler>();
89  
90          for (DefineHandler handler : TagHandlerUtils.findNextByType(nextHandler, DefineHandler.class))
91          {
92              _handlers.put(handler.getName(), handler);
93              if (log.isLoggable(Level.FINE))
94              {
95                  log.fine(tag + " found Define[" + handler.getName() + "]");
96              }
97          }
98  
99          Collection<ParamHandler> params = TagHandlerUtils.findNextByType(nextHandler, ParamHandler.class);
100         if (!params.isEmpty())
101         {
102             int i = 0;
103             _params = new ParamHandler[params.size()];
104             for (ParamHandler handler : params)
105             {
106                 _params[i++] = handler;
107             }
108         }
109         else
110         {
111             _params = null;
112         }
113     }
114 
115     /*
116      * (non-Javadoc)
117      * 
118      * @see javax.faces.view.facelets.FaceletHandler#apply(javax.faces.view.facelets.FaceletContext,
119      * javax.faces.component.UIComponent)
120      */
121     @Override
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         FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
139         String uniqueId = null;
140         try
141         {
142             if (!_template.isLiteral())
143             {
144                 uniqueId = actx.generateUniqueFaceletTagId(
145                     fcc.startComponentUniqueIdSection(), tagId);
146             }
147             else if (_params != null)
148             {
149                 uniqueId = actx.generateUniqueFaceletTagId(
150                     fcc.generateUniqueComponentId(), tagId);
151             }
152             if (_params != null)
153             {
154                 //VariableMapper vm = new VariableMapperWrapper(orig);
155                 //ctx.setVariableMapper(vm);
156                 for (int i = 0; i < _params.length; i++)
157                 {
158                     _params[i].apply(ctx, parent, _params[i].getName(ctx), _params[i].getValue(ctx), uniqueId);
159                 }
160             }
161 
162             String path;
163             boolean markInitialState = false;
164             if (!_template.isLiteral())
165             {
166                 //String uniqueId = fcc.startComponentUniqueIdSection();
167                 //path = getTemplateValue(actx, fcc, parent, uniqueId);
168                 String restoredPath = (String) ComponentSupport.restoreInitialTagState(ctx, fcc, parent, uniqueId);
169                 if (restoredPath != null)
170                 {
171                     // If is not restore view phase, the path value should be
172                     // evaluated and if is not equals, trigger markInitialState stuff.
173                     if (!PhaseId.RESTORE_VIEW.equals(ctx.getFacesContext().getCurrentPhaseId()))
174                     {
175                         path = this._template.getValue(ctx);
176                         if (path == null || path.length() == 0)
177                         {
178                             return;
179                         }
180                         if (!path.equals(restoredPath))
181                         {
182                             markInitialState = true;
183                         }
184                     }
185                     else
186                     {
187                         path = restoredPath;
188                     }
189                 }
190                 else
191                 {
192                     //No state restored, calculate path
193                     path = this._template.getValue(ctx);
194                 }
195                 ComponentSupport.saveInitialTagState(ctx, fcc, parent, uniqueId, path);
196             }
197             else
198             {
199                 path = _template.getValue(ctx);
200             }
201             try
202             {
203                 boolean oldMarkInitialState = false;
204                 Boolean isBuildingInitialState = null;
205                 if (markInitialState)
206                 {
207                     //set markInitialState flag
208                     oldMarkInitialState = fcc.isMarkInitialState();
209                     fcc.setMarkInitialState(true);
210                     isBuildingInitialState = (Boolean) ctx.getFacesContext().getAttributes().put(
211                             StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
212                 }
213                 try
214                 {
215                     ctx.includeFacelet(parent, path);
216                 }
217                 finally
218                 {
219                     if (markInitialState)
220                     {
221                         //unset markInitialState flag
222                         if (isBuildingInitialState == null)
223                         {
224                             ctx.getFacesContext().getAttributes().remove(
225                                     StateManager.IS_BUILDING_INITIAL_STATE);
226                         }
227                         else
228                         {
229                             ctx.getFacesContext().getAttributes().put(
230                                     StateManager.IS_BUILDING_INITIAL_STATE, isBuildingInitialState);
231                         }
232                         fcc.setMarkInitialState(oldMarkInitialState);
233                     }
234                 }
235             }
236             finally
237             {
238                 //ctx.setVariableMapper(orig);
239                 actx.popClient(this);
240             }
241         }
242         finally
243         {
244             if (!_template.isLiteral())
245             {
246                 fcc.endComponentUniqueIdSection();
247             }
248         }
249         if (!_template.isLiteral() && fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() &&
250             !fcc.isRefreshingTransientBuild())
251         {
252             //Mark the parent component to be saved and restored fully.
253             ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
254         }
255         if (!_template.isLiteral() && fcc.isDynamicComponentSection())
256         {
257             ComponentSupport.markComponentToRefreshDynamically(ctx.getFacesContext(), parent);
258         }
259     }
260 
261     @Override
262     public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException, FacesException,
263             FaceletException, ELException
264     {
265         if (name != null)
266         {
267             DefineHandler handler = _handlers.get(name);
268             if (handler != null)
269             {
270                 handler.applyDefinition(ctx, parent);
271                 return true;
272             }
273             else
274             {
275                 return false;
276             }
277         }
278         else
279         {
280             this.nextHandler.apply(ctx, parent);
281             return true;
282         }
283     }
284 }