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.composite;
20  
21  import java.beans.BeanDescriptor;
22  import java.beans.PropertyDescriptor;
23  import java.beans.SimpleBeanInfo;
24  import java.io.Externalizable;
25  import java.io.IOException;
26  import java.io.ObjectInput;
27  import java.io.ObjectOutput;
28  import java.util.ArrayList;
29  import java.util.Enumeration;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import javax.faces.view.AttachedObjectTarget;
35  
36  /**
37   * Implementation of BeanInfo object used by composite components.
38   * Instances of this class are found on component attribute map
39   * using the key UIComponent.BEANINFO_KEY.
40   * 
41   * The points to take into account for implement this class are this:
42   * 
43   * - The following tags:
44   * 
45   *    composite:interface
46   *    composite:attribute
47   *    composite:facet
48   *    composite:valueHolder
49   *    composite:editableValueHolder
50   *    composite:actionSource
51   *    composite:extension
52   *    
53   *    must deal with this class, so it is expected methods that manipulate
54   *    data here are called from their tag handlers.
55   *    
56   * - ViewDeclarationLanguage.retargetAttachedObjects and 
57   *   ViewDeclarationLanguage.retargetMethodExpressions read information
58   *   contained here
59   * 
60   * - This object goes on attribute map, so it is necessary that
61   *   this instance should be Serializable. But note that BeanDescriptor
62   *   is not, so the best way is implements Externalizable interface
63   *   and implement its methods. The only information we need to be Serializable
64   *   from this object is the related to BeanDescriptor, but note that
65   *   serialize information used only in build view time ( like
66   *   AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY list) is not required 
67   *   and could cause serialization exceptions. 
68   * 
69   * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
70   * @version $Revision: 881558 $ $Date: 2009-11-17 16:55:58 -0500 (Tue, 17 Nov 2009) $
71   */
72  public class CompositeComponentBeanInfo extends SimpleBeanInfo 
73      implements Externalizable
74  {
75  
76      /**
77       * Most of the information here are filled on composite:interface tag.
78       * It is also expected that AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY
79       * key is used by other handlers inside the inner map for this BeanDescriptor.
80       */
81      private BeanDescriptor _descriptor;
82      
83      /**
84       * ViewDeclarationLanguage.retargetMethodExpressions algorithm
85       * suggest that every attribute should have a PropertyDescriptor
86       * object defined for it. So, this list is expected to be filled
87       * on composite:attribute tag. This list is used only when
88       * retargetAttachedObjects and retargetAttachedMethodExpressions,
89       * and this methods are called only on buildView time, so
90       * we don't need to Serialize this list. 
91       */
92      private List<PropertyDescriptor> _propertyDescriptors;
93      
94      private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = new PropertyDescriptor[0];
95      
96      private PropertyDescriptor[] _propertyDescriptorsArray;
97      
98      /**
99       * Used for Serialization
100      */
101     public CompositeComponentBeanInfo()
102     {
103         super();
104     }
105     
106     public CompositeComponentBeanInfo(BeanDescriptor descriptor)
107     {
108         super();
109         _descriptor = descriptor;
110     }
111     
112     @Override
113     public BeanDescriptor getBeanDescriptor()
114     {
115         return _descriptor;
116     }
117 
118     @Override
119     public PropertyDescriptor[] getPropertyDescriptors()
120     {
121         if (_propertyDescriptors == null)
122         {
123             return EMPTY_PROPERTY_DESCRIPTOR_ARRAY;
124         }
125         else
126         {
127             if (_propertyDescriptorsArray == null)
128             {
129                 _propertyDescriptorsArray = _propertyDescriptors.toArray(
130                         new PropertyDescriptor[_propertyDescriptors.size()]); 
131             }
132             else if (_propertyDescriptorsArray.length != _propertyDescriptors.size())
133             {
134                 _propertyDescriptorsArray = _propertyDescriptors.toArray(
135                         new PropertyDescriptor[_propertyDescriptors.size()]);
136             }
137             return _propertyDescriptorsArray; 
138         }
139     }
140 
141     public List<PropertyDescriptor> getPropertyDescriptorsList()
142     {
143         if (_propertyDescriptors == null)
144         {
145             _propertyDescriptors = new ArrayList<PropertyDescriptor>();
146         }
147         return _propertyDescriptors;
148     }
149 
150     public void setPropertyDescriptorsList(List<PropertyDescriptor> descriptors)
151     {
152         _propertyDescriptors = descriptors;
153     }
154 
155     public void readExternal(ObjectInput in) throws IOException,
156             ClassNotFoundException
157     {
158         Class beanClass = (Class) in.readObject();
159         Class customizerClass = (Class) in.readObject();
160         if (customizerClass == null)
161         {
162             _descriptor = new BeanDescriptor(beanClass);
163         }
164         else
165         {
166             _descriptor = new BeanDescriptor(beanClass, customizerClass);
167         }
168         _descriptor.setDisplayName((String) in.readObject());
169         _descriptor.setExpert(in.readBoolean());
170         _descriptor.setName((String) in.readObject());
171         _descriptor.setPreferred(in.readBoolean());
172         _descriptor.setShortDescription((String) in.readObject());
173         
174         Map<String,Object> map = (Map) in.readObject();
175         
176         for (Map.Entry<String, Object> entry : map.entrySet())
177         {
178             _descriptor.setValue(entry.getKey(), entry.getValue());
179         }
180         _propertyDescriptors = (List<PropertyDescriptor>) in.readObject();
181     }
182 
183     public void writeExternal(ObjectOutput out) throws IOException
184     {
185         out.writeObject(_descriptor.getBeanClass());
186         out.writeObject(_descriptor.getCustomizerClass());
187         out.writeObject(_descriptor.getDisplayName());
188         out.writeBoolean(_descriptor.isExpert());
189         out.writeObject(_descriptor.getName());
190         out.writeBoolean(_descriptor.isPreferred());
191         out.writeObject(_descriptor.getShortDescription());
192         
193         Map<String,Object> map = new HashMap<String, Object>(4,1);
194         
195         for (Enumeration<String> e = _descriptor.attributeNames(); e.hasMoreElements();)
196         {
197             String name = e.nextElement();
198             
199             // It is not necessary to serialize AttachedObjectTarget list because
200             // we only use it when VDL.retargetAttachedObjects() is called and this only
201             // happen when the view is built. Also, try to serialize this instances could
202             // cause unwanted exceptions.
203             if (!AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY.equals(name))
204             {
205                 map.put(name, _descriptor.getValue(name));
206             }
207         }
208         out.writeObject(map);
209         out.writeObject(_propertyDescriptors);
210         
211     }
212 }