001 /* ActivationGroupDesc.java -- the RMI activation group descriptor
002 Copyright (c) 1996, 1997, 1998, 1999, 2004, 2006
003 Free Software Foundation, Inc.
004
005 This file is part of GNU Classpath.
006
007 GNU Classpath is free software; you can redistribute it and/or modify
008 it under the terms of the GNU General Public License as published by
009 the Free Software Foundation; either version 2, or (at your option)
010 any later version.
011
012 GNU Classpath is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of
014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 General Public License for more details.
016
017 You should have received a copy of the GNU General Public License
018 along with GNU Classpath; see the file COPYING. If not, write to the
019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020 02110-1301 USA.
021
022 Linking this library statically or dynamically with other modules is
023 making a combined work based on this library. Thus, the terms and
024 conditions of the GNU General Public License cover the whole
025 combination.
026
027 As a special exception, the copyright holders of this library give you
028 permission to link this library with independent modules to produce an
029 executable, regardless of the license terms of these independent
030 modules, and to copy and distribute the resulting executable under
031 terms of your choice, provided that you also meet, for each linked
032 independent module, the terms and conditions of the license of that
033 module. An independent module is a module which is not derived from
034 or based on this library. If you modify this library, you may extend
035 this exception to your version of the library, but you are not
036 obligated to do so. If you do not wish to do so, delete this
037 exception statement from your version. */
038
039
040 package java.rmi.activation;
041
042 import gnu.java.rmi.activation.DefaultActivationGroup;
043
044 import java.io.Serializable;
045 import java.rmi.MarshalledObject;
046 import java.util.Arrays;
047 import java.util.Enumeration;
048 import java.util.Iterator;
049 import java.util.Properties;
050 import java.util.TreeSet;
051 import java.util.zip.Adler32;
052
053 /**
054 * Contains information, necessary to create of recreate the activation objects.
055 * The group descriptor contains:
056 * <ul>
057 * <li>The name of the group's class. This class is derived from the
058 * {@link ActivationGroup}.</li>
059 * <li>The group class code location.</li>
060 * <li>The marshalled object that contains the group specific initialization
061 * information</li>
062 * </ul>
063 * The groups are created by the {@link ActivationGroup#createGroup} method that
064 * expectes the group class to have the two parameter constructor, the first
065 * parameter being the {@link ActivationGroupID} and the second the
066 * {@link MarshalledObject}.
067 *
068 * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub)
069 */
070 public final class ActivationGroupDesc
071 implements Serializable
072 {
073 /**
074 * Contains the startup options for the {@link ActivationGroup}
075 * implementations. Allows to override system properties and specify other
076 * options for the implementation groups.
077 *
078 * @author Audrius Meskauskas (audriusa@bioinformatics.org) (from stub)
079 */
080 public static class CommandEnvironment
081 implements Serializable
082 {
083
084 /**
085 * Use the SVUID for interoperability.
086 */
087 static final long serialVersionUID = 6165754737887770191L;
088
089 /**
090 * The zero size string array used as argv value when null is passed.
091 */
092 private static final String[] NO_ARGS = new String[0];
093
094 /**
095 * The path to the java executable (or null for using default jre).
096 */
097 final String command;
098
099 /**
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 */
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 */
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 */
137 public String[] getCommandOptions()
138 {
139 return options;
140 }
141
142 /**
143 * Compare for content equality.
144 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
313 public ActivationGroupDesc.CommandEnvironment getCommandEnvironment()
314 {
315 return env;
316 }
317
318 /**
319 * Compare for the content equality.
320 */
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 */
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 */
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 }