KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > nodes > PropertySupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.nodes;
21
22 import java.beans.Beans JavaDoc;
23 import java.beans.PropertyEditor JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.lang.reflect.Modifier JavaDoc;
27 import org.openide.util.Exceptions;
28 import org.openide.util.NbBundle;
29
30 /** Support class for <code>Node.Property</code>.
31 *
32 * @author Jan Jancura, Jaroslav Tulach, Ian Formanek
33 */

34 public abstract class PropertySupport<T> extends Node.Property<T> {
35     /** flag whether the property is readable */
36     private boolean canR;
37
38     /** flag whether the property is writable */
39     private boolean canW;
40
41     /** Constructs a new support.
42     * @param name the name of the property
43     * @param type the class type of the property
44     * @param displayName the display name of the property
45     * @param canR whether the property is readable
46     * @param canW whether the property is writable
47     */

48     public PropertySupport(
49         String JavaDoc name, Class JavaDoc<T> type, String JavaDoc displayName, String JavaDoc shortDescription, boolean canR, boolean canW
50     ) {
51         super(type);
52         this.setName(name);
53         setDisplayName(displayName);
54         setShortDescription(shortDescription);
55         this.canR = canR;
56         this.canW = canW;
57     }
58
59     /* Can read the value of the property.
60     * Returns the value passed into constructor.
61     * @return <CODE>true</CODE> if the read of the value is supported
62     */

63     public boolean canRead() {
64         return canR;
65     }
66
67     /* Can write the value of the property.
68     * Returns the value passed into constructor.
69     * @return <CODE>true</CODE> if the read of the value is supported
70     */

71     public boolean canWrite() {
72         return canW;
73     }
74
75     /**
76      * Like {@link Class#cast} but handles primitive types.
77      * See JDK #6456930.
78      */

79     static <T> T cast(Class JavaDoc<T> c, Object JavaDoc o) {
80         if (c.isPrimitive()) {
81             // Could try to actually type-check it, but never mind.
82
return (T) o;
83         } else {
84             return c.cast(o);
85         }
86     }
87
88     /** Support for properties from Java Reflection. */
89     public static class Reflection<T> extends Node.Property<T> {
90         /** Instance of a bean. */
91         protected Object JavaDoc instance;
92
93         /** setter method */
94         private Method JavaDoc setter;
95
96         /** getter method */
97         private Method JavaDoc getter;
98
99         /** class of property editor */
100         private Class JavaDoc<? extends PropertyEditor JavaDoc> propertyEditorClass;
101
102         /** Create a support with method objects specified.
103         * The methods must be public.
104         * @param instance (Bean) object to work on
105         * @param valueType type of the property
106         * @param getter getter method, can be <code>null</code>
107         * @param setter setter method, can be <code>null</code>
108         * @throws IllegalArgumentException if the methods are not public
109         */

110         public Reflection(Object JavaDoc instance, Class JavaDoc<T> valueType, Method JavaDoc getter, Method JavaDoc setter) {
111             super(valueType);
112
113             if ((getter != null) && !Modifier.isPublic(getter.getModifiers())) {
114                 throw new IllegalArgumentException JavaDoc("Cannot use a non-public getter " + getter); // NOI18N
115
}
116
117             if ((setter != null) && !Modifier.isPublic(setter.getModifiers())) {
118                 throw new IllegalArgumentException JavaDoc("Cannot use a non-public setter " + setter); // NOI18N
119
}
120
121             this.instance = instance;
122             this.setter = setter;
123             this.getter = getter;
124         }
125
126         /** Create a support with methods specified by name.
127         * The instance class will be examined for the named methods.
128         * But if the instance class is not public, the nearest public superclass
129         * will be used instead, so that the getters and setters remain accessible.
130         * @param instance (Bean) object to work on
131         * @param valueType type of the property
132         * @param getter name of getter method, can be <code>null</code>
133         * @param setter name of setter method, can be <code>null</code>
134         * @exception NoSuchMethodException if the getter or setter methods cannot be found
135         */

136         public Reflection(Object JavaDoc instance, Class JavaDoc<T> valueType, String JavaDoc getter, String JavaDoc setter)
137         throws NoSuchMethodException JavaDoc {
138             this(
139                 instance, valueType,
140                 (
141             // find the getter ()
142
getter == null) ? null : findAccessibleClass(instance.getClass()).getMethod(getter),
143                 (
144             // find the setter (valueType)
145
setter == null) ? null : findAccessibleClass(instance.getClass()).getMethod(
146                     setter, new Class JavaDoc<?>[] { valueType }
147                 )
148             );
149         }
150
151         // [PENDING] should use Beans API in case there is overriding BeanInfo --jglick
152

153         /** Create a support based on the property name.
154         * The getter and setter methods are constructed by capitalizing the first
155         * letter in the name of propety and prefixing it with <code>get</code> and
156         * <code>set</code>, respectively.
157         *
158         * @param instance object to work on
159         * @param valueType type of the property
160         * @param property name of property
161         * @exception NoSuchMethodException if the getter or setter methods cannot be found
162         */

163         public Reflection(Object JavaDoc instance, Class JavaDoc<T> valueType, String JavaDoc property)
164         throws NoSuchMethodException JavaDoc {
165             this(
166                 instance, valueType, findGetter(instance, valueType, property),
167                 findAccessibleClass(instance.getClass()).getMethod(
168                     firstLetterToUpperCase(property, "set"), valueType
169                 )
170             );
171         }
172
173         /** Find the nearest superclass (or same class) that is public to this one. */
174         private static <C> Class JavaDoc<? super C> findAccessibleClass(Class JavaDoc<C> clazz) {
175             if (Modifier.isPublic(clazz.getModifiers())) {
176                 return clazz;
177             } else {
178                 Class JavaDoc<? super C> sup = clazz.getSuperclass();
179
180                 if (sup == null) {
181                     return Object JavaDoc.class; // handle interfaces
182
}
183
184                 return findAccessibleClass(sup);
185             }
186         }
187
188         /** Helper method to convert the first letter of a string to uppercase.
189         * And prefix the string with some next string.
190         */

191         private static String JavaDoc firstLetterToUpperCase(String JavaDoc s, String JavaDoc pref) {
192             switch (s.length()) {
193             case 0:
194                 return pref;
195
196             case 1:
197                 return pref + Character.toUpperCase(s.charAt(0));
198
199             default:
200                 return pref + Character.toUpperCase(s.charAt(0)) + s.substring(1);
201             }
202         }
203
204         // Finds the proper getter
205
private static Method JavaDoc findGetter(Object JavaDoc instance, Class JavaDoc valueType, String JavaDoc property)
206         throws NoSuchMethodException JavaDoc {
207             NoSuchMethodException JavaDoc nsme;
208
209             try {
210                 return findAccessibleClass(instance.getClass()).getMethod(
211                     firstLetterToUpperCase(property, "get")
212                 );
213             } catch (NoSuchMethodException JavaDoc e) {
214                 if (valueType != boolean.class) {
215                     throw e;
216                 } else {
217                     nsme = e;
218                 }
219             }
220
221             // Is of type boolean and "get" getter does not exist
222
try {
223                 return findAccessibleClass(instance.getClass()).getMethod(
224                     firstLetterToUpperCase(property, "is")
225                 );
226             } catch (NoSuchMethodException JavaDoc e) {
227                 throw e;
228             }
229         }
230
231         /* Can read the value of the property.
232         * @return <CODE>true</CODE> if the read of the value is supported
233         */

234         public boolean canRead() {
235             return getter != null;
236         }
237
238         /* Getter for the value.
239         * @return the value of the property
240         * @exception IllegalAccessException cannot access the called method
241         * @exception IllegalArgumentException wrong argument
242         * @exception InvocationTargetException an exception during invocation
243         */

244         public T getValue() throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
245             if (getter == null) {
246                 throw new IllegalAccessException JavaDoc();
247             }
248
249             Object JavaDoc valideInstance = Beans.getInstanceOf(instance, getter.getDeclaringClass());
250
251             try {
252                 try {
253                     return cast(getValueType(), getter.invoke(valideInstance));
254                 } catch (IllegalAccessException JavaDoc ex) {
255                     try {
256                         getter.setAccessible(true);
257
258                         return cast(getValueType(), getter.invoke(valideInstance));
259                     } finally {
260                         getter.setAccessible(false);
261                     }
262                 }
263             } catch (IllegalArgumentException JavaDoc iae) {
264                 //Provide a better message for debugging
265
StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Attempted to invoke method ");
266                 sb.append(getter.getName());
267                 sb.append(" from class ");
268                 sb.append(getter.getDeclaringClass().getName());
269                 sb.append(" on an instance of ");
270                 sb.append(valideInstance.getClass().getName());
271                 sb.append(" Problem:");
272                 sb.append(iae.getMessage());
273                 throw (IllegalArgumentException JavaDoc) new IllegalArgumentException JavaDoc(sb.toString()).initCause(iae);
274             }
275         }
276
277         /* Can write the value of the property.
278         * @return <CODE>true</CODE> if the read of the value is supported
279         */

280         public boolean canWrite() {
281             return setter != null;
282         }
283
284         /* Setter for the value.
285         * @param val the value of the property
286         * @exception IllegalAccessException cannot access the called method
287         * @exception IllegalArgumentException wrong argument
288         * @exception InvocationTargetException an exception during invocation
289         */

290         public void setValue(T val)
291         throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
292             if (setter == null) {
293                 throw new IllegalAccessException JavaDoc();
294             }
295
296             Object JavaDoc valideInstance = Beans.getInstanceOf(instance, setter.getDeclaringClass());
297
298             try {
299                 setter.invoke(valideInstance, val);
300             } catch (IllegalAccessException JavaDoc ex) {
301                 try {
302                     setter.setAccessible(true);
303                     setter.invoke(valideInstance, val);
304                 } finally {
305                     setter.setAccessible(false);
306                 }
307             }
308         }
309
310         /* Returns property editor for this property.
311         * @return the property editor or <CODE>null</CODE> if there should not be
312         * any editor.
313         */

