View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.geronimo.common.propertyeditor;
19  
20  import java.beans.PropertyEditor;
21  import java.beans.PropertyEditorManager;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.List;
25  
26  import org.apache.geronimo.kernel.ClassLoading;
27  
28  /**
29   * The property editor manager.  This orchestrates Geronimo usage of
30   * property editors, allowing additional search paths to be added and
31   * specific editors to be registered.
32   *
33   * @version $Rev: 356022 $
34   */
35  public class PropertyEditors {
36      /**
37       * We need to register the standard register seach path and explicitly
38       * register a boolean editor to make sure ours overrides.
39       */
40      static {
41          // Append the geronimo propertyeditors package to the global search path.
42          appendEditorSearchPath("org.apache.geronimo.common.propertyeditor");
43          // and explicitly register the Boolean editor.
44          PropertyEditorManager.registerEditor(Boolean.class, BooleanEditor.class);
45          PropertyEditorManager.registerEditor(Integer.class, IntegerEditor.class);
46      }
47  
48      /**
49       * Locate an editor for qiven class of object.
50       *
51       * @param type The target object class of the property.
52       * @return The resolved editor, if any.  Returns null if a suitable editor
53       *         could not be located.
54       */
55      public static PropertyEditor findEditor(Class type) {
56          // explicit argument checking is required.
57          if (type == null) {
58              throw new IllegalArgumentException("type is null");
59          }
60  
61  
62          // try to locate this directly from the editor manager first.
63          PropertyEditor editor = PropertyEditorManager.findEditor(type);
64  
65          // we're outta here if we got one.
66          if (editor != null) {
67              return editor;
68          }
69  
70          // it's possible this was a request for an array class.  We might not
71          // recognize the array type directly, but the component type might be
72          // resolvable
73          if (type.isArray()) {
74              // do a recursive lookup on the base type
75              editor = findEditor(type.getComponentType());
76              // if we found a suitable editor for the base component type,
77              // wrapper this in an array adaptor for real use
78              if (editor != null) {
79                  return new ArrayPropertyEditorAdapter(type.getComponentType(), editor);
80              }
81          }
82          // nothing found
83          return null;
84      }
85  
86      /**
87       * Locate an editor for qiven class of object, resolved within the context of
88       * a specific ClassLoader instance.
89       *
90       * @param typeName The type name of target property class.
91       * @param loader The source ClassLoader instance.
92       * @return The resolved editor, if any.  Returns null if a suitable editor
93       *         could not be located.
94       * @throws ClassNotFoundException Thrown if unable to resolve an appropriate editor class.
95       */
96      public static PropertyEditor findEditor(String typeName, ClassLoader loader) throws ClassNotFoundException {
97          // explicit argument checking is required.
98          if (typeName == null) {
99              throw new IllegalArgumentException("typeName is null");
100         }
101 
102         Class type = null;
103         // load using the ClassLoading utility, which also manages arrays and primitive classes.
104         try {
105             type = ClassLoading.loadClass(typeName, loader);
106         } catch (ClassNotFoundException e) {
107             // We also support anonymous inner class nesting of property editors.  In that situation,
108             // the package/class names are the same, but add on the inner class specifier.
109             // If this one fails, we jump directly out with the ClassNotFoundException.
110             type = ClassLoading.loadClass(typeName + "$PropertyEditor", loader);
111         }
112 
113         // The PropertyEditorManager class uses the context class loader for all of its resolution
114         // steps.  We need force PropertyManagerEditor to use our loader, so we override the
115         // current context loader.
116         ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
117         try {
118             Thread.currentThread().setContextClassLoader(loader);
119             // now call the base findEditor() method that works directly from the property type.
120             return findEditor(type);
121         } finally {
122             // make sure we restore the context....this will happen even if findEditor()
123             // results in an exception.
124             Thread.currentThread().setContextClassLoader(oldLoader);
125         }
126     }
127 
128     /**
129      * Get a property editor for a given property type.  This is like
130      * findEditor, but throws an exception if the property is not found.
131      *
132      * @param type The target object class of the property.
133      * @return The resolved editor, if any.  Throws an exception if this cannot
134      *         be resolved.
135      * @throws PropertyEditorException Unable to find a suitable editor for this class.
136      */
137     public static PropertyEditor getEditor(Class type) {
138         // just call the non-exceptional lookup
139         PropertyEditor editor = findEditor(type);
140         // this one throws an exception if not found.
141         if (editor == null) {
142             throw new PropertyEditorException("No property editor for type: " + type);
143         }
144         return editor;
145     }
146 
147     /**
148      * Explicity register an editor class for a given target class.
149      *
150      * @param type The property class.
151      * @param editorType The editor class matched up with this type.
152      */
153     public static void registerEditor(Class type, Class editorType) {
154         // explicit argument checking is required.
155         if (type == null) {
156             throw new IllegalArgumentException("type is null");
157         }
158 
159         // explicit argument checking is required.
160         if (editorType == null) {
161             throw new IllegalArgumentException("editorType is null");
162         }
163 
164         PropertyEditorManager.registerEditor(type, editorType);
165     }
166 
167     /**
168      * Explicity register a property/editor class pair by class name.
169      *
170      * @param typeName The classname of the property.
171      * @param editorName The classname of the property editor.
172      * @throws ClassNotFoundException Thrown if unable to resolve either the type or the editor from their names.
173      */
174     public static void registerEditor(String typeName, String editorName) throws ClassNotFoundException {
175         // explicit argument checking is required.
176         if (typeName == null) {
177             throw new IllegalArgumentException("typeName is null");
178         }
179 
180         // explicit argument checking is required.
181         if (editorName == null) {
182             throw new IllegalArgumentException("editorTypeName is null");
183         }
184         // we use the current context loader for this
185         ClassLoader loader = Thread.currentThread().getContextClassLoader();
186 
187         // load both of these loaders using our ClassLoading support.
188         Class type = ClassLoading.loadClass(typeName, loader);
189         Class editor = ClassLoading.loadClass(editorName, loader);
190 
191         // we have resolved classes, so register the class information.
192         registerEditor(type, editor);
193     }
194 
195     /**
196      * Get a list containing all of the packages in the editor search path.
197      *
198      * @return a List object containing all of the registered search paths.
199      */
200     public static List getEditorSearchPath() {
201         // grrrr, Arrays.asList() returns a readonly List item, which makes it difficult
202         // to append additional items.  This means we have to do this manually.
203 
204         // start by getting the list from the editor manager, which is returned as an
205         // array of Strings.
206         String[] paths = PropertyEditorManager.getEditorSearchPath();
207 
208         // get a list matching the initial size...we don't always request this with the intend to append.
209         List pathList = new ArrayList(paths.length);
210 
211         // now MANUALLY add each of the items in the array.
212         for (int i = 0; i < paths.length; i++) {
213             pathList.add(paths[i]);
214         }
215 
216         return pathList;
217     }
218 
219     /**
220      * Sets the search order used for property editor resolution.
221      *
222      * @param path The serach path.
223      */
224     public static void setEditorSearchPath(List path) {
225         // explicit argument checking is required.
226         if (path == null) {
227             throw new IllegalArgumentException("path is null");
228         }
229 
230         // we deal in Lists, PropertyEditorManager does arrays, so we need to
231         // extract the elements into a array of Strings.
232         String[] elements = (String[]) path.toArray(new String[path.size()]);
233         PropertyEditorManager.setEditorSearchPath(elements);
234     }
235 
236     /**
237      * Append additional package names to the property editor search path.
238      *
239      * @param names The package names to append.
240      */
241     public static void appendEditorSearchPath(List newNames) {
242         // explicit argument checking is required.
243         if (newNames == null) {
244             throw new IllegalArgumentException("names is null");
245         }
246 
247         // if there's nothing to do, then do nothing :-)
248         if (newNames.isEmpty()) {
249             return;
250         }
251 
252         // append to the current names list, and set ammended list back as the current
253         // search order.
254         List currentPath = getEditorSearchPath();
255         currentPath.addAll(newNames);
256 
257         setEditorSearchPath(currentPath);
258     }
259 
260     /**
261      * Append an array of package names to the editor search path.
262      *
263      * @param names A string array containing the added names.
264      */
265     public static void appendEditorSearchPath(String[] newNames) {
266         // explicit argument checking is required.
267         if (newNames == null) {
268             throw new IllegalArgumentException("names is null");
269         }
270 
271         // only bother continuing if the array contains something.
272         if (newNames.length != 0) {
273             // just convert this to a list and add as normal.
274             appendEditorSearchPath(Arrays.asList(newNames));
275         }
276     }
277 
278     /**
279      * Append a single package name to the editor search path.
280      *
281      * @param name The new path name.
282      */
283     public static void appendEditorSearchPath(String newName) {
284         // explicit argument checking is required.
285         if (newName == null) {
286             throw new IllegalArgumentException("name is null");
287         }
288 
289         // append to the current names list, and set ammended list back as the current
290         // search order.
291         List currentPath = getEditorSearchPath();
292         currentPath.add(newName);
293 
294         setEditorSearchPath(currentPath);
295     }
296 }