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: lu4242 $)
45   * @version $Revision: 964310 $ $Date: 2010-07-15 01:17:19 -0500 (Thu, 15 Jul 2010) $
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(), "Parent not composite component or an instance of ClientBehaviorHolder: " + parent);
89          }
90          
91      }
92      
93      protected Behavior createBehavior(FaceletContext ctx)
94      {
95          if (_delegate.getBehaviorId() == null)
96          {
97              throw new TagException(
98                                     _delegate.getTag(),
99                                     "No behavior id defined");
100         }
101         return ctx.getFacesContext().getApplication().createBehavior(_delegate.getBehaviorId());
102     }
103 
104     /**
105      * This tag call _delegate.setAttributes, so the returned MetaRuleset
106      * should ignore attributes that are not supposed to be there like
107      * "binding" and "event"
108      */
109     @Override
110     public MetaRuleset createMetaRuleset(Class type)
111     {
112         MetaRuleset ruleset = new MetaRulesetImpl(_delegate.getTag(), type);
113         ruleset.ignore("binding");
114         ruleset.ignore("event");
115         return ruleset;
116     }
117 
118     /**
119      * Create a ClientBehavior and attach it to the component
120      */
121     public void applyAttachedObject(FacesContext context, UIComponent parent)
122     {
123         // Retrieve the current FaceletContext from FacesContext object
124         FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
125                 FaceletContext.FACELET_CONTEXT_KEY);
126         
127         ValueExpression ve = null;
128         Behavior behavior = null;
129         if (_delegate.getBinding() != null)
130         {
131             ve = _delegate.getBinding().getValueExpression(faceletContext, Behavior.class);
132             behavior = (Behavior) ve.getValue(faceletContext);
133         }
134         if (behavior == null)
135         {
136             behavior = this.createBehavior(faceletContext);
137             if (ve != null)
138             {
139                 ve.setValue(faceletContext, behavior);
140             }
141         }
142         if (behavior == null)
143         {
144             throw new TagException(_delegate.getTag(), "No Validator was created");
145         }
146         _delegate.setAttributes(faceletContext, behavior);
147         
148         if (behavior instanceof ClientBehavior)
149         {
150             // cast to a ClientBehaviorHolder
151             ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
152             
153             // TODO: check if the behavior could be applied to the current parent
154             // For run tests it is not necessary, so we let this one pending.
155 
156             // It is necessary to obtain a event name for add it, so we have to
157             // look first to the defined event name, otherwise take the default from
158             // the holder
159             String eventName = getEventName();
160             if (eventName == null)
161             {
162                 eventName = cvh.getDefaultEventName();
163             }
164             if (eventName == null)
165             {
166                 throw new TagAttributeException(_delegate.getEvent(), "eventName could not be defined for client behavior "+ behavior.toString());
167             }
168             else if (!cvh.getEventNames().contains(eventName))
169             {
170                 throw new TagAttributeException(_delegate.getEvent(), "eventName "+eventName+" not found on component instance");
171             }
172             else
173             {
174                 cvh.addClientBehavior(eventName, (ClientBehavior) behavior);
175             }
176             
177             AjaxHandler.registerJsfAjaxDefaultResource(faceletContext, parent);
178         }
179     }
180 
181     public String getFor()
182     {
183         TagAttribute forAttribute = _delegate.getTagAttribute("for");
184         
185         if (forAttribute == null)
186         {
187             return null;
188         }
189         else
190         {
191             return forAttribute.getValue();
192         }
193     }
194 
195     public String getEventName()
196     {
197         return _delegate.getEventName();
198     }
199 
200 }