1 /*
   2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.rmi.activation;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import java.io.Serializable;
  31 import java.rmi.MarshalledObject;
  32 import java.util.Arrays;
  33 import java.util.Properties;
  34 
  35 /**
  36  * An activation group descriptor contains the information necessary to
  37  * create/recreate an activation group in which to activate objects.
  38  * Such a descriptor contains: <ul>
  39  * <li> the group's class name,
  40  * <li> the group's code location (the location of the group's class), and
  41  * <li> a "marshalled" object that can contain group specific
  42  * initialization data. </ul> <p>
  43  *
  44  * The group's class must be a concrete subclass of
  45  * <code>ActivationGroup</code>. A subclass of
  46  * <code>ActivationGroup</code> is created/recreated via the
  47  * <code>ActivationGroup.createGroup</code> static method that invokes
  48  * a special constructor that takes two arguments: <ul>
  49  *
  50  * <li> the group's <code>ActivationGroupID</code>, and
  51  * <li> the group's initialization data (in a
  52  * <code>java.rmi.MarshalledObject</code>)</ul>
  53  *
  54  * @author      Ann Wollrath
  55  * @since       1.2
  56  * @see         ActivationGroup
  57  * @see         ActivationGroupID
  58  */
  59 public final class ActivationGroupDesc implements Serializable {
  60 
  61     /**
  62      * @serial The group's fully package qualified class name.
  63      */
  64     private String className;
  65 
  66     /**
  67      * @serial The location from where to load the group's class.
  68      */
  69     private String location;
  70 
  71     /**
  72      * @serial The group's initialization data.
  73      */
  74     private MarshalledObject<?> data;
  75 
  76     /**
  77      * @serial The controlling options for executing the VM in
  78      * another process.
  79      */
  80     private CommandEnvironment env;
  81 
  82     /**
  83      * @serial A properties map which will override those set
  84      * by default in the subprocess environment.
  85      */
  86     private Properties props;
  87 
  88     /** indicate compatibility with the Java 2 SDK v1.2 version of class */
  89     private static final long serialVersionUID = -4936225423168276595L;
  90 
  91     /**
  92      * Constructs a group descriptor that uses the system defaults for group
  93      * implementation and code location.  Properties specify Java
  94      * environment overrides (which will override system properties in
  95      * the group implementation's VM).  The command
  96      * environment can control the exact command/options used in
  97      * starting the child VM, or can be <code>null</code> to accept
  98      * rmid's default.
  99      *
 100      * <p>This constructor will create an <code>ActivationGroupDesc</code>
 101      * with a <code>null</code> group class name, which indicates the system's
 102      * default <code>ActivationGroup</code> implementation.
 103      *
 104      * @param overrides the set of properties to set when the group is
 105      * recreated.
 106      * @param cmd the controlling options for executing the VM in
 107      * another process (or <code>null</code>).
 108      * @since 1.2
 109      */
 110     public ActivationGroupDesc(Properties overrides,
 111                                CommandEnvironment cmd)
 112     {
 113         this(null, null, null, overrides, cmd);
 114     }
 115 
 116     /**
 117      * Specifies an alternate group implementation and execution
 118      * environment to be used for the group.
 119      *
 120      * @param className the group's package qualified class name or
 121      * <code>null</code>. A <code>null</code> group class name indicates
 122      * the system's default <code>ActivationGroup</code> implementation.
 123      * @param location the location from where to load the group's
 124      * class
 125      * @param data the group's initialization data contained in
 126      * marshalled form (could contain properties, for example)
 127      * @param overrides a properties map which will override those set
 128      * by default in the subprocess environment (will be translated
 129      * into <code>-D</code> options), or <code>null</code>.
 130      * @param cmd the controlling options for executing the VM in
 131      * another process (or <code>null</code>).
 132      * @since 1.2
 133      */
 134     public ActivationGroupDesc(String className,
 135                                String location,
 136                                MarshalledObject<?> data,
 137                                Properties overrides,
 138                                CommandEnvironment cmd)
 139     {
 140         this.props = overrides;
 141         this.env = cmd;
 142         this.data = data;
 143         this.location = location;
 144         this.className = className;
 145     }
 146 
 147     /**
 148      * Returns the group's class name (possibly <code>null</code>).  A
 149      * <code>null</code> group class name indicates the system's default
 150      * <code>ActivationGroup</code> implementation.
 151      * @return the group's class name
 152      * @since 1.2
 153      */
 154     public String getClassName() {
 155         return className;
 156     }
 157 
 158     /**
 159      * Returns the group's code location.
 160      * @return the group's code location
 161      * @since 1.2
 162      */
 163     public String getLocation() {
 164         return location;
 165     }
 166 
 167     /**
 168      * Returns the group's initialization data.
 169      * @return the group's initialization data
 170      * @since 1.2
 171      */
 172     public MarshalledObject<?> getData() {
 173         return data;
 174     }
 175 
 176     /**
 177      * Returns the group's property-override list.
 178      * @return the property-override list, or <code>null</code>
 179      * @since 1.2
 180      */
 181     public Properties getPropertyOverrides() {
 182         return (props != null) ? (Properties) props.clone() : null;
 183     }
 184 
 185     /**
 186      * Returns the group's command-environment control object.
 187      * @return the command-environment object, or <code>null</code>
 188      * @since 1.2
 189      */
 190     public CommandEnvironment getCommandEnvironment() {
 191         return this.env;
 192     }
 193 
 194 
 195     /**
 196      * Startup options for ActivationGroup implementations.
 197      *
 198      * This class allows overriding default system properties and
 199      * specifying implementation-defined options for ActivationGroups.
 200      * @since 1.2
 201      */
 202     public static class CommandEnvironment implements Serializable {
 203         private static final long serialVersionUID = 6165754737887770191L;
 204 
 205         /**
 206          * @serial
 207          */
 208         private String command;
 209 
 210         /**
 211          * @serial
 212          */
 213         private String[] options;
 214 
 215         /**
 216          * Create a CommandEnvironment with all the necessary
 217          * information.
 218          *
 219          * @param cmdpath the name of the java executable, including
 220          * the full path, or <code>null</code>, meaning "use rmid's default".
 221          * The named program <em>must</em> be able to accept multiple
 222          * <code>-Dpropname=value</code> options (as documented for the
 223          * "java" tool)
 224          *
 225          * @param argv extra options which will be used in creating the
 226          * ActivationGroup.  Null has the same effect as an empty
 227          * list.
 228          * @since 1.2
 229          */
 230         public CommandEnvironment(String cmdpath,
 231                                   String[] argv)
 232         {
 233             this.command = cmdpath;     // might be null
 234 
 235             // Hold a safe copy of argv in this.options
 236             if (argv == null) {
 237                 this.options = new String[0];
 238             } else {
 239                 this.options = new String[argv.length];
 240                 System.arraycopy(argv, 0, this.options, 0, argv.length);
 241             }
 242         }
 243 
 244         /**
 245          * Fetch the configured path-qualified java command name.
 246          *
 247          * @return the configured name, or <code>null</code> if configured to
 248          * accept the default
 249          * @since 1.2
 250          */
 251         public String getCommandPath() {
 252             return (this.command);
 253         }
 254 
 255         /**
 256          * Fetch the configured java command options.
 257          *
 258          * @return An array of the command options which will be passed
 259          * to the new child command by rmid.
 260          * Note that rmid may add other options before or after these
 261          * options, or both.
 262          * Never returns <code>null</code>.
 263          * @since 1.2
 264          */
 265         public String[] getCommandOptions() {
 266             return options.clone();
 267         }
 268 
 269         /**
 270          * Compares two command environments for content equality.
 271          *
 272          * @param       obj     the Object to compare with
 273          * @return      true if these Objects are equal; false otherwise.
 274          * @see         java.util.Hashtable
 275          * @since 1.2
 276          */
 277         public boolean equals(Object obj) {
 278 
 279             if (obj instanceof CommandEnvironment) {
 280                 CommandEnvironment env = (CommandEnvironment) obj;
 281                 return
 282                     ((command == null ? env.command == null :
 283                       command.equals(env.command)) &&
 284                      Arrays.equals(options, env.options));
 285             } else {
 286                 return false;
 287             }
 288         }
 289 
 290         /**
 291          * Return identical values for similar
 292          * <code>CommandEnvironment</code>s.
 293          * @return an integer
 294          * @see java.util.Hashtable
 295          */
 296         public int hashCode()
 297         {
 298             // hash command and ignore possibly expensive options
 299             return (command == null ? 0 : command.hashCode());
 300         }
 301 
 302         /**
 303          * <code>readObject</code> for custom serialization.
 304          *
 305          * <p>This method reads this object's serialized form for this
 306          * class as follows:
 307          *
 308          * <p>This method first invokes <code>defaultReadObject</code> on
 309          * the specified object input stream, and if <code>options</code>
 310          * is <code>null</code>, then <code>options</code> is set to a
 311          * zero-length array of <code>String</code>.
 312          */
 313         private void readObject(ObjectInputStream in)
 314             throws IOException, ClassNotFoundException
 315         {
 316             in.defaultReadObject();
 317             if (options == null) {
 318                 options = new String[0];
 319             }
 320         }
 321     }
 322 
 323     /**
 324      * Compares two activation group descriptors for content equality.
 325      *
 326      * @param   obj     the Object to compare with
 327      * @return  true if these Objects are equal; false otherwise.
 328      * @see             java.util.Hashtable
 329      * @since 1.2
 330      */
 331     public boolean equals(Object obj) {
 332 
 333         if (obj instanceof ActivationGroupDesc) {
 334             ActivationGroupDesc desc = (ActivationGroupDesc) obj;
 335             return
 336                 ((className == null ? desc.className == null :
 337                   className.equals(desc.className)) &&
 338                  (location == null ? desc.location == null :
 339                   location.equals(desc.location)) &&
 340                  (data == null ? desc.data == null : data.equals(desc.data)) &&
 341                  (env == null ? desc.env == null : env.equals(desc.env)) &&
 342                  (props == null ? desc.props == null :
 343                   props.equals(desc.props)));
 344         } else {
 345             return false;
 346         }
 347     }
 348 
 349     /**
 350      * Produce identical numbers for similar <code>ActivationGroupDesc</code>s.
 351      * @return an integer
 352      * @see java.util.Hashtable
 353      */
 354     public int hashCode() {
 355         // hash location, className, data, and env
 356         // but omit props (may be expensive)
 357         return ((location == null
 358                     ? 0
 359                     : location.hashCode() << 24) ^
 360                 (env == null
 361                     ? 0
 362                     : env.hashCode() << 16) ^
 363                 (className == null
 364                     ? 0
 365                     : className.hashCode() << 8) ^
 366                 (data == null
 367                     ? 0
 368                     : data.hashCode()));
 369     }
 370 }