1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 package com.unitesk.atp.tool;
33
34 import java.io.InputStream;
35 import java.io.IOException;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.Properties;
41
42 /***
43 * The table of dynamic variables.
44 * <P>A dynamic variable like usual Java variable has a name and a class.
45 * But dynamic variables are defined outside of program.
46 * It allows to change a set of defined dynamic variables and use them
47 * without program recompilation. For example, it can be used to extend
48 * program functionality in plugin-like way.</P>
49 * <P>A table of dynamic variables has a name.</P>
50 * <P>A class instance representing dynamic variable is created using
51 * class constructor without parameters.</P>
52 * <P>Parameters are passed to variable using so-called plugin properties.
53 * The value of plugin property <code>property.name</code> for variable
54 * <code>var</code> of table <code>tab</code> is passed through system property
55 * <code>tab.var.property.name</code>.
56 * </P>
57 *
58 * @author <A href="mailto:demakov@ispras.ru">Alexey Demakov</A>
59 * @author <A href="mailto:monakhov@ispras.ru">Alexander Monakhov</A>
60 * @author <A href="mailto:sophia@ispras.ru">Sophia Zelenova</A>
61 * @version $Id: DynamicVariablesTable.java,v 1.2 2004/10/11 15:00:44 all-x Exp $
62 */
63 public class DynamicVariablesTable
64 {
65 private String name;
66
67 private Map
68 private Map
69
70 /***
71 * Creates an empty dynamic variables table with the specified name.
72 *
73 * @param name the name of the table. It must be the name of Java
74 * indentifier.
75 * @throws IllegalArgumentException
76 * if <code>name</code> is incorrect format
77 */
78 public DynamicVariablesTable( String name )
79 {
80 if( !name.matches( "[a-zA-Z_]//w*(//.[a-zA-Z_]//w*)*" ) )
81 {
82 throw new IllegalArgumentException( name );
83 }
84
85 this.name = name;
86 }
87
88 /***
89 * Creates dynamic variables table with the specified name
90 * and {@link #load(InputStream) loads} variables from the specified input stream.
91 *
92 * @param name The table name.
93 * @param in The input stream containing
94 * dynamic variables definitions.
95 *
96 * @see #load(InputStream)
97 * @see #load(String,String)
98 * @see Properties#load(InputStream)
99 */
100 public DynamicVariablesTable( String name, InputStream in )
101 throws IOException
102 , ClassNotFoundException
103 {
104 this( name );
105
106 load( in );
107 }
108
109 /***
110 * Returns the names of all defined variables.
111 *
112 * @return The set containing names of all variables defined
113 * in this table.
114 */
115 public Set
116 {
117 return name_to_var.keySet();
118 }
119
120 /***
121 * Returns a variable with the specified name.
122 *
123 * @param name The variable name.
124 * @return The variable with the specified name or <code>null</code>
125 * if no such variable is defined.
126 *
127 * @see Map#get(Object)
128 */
129 public Object get( String name )
130 {
131 return name_to_var.get( name );
132 }
133
134 /***
135 * Gets the system property name for plugin property name
136 * of the specified variable.
137 *
138 * @param var The variable from this table.
139 * @param property_name
140 * The name of <code>var</code> plugin property.
141 * @return The corresponding system property name.
142 * For plugin property <code>property.name</code>
143 * of variable with name <code>var</code>
144 * from table <code>tab</code>
145 * system property name is
146 * <code>tab.var.property.name</code>.
147 * @throws IllegalArgumentException
148 * If table doesn't contain <code>var</code>.
149 */
150 public String getPropertyName( Object var, String property_name )
151 {
152 if( !var_to_name.containsKey( var ) )
153 {
154 throw new IllegalArgumentException( var.getClass().getName() );
155 }
156 return (String)var_to_name.get( var ) + "." + property_name;
157 }
158
159 /***
160 * Gets the value of plugin property with the specified name
161 * for the specified variable.
162 *
163 * @param var The variable from this table.
164 * @param property_name
165 * The name of <code>var</code> plugin property.
166 * @return The value of the plugin property
167 * for the specified variable.
168 * @throws IllegalArgumentException
169 * If table doesn't contain <code>var</code>.
170 * @see #getPropertyName(Object,String)
171 * getPropertyName( var, property_name )
172 */
173 public String getProperty( Object var, String property_name )
174 {
175 return System.getProperty( getPropertyName( var, property_name ) );
176 }
177
178 /***
179 * Gets the value of plugin property with the specified name
180 * for the specified variable
181 * or default value if this property is not defined.
182 *
183 * @param var The variable from this table.
184 * @param property_name
185 * The name of <code>var</code> plugin property.
186 * @param default_property_value
187 * A default value is used if for the specified variable
188 * there is no plugin property with the specified name.
189 * @return The value of the plugin property
190 * for the specified variable.
191 * @throws IllegalArgumentException
192 * If table doesn't contain <code>var</code>.
193 * @see #getPropertyName(Object,String)
194 * getPropertyName( var, property_name )
195 */
196 public String getProperty( Object var
197 , String property_name
198 , String default_property_value
199 )
200 {
201 return System.getProperty( getPropertyName( var, property_name )
202 , default_property_value
203 );
204 }
205
206 /***
207 * Gets the name of this table.
208 *
209 * @return The name of this table.
210 */
211 public String getName()
212 {
213 return name;
214 }
215
216 /***
217 * Checks if this table contains a variable with the specified name.
218 *
219 * @param name The name to check.
220 * @return <code>true</code> if this table contains a variable
221 * with specified name, <code>false</code> otherwise.
222 */
223 public boolean containsName( String name )
224 {
225 return name_to_var.containsKey( name );
226 }
227
228 /***
229 * Checks if this table contains the specified variable.
230 *
231 * @param var The object to check.
232 * @return <code>true</code> if this table contains
233 * the specified object, <code>false</code> otherwise.
234 */
235 public boolean containsObject( Object var )
236 {
237 return var_to_name.containsKey( var );
238 }
239
240 /***
241 * Puts the new variable with the specifed name.
242 *
243 * @param name The name of variable.
244 * @param var The value of variable.
245 * @return The previous value associated with the specified name,
246 * or <code>null</code> if there was
247 * no variable with such name.
248 */
249 public Object put( String name, Object var )
250 {
251 Object res = name_to_var.put( name, var );
252
253 if( res != null )
254 {
255 var_to_name.remove( var );
256 }
257
258 var_to_name.put( var, getName() + "." + name );
259
260 return res;
261 }
262
263 /***
264 * Loads variables from the specified input stream.
265 *
266 * @param in The input stream containing
267 * dynamic variables definitions.
268 * The data format is specified in
269 * (its structure is described in
270 * {@link java.util.Properties#load(java.io.InputStream)
271 * Properties.load( InputStream )} description.
272 * Property name is variable name
273 * and property value is variable type
274 * (fully-qualified Java class name).
275 *
276 * @throws IOException
277 * If there was an I/O error during the input stream reading.
278 * @throws IllegalArgumentException
279 * If there was no type defined for a variable.
280 * or there is a syntax error in the variable name
281 * or in the variable type.
282 * @throws ClassNotFoundException
283 * If the variable type is not found.
284 * @throws IllegalAccessException
285 * If an access to a definition of
286 * the variable type is denied.
287 * @throws InstantiationException
288 * If the variable can not be created.
289 *
290 * @see #load(String,String)
291 * load( String, String )
292 * @see java.util.Properties#load(java.io.InputStream)
293 * Properties.load( InputStream )
294 */
295 public void load( InputStream in )
296 throws IOException, ClassNotFoundException
297 {
298 Properties props = new Properties();
299
300 props.load( in );
301
302 String varname;
303 String vartype;
304
305 Iterator iter = props.keySet().iterator();
306
307 while( iter.hasNext() )
308 {
309 varname = (String)iter.next();
310 vartype = props.getProperty( varname ).trim();
311
312 if( vartype.length() == 0 )
313 {
314 throw new IllegalArgumentException( varname );
315 }
316
317 load( varname, vartype );
318 }
319 }
320
321 /***
322 * Loads a variable of the specified type and associates it with
323 * the specified name. A variable is created using class constructor
324 * without parameters.
325 *
326 * @param name The variable name.
327 * @param type The fully qualified name of variable's class.
328 *
329 * @throws IllegalArgumentException
330 * If there is a syntax error in the variable name
331 * or in the variable type.
332 * @throws ClassNotFoundException
333 * If the variable type is not found
334 * can not be accessed
335 * or if the variable can not be created.
336 * The exception message contains the class name.
337 */
338 public void load( String name, String type )
339 throws ClassNotFoundException
340 {
341 if( !name.matches( "[a-zA-Z_]//w*" ) )
342 {
343 throw new IllegalArgumentException( "name: " + name );
344 }
345
346 if( !type.matches( "[a-zA-Z_]//w*(//.[a-zA-Z_]//w*)*" ) )
347 {
348 throw new IllegalArgumentException( "type: " + type );
349 }
350
351 Object var;
352
353 try
354 {
355 var = Class.forName( type ).newInstance();
356 }
357 catch( Exception e )
358 {
359 throw new ClassNotFoundException( type, e );
360 }
361
362 put( name, var );
363 }
364 }