1 /* ActivationGroupDesc.java -- the RMI activation group descriptor
2    Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006
3    Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 
40 package java.rmi.activation;
41 
42 import gnu.java.rmi.activation.DefaultActivationGroup;
43 
44 import java.io.Serializable;
45 import java.rmi.MarshalledObject;
46 import java.util.Arrays;
47 import java.util.Enumeration;
48 import java.util.Iterator;
49 import java.util.Properties;
50 import java.util.TreeSet;
51 import java.util.zip.Adler32;
52 
53 /**
54  * Contains information, necessary to create of recreate the activation objects.
55  * The group descriptor contains:
56  * <ul>
57  * <li>The name of the group's class. This class is derived from the
58  * {@link ActivationGroup}.</li>
59  * <li>The group class code location.</li>
60  * <li>The marshalled object that contains the group specific initialization
61  * information</li>
62  * </ul>
63  * The groups are created by the {@link ActivationGroup#createGroup} method that
64  * expectes the group class to have the two parameter constructor, the first
65  * parameter being the {@link ActivationGroupID} and the second the
66  * {@link MarshalledObject}.
67  *
68  * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub)
69  */
70 public final class ActivationGroupDesc
71     implements Serializable
72 {
73   /**
74    * Contains the startup options for the {@link ActivationGroup}
75    * implementations. Allows to override system properties and specify other
76    * options for the implementation groups.
77    *
78    * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub)
79    */
80   public static class CommandEnvironment
81       implements Serializable
82   {
83 
84     /**
85      * Use the SVUID for interoperability.
86      */
87     static final long serialVersionUID = 6165754737887770191L;
88 
89     /**
90      * The zero size string array used as argv value when null is passed.
91      */
92     private static final String[] NO_ARGS = new String[0];
93 
94     /**
95      * The path to the java executable (or null for using default jre).
96      */
97     final String command;
98 
99     /**
100      * The extra parameters (may be empty array but never null).
101      */
102     final String[] options;
103 
104     /**
105      * Create the new command environment.
106      *
107      * @param commandPatch the full path (and name) to the java executable of
108      *          null for using the default executable.
109      * @param args extra options that will be used when creating the activation
110      *          group. Null has the same effect as the empty list.
111      */
CommandEnvironment(String commandPatch, String[] args)112     public CommandEnvironment(String commandPatch, String[] args)
113     {
114       command = commandPatch;
115       if (args != null)
116         options = args;
117       else
118         options = NO_ARGS;
119     }
120 
121     /**
122      * Get the path to the java executable.
123      *
124      * @return the path to the java executable or null for using the default
125      * jre.
126      */
getCommandPath()127     public String getCommandPath()
128     {
129       return command;
130     }
131 
132     /**
133      * Get the additional command options.
134      *
135      * @return the command options array, may be empty string
136      */
getCommandOptions()137     public String[] getCommandOptions()
138     {
139       return options;
140     }
141 
142     /**
143      * Compare for content equality.
144      */
equals(Object obj)145     public boolean equals(Object obj)
146     {
147       if (obj instanceof CommandEnvironment)
148         {
149           CommandEnvironment that = (CommandEnvironment) obj;
150 
151           if (command == null || that.command == null)
152             {
153               // Use direct comparison if null is involved.
154               if (command != that.command)
155                 return false;
156             }
157           else
158             {
159               // Use .equals if null is not involved.
160               if (! this.command.equals(that.command))
161                 return false;
162             }
163 
164           return Arrays.equals(options, that.options);
165         }
166       else
167         return false;
168     }
169 
170     /**
171      * Get the hash code.
172      */
hashCode()173     public int hashCode()
174     {
175       int h = command == null ? 0 : command.hashCode();
176       for (int i = 0; i < options.length; i++)
177         h ^= options[i].hashCode();
178 
179       return h;
180     }
181   }
182 
183   /**
184    * Use the SVUID for interoperability.
185    */
186   static final long serialVersionUID = - 4936225423168276595L;
187 
188   /**
189    * The group class name or null for the default group class implementation.
190    */
191   final String className;
192 
193   /**
194    * The group class download location URL (codebase), ignored by the
195    * default implementation.
196    */
197   final String location;
198 
199   /**
200    * The group initialization data.
201    */
202   final MarshalledObject<?> data;
203 
204   /**
205    * The path to the group jre and the parameters of this jre, may be
206    * null for the default jre.
207    */
208   final ActivationGroupDesc.CommandEnvironment env;
209 
210   /**
211    * The properties that override the system properties.
212    */
213   final Properties props;
214 
215   /**
216    * The cached hash code.
217    */
218   transient long hash;
219 
220   /**
221    * Create the new activation group descriptor that will use the default
222    * activation group implementation with the given properties and
223    * environment.
224    *
225    * @param aProperties the properties that override the system properties
226    * @param environment the command line (and parameters), indicating, where to
227    *          find the jre executable and with that parameters to call it. May
228    *          be null if the default executable should be used. In this case,
229    *          the activation group with the null name (the system default group)
230    *          will be created.
231    */
ActivationGroupDesc(Properties aProperties, ActivationGroupDesc.CommandEnvironment environment)232   public ActivationGroupDesc(Properties aProperties,
233                              ActivationGroupDesc.CommandEnvironment environment)
234   {
235     this(DefaultActivationGroup.class.getName(), null, null, aProperties,
236          environment);
237   }
238 
239   /**
240    * Create the new activation group descriptor.
241    *
242    * @param aClassName the name of the group implementation class. The null
243    *          value indicates the default implementation.
244    * @param aLocation the location, from where the group implementation class
245    *          should be loaded (ignored for the system default implementation).
246    * @param aData the group intialization data
247    * @param aProperties the properties that will override the system properties
248    *          of the new group. These properties will be translated into -D
249    *          options.
250    * @param environment the record, containing path to the jre executable and
251    *          start options for the jre or null for using the default jre and
252    *          options.
253    */
ActivationGroupDesc(String aClassName, String aLocation, MarshalledObject<?> aData, Properties aProperties, ActivationGroupDesc.CommandEnvironment environment)254   public ActivationGroupDesc(String aClassName, String aLocation,
255                              MarshalledObject<?> aData, Properties aProperties,
256                              ActivationGroupDesc.CommandEnvironment environment)
257   {
258     className = aClassName;
259     location = aLocation;
260     data = aData;
261     props = aProperties;
262     env = environment;
263   }
264 
265   /**
266    * Get the activation group class name.
267    *
268    * @return the activation group class name (null for default implementation)
269    */
getClassName()270   public String getClassName()
271   {
272     return className;
273   }
274 
275   /**
276    * Get the location, from where the group class will be loaded
277    *
278    * @return the location, from where the implementation should be loaded (null
279    *         for the default implementation)
280    */
getLocation()281   public String getLocation()
282   {
283     return location;
284   }
285 
286   /**
287    * Get the group intialization data.
288    *
289    * @return the group intialization data in the marshalled form.
290    */
getData()291   public MarshalledObject<?> getData()
292   {
293     return data;
294   }
295 
296   /**
297    * Get the overridded system properties.
298    *
299    * @return the overridden group system properties.
300    */
getPropertyOverrides()301   public Properties getPropertyOverrides()
302   {
303     return props;
304   }
305 
306   /**
307    * Get the group command environment, containing path to the jre executable
308    * and startup options.
309    *
310    * @return the command environment or null if the default environment should
311    *         be used.
312    */
getCommandEnvironment()313   public ActivationGroupDesc.CommandEnvironment getCommandEnvironment()
314   {
315     return env;
316   }
317 
318   /**
319    * Compare for the content equality.
320    */
equals(Object obj)321   public boolean equals(Object obj)
322   {
323     if (obj instanceof ActivationGroupDesc)
324       {
325         ActivationGroupDesc that = (ActivationGroupDesc) obj;
326 
327         // Ensure the hashcodes are computed.
328         if (hash == 0)
329           hashCode();
330         if (that.hash == 0)
331           that.hashCode();
332 
333         // We compare the hash fields as they are type long rather than int.
334         if (hash != that.hash)
335           return false;
336 
337         if (! eq(className, that.className))
338           return false;
339         if (! eq(data, that.data))
340           return false;
341         if (! eq(env, that.env))
342           return false;
343         if (! eq(location, that.location))
344           return false;
345 
346         // Compare the properties.
347         if (eq(props, that.props))
348           return true;
349 
350         if (props.size() != that.props.size())
351           return false;
352 
353         Enumeration en = props.propertyNames();
354         Object key, value;
355 
356         while (en.hasMoreElements())
357           {
358             key = en.nextElement();
359             if (! that.props.containsKey(key))
360               return false;
361             if (! eq(props.get(key), that.props.get(key)))
362               return false;
363           }
364         return true;
365       }
366     else
367       return false;
368   }
369 
370   /**
371    * Compare for direct equality if one or both parameters are null, otherwise
372    * call .equals.
373    */
eq(Object a, Object b)374   static boolean eq(Object a, Object b)
375   {
376     if (a == null || b == null)
377       return a == b;
378     else
379       return a.equals(b);
380   }
381 
382   /**
383    * Return the hashcode.
384    */
hashCode()385   public int hashCode()
386   {
387     if (hash==0)
388       {
389         // Using Adler32 - the hashcode is cached, will be computed only
390         // once and due need to scan properties is the expensive operation
391         // anyway. Reliability is more important.
392         Adler32 adler = new Adler32();
393         if (className!=null)
394           adler.update(className.getBytes());
395         if (data!=null)
396           adler.update(data.hashCode());
397         if (env!=null)
398           adler.update(env.hashCode());
399         if (location!=null)
400           adler.update(location.getBytes());
401         if (props!=null)
402           {
403             Enumeration en = props.propertyNames();
404 
405             // Using the intermediate sorted set to ensure that the
406             // properties are sorted.
407             TreeSet pr = new TreeSet();
408 
409             Object key;
410             Object value;
411             while (en.hasMoreElements())
412               {
413                 key = en.nextElement();
414                 if (key!=null)
415                   pr.add(key);
416               }
417 
418             Iterator it = pr.iterator();
419             while (it.hasNext())
420               {
421                 key = it.next();
422                 value = props.get(key);
423                 adler.update(key.hashCode());
424                 if (value!=null)
425                   adler.update(value.hashCode());
426               }
427           }
428           hash = adler.getValue();
429         }
430     return (int) hash;
431   }
432 
433 }
434