mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.rmi.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.ServerSocket;
|
||||
import java.rmi.MarshalledObject;
|
||||
import java.rmi.NoSuchObjectException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.rmi.activation.Activatable;
|
||||
import java.rmi.activation.ActivationDesc;
|
||||
import java.rmi.activation.ActivationException;
|
||||
import java.rmi.activation.ActivationGroup;
|
||||
import java.rmi.activation.ActivationGroupID;
|
||||
import java.rmi.activation.ActivationID;
|
||||
import java.rmi.activation.UnknownObjectException;
|
||||
import java.rmi.server.RMIClassLoader;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RMISocketFactory;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import sun.rmi.registry.RegistryImpl;
|
||||
|
||||
/**
|
||||
* The default activation group implementation.
|
||||
*
|
||||
* @author Ann Wollrath
|
||||
* @since 1.2
|
||||
* @see java.rmi.activation.ActivationGroup
|
||||
*/
|
||||
public class ActivationGroupImpl extends ActivationGroup {
|
||||
|
||||
// use serialVersionUID from JDK 1.2.2 for interoperability
|
||||
private static final long serialVersionUID = 5758693559430427303L;
|
||||
|
||||
/** maps persistent IDs to activated remote objects */
|
||||
private final Hashtable<ActivationID,ActiveEntry> active =
|
||||
new Hashtable<>();
|
||||
private boolean groupInactive = false;
|
||||
private final ActivationGroupID groupID;
|
||||
private final List<ActivationID> lockedIDs = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a default activation group implementation.
|
||||
*
|
||||
* @param id the group's identifier
|
||||
* @param data ignored
|
||||
*/
|
||||
public ActivationGroupImpl(ActivationGroupID id, MarshalledObject<?> data)
|
||||
throws RemoteException
|
||||
{
|
||||
super(id);
|
||||
groupID = id;
|
||||
|
||||
/*
|
||||
* Unexport activation group impl and attempt to export it on
|
||||
* an unshared anonymous port. See 4692286.
|
||||
*/
|
||||
unexportObject(this, true);
|
||||
RMIServerSocketFactory ssf = new ServerSocketFactoryImpl();
|
||||
UnicastRemoteObject.exportObject(this, 0, null, ssf);
|
||||
|
||||
if (System.getSecurityManager() == null) {
|
||||
try {
|
||||
// Provide a default security manager.
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RemoteException("unable to set security manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trivial server socket factory used to export the activation group
|
||||
* impl on an unshared port.
|
||||
*/
|
||||
private static class ServerSocketFactoryImpl
|
||||
implements RMIServerSocketFactory
|
||||
{
|
||||
public ServerSocket createServerSocket(int port) throws IOException
|
||||
{
|
||||
RMISocketFactory sf = RMISocketFactory.getSocketFactory();
|
||||
if (sf == null) {
|
||||
sf = RMISocketFactory.getDefaultSocketFactory();
|
||||
}
|
||||
return sf.createServerSocket(port);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtains a lock on the ActivationID id before returning. Allows only one
|
||||
* thread at a time to hold a lock on a particular id. If the lock for id
|
||||
* is in use, all requests for an equivalent (in the Object.equals sense)
|
||||
* id will wait for the id to be notified and use the supplied id as the
|
||||
* next lock. The caller of "acquireLock" must execute the "releaseLock"
|
||||
* method" to release the lock and "notifyAll" waiters for the id lock
|
||||
* obtained from this method. The typical usage pattern is as follows:
|
||||
*
|
||||
* try {
|
||||
* acquireLock(id);
|
||||
* // do stuff pertaining to id...
|
||||
* } finally {
|
||||
* releaseLock(id);
|
||||
* checkInactiveGroup();
|
||||
* }
|
||||
*/
|
||||
private void acquireLock(ActivationID id) {
|
||||
|
||||
ActivationID waitForID;
|
||||
|
||||
for (;;) {
|
||||
|
||||
synchronized (lockedIDs) {
|
||||
int index = lockedIDs.indexOf(id);
|
||||
if (index < 0) {
|
||||
lockedIDs.add(id);
|
||||
return;
|
||||
} else {
|
||||
waitForID = lockedIDs.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (waitForID) {
|
||||
synchronized (lockedIDs) {
|
||||
int index = lockedIDs.indexOf(waitForID);
|
||||
if (index < 0) continue;
|
||||
ActivationID actualID = lockedIDs.get(index);
|
||||
if (actualID != waitForID)
|
||||
/*
|
||||
* don't wait on an id that won't be notified.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
waitForID.wait();
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases the id lock obtained via the "acquireLock" method and then
|
||||
* notifies all threads waiting on the lock.
|
||||
*/
|
||||
private void releaseLock(ActivationID id) {
|
||||
synchronized (lockedIDs) {
|
||||
id = lockedIDs.remove(lockedIDs.indexOf(id));
|
||||
}
|
||||
|
||||
synchronized (id) {
|
||||
id.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of an activatable remote object. The
|
||||
* <code>Activator</code> calls this method to create an activatable
|
||||
* object in this group. This method should be idempotent; a call to
|
||||
* activate an already active object should return the previously
|
||||
* activated object.
|
||||
*
|
||||
* Note: this method assumes that the Activator will only invoke
|
||||
* newInstance for the same object in a serial fashion (i.e.,
|
||||
* the activator will not allow the group to see concurrent requests
|
||||
* to activate the same object.
|
||||
*
|
||||
* @param id the object's activation identifier
|
||||
* @param desc the object's activation descriptor
|
||||
* @return a marshalled object containing the activated object's stub
|
||||
*/
|
||||
public MarshalledObject<? extends Remote>
|
||||
newInstance(final ActivationID id,
|
||||
final ActivationDesc desc)
|
||||
throws ActivationException, RemoteException
|
||||
{
|
||||
RegistryImpl.checkAccess("ActivationInstantiator.newInstance");
|
||||
|
||||
if (!groupID.equals(desc.getGroupID()))
|
||||
throw new ActivationException("newInstance in wrong group");
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new InactiveGroupException("group is inactive");
|
||||
}
|
||||
|
||||
ActiveEntry entry = active.get(id);
|
||||
if (entry != null)
|
||||
return entry.mobj;
|
||||
|
||||
String className = desc.getClassName();
|
||||
|
||||
final Class<? extends Remote> cl =
|
||||
RMIClassLoader.loadClass(desc.getLocation(), className)
|
||||
.asSubclass(Remote.class);
|
||||
Remote impl = null;
|
||||
|
||||
final Thread t = Thread.currentThread();
|
||||
final ClassLoader savedCcl = t.getContextClassLoader();
|
||||
ClassLoader objcl = cl.getClassLoader();
|
||||
final ClassLoader ccl = covers(objcl, savedCcl) ? objcl : savedCcl;
|
||||
|
||||
/*
|
||||
* Fix for 4164971: allow non-public activatable class
|
||||
* and/or constructor, create the activatable object in a
|
||||
* privileged block
|
||||
*/
|
||||
try {
|
||||
/*
|
||||
* The code below is in a doPrivileged block to
|
||||
* protect against user code which code might have set
|
||||
* a global socket factory (in which case application
|
||||
* code would be on the stack).
|
||||
*/
|
||||
impl = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Remote>() {
|
||||
public Remote run() throws InstantiationException,
|
||||
NoSuchMethodException, IllegalAccessException,
|
||||
InvocationTargetException
|
||||
{
|
||||
Constructor<? extends Remote> constructor =
|
||||
cl.getDeclaredConstructor(
|
||||
ActivationID.class, MarshalledObject.class);
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
/*
|
||||
* Fix for 4289544: make sure to set the
|
||||
* context class loader to be the class
|
||||
* loader of the impl class before
|
||||
* constructing that class.
|
||||
*/
|
||||
t.setContextClassLoader(ccl);
|
||||
return constructor.newInstance(id,
|
||||
desc.getData());
|
||||
} finally {
|
||||
t.setContextClassLoader(savedCcl);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
Throwable e = pae.getException();
|
||||
|
||||
// narrow the exception's type and rethrow it
|
||||
if (e instanceof InstantiationException) {
|
||||
throw (InstantiationException) e;
|
||||
} else if (e instanceof NoSuchMethodException) {
|
||||
throw (NoSuchMethodException) e;
|
||||
} else if (e instanceof IllegalAccessException) {
|
||||
throw (IllegalAccessException) e;
|
||||
} else if (e instanceof InvocationTargetException) {
|
||||
throw (InvocationTargetException) e;
|
||||
} else if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
} else if (e instanceof Error) {
|
||||
throw (Error) e;
|
||||
}
|
||||
}
|
||||
|
||||
entry = new ActiveEntry(impl);
|
||||
active.put(id, entry);
|
||||
return entry.mobj;
|
||||
|
||||
} catch (NoSuchMethodException | NoSuchMethodError e) {
|
||||
/* user forgot to provide activatable constructor?
|
||||
* or code recompiled and user forgot to provide
|
||||
* activatable constructor?
|
||||
*/
|
||||
throw new ActivationException
|
||||
("Activatable object must provide an activation"+
|
||||
" constructor", e );
|
||||
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ActivationException("exception in object constructor",
|
||||
e.getTargetException());
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new ActivationException("unable to activate object", e);
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The group's <code>inactiveObject</code> method is called
|
||||
* indirectly via a call to the <code>Activatable.inactive</code>
|
||||
* method. A remote object implementation must call
|
||||
* <code>Activatable</code>'s <code>inactive</code> method when
|
||||
* that object deactivates (the object deems that it is no longer
|
||||
* active). If the object does not call
|
||||
* <code>Activatable.inactive</code> when it deactivates, the
|
||||
* object will never be garbage collected since the group keeps
|
||||
* strong references to the objects it creates. <p>
|
||||
*
|
||||
* The group's <code>inactiveObject</code> method
|
||||
* unexports the remote object from the RMI runtime so that the
|
||||
* object can no longer receive incoming RMI calls. This call will
|
||||
* only succeed if the object has no pending/executing calls. If
|
||||
* the object does have pending/executing RMI calls, then false
|
||||
* will be returned.
|
||||
*
|
||||
* If the object has no pending/executing calls, the object is
|
||||
* removed from the RMI runtime and the group informs its
|
||||
* <code>ActivationMonitor</code> (via the monitor's
|
||||
* <code>inactiveObject</code> method) that the remote object is
|
||||
* not currently active so that the remote object will be
|
||||
* re-activated by the activator upon a subsequent activation
|
||||
* request.
|
||||
*
|
||||
* @param id the object's activation identifier
|
||||
* @return true if the operation succeeds (the operation will
|
||||
* succeed if the object in currently known to be active and is
|
||||
* either already unexported or is currently exported and has no
|
||||
* pending/executing calls); false is returned if the object has
|
||||
* pending/executing calls in which case it cannot be deactivated
|
||||
* @exception UnknownObjectException if object is unknown (may already
|
||||
* be inactive)
|
||||
* @exception RemoteException if call informing monitor fails
|
||||
*/
|
||||
public boolean inactiveObject(ActivationID id)
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new ActivationException("group is inactive");
|
||||
}
|
||||
|
||||
ActiveEntry entry = active.get(id);
|
||||
if (entry == null) {
|
||||
// REMIND: should this be silent?
|
||||
throw new UnknownObjectException("object not active");
|
||||
}
|
||||
|
||||
try {
|
||||
if (Activatable.unexportObject(entry.impl, false) == false)
|
||||
return false;
|
||||
} catch (NoSuchObjectException allowUnexportedObjects) {
|
||||
}
|
||||
|
||||
try {
|
||||
super.inactiveObject(id);
|
||||
} catch (UnknownObjectException allowUnregisteredObjects) {
|
||||
}
|
||||
|
||||
active.remove(id);
|
||||
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the group has become inactive and
|
||||
* marks it as such.
|
||||
*/
|
||||
private void checkInactiveGroup() {
|
||||
boolean groupMarkedInactive = false;
|
||||
synchronized (this) {
|
||||
if (active.size() == 0 && lockedIDs.size() == 0 &&
|
||||
groupInactive == false)
|
||||
{
|
||||
groupInactive = true;
|
||||
groupMarkedInactive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (groupMarkedInactive) {
|
||||
try {
|
||||
super.inactiveGroup();
|
||||
} catch (Exception ignoreDeactivateFailure) {
|
||||
}
|
||||
|
||||
try {
|
||||
UnicastRemoteObject.unexportObject(this, true);
|
||||
} catch (NoSuchObjectException allowUnexportedGroup) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The group's <code>activeObject</code> method is called when an
|
||||
* object is exported (either by <code>Activatable</code> object
|
||||
* construction or an explicit call to
|
||||
* <code>Activatable.exportObject</code>. The group must inform its
|
||||
* <code>ActivationMonitor</code> that the object is active (via
|
||||
* the monitor's <code>activeObject</code> method) if the group
|
||||
* hasn't already done so.
|
||||
*
|
||||
* @param id the object's identifier
|
||||
* @param impl the remote object implementation
|
||||
* @exception UnknownObjectException if object is not registered
|
||||
* @exception RemoteException if call informing monitor fails
|
||||
*/
|
||||
public void activeObject(ActivationID id, Remote impl)
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
|
||||
try {
|
||||
acquireLock(id);
|
||||
synchronized (this) {
|
||||
if (groupInactive == true)
|
||||
throw new ActivationException("group is inactive");
|
||||
}
|
||||
if (!active.contains(id)) {
|
||||
ActiveEntry entry = new ActiveEntry(impl);
|
||||
active.put(id, entry);
|
||||
// created new entry, so inform monitor of active object
|
||||
try {
|
||||
super.activeObject(id, entry.mobj);
|
||||
} catch (RemoteException e) {
|
||||
// daemon can still find it by calling newInstance
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
releaseLock(id);
|
||||
checkInactiveGroup();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry in table for active object.
|
||||
*/
|
||||
private static class ActiveEntry {
|
||||
Remote impl;
|
||||
MarshalledObject<Remote> mobj;
|
||||
|
||||
ActiveEntry(Remote impl) throws ActivationException {
|
||||
this.impl = impl;
|
||||
try {
|
||||
this.mobj = new MarshalledObject<Remote>(impl);
|
||||
} catch (IOException e) {
|
||||
throw new
|
||||
ActivationException("failed to marshal remote object", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the first argument is either equal to, or is a
|
||||
* descendant of, the second argument. Null is treated as the root of
|
||||
* the tree.
|
||||
*/
|
||||
private static boolean covers(ClassLoader sub, ClassLoader sup) {
|
||||
if (sup == null) {
|
||||
return true;
|
||||
} else if (sub == null) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
if (sub == sup) {
|
||||
return true;
|
||||
}
|
||||
sub = sub.getParent();
|
||||
} while (sub != null);
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue