ActivationID.java revision 13901:b2a69d66dc65
1/*
2 * Copyright (c) 1997, 2013, 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.InvalidObjectException;
30import java.io.ObjectInputStream;
31import java.io.ObjectOutputStream;
32import java.io.Serializable;
33import java.lang.reflect.InvocationHandler;
34import java.lang.reflect.Proxy;
35import java.rmi.MarshalledObject;
36import java.rmi.Remote;
37import java.rmi.RemoteException;
38import java.rmi.UnmarshalException;
39import java.rmi.server.RemoteObject;
40import java.rmi.server.RemoteObjectInvocationHandler;
41import java.rmi.server.RemoteRef;
42import java.rmi.server.UID;
43
44/**
45 * Activation makes use of special identifiers to denote remote
46 * objects that can be activated over time. An activation identifier
47 * (an instance of the class <code>ActivationID</code>) contains several
48 * pieces of information needed for activating an object:
49 * <ul>
50 * <li> a remote reference to the object's activator (a {@link
51 * java.rmi.server.RemoteRef RemoteRef}
52 * instance), and
53 * <li> a unique identifier (a {@link java.rmi.server.UID UID}
54 * instance) for the object. </ul> <p>
55 *
56 * An activation identifier for an object can be obtained by registering
57 * an object with the activation system. Registration is accomplished
58 * in a few ways: <ul>
59 * <li>via the <code>Activatable.register</code> method
60 * <li>via the first <code>Activatable</code> constructor (that takes
61 * three arguments and both registers and exports the object, and
62 * <li>via the first <code>Activatable.exportObject</code> method
63 * that takes the activation descriptor, object and port as arguments;
64 * this method both registers and exports the object. </ul>
65 *
66 * @author      Ann Wollrath
67 * @see         Activatable
68 * @since       1.2
69 */
70public class ActivationID implements Serializable {
71    /**
72     * the object's activator
73     */
74    private transient Activator activator;
75
76    /**
77     * the object's unique id
78     */
79    private transient UID uid = new UID();
80
81    /** indicate compatibility with the Java 2 SDK v1.2 version of class */
82    private static final long serialVersionUID = -4608673054848209235L;
83
84    /**
85     * The constructor for <code>ActivationID</code> takes a single
86     * argument, activator, that specifies a remote reference to the
87     * activator responsible for activating the object associated with
88     * this identifier. An instance of <code>ActivationID</code> is globally
89     * unique.
90     *
91     * @param activator reference to the activator responsible for
92     * activating the object
93     * @throws UnsupportedOperationException if and only if activation is
94     *         not supported by this implementation
95     * @since 1.2
96     */
97    public ActivationID(Activator activator) {
98        this.activator = activator;
99    }
100
101    /**
102     * Activate the object for this id.
103     *
104     * @param force if true, forces the activator to contact the group
105     * when activating the object (instead of returning a cached reference);
106     * if false, returning a cached value is acceptable.
107     * @return the reference to the active remote object
108     * @exception ActivationException if activation fails
109     * @exception UnknownObjectException if the object is unknown
110     * @exception RemoteException if remote call fails
111     * @since 1.2
112     */
113    public Remote activate(boolean force)
114        throws ActivationException, UnknownObjectException, RemoteException
115    {
116        try {
117            MarshalledObject<? extends Remote> mobj =
118                activator.activate(this, force);
119            return mobj.get();
120        } catch (RemoteException e) {
121            throw e;
122        } catch (IOException e) {
123            throw new UnmarshalException("activation failed", e);
124        } catch (ClassNotFoundException e) {
125            throw new UnmarshalException("activation failed", e);
126        }
127
128    }
129
130    /**
131     * Returns a hashcode for the activation id.  Two identifiers that
132     * refer to the same remote object will have the same hash code.
133     *
134     * @see java.util.Hashtable
135     * @since 1.2
136     */
137    public int hashCode() {
138        return uid.hashCode();
139    }
140
141    /**
142     * Compares two activation ids for content equality.
143     * Returns true if both of the following conditions are true:
144     * 1) the unique identifiers equivalent (by content), and
145     * 2) the activator specified in each identifier
146     *    refers to the same remote object.
147     *
148     * @param   obj     the Object to compare with
149     * @return  true if these Objects are equal; false otherwise.
150     * @see             java.util.Hashtable
151     * @since 1.2
152     */
153    public boolean equals(Object obj) {
154        if (obj instanceof ActivationID) {
155            ActivationID id = (ActivationID) obj;
156            return (uid.equals(id.uid) && activator.equals(id.activator));
157        } else {
158            return false;
159        }
160    }
161
162    /**
163     * <code>writeObject</code> for custom serialization.
164     *
165     * <p>This method writes this object's serialized form for
166     * this class as follows:
167     *
168     * <p>The <code>writeObject</code> method is invoked on
169     * <code>out</code> passing this object's unique identifier
170     * (a {@link java.rmi.server.UID UID} instance) as the argument.
171     *
172     * <p>Next, the {@link
173     * java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput)
174     * getRefClass} method is invoked on the activator's
175     * <code>RemoteRef</code> instance to obtain its external ref
176     * type name.  Next, the <code>writeUTF</code> method is
177     * invoked on <code>out</code> with the value returned by
178     * <code>getRefClass</code>, and then the
179     * <code>writeExternal</code> method is invoked on the
180     * <code>RemoteRef</code> instance passing <code>out</code>
181     * as the argument.
182     *
183     * @serialData The serialized data for this class comprises a
184     * <code>java.rmi.server.UID</code> (written with
185     * <code>ObjectOutput.writeObject</code>) followed by the
186     * external ref type name of the activator's
187     * <code>RemoteRef</code> instance (a string written with
188     * <code>ObjectOutput.writeUTF</code>), followed by the
189     * external form of the <code>RemoteRef</code> instance as
190     * written by its <code>writeExternal</code> method.
191     *
192     * <p>The external ref type name of the
193     * <code>RemoteRef</Code> instance is
194     * determined using the definitions of external ref type
195     * names specified in the {@link java.rmi.server.RemoteObject
196     * RemoteObject} <code>writeObject</code> method
197     * <b>serialData</b> specification.  Similarly, the data
198     * written by the <code>writeExternal</code> method and read
199     * by the <code>readExternal</code> method of
200     * <code>RemoteRef</code> implementation classes
201     * corresponding to each of the defined external ref type
202     * names is specified in the {@link
203     * java.rmi.server.RemoteObject RemoteObject}
204     * <code>writeObject</code> method <b>serialData</b>
205     * specification.
206     **/
207    private void writeObject(ObjectOutputStream out)
208        throws IOException, ClassNotFoundException
209    {
210        out.writeObject(uid);
211
212        RemoteRef ref;
213        if (activator instanceof RemoteObject) {
214            ref = ((RemoteObject) activator).getRef();
215        } else if (Proxy.isProxyClass(activator.getClass())) {
216            InvocationHandler handler = Proxy.getInvocationHandler(activator);
217            if (!(handler instanceof RemoteObjectInvocationHandler)) {
218                throw new InvalidObjectException(
219                    "unexpected invocation handler");
220            }
221            ref = ((RemoteObjectInvocationHandler) handler).getRef();
222
223        } else {
224            throw new InvalidObjectException("unexpected activator type");
225        }
226        out.writeUTF(ref.getRefClass(out));
227        ref.writeExternal(out);
228    }
229
230    /**
231     * <code>readObject</code> for custom serialization.
232     *
233     * <p>This method reads this object's serialized form for this
234     * class as follows:
235     *
236     * <p>The <code>readObject</code> method is invoked on
237     * <code>in</code> to read this object's unique identifier
238     * (a {@link java.rmi.server.UID UID} instance).
239     *
240     * <p>Next, the <code>readUTF</code> method is invoked on
241     * <code>in</code> to read the external ref type name of the
242     * <code>RemoteRef</code> instance for this object's
243     * activator.  Next, the <code>RemoteRef</code>
244     * instance is created of an implementation-specific class
245     * corresponding to the external ref type name (returned by
246     * <code>readUTF</code>), and the <code>readExternal</code>
247     * method is invoked on that <code>RemoteRef</code> instance
248     * to read the external form corresponding to the external
249     * ref type name.
250     *
251     * <p>Note: If the external ref type name is
252     * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>,
253     * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>,
254     * or <code>"ActivatableRef"</code>, a corresponding
255     * implementation-specific class must be found, and its
256     * <code>readExternal</code> method must read the serial data
257     * for that external ref type name as specified to be written
258     * in the <b>serialData</b> documentation for this class.
259     * If the external ref type name is any other string (of non-zero
260     * length), a <code>ClassNotFoundException</code> will be thrown,
261     * unless the implementation provides an implementation-specific
262     * class corresponding to that external ref type name, in which
263     * case the <code>RemoteRef</code> will be an instance of
264     * that implementation-specific class.
265     */
266    private void readObject(ObjectInputStream in)
267        throws IOException, ClassNotFoundException
268    {
269        uid = (UID)in.readObject();
270
271        try {
272            Class<? extends RemoteRef> refClass =
273                Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
274                .asSubclass(RemoteRef.class);
275            RemoteRef ref = refClass.newInstance();
276            ref.readExternal(in);
277            activator = (Activator)
278                Proxy.newProxyInstance(Activator.class.getClassLoader(),
279                                       new Class<?>[] { Activator.class },
280                                       new RemoteObjectInvocationHandler(ref));
281        } catch (InstantiationException e) {
282            throw (IOException)
283                new InvalidObjectException(
284                    "Unable to create remote reference").initCause(e);
285        } catch (IllegalAccessException e) {
286            throw (IOException)
287                new InvalidObjectException(
288                    "Unable to create remote reference").initCause(e);
289        }
290    }
291}
292