History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/rmi/server/ActivationGroupImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/rmi/server/ActivationGroupImpl.java+505−0
@@ -0,0 +1,505 @@
1/*
2 * Copyright (c) 1997, 2006, 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 sun.rmi.server;
27
28import java.io.IOException;
29import java.lang.reflect.Constructor;
30import java.lang.reflect.InvocationTargetException;
31import java.net.ServerSocket;
32import java.rmi.MarshalledObject;
33import java.rmi.NoSuchObjectException;
34import java.rmi.Remote;
35import java.rmi.RemoteException;
36import java.rmi.activation.Activatable;
37import java.rmi.activation.ActivationDesc;
38import java.rmi.activation.ActivationException;
39import java.rmi.activation.ActivationGroup;
40import java.rmi.activation.ActivationGroupID;
41import java.rmi.activation.ActivationID;
42import java.rmi.activation.UnknownObjectException;
43import java.rmi.server.RMIClassLoader;
44import java.rmi.server.RMIServerSocketFactory;
45import java.rmi.server.RMISocketFactory;
46import java.rmi.server.UnicastRemoteObject;
47import java.security.AccessController;
48import java.security.PrivilegedActionException;
49import java.security.PrivilegedExceptionAction;
50import java.util.ArrayList;
51import java.util.Hashtable;
52import java.util.List;
53import sun.rmi.registry.RegistryImpl;
54
55/**
56 * The default activation group implementation.
57 *
58 * @author Ann Wollrath
59 * @since 1.2
60 * @see java.rmi.activation.ActivationGroup
61 */
62public class ActivationGroupImpl extends ActivationGroup {
63
64 // use serialVersionUID from JDK 1.2.2 for interoperability
65 private static final long serialVersionUID = 5758693559430427303L;
66
67 /** maps persistent IDs to activated remote objects */
68 private final Hashtable<ActivationID,ActiveEntry> active =
69 new Hashtable<ActivationID,ActiveEntry>();
70 private boolean groupInactive = false;
71 private final ActivationGroupID groupID;
72 private final List<ActivationID> lockedIDs = new ArrayList<ActivationID>();
73
74 /**
75 * Creates a default activation group implementation.
76 *
77 * @param id the group's identifier
78 * @param data ignored
79 */
80 public ActivationGroupImpl(ActivationGroupID id, MarshalledObject<?> data)
81 throws RemoteException
82 {
83 super(id);
84 groupID = id;
85
86 /*
87 * Unexport activation group impl and attempt to export it on
88 * an unshared anonymous port. See 4692286.
89 */
90 unexportObject(this, true);
91 RMIServerSocketFactory ssf = new ServerSocketFactoryImpl();
92 UnicastRemoteObject.exportObject(this, 0, null, ssf);
93
94 if (System.getSecurityManager() == null) {
95 try {
96 // Provide a default security manager.
97 System.setSecurityManager(new SecurityManager());
98
99 } catch (Exception e) {
100 throw new RemoteException("unable to set security manager", e);
101 }
102 }
103 }
104
105 /**
106 * Trivial server socket factory used to export the activation group
107 * impl on an unshared port.
108 */
109 private static class ServerSocketFactoryImpl
110 implements RMIServerSocketFactory
111 {
112 public ServerSocket createServerSocket(int port) throws IOException
113 {
114 RMISocketFactory sf = RMISocketFactory.getSocketFactory();
115 if (sf == null) {
116 sf = RMISocketFactory.getDefaultSocketFactory();
117 }
118 return sf.createServerSocket(port);
119 }
120 }
121
122 /*
123 * Obtains a lock on the ActivationID id before returning. Allows only one
124 * thread at a time to hold a lock on a particular id. If the lock for id
125 * is in use, all requests for an equivalent (in the Object.equals sense)
126 * id will wait for the id to be notified and use the supplied id as the
127 * next lock. The caller of "acquireLock" must execute the "releaseLock"
128 * method" to release the lock and "notifyAll" waiters for the id lock
129 * obtained from this method. The typical usage pattern is as follows:
130 *
131 * try {
132 * acquireLock(id);
133 * // do stuff pertaining to id...
134 * } finally {
135 * releaseLock(id);
136 * checkInactiveGroup();
137 * }
138 */
139 private void acquireLock(ActivationID id) {
140
141 ActivationID waitForID;
142
143 for (;;) {
144
145 synchronized (lockedIDs) {
146 int index = lockedIDs.indexOf(id);
147 if (index < 0) {
148 lockedIDs.add(id);
149 return;
150 } else {
151 waitForID = lockedIDs.get(index);
152 }
153 }
154
155 synchronized (waitForID) {
156 synchronized (lockedIDs) {
157 int index = lockedIDs.indexOf(waitForID);
158 if (index < 0) continue;
159 ActivationID actualID = lockedIDs.get(index);
160 if (actualID != waitForID)
161 /*
162 * don't wait on an id that won't be notified.
163 */
164 continue;
165 }
166
167 try {
168 waitForID.wait();
169 } catch (InterruptedException ignore) {
170 }
171 }
172 }
173
174 }
175
176 /*
177 * Releases the id lock obtained via the "acquireLock" method and then
178 * notifies all threads waiting on the lock.
179 */
180 private void releaseLock(ActivationID id) {
181 synchronized (lockedIDs) {
182 id = lockedIDs.remove(lockedIDs.indexOf(id));
183 }
184
185 synchronized (id) {
186 id.notifyAll();
187 }
188 }
189
190 /**
191 * Creates a new instance of an activatable remote object. The
192 * <code>Activator</code> calls this method to create an activatable
193 * object in this group. This method should be idempotent; a call to
194 * activate an already active object should return the previously
195 * activated object.
196 *
197 * Note: this method assumes that the Activator will only invoke
198 * newInstance for the same object in a serial fashion (i.e.,
199 * the activator will not allow the group to see concurrent requests
200 * to activate the same object.
201 *
202 * @param id the object's activation identifier
203 * @param desc the object's activation descriptor
204 * @return a marshalled object containing the activated object's stub
205 */
206 public MarshalledObject<? extends Remote>
207 newInstance(final ActivationID id,
208 final ActivationDesc desc)
209 throws ActivationException, RemoteException
210 {
211 RegistryImpl.checkAccess("ActivationInstantiator.newInstance");
212
213 if (!groupID.equals(desc.getGroupID()))
214 throw new ActivationException("newInstance in wrong group");
215
216 try {
217 acquireLock(id);
218 synchronized (this) {
219 if (groupInactive == true)
220 throw new InactiveGroupException("group is inactive");
221 }
222
223 ActiveEntry entry = active.get(id);
224 if (entry != null)
225 return entry.mobj;
226
227 String className = desc.getClassName();
228
229 final Class<? extends Remote> cl =
230 RMIClassLoader.loadClass(desc.getLocation(), className)
231 .asSubclass(Remote.class);
232 Remote impl = null;
233
234 final Thread t = Thread.currentThread();
235 final ClassLoader savedCcl = t.getContextClassLoader();
236 ClassLoader objcl = cl.getClassLoader();
237 final ClassLoader ccl = covers(objcl, savedCcl) ? objcl : savedCcl;
238
239 /*
240 * Fix for 4164971: allow non-public activatable class
241 * and/or constructor, create the activatable object in a
242 * privileged block
243 */
244 try {
245 /*
246 * The code below is in a doPrivileged block to
247 * protect against user code which code might have set
248 * a global socket factory (in which case application
249 * code would be on the stack).
250 */
251 impl = AccessController.doPrivileged(
252 new PrivilegedExceptionAction<Remote>() {
253 public Remote run() throws InstantiationException,
254 NoSuchMethodException, IllegalAccessException,
255 InvocationTargetException
256 {
257 Constructor<? extends Remote> constructor =
258 cl.getDeclaredConstructor(
259 ActivationID.class, MarshalledObject.class);
260 constructor.setAccessible(true);
261 try {
262 /*
263 * Fix for 4289544: make sure to set the
264 * context class loader to be the class
265 * loader of the impl class before
266 * constructing that class.
267 */
268 t.setContextClassLoader(ccl);
269 return constructor.newInstance(id,
270 desc.getData());
271 } finally {
272 t.setContextClassLoader(savedCcl);
273 }
274 }
275 });
276 } catch (PrivilegedActionException pae) {
277 Throwable e = pae.getException();
278
279 // narrow the exception's type and rethrow it
280 if (e instanceof InstantiationException) {
281 throw (InstantiationException) e;
282 } else if (e instanceof NoSuchMethodException) {
283 throw (NoSuchMethodException) e;
284 } else if (e instanceof IllegalAccessException) {
285 throw (IllegalAccessException) e;
286 } else if (e instanceof InvocationTargetException) {
287 throw (InvocationTargetException) e;
288 } else if (e instanceof RuntimeException) {
289 throw (RuntimeException) e;
290 } else if (e instanceof Error) {
291 throw (Error) e;
292 }
293 }
294
295 entry = new ActiveEntry(impl);
296 active.put(id, entry);
297 return entry.mobj;
298
299 } catch (NoSuchMethodException e) {
300 /* user forgot to provide activatable constructor? */
301 throw new ActivationException
302 ("Activatable object must provide an activation"+
303 " constructor", e);
304
305 } catch (NoSuchMethodError e) {
306 /* code recompiled and user forgot to provide
307 * activatable constructor?
308 */
309 throw new ActivationException
310 ("Activatable object must provide an activation"+
311 " constructor", e );
312
313 } catch (InvocationTargetException e) {
314 throw new ActivationException("exception in object constructor",
315 e.getTargetException());
316
317 } catch (Exception e) {
318 throw new ActivationException("unable to activate object", e);
319 } finally {
320 releaseLock(id);
321 checkInactiveGroup();
322 }
323 }
324
325
326 /**
327 * The group's <code>inactiveObject</code> method is called
328 * indirectly via a call to the <code>Activatable.inactive</code>
329 * method. A remote object implementation must call
330 * <code>Activatable</code>'s <code>inactive</code> method when
331 * that object deactivates (the object deems that it is no longer
332 * active). If the object does not call
333 * <code>Activatable.inactive</code> when it deactivates, the
334 * object will never be garbage collected since the group keeps
335 * strong references to the objects it creates. <p>
336 *
337 * The group's <code>inactiveObject</code> method
338 * unexports the remote object from the RMI runtime so that the
339 * object can no longer receive incoming RMI calls. This call will
340 * only succeed if the object has no pending/executing calls. If
341 * the object does have pending/executing RMI calls, then false
342 * will be returned.
343 *
344 * If the object has no pending/executing calls, the object is
345 * removed from the RMI runtime and the group informs its
346 * <code>ActivationMonitor</code> (via the monitor's
347 * <code>inactiveObject</code> method) that the remote object is
348 * not currently active so that the remote object will be
349 * re-activated by the activator upon a subsequent activation
350 * request.
351 *
352 * @param id the object's activation identifier
353 * @returns true if the operation succeeds (the operation will
354 * succeed if the object in currently known to be active and is
355 * either already unexported or is currently exported and has no
356 * pending/executing calls); false is returned if the object has
357 * pending/executing calls in which case it cannot be deactivated
358 * @exception UnknownObjectException if object is unknown (may already
359 * be inactive)
360 * @exception RemoteException if call informing monitor fails
361 */
362 public boolean inactiveObject(ActivationID id)
363 throws ActivationException, UnknownObjectException, RemoteException
364 {
365
366 try {
367 acquireLock(id);
368 synchronized (this) {
369 if (groupInactive == true)
370 throw new ActivationException("group is inactive");
371 }
372
373 ActiveEntry entry = active.get(id);
374 if (entry == null) {
375 // REMIND: should this be silent?
376 throw new UnknownObjectException("object not active");
377 }
378
379 try {
380 if (Activatable.unexportObject(entry.impl, false) == false)
381 return false;
382 } catch (NoSuchObjectException allowUnexportedObjects) {
383 }
384
385 try {
386 super.inactiveObject(id);
387 } catch (UnknownObjectException allowUnregisteredObjects) {
388 }
389
390 active.remove(id);
391
392 } finally {
393 releaseLock(id);
394 checkInactiveGroup();
395 }
396
397 return true;
398 }
399
400 /*
401 * Determines if the group has become inactive and
402 * marks it as such.
403 */
404 private void checkInactiveGroup() {
405 boolean groupMarkedInactive = false;
406 synchronized (this) {
407 if (active.size() == 0 && lockedIDs.size() == 0 &&
408 groupInactive == false)
409 {
410 groupInactive = true;
411 groupMarkedInactive = true;
412 }
413 }
414
415 if (groupMarkedInactive) {
416 try {
417 super.inactiveGroup();
418 } catch (Exception ignoreDeactivateFailure) {
419 }
420
421 try {
422 UnicastRemoteObject.unexportObject(this, true);
423 } catch (NoSuchObjectException allowUnexportedGroup) {
424 }
425 }
426 }
427
428 /**
429 * The group's <code>activeObject</code> method is called when an
430 * object is exported (either by <code>Activatable</code> object
431 * construction or an explicit call to
432 * <code>Activatable.exportObject</code>. The group must inform its
433 * <code>ActivationMonitor</code> that the object is active (via
434 * the monitor's <code>activeObject</code> method) if the group
435 * hasn't already done so.
436 *
437 * @param id the object's identifier
438 * @param obj the remote object implementation
439 * @exception UnknownObjectException if object is not registered
440 * @exception RemoteException if call informing monitor fails
441 */
442 public void activeObject(ActivationID id, Remote impl)
443 throws ActivationException, UnknownObjectException, RemoteException
444 {
445
446 try {
447 acquireLock(id);
448 synchronized (this) {
449 if (groupInactive == true)
450 throw new ActivationException("group is inactive");
451 }
452 if (!active.contains(id)) {
453 ActiveEntry entry = new ActiveEntry(impl);
454 active.put(id, entry);
455 // created new entry, so inform monitor of active object
456 try {
457 super.activeObject(id, entry.mobj);
458 } catch (RemoteException e) {
459 // daemon can still find it by calling newInstance
460 }
461 }
462 } finally {
463 releaseLock(id);
464 checkInactiveGroup();
465 }
466 }
467
468 /**
469 * Entry in table for active object.
470 */
471 private static class ActiveEntry {
472 Remote impl;
473 MarshalledObject<Remote> mobj;
474
475 ActiveEntry(Remote impl) throws ActivationException {
476 this.impl = impl;
477 try {
478 this.mobj = new MarshalledObject<Remote>(impl);
479 } catch (IOException e) {
480 throw new
481 ActivationException("failed to marshal remote object", e);
482 }
483 }
484 }
485
486 /**
487 * Returns true if the first argument is either equal to, or is a
488 * descendant of, the second argument. Null is treated as the root of
489 * the tree.
490 */
491 private static boolean covers(ClassLoader sub, ClassLoader sup) {
492 if (sup == null) {
493 return true;
494 } else if (sub == null) {
495 return false;
496 }
497 do {
498 if (sub == sup) {
499 return true;
500 }
501 sub = sub.getParent();
502 } while (sub != null);
503 return false;
504 }
505}