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 }