314         public PropertyEditor JavaDoc getPropertyEditor() {
315             if (propertyEditorClass != null) {
316                 try {
317                     return propertyEditorClass.newInstance();
318                 } catch (InstantiationException JavaDoc ex) {
319                     Exceptions.printStackTrace(ex);
320                 } catch (IllegalAccessException JavaDoc iex) {
321                     Exceptions.printStackTrace(iex);
322                 }
323             }
324
325             return super.getPropertyEditor();
326         }
327
328         /** Set the property editor explicitly.
329         * @param clazz class type of the property editor
330         */

331         public void setPropertyEditorClass(Class JavaDoc<? extends PropertyEditor JavaDoc> clazz) {
332             propertyEditorClass = clazz;
333         }
334     }
335
336     /** A simple read/write property.
337     * Subclasses should implement
338     * {@link #getValue} and {@link #setValue}.
339     */

340     public static abstract class ReadWrite<T> extends PropertySupport<T> {
341         /** Construct a new support.
342         * @param name the name of the property
343         * @param type the class type of the property
344         * @param displayName the display name of the property
345         * @param shortDescription a short description of the property
346         */

347         public ReadWrite(String JavaDoc name, Class JavaDoc<T> type, String JavaDoc displayName, String JavaDoc shortDescription) {
348             super(name, type, displayName, shortDescription, true, true);
349         }
350     }
351
352     /** A simple read-only property.
353     * Subclasses should implement {@link #getValue}.
354     */

355     public static abstract class ReadOnly<T> extends PropertySupport<T> {
356         /** Construct a new support.
357         * @param name the name of the property
358         * @param type the class type of the property
359         * @param displayName the display name of the property
360         * @param shortDescription a short description of the property
361         */

362         public ReadOnly(String JavaDoc name, Class JavaDoc<T> type, String JavaDoc displayName, String JavaDoc shortDescription) {
363             super(name, type, displayName, shortDescription, true, false);
364         }
365
366         /* Setter for the value.
367         * @param val the value of the property
368         * @exception IllegalAccessException cannot access the called method
369         * @exception IllegalArgumentException wrong argument
370         * @exception InvocationTargetException an exception during invocation
371         */

372         @Override JavaDoc
373         public void setValue(T val)
374         throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
375             throw new IllegalAccessException JavaDoc("Cannot write to ReadOnly property"); // NOI18N
376
}
377     }
378
379     /** A simple write-only property.
380     * Subclasses should implement {@link #setValue}.
381     */

382     public static abstract class WriteOnly<T> extends PropertySupport<T> {
383         /** Construct a new support.
384         * @param name the name of the property
385         * @param type the class type of the property
386         * @param displayName the display name of the property
387         * @param shortDescription a short description of the property
388         */

389         public WriteOnly(String JavaDoc name, Class JavaDoc<T> type, String JavaDoc displayName, String JavaDoc shortDescription) {
390             super(name, type, displayName, shortDescription, false, true);
391         }
392
393         /* Getter for the value.
394         * @return the value of the property
395         * @exception IllegalAccessException cannot access the called method
396         * @exception IllegalArgumentException wrong argument
397         * @exception InvocationTargetException an exception during invocation
398         */

399         @Override JavaDoc
400         public T getValue() throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
401             throw new IllegalAccessException JavaDoc("Cannod read from WriteOnly property"); // NOI18N
402
}
403     }
404
405     /** Support for the name property of a node. Delegates {@link #setValue} and {@link #getValue}
406     * to {@link Node#setName} and {@link Node#getName}.
407     */

408     public static final class Name extends PropertySupport<String JavaDoc> {
409         /** The node to which we delegate the work. */
410         private final Node node;
411
412         /** Create the name property for a node with the standard name and hint.
413         * @param node the node
414         */

415         public Name(final Node node) {
416             this(
417                 node, NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardName"),
418                 NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardHint")
419             );
420         }
421
422         /** Create the name property for a node.
423         * @param node the node
424         * @param propName name of the "name" property
425         * @param hint hint message for the "name" property
426         */

427         public Name(final Node node, final String JavaDoc propName, final String JavaDoc hint) {
428             super(Node.PROP_NAME, String JavaDoc.class, propName, hint, true, node.canRename());
429             this.node = node;
430         }
431
432         /* Getter for the value. Delegates to Node.getName().
433         * @return the name
434         */

435         public String JavaDoc getValue() throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
436             return node.getName();
437         }
438
439         /* Setter for the value. Delegates to Node.setName().
440         * @param val new name
441         */

442         public void setValue(String JavaDoc val)
443         throws IllegalAccessException JavaDoc, IllegalArgumentException JavaDoc, InvocationTargetException JavaDoc {
444             Object JavaDoc oldName = node.getName();
445             node.setName(val);
446             node.firePropertyChange(Node.PROP_NAME, oldName, val);
447         }
448     }
449      // end of Name inner class
450
}
451
Popular Tags