blob: abe717937f61ff9e313bb5082b0e4d99909ea7c0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 * @since 1.2
94 */
95 public ActivationID(Activator activator) {
96 this.activator = activator;
97 }
98
99 /**
100 * Activate the object for this id.
101 *
102 * @param force if true, forces the activator to contact the group
103 * when activating the object (instead of returning a cached reference);
104 * if false, returning a cached value is acceptable.
105 * @return the reference to the active remote object
106 * @exception ActivationException if activation fails
107 * @exception UnknownObjectException if the object is unknown
108 * @exception RemoteException if remote call fails
109 * @since 1.2
110 */
111 public Remote activate(boolean force)
112 throws ActivationException, UnknownObjectException, RemoteException
113 {
114 try {
115 MarshalledObject<? extends Remote> mobj =
116 activator.activate(this, force);
117 return mobj.get();
118 } catch (RemoteException e) {
119 throw e;
120 } catch (IOException e) {
121 throw new UnmarshalException("activation failed", e);
122 } catch (ClassNotFoundException e) {
123 throw new UnmarshalException("activation failed", e);
124 }
125
126 }
127
128 /**
129 * Returns a hashcode for the activation id. Two identifiers that
130 * refer to the same remote object will have the same hash code.
131 *
132 * @see java.util.Hashtable
133 * @since 1.2
134 */
135 public int hashCode() {
136 return uid.hashCode();
137 }
138
139 /**
140 * Compares two activation ids for content equality.
141 * Returns true if both of the following conditions are true:
142 * 1) the unique identifiers equivalent (by content), and
143 * 2) the activator specified in each identifier
144 * refers to the same remote object.
145 *
146 * @param obj the Object to compare with
147 * @return true if these Objects are equal; false otherwise.
148 * @see java.util.Hashtable
149 * @since 1.2
150 */
151 public boolean equals(Object obj) {
152 if (obj instanceof ActivationID) {
153 ActivationID id = (ActivationID) obj;
154 return (uid.equals(id.uid) && activator.equals(id.activator));
155 } else {
156 return false;
157 }
158 }
159
160 /**
161 * <code>writeObject</code> for custom serialization.
162 *
163 * <p>This method writes this object's serialized form for
164 * this class as follows:
165 *
166 * <p>The <code>writeObject</code> method is invoked on
167 * <code>out</code> passing this object's unique identifier
168 * (a {@link java.rmi.server.UID UID} instance) as the argument.
169 *
170 * <p>Next, the {@link
171 * java.rmi.server.RemoteRef#getRefClass(java.io.ObjectOutput)
172 * getRefClass} method is invoked on the activator's
173 * <code>RemoteRef</code> instance to obtain its external ref
174 * type name. Next, the <code>writeUTF</code> method is
175 * invoked on <code>out</code> with the value returned by
176 * <code>getRefClass</code>, and then the
177 * <code>writeExternal</code> method is invoked on the
178 * <code>RemoteRef</code> instance passing <code>out</code>
179 * as the argument.
180 *
181 * @serialData The serialized data for this class comprises a
182 * <code>java.rmi.server.UID</code> (written with
183 * <code>ObjectOutput.writeObject</code>) followed by the
184 * external ref type name of the activator's
185 * <code>RemoteRef</code> instance (a string written with
186 * <code>ObjectOutput.writeUTF</code>), followed by the
187 * external form of the <code>RemoteRef</code> instance as
188 * written by its <code>writeExternal</code> method.
189 *
190 * <p>The external ref type name of the
191 * <code>RemoteRef</Code> instance is
192 * determined using the definitions of external ref type
193 * names specified in the {@link java.rmi.server.RemoteObject
194 * RemoteObject} <code>writeObject</code> method
195 * <b>serialData</b> specification. Similarly, the data
196 * written by the <code>writeExternal</code> method and read
197 * by the <code>readExternal</code> method of
198 * <code>RemoteRef</code> implementation classes
199 * corresponding to each of the defined external ref type
200 * names is specified in the {@link
201 * java.rmi.server.RemoteObject RemoteObject}
202 * <code>writeObject</code> method <b>serialData</b>
203 * specification.
204 **/
205 private void writeObject(ObjectOutputStream out)
206 throws IOException, ClassNotFoundException
207 {
208 out.writeObject(uid);
209
210 RemoteRef ref;
211 if (activator instanceof RemoteObject) {
212 ref = ((RemoteObject) activator).getRef();
213 } else if (Proxy.isProxyClass(activator.getClass())) {
214 InvocationHandler handler = Proxy.getInvocationHandler(activator);
215 if (!(handler instanceof RemoteObjectInvocationHandler)) {
216 throw new InvalidObjectException(
217 "unexpected invocation handler");
218 }
219 ref = ((RemoteObjectInvocationHandler) handler).getRef();
220
221 } else {
222 throw new InvalidObjectException("unexpected activator type");
223 }
224 out.writeUTF(ref.getRefClass(out));
225 ref.writeExternal(out);
226 }
227
228 /**
229 * <code>readObject</code> for custom serialization.
230 *
231 * <p>This method reads this object's serialized form for this
232 * class as follows:
233 *
234 * <p>The <code>readObject</code> method is invoked on
235 * <code>in</code> to read this object's unique identifier
236 * (a {@link java.rmi.server.UID UID} instance).
237 *
238 * <p>Next, the <code>readUTF</code> method is invoked on
239 * <code>in</code> to read the external ref type name of the
240 * <code>RemoteRef</code> instance for this object's
241 * activator. Next, the <code>RemoteRef</code>
242 * instance is created of an implementation-specific class
243 * corresponding to the external ref type name (returned by
244 * <code>readUTF</code>), and the <code>readExternal</code>
245 * method is invoked on that <code>RemoteRef</code> instance
246 * to read the external form corresponding to the external
247 * ref type name.
248 *
249 * <p>Note: If the external ref type name is
250 * <code>"UnicastRef"</code>, <code>"UnicastServerRef"</code>,
251 * <code>"UnicastRef2"</code>, <code>"UnicastServerRef2"</code>,
252 * or <code>"ActivatableRef"</code>, a corresponding
253 * implementation-specific class must be found, and its
254 * <code>readExternal</code> method must read the serial data
255 * for that external ref type name as specified to be written
256 * in the <b>serialData</b> documentation for this class.
257 * If the external ref type name is any other string (of non-zero
258 * length), a <code>ClassNotFoundException</code> will be thrown,
259 * unless the implementation provides an implementation-specific
260 * class corresponding to that external ref type name, in which
261 * case the <code>RemoteRef</code> will be an instance of
262 * that implementation-specific class.
263 */
264 private void readObject(ObjectInputStream in)
265 throws IOException, ClassNotFoundException
266 {
267 uid = (UID)in.readObject();
268
269 try {
270 Class<? extends RemoteRef> refClass =
271 Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
272 .asSubclass(RemoteRef.class);
273 RemoteRef ref = refClass.newInstance();
274 ref.readExternal(in);
275 activator = (Activator)
276 Proxy.newProxyInstance(null,
277 new Class<?>[] { Activator.class },
278 new RemoteObjectInvocationHandler(ref));
279
280 } catch (InstantiationException e) {
281 throw (IOException)
282 new InvalidObjectException(
283 "Unable to create remote reference").initCause(e);
284 } catch (IllegalAccessException e) {
285 throw (IOException)
286 new InvalidObjectException(
287 "Unable to create remote reference").initCause(e);
288 }
289 }
290}