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
26package java.rmi.activation;
27
28import java.io.IOException;
29import java.io.ObjectInputStream;
30import java.io.Serializable;
31import java.rmi.MarshalledObject;
32import java.util.Arrays;
33import 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 */
59public 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}
371