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.jsf;
20  
21  import java.io.IOException;
22  
23  import javax.el.ValueExpression;
24  import javax.faces.component.UIComponent;
25  import javax.faces.component.behavior.Behavior;
26  import javax.faces.component.behavior.ClientBehavior;
27  import javax.faces.component.behavior.ClientBehaviorHolder;
28  import javax.faces.context.FacesContext;
29  import javax.faces.view.BehaviorHolderAttachedObjectHandler;
30  import javax.faces.view.facelets.BehaviorHandler;
31  import javax.faces.view.facelets.ComponentHandler;
32  import javax.faces.view.facelets.FaceletContext;
33  import javax.faces.view.facelets.MetaRuleset;
34  import javax.faces.view.facelets.TagAttribute;
35  import javax.faces.view.facelets.TagAttributeException;
36  import javax.faces.view.facelets.TagException;
37  import javax.faces.view.facelets.TagHandlerDelegate;
38  
39  import org.apache.myfaces.view.facelets.FaceletCompositionContext;
40  import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
41  import org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler;
42  
43  /**
44   * @author Leonardo Uribe (latest modification by $Author$)
45   * @version $Revision$ $Date$
46   *
47   * @since 2.0
48   */
49  public class BehaviorTagHandlerDelegate extends TagHandlerDelegate implements BehaviorHolderAttachedObjectHandler
50  {
51  
52      private BehaviorHandler _delegate;
53      
54      public BehaviorTagHandlerDelegate(BehaviorHandler delegate)
55      {
56          _delegate = delegate;
57      }
58  
59      @Override
60      public void apply(FaceletContext ctx, UIComponent parent) throws IOException
61      {
62          if (!ComponentHandler.isNew(parent))
63          {
64              return;
65          }
66          // Note that the only contract defined at this moment based on behavior api
67          // is client behavior, so it is enough to cast it here. In the future, new
68          // implementations should be added here.
69          if (parent instanceof ClientBehaviorHolder)
70          {
71              applyAttachedObject(ctx.getFacesContext(), parent);
72          }
73          else if (UIComponent.isCompositeComponent(parent))
74          {
75              FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
76              // It is supposed that for composite components, this tag should
77              // add itself as a target, but note that on whole api does not exists
78              // some tag that expose client behaviors as targets for composite
79              // components. In RI, there exists a tag called composite:clientBehavior,
80              // but does not appear on spec or javadoc, maybe because this could be
81              // understand as an implementation detail, after all there exists a key
82              // called AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY that could be
83              // used to create a tag outside jsf implementation to attach targets.
84              mctx.addAttachedObjectHandler(parent, _delegate);
85          }
86          else
87          {
88              throw new TagException(_delegate.getTag(),
89                      "Parent not composite component or an instance of ClientBehaviorHolder: " + parent);
90          }
91          
92      }
93      
94      protected Behavior createBehavior(FaceletContext ctx)
95      {
96          if (_delegate.getBehaviorId() == null)
97          {
98              throw new TagException(
99                                     _delegate.getTag(),
100                                    "No behavior id defined");
101         }
102         return ctx.getFacesContext().getApplication().createBehavior(_delegate.getBehaviorId());
103     }
104 
105     /**
106      * This tag call _delegate.setAttributes, so the returned MetaRuleset
107      * should ignore attributes that are not supposed to be there like
108      * "binding" and "event"
109      */
110     @Override
111     public MetaRuleset createMetaRuleset(Class type)
112     {
113         MetaRuleset ruleset = new MetaRulesetImpl(_delegate.getTag(), type);
114         ruleset.ignore("binding");
115         ruleset.ignore("event");
116         return ruleset;
117     }
118 
119     /**
120      * Create a ClientBehavior and attach it to the component
121      */
122     public void applyAttachedObject(FacesContext context, UIComponent parent)
123     {
124         // Retrieve the current FaceletContext from FacesContext object
125         FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
126                 FaceletContext.FACELET_CONTEXT_KEY);
127         
128         ValueExpression ve = null;
129         Behavior behavior = null;
130         if (_delegate.getBinding() != null)
131         {
132             ve = _delegate.getBinding().getValueExpression(faceletContext, Behavior.class);
133             behavior = (Behavior) ve.getValue(faceletContext);
134         }
135         if (behavior == null)
136         {
137             behavior = this.createBehavior(faceletContext);
138             if (ve != null)
139             {
140                 ve.setValue(faceletContext, behavior);
141             }
142         }
143         if (behavior == null)
144         {
145             throw new TagException(_delegate.getTag(), "No Validator was created");
146         }
147         _delegate.setAttributes(faceletContext, behavior);
148         
149         if (behavior instanceof ClientBehavior)
150         {
151             // cast to a ClientBehaviorHolder
152             ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
153             
154             // TODO: check if the behavior could be applied to the current parent
155             // For run tests it is not necessary, so we let this one pending.
156 
157             // It is necessary to obtain a event name for add it, so we have to
158             // look first to the defined event name, otherwise take the default from
159             // the holder
160             String eventName = getEventName();
161             if (eventName == null)
162             {
163                 eventName = cvh.getDefaultEventName();
164             }
165             if (eventName == null)
166             {
167                 throw new TagAttributeException(_delegate.getEvent(),
168                         "eventName could not be defined for client behavior "+ behavior.toString());
169             }
170             else if (!cvh.getEventNames().contains(eventName))
171             {
172                 throw new TagAttributeException(_delegate.getEvent(),
173                         "eventName "+eventName+" not found on component instance");
174             }
175             else
176             {
177                 cvh.addClientBehavior(eventName, (ClientBehavior) behavior);
178             }
179             
180             AjaxHandler.registerJsfAjaxDefaultResource(faceletContext, parent);
181         }
182     }
183 
184     public String getFor()
185     {
186         TagAttribute forAttribute = _delegate.getTagAttribute("for");
187         
188         if (forAttribute == null)
189         {
190             return null;
191         }
192         else
193         {
194             return forAttribute.getValue();
195         }
196     }
197 
198     public String getEventName()
199     {
200         return _delegate.getEventName();
201     }
202 
203 }