Line | Hits | Source |
---|---|---|
1 | /* | |
2 | Chrysalis Web Framework [http://chrysalis.sourceforge.net] | |
3 | Copyright (c) 2002, 2003, 2004, Paul Strack | |
4 | ||
5 | All rights reserved. | |
6 | ||
7 | Redistribution and use in source and binary forms, with or without | |
8 | modification, are permitted provided that the following conditions are met: | |
9 | ||
10 | 1. Redistributions of source code must retain the above copyright notice, this | |
11 | list of conditions and the following disclaimer. | |
12 | ||
13 | 2. Redistributions in binary form must reproduce the above copyright notice, | |
14 | this list of conditions and the following disclaimer in the documentation | |
15 | and/or other materials provided with the distribution. | |
16 | ||
17 | 3. Neither the name of the copyright holder nor the names of its contributors | |
18 | may be used to endorse or promote products derived from this software without | |
19 | specific prior written permission. | |
20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | package org.chwf.filter; | |
34 | ||
35 | import java.beans.BeanInfo; | |
36 | import java.beans.IntrospectionException; | |
37 | import java.beans.Introspector; | |
38 | import java.beans.PropertyDescriptor; | |
39 | import java.util.Iterator; | |
40 | import java.util.Map; | |
41 | ||
42 | import org.chwf.config.Config; | |
43 | import org.chwf.config.PolymorphicConfig; | |
44 | import org.chwf.converter.Converter; | |
45 | import org.chwf.plugin.OptionLister; | |
46 | import org.chwf.util.MiscUtils; | |
47 | ||
48 | /** | |
49 | * Generic default filter created through introspection. Custom bean | |
50 | * filters can subclass this class, instead of <code>BeanFilter</code>, | |
51 | * to set most of the filter's functionality through reflection. The | |
52 | * custom filter can then customize the filters for individual properties | |
53 | * and methods by calling the appropriate <code>putFilter</code> method: | |
54 | * | |
55 | * <pre> | |
56 | * package example; | |
57 | * import java.text.*; | |
58 | * import org.chwf.filter.*; | |
59 | * | |
60 | * public class AccountFilter extends GenericBeanFilter { | |
61 | * public AccountFilter() { | |
62 | * super(Account.class); | |
63 | * | |
64 | * // startDate property filter as an anonymous inner class: | |
65 | * PropertyFilter sdFilter = | |
66 | * new PropertyFilter("startDate", java.util.Date.class) { | |
67 | * | |
68 | * public String get(Object object) { | |
69 | * DateFormat df = SimpleDateFormat("mm/dd/yyyy"); | |
70 | * java.util.Date date = ((Account) object).getStartDate(); | |
71 | * if (date == null) { | |
72 | * return null; | |
73 | * } else { | |
74 | * return df.format(date); | |
75 | * } | |
76 | * } | |
77 | * | |
78 | * public void set(Object object, String value) { | |
79 | * DateFormat df = SimpleDateFormat("mm/dd/yyyy"); | |
80 | * try { | |
81 | * ((Account) object).setStartDate(df.parse(value)); | |
82 | * } catch (java.text.ParseException ex) { | |
83 | * throw new IllegalArgumentException(ex.getMessage()); | |
84 | * } | |
85 | * } | |
86 | * }; | |
87 | * | |
88 | * putPropertyFilter("startDate", sdFilter); | |
89 | * | |
90 | * initializePropertyAttributes(); // Using configuration | |
91 | * } | |
92 | * }</pre> | |
93 | * | |
94 | * @author <a href="mailto:pfstrack@users.sourceforge.net">Paul Strack</a> | |
95 | */ | |
96 | 1 | public class GenericBeanFilter extends BeanFilter { |
97 | ||
98 | /** | |
99 | * This constructor initializes the property and method filters for the | |
100 | * bean. It does <i>not</i> initialize property attributes.<p> | |
101 | * | |
102 | * @param beanClass The class being filtered. | |
103 | * @throws InitializationException If initialization fails for any reason. | |
104 | */ | |
105 | public GenericBeanFilter(Class beanClass) throws InitializationException { | |
106 | 26 | super(beanClass); |
107 | try { | |
108 | 26 | BeanInfo info = Introspector.getBeanInfo(beanClass); |
109 | 26 | initializeProperties(info); |
110 | 26 | Introspector.flushFromCaches(beanClass); // To avoid cluttering memory |
111 | 26 | } catch (Exception ex) { |
112 | 0 | throw new InitializationException( |
113 | InitializationException.MESSAGE_INIT_FAILED, | |
114 | new Object[] { ex }); | |
115 | } | |
116 | 26 | } |
117 | ||
118 | /** | |
119 | * This method initializes property attributes, using the JavaBean config | |
120 | * file described in the package documentation.<p> | |
121 | * | |
122 | * @throws InitializationException If introspection fails. | |
123 | */ | |
124 | protected void initializePropertyAttributes() | |
125 | throws InitializationException { | |
126 | // Set defaults: | |
127 | 26 | PropertyFilter[] filters = getPropertyFilters(); |
128 | 26 | initDefaultAttributeValues(filters); |
129 | 26 | initFromConfig(filters); |
130 | 26 | } |
131 | ||
132 | /** | |
133 | * Initialize default attribute values for label, datatype and readonly. | |
134 | * | |
135 | * @param filters The Property Filters | |
136 | */ | |
137 | private void initDefaultAttributeValues(PropertyFilter[] filters) { | |
138 | 129 | for (int i = 0; i < filters.length; i++) { |
139 | 103 | PropertyFilter filter = filters[i]; |
140 | 103 | String label = deriveLabel(filter); |
141 | 103 | filter.setAttribute(ATTRIBUTE_LABEL, label); |
142 | 103 | String type = MiscUtils.getWrapper(filter.getType()).getName(); |
143 | 103 | filter.setAttribute(ATTRIBUTE_DATATYPE, type); |
144 | 103 | if (!filter.isWriteable()) { |
145 | 60 | filter.setAttribute(ATTRIBUTE_READONLY, new Boolean(true)); |
146 | } | |
147 | } | |
148 | 26 | } |
149 | ||
150 | /** | |
151 | * Initialize property attributes using config. | |
152 | * | |
153 | * @param filters The Property Filters | |
154 | * @throws InitializationException If something goes wrong. | |
155 | */ | |
156 | private void initFromConfig(PropertyFilter[] filters) | |
157 | throws InitializationException { | |
158 | try { | |
159 | 26 | Class beanClass = getBeanClass(); |
160 | 26 | Config config = PolymorphicConfig.getConfig(beanClass); |
161 | 129 | for (int j = 0; j < filters.length; j++) { |
162 | 103 | PropertyFilter filter = filters[j]; |
163 | 103 | String filterName = filter.getName(); |
164 | 103 | Map data = config.getMap(filterName); |
165 | 103 | Iterator attributes = data.keySet().iterator(); |
166 | 103 | Class type = filter.getType(); |
167 | 280 | while (attributes.hasNext()) { |
168 | 74 | String attribute = (String) attributes.next(); |
169 | 74 | if (!(attribute.indexOf('.') > 0)) { |
170 | 27 | String value = (String) data.get(attribute); |
171 | 27 | if (attribute.equals(ATTRIBUTE_MAXLENGTH) |
172 | || attribute.equals(ATTRIBUTE_MINLENGTH) | |
173 | || attribute.equals(ATTRIBUTE_SCALE)) { | |
174 | 7 | Converter converter = Converter.getConverter(Integer.TYPE); |
175 | 7 | filter.setAttribute(attribute, converter.parse(value)); |
176 | 20 | } else if ( |
177 | attribute.equals(ATTRIBUTE_MIN) | |
178 | || attribute.equals(ATTRIBUTE_MAX)) { | |
179 | 15 | Converter converter = Converter.getConverter(type); |
180 | 15 | filter.setAttribute(attribute, converter.parse(value)); |
181 | 5 | } else if (attribute.equals(ATTRIBUTE_REQUIRED)) { |
182 | 1 | Converter converter = Converter.getConverter(Boolean.TYPE); |
183 | 1 | filter.setAttribute(attribute, converter.parse(value)); |
184 | } else { | |
185 | 4 | filter.setAttribute(attribute, value); |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | 103 | Map options = |
191 | OptionLister.getInstance().loadOptionList(beanClass, filterName); | |
192 | 103 | if (options != null) { |
193 | 6 | filter.setAttribute(BeanFilter.ATTRIBUTE_OPTIONS, options); |
194 | } | |
195 | } | |
196 | 26 | } catch (Exception ex) { |
197 | 0 | Object[] arguments = { ex }; |
198 | 0 | throw new InitializationException( |
199 | InitializationException.MESSAGE_PROPERTY_INIT_FAILED, | |
200 | new Object[] { ex }); | |
201 | } | |
202 | 26 | } |
203 | ||
204 | /** | |
205 | * Initialize property filters. | |
206 | * | |
207 | * @param info The BeanInfo for the class. | |
208 | * @throws IntrospectionException For BeanInfo exceptions. | |
209 | */ | |
210 | private void initializeProperties(BeanInfo info) | |
211 | throws IntrospectionException { | |
212 | 26 | PropertyDescriptor[] properties = info.getPropertyDescriptors(); |
213 | 129 | for (int i = 0; i < properties.length; i++) { |
214 | try { | |
215 | 103 | putPropertyFilter( |
216 | properties[i].getName(), | |
217 | new GenericPropertyFilter(getBeanClass(), properties[i])); | |
218 | 103 | } catch (InitializationException ex) { |
219 | // Suppress properties whose filter cannot be constructed. | |
220 | 0 | i = i * 1; // Dummy op so that checkstyle does not complain |
221 | } | |
222 | } | |
223 | 26 | } |
224 | ||
225 | /** | |
226 | * Method that derives the propery label from the property name, | |
227 | * by "un-camel-casing" the name. | |
228 | * | |
229 | * @param filter The property filter. | |
230 | * @return The derived label. | |
231 | */ | |
232 | private String deriveLabel(PropertyFilter filter) { | |
233 | 103 | char[] name = filter.getName().toCharArray(); |
234 | 103 | StringBuffer label = new StringBuffer(name.length); |
235 | 103 | label.append(Character.toUpperCase(name[0])); |
236 | 103 | boolean wasUppercase = Character.isUpperCase(name[0]); |
237 | 750 | for (int i = 1; i < name.length; i++) { |
238 | 647 | char c = name[i]; |
239 | 647 | if (Character.isUpperCase(c)) { |
240 | 49 | if (!wasUppercase) { |
241 | 45 | label.append(' '); |
242 | } | |
243 | 49 | label.append(c); |
244 | 49 | wasUppercase = true; |
245 | } else { | |
246 | 598 | label.append(c); |
247 | 598 | wasUppercase = false; |
248 | } | |
249 | } | |
250 | 103 | return label.toString(); |
251 | } | |
252 | ||
253 | /** Constant for specifying string parameters in reflection. */ | |
254 | 1 | private static final Class[] STRING_PARAM = { String.class }; |
255 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |