KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > util > PropertiesBean


1 /*
2  * PropertiesBean.java: a "serializable" Java Bean that uses a
3  * java.util.Properties backend.
4  * :noTabs=false:
5  *
6  * Copyright (C) 2006 Marcelo Vanzin
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Library General Public License as published
10  * by the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */

22 package org.gjt.sp.util;
23
24 import java.beans.BeanInfo JavaDoc;
25 import java.beans.IntrospectionException JavaDoc;
26 import java.beans.Introspector JavaDoc;
27 import java.beans.PropertyDescriptor JavaDoc;
28
29 import java.lang.reflect.Array JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31
32 import java.util.HashMap JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Properties JavaDoc;
35 import java.util.StringTokenizer JavaDoc;
36
37 /**
38  * A "java bean" that can serialize itself into a java.util.Properties
39  * instance. For the serialization, the class uses the java beans
40  * instrospection mechanism to figure out the class's available
41  * properties, and saves all the properties as strings in the properties
42  * object.
43  *
44  * <p>Properties are saved based on a "root", which is set up during the
45  * instantiation of the object. The properties will be set as
46  * <code>root.property_name</code>.</p>
47  *
48  * <p>Only native types (boolean, char, double, float, int, long, short),
49  * Strings, and arrays of those types are supported. Also, nested
50  * beans are not supported presently.</p>
51  *
52  * @author Marcelo Vanzin
53  * @since jEdit 4.3pre7
54  */

55 public abstract class PropertiesBean
56 {
57
58     /**
59      * Mostly for internal use by jEdit. Clear the entries in the
60      * internal cache, so that new classes are re-scanned. Used when
61      * loading/unloading plugins, to avoid having stale data in the cache.
62      */

63     public static void clearPropertyCache()
64     {
65         PROPERTY_CACHE.clear();
66     }
67
68     // Constructors
69

70     /**
71      * Creates a new instance with the given root and the default array
72      * separator char (':').
73      *
74      * @param root A non-null string that will be the "root" of the
75      * serialized properties.
76      */

77     protected PropertiesBean(String JavaDoc root)
78     {
79         this(root, ':');
80     }
81
82     /**
83      * Creates a new instance with the given root and the given array
84      * separator character.
85      *
86      * @param root A non-null string that will be the "root" of the
87      * serialized properties.
88      * @param arraysep A character that will be used to define the
89      * separator of elements of an array property.
90      */

91     protected PropertiesBean(String JavaDoc root, char arraysep)
92     {
93         if (root == null)
94             throw new IllegalArgumentException JavaDoc("root cannot be null");
95         this.root = root;
96         this.arraysep = arraysep;
97     }
98
99     // Public methods
100

101     /**
102      * Loads the bean's properties from the given object.
103      */

104     public void load(Properties JavaDoc p)
105     {
106         try
107         {
108             PropertyDescriptor JavaDoc[] _props = getPropertyDescriptors();
109             for (int i = 0; i < _props.length; i++)
110             {
111                 if ("class".equals(_props[i].getName()))
112                     continue;
113
114                 Method JavaDoc _set = _props[i].getWriteMethod();
115                 if (_set != null)
116                 {
117                     String JavaDoc _pname = root + "." + _props[i].getName();
118                     Object JavaDoc _val = p.getProperty(_pname);
119                     if (_val != null)
120                         _val = parse((String JavaDoc)_val, _props[i].getPropertyType());
121                     _set.invoke(this, _val);
122                 }
123             }
124         }
125         catch (Exception JavaDoc e)
126         {
127             // These exceptions shouldn't occur during normal runtime,
128
// so we catch them and print an error message. Users of this
129
// class should fix these before releasing the code.
130
Log.log(Log.ERROR, this, e);
131         }
132     }
133
134     /**
135      * Saves the bean's properties into the given object.
136      */

137     public void save(Properties JavaDoc p)
138     {
139         try
140         {
141             PropertyDescriptor JavaDoc[] _props = getPropertyDescriptors();
142             for (int i = 0; i < _props.length; i++)
143             {
144                 if ("class".equals(_props[i].getName()))
145                     continue;
146
147                 Method JavaDoc _get = _props[i].getReadMethod();
148                 if (_get != null)
149                 {
150                     Object JavaDoc _val = _get.invoke(this);
151                     String JavaDoc _pname = root + "." + _props[i].getName();
152                     if (_val != null)
153                         p.setProperty(_pname, encode(_val));
154                     else
155                         p.remove(_pname);
156                 }
157             }
158         }
159         catch (Exception JavaDoc e)
160         {
161             // These exceptions shouldn't occur during normal runtime,
162
// so we catch them and print an error message. Users of this
163
// class should fix these before releasing the code.
164
Log.log(Log.ERROR, this, e);
165         }
166     }
167
168     /**
169      * Cleans the entries related to this object from the given object.
170      */

171     public void clean(Properties JavaDoc p)
172     {
173
174         try
175         {
176             PropertyDescriptor JavaDoc[] _props = getPropertyDescriptors();
177             for (int i = 0; i < _props.length; i++)
178             {
179                 if ("class".equals(_props[i].getName()))
180                     continue;
181
182                 String JavaDoc _pname = root + "." + _props[i].getName();
183                 p.remove(_pname);
184             }
185         }
186         catch (Exception JavaDoc e)
187         {
188             // These exceptions shouldn't occur during normal runtime,
189
// so we catch them and print an error message. Users of this
190
// class should fix these before releasing the code.
191
Log.log(Log.ERROR, this, e);
192         }
193     }
194
195     // Private methods
196

197     private PropertyDescriptor JavaDoc[] getPropertyDescriptors()
198         throws IntrospectionException JavaDoc
199     {
200         PropertyDescriptor JavaDoc[] _props;
201         synchronized (PROPERTY_CACHE)
202         {
203             _props = PROPERTY_CACHE.get(getClass().getName());
204             if (_props == null)
205             {
206                 BeanInfo JavaDoc _info = Introspector.getBeanInfo(getClass());
207                 _props = _info.getPropertyDescriptors();
208                 PROPERTY_CACHE.put(getClass().getName(), _props);
209             }
210         }
211         return _props;
212     }
213
214     private String JavaDoc encode(Object JavaDoc value)
215     {
216         Class JavaDoc _class = value.getClass();
217         if (_class.isArray())
218         {
219             StringBuilder JavaDoc _val = new StringBuilder JavaDoc();
220             int _len = Array.getLength(value);
221             for (int i = 0; i < _len; i++)
222             {
223                 String JavaDoc _str = encode(Array.get(value, i));
224                 if (_str == null)
225                     return null;
226                 _val.append(_str);
227                 if (i < _len - 1)
228                     _val.append(arraysep);
229             }
230             return _val.toString();
231         }
232         else
233         {
234             // just make sure it's a supported type.
235
if (_class != Boolean JavaDoc.class && _class != Boolean.TYPE
236                 && _class != Character JavaDoc.class && _class != Character.TYPE
237                 && _class != Double JavaDoc.class && _class != Double.TYPE
238                 && _class != Float JavaDoc.class && _class != Float.TYPE
239                 && _class != Integer JavaDoc.class && _class != Integer.TYPE
240                 && _class != Long JavaDoc.class && _class != Long.TYPE
241                 && _class != Short JavaDoc.class && _class != Short.TYPE
242                 && _class != String JavaDoc.class)
243             {
244                 Log.log(Log.WARNING, this, "unsupported type: " + _class.getName());
245                 return null;
246             }
247             return value.toString();
248         }
249     }
250
251     private Object JavaDoc parse(String JavaDoc value, Class JavaDoc<?> _class)
252     {
253         Object JavaDoc _ret = null;
254         if (_class.isArray())
255         {
256             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value, String.valueOf(arraysep));
257             Class JavaDoc _type = _class.getComponentType();
258             _ret = Array.newInstance(_type, st.countTokens());
259             int _cnt = st.countTokens();
260             for (int i = 0; i < _cnt; i++)
261             {
262                 Object JavaDoc _val = parse(st.nextToken(), _type);
263                 if (_val == null)
264                     return null;
265                 Array.set(_ret, i, _val);
266             }
267         }
268         else
269         {
270             if (_class == Boolean JavaDoc.class || _class == Boolean.TYPE)
271                 _ret = Boolean.valueOf(value);
272             else if (_class == Character JavaDoc.class || _class == Character.TYPE)
273                 _ret = Character.valueOf(value.charAt(0));
274             else if (_class == Double JavaDoc.class || _class == Double.TYPE)
275                 _ret = Double.valueOf(value);
276             else if (_class == Float JavaDoc.class || _class == Float.TYPE)
277                 _ret = Float.valueOf(value);
278             else if (_class == Integer JavaDoc.class || _class == Integer.TYPE)
279                 _ret = Integer.valueOf(value);
280             else if (_class == Long JavaDoc.class || _class == Long.TYPE)
281                 _ret = Long.valueOf(value);
282             else if (_class == Short JavaDoc.class || _class == Short.TYPE)
283                 _ret = Short.valueOf(value);
284             else if (_class == String JavaDoc.class)
285                 _ret = value;
286             else
287                 Log.log(Log.WARNING, this, "unsupported type: " + _class.getName());
288
289         }
290         return _ret;
291     }
292
293     // Static variables
294

295     /** Holds a cache of class name -> PropertyDescriptor[] mappings. */
296     private static final Map JavaDoc<String JavaDoc,PropertyDescriptor JavaDoc[]> PROPERTY_CACHE
297         = new HashMap JavaDoc<String JavaDoc,PropertyDescriptor JavaDoc[]>();
298
299     // Instance variables
300

301     private final char arraysep;
302     private final String JavaDoc root;
303
304 }
305
306
Popular Tags