feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,412 @@
/*
* Copyright (c) 1997, 2013, 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.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.*;
import java.rmi.activation.*;
import java.rmi.server.Operation;
import java.rmi.server.RMIClassLoader;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef;
import java.rmi.server.RemoteStub;
@SuppressWarnings("deprecation")
public class ActivatableRef implements RemoteRef {
private static final long serialVersionUID = 7579060052569229166L;
protected ActivationID id;
protected RemoteRef ref;
transient boolean force = false;
private static final int MAX_RETRIES = 3;
private static final String versionComplaint =
"activation requires 1.2 stubs";
/**
* Create a new (empty) ActivatableRef
*/
public ActivatableRef()
{}
/**
* Create a ActivatableRef with the specified id
*/
public ActivatableRef(ActivationID id, RemoteRef ref)
{
this.id = id;
this.ref = ref;
}
/**
* Returns the stub for the remote object whose class is
* specified in the activation descriptor. The ActivatableRef
* in the resulting stub has its activation id set to the
* activation id supplied as the second argument.
*/
public static Remote getStub(ActivationDesc desc, ActivationID id)
throws StubNotFoundException
{
String className = desc.getClassName();
try {
Class<?> cl =
RMIClassLoader.loadClass(desc.getLocation(), className);
RemoteRef clientRef = new ActivatableRef(id, null);
return Util.createProxy(cl, clientRef, false);
} catch (IllegalArgumentException e) {
throw new StubNotFoundException(
"class implements an illegal remote interface", e);
} catch (ClassNotFoundException e) {
throw new StubNotFoundException("unable to load class: " +
className, e);
} catch (MalformedURLException e) {
throw new StubNotFoundException("malformed URL", e);
}
}
/**
* Invoke method on remote object. This method delegates remote
* method invocation to the underlying ref type. If the
* underlying reference is not known (is null), then the object
* must be activated first. If an attempt at method invocation
* fails, the object should force reactivation. Method invocation
* must preserve "at most once" call semantics. In RMI, "at most
* once" applies to parameter deserialization at the remote site
* and the remote object's method execution. "At most once" does
* not apply to parameter serialization at the client so the
* parameters of a call don't need to be buffered in anticipation
* of call retry. Thus, a method call is only be retried if the
* initial method invocation does not execute at all at the server
* (including parameter deserialization).
*/
public Object invoke(Remote obj,
java.lang.reflect.Method method,
Object[] params,
long opnum)
throws Exception
{
boolean force = false;
RemoteRef localRef;
Exception exception = null;
/*
* Attempt object activation if active ref is unknown.
* Throws a RemoteException if object can't be activated.
*/
synchronized (this) {
if (ref == null) {
localRef = activate(force);
force = true;
} else {
localRef = ref;
}
}
for (int retries = MAX_RETRIES; retries > 0; retries--) {
try {
return localRef.invoke(obj, method, params, opnum);
} catch (NoSuchObjectException e) {
/*
* Object is not active in VM; retry call
*/
exception = e;
} catch (ConnectException e) {
/*
* Failure during connection setup; retry call
*/
exception = e;
} catch (UnknownHostException e) {
/*
* Failure during connection setup; retry call.
*/
exception = e;
} catch (ConnectIOException e) {
/*
* Failure setting up multiplexed connection or reusing
* cached connection; retry call
*/
exception = e;
} catch (MarshalException e) {
/*
* Failure during parameter serialization; call may
* have reached server, so call retry not possible.
*/
throw e;
} catch (ServerError e) {
/*
* Call reached server; propagate remote exception.
*/
throw e;
} catch (ServerException e) {
/*
* Call reached server; propagate remote exception
*/
throw e;
} catch (RemoteException e) {
/*
* This is a catch-all for other RemoteExceptions.
* UnmarshalException being the only one relevant.
*
* StubNotFoundException should never show up because
* it is generally thrown when attempting to locate
* a stub.
*
* UnexpectedException should never show up because
* it is only thrown by a stub and would be wrapped
* in a ServerException if it was propagated by a
* remote call.
*/
synchronized (this) {
if (localRef == ref) {
ref = null; // this may be overly conservative
}
}
throw e;
}
if (retries > 1) {
/*
* Activate object, since object could not be reached.
*/
synchronized (this) {
if (localRef.remoteEquals(ref) || ref == null) {
RemoteRef newRef = activate(force);
if (newRef.remoteEquals(localRef) &&
exception instanceof NoSuchObjectException &&
force == false) {
/*
* If last exception was NoSuchObjectException,
* then old value of ref is definitely wrong,
* so make sure that it is different.
*/
newRef = activate(true);
}
localRef = newRef;
force = true;
} else {
localRef = ref;
force = false;
}
}
}
}
/*
* Retries unsuccessful, so throw last exception
*/
throw exception;
}
/**
* private method to obtain the ref for a call.
*/
private synchronized RemoteRef getRef()
throws RemoteException
{
if (ref == null) {
ref = activate(false);
}
return ref;
}
/**
* private method to activate the remote object.
*
* NOTE: the caller must be synchronized on "this" before
* calling this method.
*/
private RemoteRef activate(boolean force)
throws RemoteException
{
assert Thread.holdsLock(this);
ref = null;
try {
/*
* Activate the object and retrieve the remote reference
* from inside the stub returned as the result. Then
* set this activatable ref's internal ref to be the
* ref inside the ref of the stub. In more clear terms,
* the stub returned from the activate call contains an
* ActivatableRef. We need to set the ref in *this*
* ActivatableRef to the ref inside the ActivatableRef
* retrieved from the stub. The ref type embedded in the
* ActivatableRef is typically a UnicastRef.
*/
Remote proxy = id.activate(force);
ActivatableRef newRef = null;
if (proxy instanceof RemoteStub) {
newRef = (ActivatableRef) ((RemoteStub) proxy).getRef();
} else {
/*
* Assume that proxy is an instance of a dynamic proxy
* class. If that assumption is not correct, or either of
* the casts below fails, the resulting exception will be
* wrapped in an ActivateFailedException below.
*/
RemoteObjectInvocationHandler handler =
(RemoteObjectInvocationHandler)
Proxy.getInvocationHandler(proxy);
newRef = (ActivatableRef) handler.getRef();
}
ref = newRef.ref;
return ref;
} catch (ConnectException e) {
throw new ConnectException("activation failed", e);
} catch (RemoteException e) {
throw new ConnectIOException("activation failed", e);
} catch (UnknownObjectException e) {
throw new NoSuchObjectException("object not registered");
} catch (ActivationException e) {
throw new ActivateFailedException("activation failed", e);
}
}
/**
* This call is used by the old 1.1 stub protocol and is
* unsupported since activation requires 1.2 stubs.
*/
public synchronized RemoteCall newCall(RemoteObject obj,
Operation[] ops,
int opnum,
long hash)
throws RemoteException
{
throw new UnsupportedOperationException(versionComplaint);
}
/**
* This call is used by the old 1.1 stub protocol and is
* unsupported since activation requires 1.2 stubs.
*/
public void invoke(RemoteCall call) throws Exception
{
throw new UnsupportedOperationException(versionComplaint);
}
/**
* This call is used by the old 1.1 stub protocol and is
* unsupported since activation requires 1.2 stubs.
*/
public void done(RemoteCall call) throws RemoteException {
throw new UnsupportedOperationException(versionComplaint);
}
/**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out)
{
return "ActivatableRef";
}
/**
* Write out external representation for remote ref.
*/
public void writeExternal(ObjectOutput out) throws IOException
{
RemoteRef localRef = ref;
out.writeObject(id);
if (localRef == null) {
out.writeUTF("");
} else {
out.writeUTF(localRef.getRefClass(out));
localRef.writeExternal(out);
}
}
/**
* Read in external representation for remote ref.
* @exception ClassNotFoundException If the class for an object
* being restored cannot be found.
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
id = (ActivationID)in.readObject();
ref = null;
String className = in.readUTF();
if (className.equals("")) return;
try {
Class<?> refClass = Class.forName(RemoteRef.packagePrefix + "." +
className);
ref = (RemoteRef)refClass.newInstance();
ref.readExternal(in);
} catch (InstantiationException e) {
throw new UnmarshalException("Unable to create remote reference",
e);
} catch (IllegalAccessException e) {
throw new UnmarshalException("Illegal access creating remote reference");
}
}
//----------------------------------------------------------------------;
/**
* Method from object, forward from RemoteObject
*/
public String remoteToString() {
return Util.getUnqualifiedName(getClass()) +
" [remoteRef: " + ref + "]";
}
/**
* default implementation of hashCode for remote objects
*/
public int remoteHashCode() {
return id.hashCode();
}
/** default implementation of equals for remote objects
*/
public boolean remoteEquals(RemoteRef ref) {
if (ref instanceof ActivatableRef)
return id.equals(((ActivatableRef)ref).id);
return false;
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 1997, 2003, 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.io.NotSerializableException;
import java.io.ObjectOutput;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.activation.ActivationID;
import sun.rmi.transport.LiveRef;
/**
* Server-side ref for a persistent remote impl.
*
* @author Ann Wollrath
*/
public class ActivatableServerRef extends UnicastServerRef2 {
private static final long serialVersionUID = 2002967993223003793L;
private ActivationID id;
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public ActivatableServerRef(ActivationID id, int port)
{
this(id, port, null, null);
}
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public ActivatableServerRef(ActivationID id, int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
{
super(new LiveRef(port, csf, ssf));
this.id = id;
}
/**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out)
{
return "ActivatableServerRef";
}
/**
* Return the client remote reference for this remoteRef.
* In the case of a client RemoteRef "this" is the answer.
* For a server remote reference, a client side one will have to
* found or created.
*/
protected RemoteRef getClientRef() {
return new ActivatableRef(id, new UnicastRef2(ref));
}
/**
* Prevents serialization (because deserializaion is impossible).
*/
public void writeExternal(ObjectOutput out) throws IOException {
throw new NotSerializableException(
"ActivatableServerRef not serializable");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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
* @returns 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 obj 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;
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 1997, 2002, 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.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationGroup;
/**
* This is the bootstrap code to start a VM executing an activation
* group.
*
* The activator spawns (as a child process) an activation group as needed
* and directs activation requests to the appropriate activation
* group. After spawning the VM, the activator passes some
* information to the bootstrap code via its stdin: <p>
* <ul>
* <li> the activation group's id,
* <li> the activation group's descriptor (an instance of the class
* java.rmi.activation.ActivationGroupDesc) for the group, adn
* <li> the group's incarnation number.
* </ul><p>
*
* When the bootstrap VM starts executing, it reads group id and
* descriptor from its stdin so that it can create the activation
* group for the VM.
*
* @author Ann Wollrath
*/
public abstract class ActivationGroupInit
{
/**
* Main program to start a VM for an activation group.
*/
public static void main(String args[])
{
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
// read group id, descriptor, and incarnation number from stdin
MarshalInputStream in = new MarshalInputStream(System.in);
ActivationGroupID id = (ActivationGroupID)in.readObject();
ActivationGroupDesc desc = (ActivationGroupDesc)in.readObject();
long incarnation = in.readLong();
// create and set group for the VM
ActivationGroup.createGroup(id, desc, incarnation);
} catch (Exception e) {
System.err.println("Exception in starting ActivationGroupInit:");
e.printStackTrace();
} finally {
try {
System.in.close();
// note: system out/err shouldn't be closed
// since the parent may want to read them.
} catch (Exception ex) {
// ignore exceptions
}
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2016, 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.ObjectStreamClass;
import java.lang.reflect.Method;
/**
* Implementing this interface to have a deserialization control when RMI
* dispatches a remote request. If an exported object implements this interface,
* RMI dispatching mechanism will call the method {@code check} every time
* deserialising a remote object for invoking a method of the exported object.
*
* @author sjiang
*/
public interface DeserializationChecker {
/**
* Will be called to check a descriptor.
* This method may be called 2 times, the first time is when a descriptor is read
* from the stream, the second is just before creating an object described
* by this descriptor.
*
* @param method the method invoked from a remote request.
* @param descriptor The descriptor of the class of any object deserialised
* while deserialising the parameter. The first descriptor will be that of
* the top level object (the concrete class of the parameter itself);
* Subsequent calls with the same {@code method}, {@code paramIndex} and
* {@code callID} will correspond to objects contained in the parameter.
* @param paramIndex an index indicates the position of a parameter in the
* method. This index will be reused for deserialising all
* objects contained in the parameter object. For example, the parameter
* being deserialised is a {@code List}, all deserialisation calls for its
* elements will have same index.
* @param callID a unique ID identifying one
* time method invocation, the same ID is used for deserialization call of
* all parameters within the method.
*/
public void check(Method method,
ObjectStreamClass descriptor,
int paramIndex,
int callID);
/**
* Will be called to validate a Proxy interfaces from a remote user before loading it.
* @param method the method invoked from a remote request.
* @param ifaces a string table of all interfaces implemented by the proxy to be checked.
* @param paramIndex an index indicates the position of a parameter in the
* method. This index will be reused for deserialising all
* objects contained in the parameter object. For example, the parameter
* being deserialised is a {@code List}, all deserialisation calls for its
* elements will have same index.
* @param callID a unique ID identifying one
* time method invocation, the same ID is used for deserialization call of
* all parameters within the method.
*/
public void checkProxyClass(Method method,
String[] ifaces,
int paramIndex,
int callID);
/**
* Inform of the completion of parameter deserialisation for a method invocation.
* This is useful if the last parameter is a complex object, like a {@code List}
* which elements are complex object too.
*
* The default implementation does nothing.
* @param callID the ID identifying a method invocation.
*/
public default void end(int callID) {}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 1996, 2013, 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.rmi.Remote;
import java.rmi.server.RemoteCall;
/**
* The Dispatcher interface allows the transport to make
* the upcall to the server side remote reference.
*/
@SuppressWarnings("deprecation")
public interface Dispatcher {
/**
* Call to dispatch to the remote object (on the server side).
* The up-call to the server and the marshaling of return result
* (or exception) should be handled before returning from this
* method.
* @param obj the target remote object for the call
* @param call the "remote call" from which operation and
* method arguments can be obtained.
* @exception RemoteException unable to marshal
* return result
*/
void dispatch(Remote obj, RemoteCall call)
throws java.io.IOException;
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2005, 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.rmi.activation.ActivationException;
/**
* Thrown if a local or remote call is made on a group implementation
* instance that is inactive.
*
* @author Sun Microsystems, Inc.
*
* @since 1.6
*/
public class InactiveGroupException extends ActivationException {
private static final long serialVersionUID = -7491041778450214975L;
/**
* Constructs an instance with the specified detail message.
*
* @param s the detail message
*/
public InactiveGroupException(String s) {
super(s);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,357 @@
/*
* Copyright (c) 1996, 2016, 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.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
import java.util.*;
import java.security.AccessControlException;
import java.security.Permission;
import java.rmi.server.RMIClassLoader;
import sun.misc.ObjectStreamClassValidator;
import sun.misc.SharedSecrets;
/**
* MarshalInputStream is an extension of ObjectInputStream. When resolving
* a class, it reads an object from the stream written by a corresponding
* MarshalOutputStream. If the class to be resolved is not available
* locally, from the first class loader on the execution stack, or from the
* context class loader of the current thread, it will attempt to load the
* class from the location annotated by the sending MarshalOutputStream.
* This location object must be a string representing a path of URLs.
*
* A new MarshalInputStream should be created to deserialize remote objects or
* graphs containing remote objects. Objects are created from the stream
* using the ObjectInputStream.readObject method.
*
* @author Peter Jones
*/
public class MarshalInputStream extends ObjectInputStream {
interface StreamChecker extends ObjectStreamClassValidator {
void checkProxyInterfaceNames(String[] ifaces);
}
private volatile StreamChecker streamChecker = null;
/**
* Value of "java.rmi.server.useCodebaseOnly" property,
* as cached at class initialization time.
*
* The default value is true. That is, the value is true
* if the property is absent or is not equal to "false".
* The value is only false when the property is present
* and is equal to "false".
*/
private static final boolean useCodebaseOnlyProperty =
! java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"java.rmi.server.useCodebaseOnly", "true"))
.equalsIgnoreCase("false");
/** table to hold sun classes to which access is explicitly permitted */
protected static Map<String, Class<?>> permittedSunClasses
= new HashMap<>(3);
/** if true, don't try superclass first in resolveClass() */
private boolean skipDefaultResolveClass = false;
/** callbacks to make when done() called: maps Object to Runnable */
private final Map<Object, Runnable> doneCallbacks
= new HashMap<>(3);
/**
* if true, load classes (if not available locally) only from the
* URL specified by the "java.rmi.server.codebase" property.
*/
private boolean useCodebaseOnly = useCodebaseOnlyProperty;
/*
* Fix for 4179055: The remote object services inside the
* activation daemon use stubs that are in the package
* sun.rmi.server. Classes for these stubs should be loaded from
* the classpath by RMI system code and not by the normal
* unmarshalling process as applications should not need to have
* permission to access the sun implementation classes.
*
* Note: this fix should be redone when API changes may be
* integrated
*
* During parameter unmarshalling RMI needs to explicitly permit
* access to three sun.* stub classes
*/
static {
try {
String system =
"sun.rmi.server.Activation$ActivationSystemImpl_Stub";
String registry = "sun.rmi.registry.RegistryImpl_Stub";
permittedSunClasses.put(system, Class.forName(system));
permittedSunClasses.put(registry, Class.forName(registry));
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError("Missing system class: " +
e.getMessage());
}
}
/**
* Create a new MarshalInputStream object.
*/
public MarshalInputStream(InputStream in)
throws IOException, StreamCorruptedException
{
super(in);
}
/**
* Returns a callback previously registered via the setDoneCallback
* method with given key, or null if no callback has yet been registered
* with that key.
*/
public Runnable getDoneCallback(Object key) {
return doneCallbacks.get(key); // not thread-safe
}
/**
* Registers a callback to make when this stream's done() method is
* invoked, along with a key for retrieving the same callback instance
* subsequently from the getDoneCallback method.
*/
public void setDoneCallback(Object key, Runnable callback) {
//assert(!doneCallbacks.contains(key));
doneCallbacks.put(key, callback); // not thread-safe
}
/**
* Indicates that the user of this MarshalInputStream is done reading
* objects from it, so all callbacks registered with the setDoneCallback
* method should now be (synchronously) executed. When this method
* returns, there are no more callbacks registered.
*
* This method is implicitly invoked by close() before it delegates to
* the superclass's close method.
*/
public void done() {
Iterator<Runnable> iter = doneCallbacks.values().iterator();
while (iter.hasNext()) { // not thread-safe
Runnable callback = iter.next();
callback.run();
}
doneCallbacks.clear();
}
/**
* Closes this stream, implicitly invoking done() first.
*/
public void close() throws IOException {
done();
super.close();
}
/**
* resolveClass is extended to acquire (if present) the location
* from which to load the specified class.
* It will find, load, and return the class.
*/
protected Class<?> resolveClass(ObjectStreamClass classDesc)
throws IOException, ClassNotFoundException
{
/*
* Always read annotation written by MarshalOutputStream
* describing where to load class from.
*/
Object annotation = readLocation();
String className = classDesc.getName();
/*
* Unless we were told to skip this consideration, choose the
* "default loader" to simulate the default ObjectInputStream
* resolveClass mechanism (that is, choose the first non-null
* loader on the execution stack) to maximize the likelihood of
* type compatibility with calling code. (This consideration
* is skipped during server parameter unmarshalling using the 1.2
* stub protocol, because there would never be a non-null class
* loader on the stack in that situation anyway.)
*/
ClassLoader defaultLoader =
skipDefaultResolveClass ? null : latestUserDefinedLoader();
/*
* If the "java.rmi.server.useCodebaseOnly" property was true or
* useCodebaseOnly() was called or the annotation is not a String,
* load from the local loader using the "java.rmi.server.codebase"
* URL. Otherwise, load from a loader using the codebase URL in
* the annotation.
*/
String codebase = null;
if (!useCodebaseOnly && annotation instanceof String) {
codebase = (String) annotation;
}
try {
return RMIClassLoader.loadClass(codebase, className,
defaultLoader);
} catch (AccessControlException e) {
return checkSunClass(className, e);
} catch (ClassNotFoundException e) {
/*
* Fix for 4442373: delegate to ObjectInputStream.resolveClass()
* to resolve primitive classes.
*/
try {
if (Character.isLowerCase(className.charAt(0)) &&
className.indexOf('.') == -1)
{
return super.resolveClass(classDesc);
}
} catch (ClassNotFoundException e2) {
}
throw e;
}
}
/**
* resolveProxyClass is extended to acquire (if present) the location
* to determine the class loader to define the proxy class in.
*/
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException
{
StreamChecker checker = streamChecker;
if (checker != null) {
checker.checkProxyInterfaceNames(interfaces);
}
/*
* Always read annotation written by MarshalOutputStream.
*/
Object annotation = readLocation();
ClassLoader defaultLoader =
skipDefaultResolveClass ? null : latestUserDefinedLoader();
String codebase = null;
if (!useCodebaseOnly && annotation instanceof String) {
codebase = (String) annotation;
}
return RMIClassLoader.loadProxyClass(codebase, interfaces,
defaultLoader);
}
/*
* Returns first non-privileged class loader on the stack (excluding
* reflection generated frames) or the extension class loader if only
* class loaded by the boot class loader and extension class loader are
* found on the stack.
*/
private static ClassLoader latestUserDefinedLoader() {
return sun.misc.VM.latestUserDefinedLoader();
}
/**
* Fix for 4179055: Need to assist resolving sun stubs; resolve
* class locally if it is a "permitted" sun class
*/
private Class<?> checkSunClass(String className, AccessControlException e)
throws AccessControlException
{
// ensure that we are giving out a stub for the correct reason
Permission perm = e.getPermission();
String name = null;
if (perm != null) {
name = perm.getName();
}
Class<?> resolvedClass = permittedSunClasses.get(className);
// if class not permitted, throw the SecurityException
if ((name == null) ||
(resolvedClass == null) ||
((!name.equals("accessClassInPackage.sun.rmi.server")) &&
(!name.equals("accessClassInPackage.sun.rmi.registry"))))
{
throw e;
}
return resolvedClass;
}
/**
* Return the location for the class in the stream. This method can
* be overridden by subclasses that store this annotation somewhere
* else than as the next object in the stream, as is done by this class.
*/
protected Object readLocation()
throws IOException, ClassNotFoundException
{
return readObject();
}
/**
* Set a flag to indicate that the superclass's default resolveClass()
* implementation should not be invoked by our resolveClass().
*/
void skipDefaultResolveClass() {
skipDefaultResolveClass = true;
}
/**
* Disable code downloading except from the URL specified by the
* "java.rmi.server.codebase" property.
*/
void useCodebaseOnly() {
useCodebaseOnly = true;
}
synchronized void setStreamChecker(StreamChecker checker) {
streamChecker = checker;
SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException,
ClassNotFoundException {
ObjectStreamClass descriptor = super.readClassDescriptor();
validateDesc(descriptor);
return descriptor;
}
private void validateDesc(ObjectStreamClass descriptor) {
StreamChecker checker;
synchronized (this) {
checker = streamChecker;
}
if (checker != null) {
checker.validateDescriptor(descriptor);
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 1996, 2008, 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.*;
import java.rmi.Remote;
import java.rmi.server.RemoteStub;
import sun.rmi.transport.ObjectTable;
import sun.rmi.transport.Target;
/**
* A MarshalOutputStream extends ObjectOutputStream to add functions
* specific to marshaling of remote object references. If it is
* necessary to serialize remote objects or objects that contain
* references to remote objects a MarshalOutputStream must be used
* instead of ObjectOutputStream. <p>
*
* A new MarshalOutputStream is constructed to serialize remote
* objects or graphs containing remote objects. Objects are written to
* the stream using the ObjectOutputStream.writeObject method. <p>
*
* MarshalOutputStream maps remote objects to the corresponding remote
* stub and embeds the location from which to load the stub
* classes. The location may be ignored by the client but is supplied.
*/
public class MarshalOutputStream extends ObjectOutputStream
{
/**
* Creates a marshal output stream with protocol version 1.
*/
public MarshalOutputStream(OutputStream out) throws IOException {
this(out, ObjectStreamConstants.PROTOCOL_VERSION_1);
}
/**
* Creates a marshal output stream with the given protocol version.
*/
public MarshalOutputStream(OutputStream out, int protocolVersion)
throws IOException
{
super(out);
this.useProtocolVersion(protocolVersion);
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
enableReplaceObject(true);
return null;
}
});
}
/**
* Checks for objects that are instances of java.rmi.Remote
* that need to be serialized as proxy objects.
*/
protected final Object replaceObject(Object obj) throws IOException {
if ((obj instanceof Remote) && !(obj instanceof RemoteStub)) {
Target target = ObjectTable.getTarget((Remote) obj);
if (target != null) {
return target.getStub();
}
}
return obj;
}
/**
* Serializes a location from which to load the the specified class.
*/
protected void annotateClass(Class<?> cl) throws IOException {
writeLocation(java.rmi.server.RMIClassLoader.getClassAnnotation(cl));
}
/**
* Serializes a location from which to load the specified class.
*/
protected void annotateProxyClass(Class<?> cl) throws IOException {
annotateClass(cl);
}
/**
* Writes the location for the class into the stream. This method can
* be overridden by subclasses that store this annotation somewhere
* else than as the next object in the stream, as is done by this class.
*/
protected void writeLocation(String location) throws IOException {
writeObject(location);
}
}

View File

@@ -0,0 +1,519 @@
/*
* Copyright (c) 1996, 2017, 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.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.rmi.MarshalException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.security.AccessController;
import sun.misc.SharedSecrets;
import sun.rmi.runtime.Log;
import sun.rmi.transport.Connection;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.StreamRemoteCall;
import sun.security.action.GetBooleanAction;
/**
* NOTE: There is a JDK-internal dependency on the existence of this
* class's getLiveRef method (as it is inherited by UnicastRef2) in
* the implementation of javax.management.remote.rmi.RMIConnector.
*/
@SuppressWarnings("deprecation")
public class UnicastRef implements RemoteRef {
/**
* Client-side transport log.
*/
public static final Log clientRefLog =
Log.getLog("sun.rmi.client.ref", "transport", Util.logLevel);
/**
* Client-side call log.
*/
public static final Log clientCallLog =
Log.getLog("sun.rmi.client.call", "RMI",
AccessController.doPrivileged(
new GetBooleanAction("sun.rmi.client.logCalls")));
private static final long serialVersionUID = 8258372400816541186L;
protected LiveRef ref;
/**
* Create a new (empty) Unicast remote reference.
*/
public UnicastRef() {
}
/**
* Create a new Unicast RemoteRef.
*/
public UnicastRef(LiveRef liveRef) {
ref = liveRef;
}
/**
* Returns the current value of this UnicastRef's underlying
* LiveRef.
*
* NOTE: There is a JDK-internal dependency on the existence of
* this method (as it is inherited by UnicastRef) in the
* implementation of javax.management.remote.rmi.RMIConnector.
**/
public LiveRef getLiveRef() {
return ref;
}
/**
* Invoke a method. This form of delegating method invocation
* to the reference allows the reference to take care of
* setting up the connection to the remote host, marshalling
* some representation for the method and parameters, then
* communicating the method invocation to the remote host.
* This method either returns the result of a method invocation
* on the remote object which resides on the remote host or
* throws a RemoteException if the call failed or an
* application-level exception if the remote invocation throws
* an exception.
*
* @param obj the proxy for the remote object
* @param method the method to be invoked
* @param params the parameter list
* @param opnum a hash that may be used to represent the method
* @since 1.2
*/
public Object invoke(Remote obj,
Method method,
Object[] params,
long opnum)
throws Exception
{
if (clientRefLog.isLoggable(Log.VERBOSE)) {
clientRefLog.log(Log.VERBOSE, "method: " + method);
}
if (clientCallLog.isLoggable(Log.VERBOSE)) {
logClientCall(obj, method);
}
Connection conn = ref.getChannel().newConnection();
RemoteCall call = null;
boolean reuse = true;
/* If the call connection is "reused" early, remember not to
* reuse again.
*/
boolean alreadyFreed = false;
try {
if (clientRefLog.isLoggable(Log.VERBOSE)) {
clientRefLog.log(Log.VERBOSE, "opnum = " + opnum);
}
// create call context
call = new StreamRemoteCall(conn, ref.getObjID(), -1, opnum);
// marshal parameters
try {
ObjectOutput out = call.getOutputStream();
marshalCustomCallData(out);
Class<?>[] types = method.getParameterTypes();
for (int i = 0; i < types.length; i++) {
marshalValue(types[i], params[i], out);
}
} catch (IOException e) {
clientRefLog.log(Log.BRIEF,
"IOException marshalling arguments: ", e);
throw new MarshalException("error marshalling arguments", e);
}
// unmarshal return
call.executeCall();
try {
Class<?> rtype = method.getReturnType();
if (rtype == void.class)
return null;
ObjectInput in = call.getInputStream();
/* StreamRemoteCall.done() does not actually make use
* of conn, therefore it is safe to reuse this
* connection before the dirty call is sent for
* registered refs.
*/
Object returnValue = unmarshalValue(rtype, in);
/* we are freeing the connection now, do not free
* again or reuse.
*/
alreadyFreed = true;
/* if we got to this point, reuse must have been true. */
clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
/* Free the call's connection early. */
ref.getChannel().free(conn, true);
return returnValue;
} catch (IOException | ClassNotFoundException e) {
// disable saving any refs in the inputStream for GC
((StreamRemoteCall)call).discardPendingRefs();
clientRefLog.log(Log.BRIEF,
e.getClass().getName() + " unmarshalling return: ", e);
throw new UnmarshalException("error unmarshalling return", e);
} finally {
try {
call.done();
} catch (IOException e) {
/* WARNING: If the conn has been reused early,
* then it is too late to recover from thrown
* IOExceptions caught here. This code is relying
* on StreamRemoteCall.done() not actually
* throwing IOExceptions.
*/
reuse = false;
}
}
} catch (RuntimeException e) {
/*
* Need to distinguish between client (generated by the
* invoke method itself) and server RuntimeExceptions.
* Client side RuntimeExceptions are likely to have
* corrupted the call connection and those from the server
* are not likely to have done so. If the exception came
* from the server the call connection should be reused.
*/
if ((call == null) ||
(((StreamRemoteCall) call).getServerException() != e))
{
reuse = false;
}
throw e;
} catch (RemoteException e) {
/*
* Some failure during call; assume connection cannot
* be reused. Must assume failure even if ServerException
* or ServerError occurs since these failures can happen
* during parameter deserialization which would leave
* the connection in a corrupted state.
*/
reuse = false;
throw e;
} catch (Error e) {
/* If errors occurred, the connection is most likely not
* reusable.
*/
reuse = false;
throw e;
} finally {
/* alreadyFreed ensures that we do not log a reuse that
* may have already happened.
*/
if (!alreadyFreed) {
if (clientRefLog.isLoggable(Log.BRIEF)) {
clientRefLog.log(Log.BRIEF, "free connection (reuse = " +
reuse + ")");
}
ref.getChannel().free(conn, reuse);
}
}
}
protected void marshalCustomCallData(ObjectOutput out) throws IOException
{}
/**
* Marshal value to an ObjectOutput sink using RMI's serialization
* format for parameters or return values.
*/
protected static void marshalValue(Class<?> type, Object value,
ObjectOutput out)
throws IOException
{
if (type.isPrimitive()) {
if (type == int.class) {
out.writeInt(((Integer) value).intValue());
} else if (type == boolean.class) {
out.writeBoolean(((Boolean) value).booleanValue());
} else if (type == byte.class) {
out.writeByte(((Byte) value).byteValue());
} else if (type == char.class) {
out.writeChar(((Character) value).charValue());
} else if (type == short.class) {
out.writeShort(((Short) value).shortValue());
} else if (type == long.class) {
out.writeLong(((Long) value).longValue());
} else if (type == float.class) {
out.writeFloat(((Float) value).floatValue());
} else if (type == double.class) {
out.writeDouble(((Double) value).doubleValue());
} else {
throw new Error("Unrecognized primitive type: " + type);
}
} else {
out.writeObject(value);
}
}
/**
* Unmarshal value from an ObjectInput source using RMI's serialization
* format for parameters or return values.
*/
protected static Object unmarshalValue(Class<?> type, ObjectInput in)
throws IOException, ClassNotFoundException
{
if (type.isPrimitive()) {
if (type == int.class) {
return Integer.valueOf(in.readInt());
} else if (type == boolean.class) {
return Boolean.valueOf(in.readBoolean());
} else if (type == byte.class) {
return Byte.valueOf(in.readByte());
} else if (type == char.class) {
return Character.valueOf(in.readChar());
} else if (type == short.class) {
return Short.valueOf(in.readShort());
} else if (type == long.class) {
return Long.valueOf(in.readLong());
} else if (type == float.class) {
return Float.valueOf(in.readFloat());
} else if (type == double.class) {
return Double.valueOf(in.readDouble());
} else {
throw new Error("Unrecognized primitive type: " + type);
}
} else if (type == String.class && in instanceof ObjectInputStream) {
return SharedSecrets.getJavaObjectInputStreamReadString().readString((ObjectInputStream)in);
} else {
return in.readObject();
}
}
/**
* Create an appropriate call object for a new call on this object.
* Passing operation array and index, allows the stubs generator to
* assign the operation indexes and interpret them. The RemoteRef
* may need the operation to encode in for the call.
*/
public RemoteCall newCall(RemoteObject obj, Operation[] ops, int opnum,
long hash)
throws RemoteException
{
clientRefLog.log(Log.BRIEF, "get connection");
Connection conn = ref.getChannel().newConnection();
try {
clientRefLog.log(Log.VERBOSE, "create call context");
/* log information about the outgoing call */
if (clientCallLog.isLoggable(Log.VERBOSE)) {
logClientCall(obj, ops[opnum]);
}
RemoteCall call =
new StreamRemoteCall(conn, ref.getObjID(), opnum, hash);
try {
marshalCustomCallData(call.getOutputStream());
} catch (IOException e) {
throw new MarshalException("error marshaling " +
"custom call data");
}
return call;
} catch (RemoteException e) {
ref.getChannel().free(conn, false);
throw e;
}
}
/**
* Invoke makes the remote call present in the RemoteCall object.
*
* Invoke will raise any "user" exceptions which
* should pass through and not be caught by the stub. If any
* exception is raised during the remote invocation, invoke should
* take care of cleaning up the connection before raising the
* "user" or remote exception.
*/
public void invoke(RemoteCall call) throws Exception {
try {
clientRefLog.log(Log.VERBOSE, "execute call");
call.executeCall();
} catch (RemoteException e) {
/*
* Call did not complete; connection can't be reused.
*/
clientRefLog.log(Log.BRIEF, "exception: ", e);
free(call, false);
throw e;
} catch (Error e) {
/* If errors occurred, the connection is most likely not
* reusable.
*/
clientRefLog.log(Log.BRIEF, "error: ", e);
free(call, false);
throw e;
} catch (RuntimeException e) {
/*
* REMIND: Since runtime exceptions are no longer wrapped,
* we can't assue that the connection was left in
* a reusable state. Is this okay?
*/
clientRefLog.log(Log.BRIEF, "exception: ", e);
free(call, false);
throw e;
} catch (Exception e) {
/*
* Assume that these other exceptions are user exceptions
* and leave the connection in a reusable state.
*/
clientRefLog.log(Log.BRIEF, "exception: ", e);
free(call, true);
/* reraise user (and unknown) exceptions. */
throw e;
}
/*
* Don't free the connection if an exception did not
* occur because the stub needs to unmarshal the
* return value. The connection will be freed
* by a call to the "done" method.
*/
}
/**
* Private method to free a connection.
*/
private void free(RemoteCall call, boolean reuse) throws RemoteException {
Connection conn = ((StreamRemoteCall)call).getConnection();
ref.getChannel().free(conn, reuse);
}
/**
* Done should only be called if the invoke returns successfully
* (non-exceptionally) to the stub. It allows the remote reference to
* clean up (or reuse) the connection.
*/
public void done(RemoteCall call) throws RemoteException {
/* Done only uses the connection inside the call to obtain the
* channel the connection uses. Once all information is read
* from the connection, the connection may be freed.
*/
clientRefLog.log(Log.BRIEF, "free connection (reuse = true)");
/* Free the call connection early. */
free(call, true);
try {
call.done();
} catch (IOException e) {
/* WARNING: If the conn has been reused early, then it is
* too late to recover from thrown IOExceptions caught
* here. This code is relying on StreamRemoteCall.done()
* not actually throwing IOExceptions.
*/
}
}
/**
* Log the details of an outgoing call. The method parameter is either of
* type java.lang.reflect.Method or java.rmi.server.Operation.
*/
void logClientCall(Object obj, Object method) {
clientCallLog.log(Log.VERBOSE, "outbound call: " +
ref + " : " + obj.getClass().getName() +
ref.getObjID().toString() + ": " + method);
}
/**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out) {
return "UnicastRef";
}
/**
* Write out external representation for remote ref.
*/
public void writeExternal(ObjectOutput out) throws IOException {
ref.write(out, false);
}
/**
* Read in external representation for remote ref.
* @exception ClassNotFoundException If the class for an object
* being restored cannot be found.
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
ref = LiveRef.read(in, false);
}
//----------------------------------------------------------------------;
/**
* Method from object, forward from RemoteObject
*/
public String remoteToString() {
return Util.getUnqualifiedName(getClass()) + " [liveRef: " + ref + "]";
}
/**
* default implementation of hashCode for remote objects
*/
public int remoteHashCode() {
return ref.hashCode();
}
/** default implementation of equals for remote objects
*/
public boolean remoteEquals(RemoteRef sub) {
if (sub instanceof UnicastRef)
return ref.remoteEquals(((UnicastRef)sub).ref);
return false;
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.io.ObjectInput;
import java.io.ObjectOutput;
import sun.rmi.transport.LiveRef;
/**
* NOTE: There is a JDK-internal dependency on the existence of this
* class and its getLiveRef method (inherited from UnicastRef) in the
* implementation of javax.management.remote.rmi.RMIConnector.
**/
public class UnicastRef2 extends UnicastRef {
private static final long serialVersionUID = 1829537514995881838L;
/**
* Create a new (empty) Unicast remote reference.
*/
public UnicastRef2()
{}
/**
* Create a new Unicast RemoteRef.
*/
public UnicastRef2(LiveRef liveRef) {
super(liveRef);
}
/**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out)
{
return "UnicastRef2";
}
/**
* Write out external representation for remote ref.
*/
public void writeExternal(ObjectOutput out) throws IOException
{
ref.write(out, true);
}
/**
* Read in external representation for remote ref.
* @exception ClassNotFoundException If the class for an object
* being restored cannot be found.
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
ref = LiveRef.read(in, true);
}
}

View File

@@ -0,0 +1,689 @@
/*
* Copyright (c) 1996, 2019, 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.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectStreamClass;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.AccessException;
import java.rmi.MarshalException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.ServerError;
import java.rmi.ServerException;
import java.rmi.UnmarshalException;
import java.rmi.server.ExportException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteRef;
import java.rmi.server.RemoteStub;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.ServerRef;
import java.rmi.server.Skeleton;
import java.rmi.server.SkeletonNotFoundException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import sun.misc.ObjectInputFilter;
import sun.rmi.runtime.Log;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.StreamRemoteCall;
import sun.rmi.transport.Target;
import sun.rmi.transport.tcp.TCPTransport;
import sun.security.action.GetBooleanAction;
/**
* UnicastServerRef implements the remote reference layer server-side
* behavior for remote objects exported with the "UnicastRef" reference
* type.
* If an {@link ObjectInputFilter ObjectInputFilter} is supplied it is
* invoked during deserialization to filter the arguments,
* otherwise the default filter of {@link ObjectInputStream ObjectInputStream}
* applies.
*
* @author Ann Wollrath
* @author Roger Riggs
* @author Peter Jones
*/
@SuppressWarnings("deprecation")
public class UnicastServerRef extends UnicastRef
implements ServerRef, Dispatcher
{
/** value of server call log property */
public static final boolean logCalls = AccessController.doPrivileged(
new GetBooleanAction("java.rmi.server.logCalls"));
/** server call log */
public static final Log callLog =
Log.getLog("sun.rmi.server.call", "RMI", logCalls);
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = -7384275867073752268L;
/** flag to enable writing exceptions to System.err */
private static final boolean wantExceptionLog =
AccessController.doPrivileged(
new GetBooleanAction("sun.rmi.server.exceptionTrace"));
private boolean forceStubUse = false;
/**
* flag to remove server-side stack traces before marshalling
* exceptions thrown by remote invocations to this VM
*/
private static final boolean suppressStackTraces =
AccessController.doPrivileged(
new GetBooleanAction(
"sun.rmi.server.suppressStackTraces"));
/**
* skeleton to dispatch remote calls through, for 1.1 stub protocol
* (may be null if stub class only uses 1.2 stub protocol)
*/
private transient Skeleton skel;
// The ObjectInputFilter for checking the invocation arguments
private final transient ObjectInputFilter filter;
/** maps method hash to Method object for each remote method */
private transient Map<Long,Method> hashToMethod_Map = null;
/**
* A weak hash map, mapping classes to hash maps that map method
* hashes to method objects.
**/
private static final WeakClassHashMap<Map<Long,Method>> hashToMethod_Maps =
new HashToMethod_Maps();
/** cache of impl classes that have no corresponding skeleton class */
private static final Map<Class<?>,?> withoutSkeletons =
Collections.synchronizedMap(new WeakHashMap<Class<?>,Void>());
private final AtomicInteger methodCallIDCount = new AtomicInteger(0);
/**
* Create a new (empty) Unicast server remote reference.
* The filter is null to defer to the default ObjectInputStream filter, if any.
*/
public UnicastServerRef() {
this.filter = null;
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef.
* The filter is null to defer to the default ObjectInputStream filter, if any.
*/
public UnicastServerRef(LiveRef ref) {
super(ref);
this.filter = null;
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef and filter.
*/
public UnicastServerRef(LiveRef ref, ObjectInputFilter filter) {
super(ref);
this.filter = filter;
}
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public UnicastServerRef(int port) {
super(new LiveRef(port));
this.filter = null;
}
/**
* Constructs a UnicastServerRef to be exported on an
* anonymous port (i.e., 0) and that uses a pregenerated stub class
* (NOT a dynamic proxy instance) if 'forceStubUse' is 'true'.
*
* This constructor is only called by the method
* UnicastRemoteObject.exportObject(Remote) passing 'true' for
* 'forceStubUse'. The UnicastRemoteObject.exportObject(Remote) method
* returns RemoteStub, so it must ensure that the stub for the
* exported object is an instance of a pregenerated stub class that
* extends RemoteStub (instead of an instance of a dynamic proxy class
* which is not an instance of RemoteStub).
**/
public UnicastServerRef(boolean forceStubUse) {
this(0);
this.forceStubUse = forceStubUse;
}
/**
* With the addition of support for dynamic proxies as stubs, this
* method is obsolete because it returns RemoteStub instead of the more
* general Remote. It should not be called. It sets the
* 'forceStubUse' flag to true so that the stub for the exported object
* is forced to be an instance of the pregenerated stub class, which
* extends RemoteStub.
*
* Export this object, create the skeleton and stubs for this
* dispatcher. Create a stub based on the type of the impl,
* initialize it with the appropriate remote reference. Create the
* target defined by the impl, dispatcher (this) and stub.
* Export that target via the Ref.
**/
public RemoteStub exportObject(Remote impl, Object data)
throws RemoteException
{
forceStubUse = true;
return (RemoteStub) exportObject(impl, data, false);
}
/**
* Export this object, create the skeleton and stubs for this
* dispatcher. Create a stub based on the type of the impl,
* initialize it with the appropriate remote reference. Create the
* target defined by the impl, dispatcher (this) and stub.
* Export that target via the Ref.
*/
public Remote exportObject(Remote impl, Object data,
boolean permanent)
throws RemoteException
{
Class<?> implClass = impl.getClass();
Remote stub;
try {
stub = Util.createProxy(implClass, getClientRef(), forceStubUse);
} catch (IllegalArgumentException e) {
throw new ExportException(
"remote object implements illegal remote interface", e);
}
if (stub instanceof RemoteStub) {
setSkeleton(impl);
}
Target target =
new Target(impl, this, stub, ref.getObjID(), permanent);
ref.exportObject(target);
hashToMethod_Map = hashToMethod_Maps.get(implClass);
return stub;
}
/**
* Return the hostname of the current client. When called from a
* thread actively handling a remote method invocation the
* hostname of the client is returned.
* @exception ServerNotActiveException If called outside of servicing
* a remote method invocation.
*/
public String getClientHost() throws ServerNotActiveException {
return TCPTransport.getClientHost();
}
/**
* Discovers and sets the appropriate skeleton for the impl.
*/
public void setSkeleton(Remote impl) throws RemoteException {
if (!withoutSkeletons.containsKey(impl.getClass())) {
try {
skel = Util.createSkeleton(impl);
} catch (SkeletonNotFoundException e) {
/*
* Ignore exception for skeleton class not found, because a
* skeleton class is not necessary with the 1.2 stub protocol.
* Remember that this impl's class does not have a skeleton
* class so we don't waste time searching for it again.
*/
withoutSkeletons.put(impl.getClass(), null);
}
}
}
/**
* Call to dispatch to the remote object (on the server side).
* The up-call to the server and the marshalling of return result
* (or exception) should be handled before returning from this
* method.
* @param obj the target remote object for the call
* @param call the "remote call" from which operation and
* method arguments can be obtained.
* @exception IOException If unable to marshal return result or
* release input or output streams
*/
public void dispatch(Remote obj, RemoteCall call) throws IOException {
// positive operation number in 1.1 stubs;
// negative version number in 1.2 stubs and beyond...
int num;
long op;
try {
// read remote call header
ObjectInput in;
try {
in = call.getInputStream();
num = in.readInt();
} catch (Exception readEx) {
throw new UnmarshalException("error unmarshalling call header",
readEx);
}
if (skel != null) {
// If there is a skeleton, use it
oldDispatch(obj, call, num);
return;
} else if (num >= 0){
throw new UnmarshalException(
"skeleton class not found but required for client version");
}
try {
op = in.readLong();
} catch (Exception readEx) {
throw new UnmarshalException("error unmarshalling call header",
readEx);
}
/*
* Since only system classes (with null class loaders) will be on
* the execution stack during parameter unmarshalling for the 1.2
* stub protocol, tell the MarshalInputStream not to bother trying
* to resolve classes using its superclasses's default method of
* consulting the first non-null class loader on the stack.
*/
MarshalInputStream marshalStream = (MarshalInputStream) in;
marshalStream.skipDefaultResolveClass();
Method method = hashToMethod_Map.get(op);
if (method == null) {
throw new UnmarshalException("unrecognized method hash: " +
"method not supported by remote object");
}
// if calls are being logged, write out object id and operation
logCall(obj, method);
// unmarshal parameters
Object[] params = null;
try {
unmarshalCustomCallData(in);
params = unmarshalParameters(obj, method, marshalStream);
} catch (AccessException aex) {
// For compatibility, AccessException is not wrapped in UnmarshalException
// disable saving any refs in the inputStream for GC
((StreamRemoteCall) call).discardPendingRefs();
throw aex;
} catch (java.io.IOException | ClassNotFoundException e) {
// disable saving any refs in the inputStream for GC
((StreamRemoteCall) call).discardPendingRefs();
throw new UnmarshalException(
"error unmarshalling arguments", e);
} finally {
call.releaseInputStream();
}
// make upcall on remote object
Object result;
try {
result = method.invoke(obj, params);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
// marshal return value
try {
ObjectOutput out = call.getResultStream(true);
Class<?> rtype = method.getReturnType();
if (rtype != void.class) {
marshalValue(rtype, result, out);
}
} catch (IOException ex) {
throw new MarshalException("error marshalling return", ex);
/*
* This throw is problematic because when it is caught below,
* we attempt to marshal it back to the client, but at this
* point, a "normal return" has already been indicated,
* so marshalling an exception will corrupt the stream.
* This was the case with skeletons as well; there is no
* immediately obvious solution without a protocol change.
*/
}
} catch (Throwable e) {
Throwable origEx = e;
logCallException(e);
ObjectOutput out = call.getResultStream(false);
if (e instanceof Error) {
e = new ServerError(
"Error occurred in server thread", (Error) e);
} else if (e instanceof RemoteException) {
e = new ServerException(
"RemoteException occurred in server thread",
(Exception) e);
}
if (suppressStackTraces) {
clearStackTraces(e);
}
out.writeObject(e);
// AccessExceptions should cause Transport.serviceCall
// to flag the connection as unusable.
if (origEx instanceof AccessException) {
throw new IOException("Connection is not reusable", origEx);
}
} finally {
call.releaseInputStream(); // in case skeleton doesn't
call.releaseOutputStream();
}
}
/**
* Sets a filter for invocation arguments, if a filter has been set.
* Called by dispatch before the arguments are read.
*/
protected void unmarshalCustomCallData(ObjectInput in)
throws IOException, ClassNotFoundException {
if (filter != null &&
in instanceof ObjectInputStream) {
// Set the filter on the stream
ObjectInputStream ois = (ObjectInputStream) in;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
ObjectInputFilter.Config.setObjectInputFilter(ois, filter);
return null;
}
});
}
}
/**
* Handle server-side dispatch using the RMI 1.1 stub/skeleton
* protocol, given a non-negative operation number or negative method hash
* that has already been read from the call stream.
* Exceptions are handled by the caller to be sent to the remote client.
*
* @param obj the target remote object for the call
* @param call the "remote call" from which operation and
* method arguments can be obtained.
* @param op the operation number
* @throws Exception if unable to marshal return result or
* release input or output streams
*/
private void oldDispatch(Remote obj, RemoteCall call, int op)
throws Exception
{
long hash; // hash for matching stub with skeleton
// read remote call header
ObjectInput in;
in = call.getInputStream();
try {
Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
if (clazz.isAssignableFrom(skel.getClass())) {
((MarshalInputStream)in).useCodebaseOnly();
}
} catch (ClassNotFoundException ignore) { }
try {
hash = in.readLong();
} catch (Exception ioe) {
throw new UnmarshalException("error unmarshalling call header", ioe);
}
// if calls are being logged, write out object id and operation
Operation[] operations = skel.getOperations();
logCall(obj, op >= 0 && op < operations.length ? operations[op] : "op: " + op);
unmarshalCustomCallData(in);
// dispatch to skeleton for remote object
skel.dispatch(obj, call, op, hash);
}
/**
* Clear the stack trace of the given Throwable by replacing it with
* an empty StackTraceElement array, and do the same for all of its
* chained causative exceptions.
*/
public static void clearStackTraces(Throwable t) {
StackTraceElement[] empty = new StackTraceElement[0];
while (t != null) {
t.setStackTrace(empty);
t = t.getCause();
}
}
/**
* Log the details of an incoming call. The method parameter is either of
* type java.lang.reflect.Method or java.rmi.server.Operation.
*/
private void logCall(Remote obj, Object method) {
if (callLog.isLoggable(Log.VERBOSE)) {
String clientHost;
try {
clientHost = getClientHost();
} catch (ServerNotActiveException snae) {
clientHost = "(local)"; // shouldn't happen
}
callLog.log(Log.VERBOSE, "[" + clientHost + ": " +
obj.getClass().getName() +
ref.getObjID().toString() + ": " +
method + "]");
}
}
/**
* Log the exception detail of an incoming call.
*/
private void logCallException(Throwable e) {
// if calls are being logged, log them
if (callLog.isLoggable(Log.BRIEF)) {
String clientHost = "";
try {
clientHost = "[" + getClientHost() + "] ";
} catch (ServerNotActiveException snae) {
}
callLog.log(Log.BRIEF, clientHost + "exception: ", e);
}
// write exceptions (only) to System.err if desired
if (wantExceptionLog) {
java.io.PrintStream log = System.err;
synchronized (log) {
log.println();
log.println("Exception dispatching call to " +
ref.getObjID() + " in thread \"" +
Thread.currentThread().getName() +
"\" at " + (new Date()) + ":");
e.printStackTrace(log);
}
}
}
/**
* Returns the class of the ref type to be serialized.
*/
public String getRefClass(ObjectOutput out) {
return "UnicastServerRef";
}
/**
* Return the client remote reference for this remoteRef.
* In the case of a client RemoteRef "this" is the answer.
* For a server remote reference, a client side one will have to
* found or created.
*/
protected RemoteRef getClientRef() {
return new UnicastRef(ref);
}
/**
* Write out external representation for remote ref.
*/
public void writeExternal(ObjectOutput out) throws IOException {
}
/**
* Read in external representation for remote ref.
* @exception ClassNotFoundException If the class for an object
* being restored cannot be found.
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
// object is re-exported elsewhere (e.g., by UnicastRemoteObject)
ref = null;
skel = null;
}
/**
* A weak hash map, mapping classes to hash maps that map method
* hashes to method objects.
**/
private static class HashToMethod_Maps
extends WeakClassHashMap<Map<Long,Method>>
{
HashToMethod_Maps() {}
protected Map<Long,Method> computeValue(Class<?> remoteClass) {
Map<Long,Method> map = new HashMap<>();
for (Class<?> cl = remoteClass;
cl != null;
cl = cl.getSuperclass())
{
for (Class<?> intf : cl.getInterfaces()) {
if (Remote.class.isAssignableFrom(intf)) {
for (Method method : intf.getMethods()) {
final Method m = method;
/*
* Set this Method object to override language
* access checks so that the dispatcher can invoke
* methods from non-public remote interfaces.
*/
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
m.setAccessible(true);
return null;
}
});
map.put(Util.computeMethodHash(m), m);
}
}
}
}
return map;
}
}
/**
* Unmarshal parameters for the given method of the given instance over
* the given marshalinputstream. Perform any necessary checks.
*/
private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in)
throws IOException, ClassNotFoundException {
return (obj instanceof DeserializationChecker) ?
unmarshalParametersChecked((DeserializationChecker)obj, method, in) :
unmarshalParametersUnchecked(method, in);
}
/**
* Unmarshal parameters for the given method of the given instance over
* the given marshalinputstream. Do not perform any additional checks.
*/
private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in)
throws IOException, ClassNotFoundException {
Class<?>[] types = method.getParameterTypes();
Object[] params = new Object[types.length];
for (int i = 0; i < types.length; i++) {
params[i] = unmarshalValue(types[i], in);
}
return params;
}
/**
* Unmarshal parameters for the given method of the given instance over
* the given marshalinputstream. Do perform all additional checks.
*/
private Object[] unmarshalParametersChecked(
DeserializationChecker checker,
Method method, MarshalInputStream in)
throws IOException, ClassNotFoundException {
int callID = methodCallIDCount.getAndIncrement();
MyChecker myChecker = new MyChecker(checker, method, callID);
in.setStreamChecker(myChecker);
try {
Class<?>[] types = method.getParameterTypes();
Object[] values = new Object[types.length];
for (int i = 0; i < types.length; i++) {
myChecker.setIndex(i);
values[i] = unmarshalValue(types[i], in);
}
myChecker.end(callID);
return values;
} finally {
in.setStreamChecker(null);
}
}
private static class MyChecker implements MarshalInputStream.StreamChecker {
private final DeserializationChecker descriptorCheck;
private final Method method;
private final int callID;
private int parameterIndex;
MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) {
this.descriptorCheck = descriptorCheck;
this.method = method;
this.callID = callID;
}
@Override
public void validateDescriptor(ObjectStreamClass descriptor) {
descriptorCheck.check(method, descriptor, parameterIndex, callID);
}
@Override
public void checkProxyInterfaceNames(String[] ifaces) {
descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID);
}
void setIndex(int parameterIndex) {
this.parameterIndex = parameterIndex;
}
void end(int callId) {
descriptorCheck.end(callId);
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 1997, 2002, 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.ObjectOutput;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.RemoteRef;
import sun.misc.ObjectInputFilter;
import sun.rmi.transport.LiveRef;
/**
* Server-side ref for a remote impl that uses a custom socket factory.
*
* @author Ann Wollrath
* @author Roger Riggs
*/
public class UnicastServerRef2 extends UnicastServerRef
{
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = -2289703812660767614L;
/**
* Create a new (empty) Unicast server remote reference.
*/
public UnicastServerRef2()
{}
/**
* Construct a Unicast server remote reference for a specified
* liveRef.
*/
public UnicastServerRef2(LiveRef ref)
{
super(ref);
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef and filter.
*/
public UnicastServerRef2(LiveRef ref,
ObjectInputFilter filter)
{
super(ref, filter);
}
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public UnicastServerRef2(int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf)
{
super(new LiveRef(port, csf, ssf));
}
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public UnicastServerRef2(int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf,
ObjectInputFilter filter)
{
super(new LiveRef(port, csf, ssf), filter);
}
/**
* Returns the class of the ref type to be serialized
*/
public String getRefClass(ObjectOutput out)
{
return "UnicastServerRef2";
}
/**
* Return the client remote reference for this remoteRef.
* In the case of a client RemoteRef "this" is the answer.
* For a server remote reference, a client side one will have to
* found or created.
*/
protected RemoteRef getClientRef() {
return new UnicastRef2(ref);
}
}

View File

@@ -0,0 +1,466 @@
/*
* Copyright (c) 1996, 2013, 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.ByteArrayOutputStream;
import java.io.IOException;
import java.io.DataOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.StubNotFoundException;
import java.rmi.registry.Registry;
import java.rmi.server.LogStream;
import java.rmi.server.ObjID;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef;
import java.rmi.server.RemoteStub;
import java.rmi.server.Skeleton;
import java.rmi.server.SkeletonNotFoundException;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.DigestOutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import sun.rmi.registry.RegistryImpl;
import sun.rmi.runtime.Log;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import sun.security.action.GetBooleanAction;
import sun.security.action.GetPropertyAction;
/**
* A utility class with static methods for creating stubs/proxies and
* skeletons for remote objects.
*/
@SuppressWarnings("deprecation")
public final class Util {
/** "server" package log level */
static final int logLevel = LogStream.parseLevel(
AccessController.doPrivileged(
new GetPropertyAction("sun.rmi.server.logLevel")));
/** server reference log */
public static final Log serverRefLog =
Log.getLog("sun.rmi.server.ref", "transport", Util.logLevel);
/** cached value of property java.rmi.server.ignoreStubClasses */
private static final boolean ignoreStubClasses =
AccessController.doPrivileged(
new GetBooleanAction("java.rmi.server.ignoreStubClasses")).
booleanValue();
/** cache of impl classes that have no corresponding stub class */
private static final Map<Class<?>, Void> withoutStubs =
Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>(11));
/** parameter types for stub constructor */
private static final Class<?>[] stubConsParamTypes = { RemoteRef.class };
private Util() {
}
/**
* Returns a proxy for the specified implClass.
*
* If both of the following criteria is satisfied, a dynamic proxy for
* the specified implClass is returned (otherwise a RemoteStub instance
* for the specified implClass is returned):
*
* a) either the property java.rmi.server.ignoreStubClasses is true or
* a pregenerated stub class does not exist for the impl class, and
* b) forceStubUse is false.
*
* If the above criteria are satisfied, this method constructs a
* dynamic proxy instance (that implements the remote interfaces of
* implClass) constructed with a RemoteObjectInvocationHandler instance
* constructed with the clientRef.
*
* Otherwise, this method loads the pregenerated stub class (which
* extends RemoteStub and implements the remote interfaces of
* implClass) and constructs an instance of the pregenerated stub
* class with the clientRef.
*
* @param implClass the class to obtain remote interfaces from
* @param clientRef the remote ref to use in the invocation handler
* @param forceStubUse if true, forces creation of a RemoteStub
* @throws IllegalArgumentException if implClass implements illegal
* remote interfaces
* @throws StubNotFoundException if problem locating/creating stub or
* creating the dynamic proxy instance
**/
public static Remote createProxy(Class<?> implClass,
RemoteRef clientRef,
boolean forceStubUse)
throws StubNotFoundException
{
Class<?> remoteClass;
try {
remoteClass = getRemoteClass(implClass);
} catch (ClassNotFoundException ex ) {
throw new StubNotFoundException(
"object does not implement a remote interface: " +
implClass.getName());
}
if (forceStubUse ||
!(ignoreStubClasses || !stubClassExists(remoteClass)))
{
return createStub(remoteClass, clientRef);
}
final ClassLoader loader = implClass.getClassLoader();
final Class<?>[] interfaces = getRemoteInterfaces(implClass);
final InvocationHandler handler =
new RemoteObjectInvocationHandler(clientRef);
/* REMIND: private remote interfaces? */
try {
return AccessController.doPrivileged(new PrivilegedAction<Remote>() {
public Remote run() {
return (Remote) Proxy.newProxyInstance(loader,
interfaces,
handler);
}});
} catch (IllegalArgumentException e) {
throw new StubNotFoundException("unable to create proxy", e);
}
}
/**
* Returns true if a stub class for the given impl class can be loaded,
* otherwise returns false.
*
* @param remoteClass the class to obtain remote interfaces from
*/
private static boolean stubClassExists(Class<?> remoteClass) {
if (!withoutStubs.containsKey(remoteClass)) {
try {
Class.forName(remoteClass.getName() + "_Stub",
false,
remoteClass.getClassLoader());
return true;
} catch (ClassNotFoundException cnfe) {
withoutStubs.put(remoteClass, null);
}
}
return false;
}
/*
* Returns the class/superclass that implements the remote interface.
* @throws ClassNotFoundException if no class is found to have a
* remote interface
*/
private static Class<?> getRemoteClass(Class<?> cl)
throws ClassNotFoundException
{
while (cl != null) {
Class<?>[] interfaces = cl.getInterfaces();
for (int i = interfaces.length -1; i >= 0; i--) {
if (Remote.class.isAssignableFrom(interfaces[i]))
return cl; // this class implements remote object
}
cl = cl.getSuperclass();
}
throw new ClassNotFoundException(
"class does not implement java.rmi.Remote");
}
/**
* Returns an array containing the remote interfaces implemented
* by the given class.
*
* @param remoteClass the class to obtain remote interfaces from
* @throws IllegalArgumentException if remoteClass implements
* any illegal remote interfaces
* @throws NullPointerException if remoteClass is null
*/
private static Class<?>[] getRemoteInterfaces(Class<?> remoteClass) {
ArrayList<Class<?>> list = new ArrayList<>();
getRemoteInterfaces(list, remoteClass);
return list.toArray(new Class<?>[list.size()]);
}
/**
* Fills the given array list with the remote interfaces implemented
* by the given class.
*
* @throws IllegalArgumentException if the specified class implements
* any illegal remote interfaces
* @throws NullPointerException if the specified class or list is null
*/
private static void getRemoteInterfaces(ArrayList<Class<?>> list, Class<?> cl) {
Class<?> superclass = cl.getSuperclass();
if (superclass != null) {
getRemoteInterfaces(list, superclass);
}
Class<?>[] interfaces = cl.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Class<?> intf = interfaces[i];
/*
* If it is a remote interface (if it extends from
* java.rmi.Remote) and is not already in the list,
* then add the interface to the list.
*/
if (Remote.class.isAssignableFrom(intf)) {
if (!(list.contains(intf))) {
Method[] methods = intf.getMethods();
for (int j = 0; j < methods.length; j++) {
checkMethod(methods[j]);
}
list.add(intf);
}
}
}
}
/**
* Verifies that the supplied method has at least one declared exception
* type that is RemoteException or one of its superclasses. If not,
* then this method throws IllegalArgumentException.
*
* @throws IllegalArgumentException if m is an illegal remote method
*/
private static void checkMethod(Method m) {
Class<?>[] ex = m.getExceptionTypes();
for (int i = 0; i < ex.length; i++) {
if (ex[i].isAssignableFrom(RemoteException.class))
return;
}
throw new IllegalArgumentException(
"illegal remote method encountered: " + m);
}
/**
* Creates a RemoteStub instance for the specified class, constructed
* with the specified RemoteRef. The supplied class must be the most
* derived class in the remote object's superclass chain that
* implements a remote interface. The stub class name is the name of
* the specified remoteClass with the suffix "_Stub". The loading of
* the stub class is initiated from class loader of the specified class
* (which may be the bootstrap class loader).
**/
private static RemoteStub createStub(Class<?> remoteClass, RemoteRef ref)
throws StubNotFoundException
{
String stubname = remoteClass.getName() + "_Stub";
/* Make sure to use the local stub loader for the stub classes.
* When loaded by the local loader the load path can be
* propagated to remote clients, by the MarshalOutputStream/InStream
* pickle methods
*/
try {
Class<?> stubcl =
Class.forName(stubname, false, remoteClass.getClassLoader());
Constructor<?> cons = stubcl.getConstructor(stubConsParamTypes);
return (RemoteStub) cons.newInstance(new Object[] { ref });
} catch (ClassNotFoundException e) {
throw new StubNotFoundException(
"Stub class not found: " + stubname, e);
} catch (NoSuchMethodException e) {
throw new StubNotFoundException(
"Stub class missing constructor: " + stubname, e);
} catch (InstantiationException e) {
throw new StubNotFoundException(
"Can't create instance of stub class: " + stubname, e);
} catch (IllegalAccessException e) {
throw new StubNotFoundException(
"Stub class constructor not public: " + stubname, e);
} catch (InvocationTargetException e) {
throw new StubNotFoundException(
"Exception creating instance of stub class: " + stubname, e);
} catch (ClassCastException e) {
throw new StubNotFoundException(
"Stub class not instance of RemoteStub: " + stubname, e);
}
}
/**
* Locate and return the Skeleton for the specified remote object
*/
static Skeleton createSkeleton(Remote object)
throws SkeletonNotFoundException
{
Class<?> cl;
try {
cl = getRemoteClass(object.getClass());
} catch (ClassNotFoundException ex ) {
throw new SkeletonNotFoundException(
"object does not implement a remote interface: " +
object.getClass().getName());
}
// now try to load the skeleton based ont he name of the class
String skelname = cl.getName() + "_Skel";
try {
Class<?> skelcl = Class.forName(skelname, false, cl.getClassLoader());
return (Skeleton)skelcl.newInstance();
} catch (ClassNotFoundException ex) {
throw new SkeletonNotFoundException("Skeleton class not found: " +
skelname, ex);
} catch (InstantiationException ex) {
throw new SkeletonNotFoundException("Can't create skeleton: " +
skelname, ex);
} catch (IllegalAccessException ex) {
throw new SkeletonNotFoundException("No public constructor: " +
skelname, ex);
} catch (ClassCastException ex) {
throw new SkeletonNotFoundException(
"Skeleton not of correct class: " + skelname, ex);
}
}
/**
* Compute the "method hash" of a remote method. The method hash
* is a long containing the first 64 bits of the SHA digest from
* the UTF encoded string of the method name and descriptor.
*/
public static long computeMethodHash(Method m) {
long hash = 0;
ByteArrayOutputStream sink = new ByteArrayOutputStream(127);
try {
MessageDigest md = MessageDigest.getInstance("SHA");
DataOutputStream out = new DataOutputStream(
new DigestOutputStream(sink, md));
String s = getMethodNameAndDescriptor(m);
if (serverRefLog.isLoggable(Log.VERBOSE)) {
serverRefLog.log(Log.VERBOSE,
"string used for method hash: \"" + s + "\"");
}
out.writeUTF(s);
// use only the first 64 bits of the digest for the hash
out.flush();
byte hasharray[] = md.digest();
for (int i = 0; i < Math.min(8, hasharray.length); i++) {
hash += ((long) (hasharray[i] & 0xFF)) << (i * 8);
}
} catch (IOException ignore) {
/* can't happen, but be deterministic anyway. */
hash = -1;
} catch (NoSuchAlgorithmException complain) {
throw new SecurityException(complain.getMessage());
}
return hash;
}
/**
* Return a string consisting of the given method's name followed by
* its "method descriptor", as appropriate for use in the computation
* of the "method hash".
*
* See section 4.3.3 of The Java Virtual Machine Specification for
* the definition of a "method descriptor".
*/
private static String getMethodNameAndDescriptor(Method m) {
StringBuffer desc = new StringBuffer(m.getName());
desc.append('(');
Class<?>[] paramTypes = m.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
desc.append(getTypeDescriptor(paramTypes[i]));
}
desc.append(')');
Class<?> returnType = m.getReturnType();
if (returnType == void.class) { // optimization: handle void here
desc.append('V');
} else {
desc.append(getTypeDescriptor(returnType));
}
return desc.toString();
}
/**
* Get the descriptor of a particular type, as appropriate for either
* a parameter or return type in a method descriptor.
*/
private static String getTypeDescriptor(Class<?> type) {
if (type.isPrimitive()) {
if (type == int.class) {
return "I";
} else if (type == boolean.class) {
return "Z";
} else if (type == byte.class) {
return "B";
} else if (type == char.class) {
return "C";
} else if (type == short.class) {
return "S";
} else if (type == long.class) {
return "J";
} else if (type == float.class) {
return "F";
} else if (type == double.class) {
return "D";
} else if (type == void.class) {
return "V";
} else {
throw new Error("unrecognized primitive type: " + type);
}
} else if (type.isArray()) {
/*
* According to JLS 20.3.2, the getName() method on Class does
* return the VM type descriptor format for array classes (only);
* using that should be quicker than the otherwise obvious code:
*
* return "[" + getTypeDescriptor(type.getComponentType());
*/
return type.getName().replace('.', '/');
} else {
return "L" + type.getName().replace('.', '/') + ";";
}
}
/**
* Returns the binary name of the given type without package
* qualification. Nested types are treated no differently from
* top-level types, so for a nested type, the returned name will
* still be qualified with the simple name of its enclosing
* top-level type (and perhaps other enclosing types), the
* separator will be '$', etc.
**/
public static String getUnqualifiedName(Class<?> c) {
String binaryName = c.getName();
return binaryName.substring(binaryName.lastIndexOf('.') + 1);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2003, 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.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Abstract class that maps Class objects to lazily-computed values of
* type V. A concrete subclass must implement the computeValue method
* to determine how the values are computed.
*
* The keys are only weakly reachable through this map, so this map
* does not prevent a class (along with its class loader, etc.) from
* being garbage collected if it is not otherwise strongly reachable.
* The values are only softly reachable through this map, so that the
* computed values generally persist while not otherwise strongly
* reachable, but their storage may be reclaimed if necessary. Also,
* note that if a key is strongly reachable from a value, then the key
* is effectively softly reachable through this map, which may delay
* garbage collection of classes (see 4429536).
**/
public abstract class WeakClassHashMap<V> {
private Map<Class<?>,ValueCell<V>> internalMap = new WeakHashMap<>();
protected WeakClassHashMap() { }
public V get(Class<?> remoteClass) {
/*
* Use a mutable cell (a one-element list) to hold the soft
* reference to a value, to allow the lazy value computation
* to be synchronized with entry-level granularity instead of
* by locking the whole table.
*/
ValueCell<V> valueCell;
synchronized (internalMap) {
valueCell = internalMap.get(remoteClass);
if (valueCell == null) {
valueCell = new ValueCell<V>();
internalMap.put(remoteClass, valueCell);
}
}
synchronized (valueCell) {
V value = null;
if (valueCell.ref != null) {
value = valueCell.ref.get();
}
if (value == null) {
value = computeValue(remoteClass);
valueCell.ref = new SoftReference<V>(value);
}
return value;
}
}
protected abstract V computeValue(Class<?> remoteClass);
private static class ValueCell<T> {
Reference<T> ref = null;
ValueCell() { }
}
}