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  import javax.el.ELException;
28  import javax.el.VariableMapper;
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  import org.apache.myfaces.view.facelets.AbstractFaceletContext;
39  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
40  import org.apache.myfaces.view.facelets.TemplateClient;
41  import org.apache.myfaces.view.facelets.el.VariableMapperWrapper;
42  import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
43  import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
44  
45  /**
46   * The decorate tag acts the same as a composition tag, but it will not trim 
47   * everything outside of it. This is useful in cases where you have a list of 
48   * items in a document, which you would like to be decorated or framed.
49   *  
50   * The sum of it all is that you can take any element in the document and decorate 
51   * it with some external logic as provided by the template.
52   * 
53   * NOTE: This implementation is provided for compatibility reasons and
54   * it is considered faulty. It is enabled using
55   * org.apache.myfaces.STRICT_JSF_2_FACELETS_COMPATIBILITY web config param.
56   * Don't use it if EL expression caching is enabled.
57   * 
58   * @author Jacob Hookom
59   * @version $Id: DecorateHandler.java,v 1.16 2008/07/13 19:01:41 rlubke Exp $
60   */
61  //@JSFFaceletTag(name="ui:decorate")
62  public final class LegacyDecorateHandler extends TagHandler implements TemplateClient
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 LegacyParamHandler[] _params;
80  
81      /**
82       * @param config
83       */
84      public LegacyDecorateHandler(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<LegacyParamHandler> params = TagHandlerUtils.findNextByType(nextHandler, 
100                 LegacyParamHandler.class);
101         if (!params.isEmpty())
102         {
103             int i = 0;
104             _params = new LegacyParamHandler[params.size()];
105             for (LegacyParamHandler 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     @Override
123     public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException,
124             ELException
125     {
126         VariableMapper orig = ctx.getVariableMapper();
127         AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
128         actx.pushClient(this);
129 
130         if (_params != null)
131         {
132             VariableMapper vm = new VariableMapperWrapper(orig);
133             ctx.setVariableMapper(vm);
134             for (int i = 0; i < _params.length; i++)
135             {
136                 _params[i].apply(ctx, parent);
137             }
138         }
139 
140         FaceletCompositionContext fcc = FaceletCompositionContext.getCurrentInstance(ctx);
141         String path;
142         boolean markInitialState = false;
143         if (!_template.isLiteral())
144         {
145             String uniqueId = actx.generateUniqueFaceletTagId(fcc.startComponentUniqueIdSection(), tagId);
146             //path = getTemplateValue(actx, fcc, parent, uniqueId);
147             String restoredPath = (String) ComponentSupport.restoreInitialTagState(ctx, fcc, parent, uniqueId);
148             if (restoredPath != null)
149             {
150                 // If is not restore view phase, the path value should be
151                 // evaluated and if is not equals, trigger markInitialState stuff.
152                 if (!PhaseId.RESTORE_VIEW.equals(ctx.getFacesContext().getCurrentPhaseId()))
153                 {
154                     path = this._template.getValue(ctx);
155                     if (path == null || path.length() == 0)
156                     {
157                         return;
158                     }
159                     if (!path.equals(restoredPath))
160                     {
161                         markInitialState = true;
162                     }
163                 }
164                 else
165                 {
166                     path = restoredPath;
167                 }
168             }
169             else
170             {
171                 //No state restored, calculate path
172                 path = this._template.getValue(ctx);
173             }
174             ComponentSupport.saveInitialTagState(ctx, fcc, parent, uniqueId, path);
175         }
176         else
177         {
178             path = _template.getValue(ctx);
179         }
180         try
181         {
182             try
183             {
184                 boolean oldMarkInitialState = false;
185                 Boolean isBuildingInitialState = null;
186                 if (markInitialState)
187                 {
188                     //set markInitialState flag
189                     oldMarkInitialState = fcc.isMarkInitialState();
190                     fcc.setMarkInitialState(true);
191                     isBuildingInitialState = (Boolean) ctx.getFacesContext().getAttributes().put(
192                             StateManager.IS_BUILDING_INITIAL_STATE, Boolean.TRUE);
193                 }
194                 try
195                 {
196                     ctx.includeFacelet(parent, path);
197                 }
198                 finally
199                 {
200                     if (markInitialState)
201                     {
202                         //unset markInitialState flag
203                         if (isBuildingInitialState == null)
204                         {
205                             ctx.getFacesContext().getAttributes().remove(
206                                     StateManager.IS_BUILDING_INITIAL_STATE);
207                         }
208                         else
209                         {
210                             ctx.getFacesContext().getAttributes().put(
211                                     StateManager.IS_BUILDING_INITIAL_STATE, isBuildingInitialState);
212                         }
213                         fcc.setMarkInitialState(oldMarkInitialState);
214                     }
215                 }
216             }
217             finally
218             {
219                 ctx.setVariableMapper(orig);
220                 actx.popClient(this);
221             }
222         }
223         finally
224         {
225             if (!_template.isLiteral())
226             {
227                 fcc.endComponentUniqueIdSection();
228             }
229         }
230         if (!_template.isLiteral() && fcc.isUsingPSSOnThisView() && fcc.isRefreshTransientBuildOnPSS() &&
231             !fcc.isRefreshingTransientBuild())
232         {
233             //Mark the parent component to be saved and restored fully.
234             ComponentSupport.markComponentToRestoreFully(ctx.getFacesContext(), parent);
235         }
236         if (!_template.isLiteral() && fcc.isDynamicComponentSection())
237         {
238             ComponentSupport.markComponentToRefreshDynamically(ctx.getFacesContext(), parent);
239         }
240     }
241 
242     @Override
243     public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException, FacesException,
244             FaceletException, ELException
245     {
246         if (name != null)
247         {
248             DefineHandler handler = _handlers.get(name);
249             if (handler != null)
250             {
251                 handler.applyDefinition(ctx, parent);
252                 return true;
253             }
254             else
255             {
256                 return false;
257             }
258         }
259         else
260         {
261             this.nextHandler.apply(ctx, parent);
262             return true;
263         }
264     }
265 }