View Javadoc

1   /*
2    * Copyright (c) 2001-2004,
3    * RedVerst Group, ISP RAS http://www.ispras.ru
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are met:
8    *
9    * 1. Redistributions of source code must retain the above copyright notice, this
10   *    list of conditions and the following disclaimer.
11   *
12   * 2. Redistributions in binary form must reproduce the above copyright notice,
13   *    this list of conditions and the following disclaimer in the documentation
14   *    and/or other materials provided with the distribution.
15   *
16   * 3. The names "ATP", "TreeDL", "RedVerst", "ISP RAS"
17   *    may not be used to endorse or promote products derived from this software
18   *    without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/*String,Object*/ name_to_var  = new HashMap();
68      private Map/*Object,String*/ var_to_name  = new HashMap();
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/*String*/ names()
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 }