feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
412
jdkSrc/jdk8/sun/rmi/server/ActivatableRef.java
Normal file
412
jdkSrc/jdk8/sun/rmi/server/ActivatableRef.java
Normal 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;
|
||||
}
|
||||
}
|
||||
93
jdkSrc/jdk8/sun/rmi/server/ActivatableServerRef.java
Normal file
93
jdkSrc/jdk8/sun/rmi/server/ActivatableServerRef.java
Normal 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");
|
||||
}
|
||||
}
|
||||
2559
jdkSrc/jdk8/sun/rmi/server/Activation.java
Normal file
2559
jdkSrc/jdk8/sun/rmi/server/Activation.java
Normal file
File diff suppressed because it is too large
Load Diff
500
jdkSrc/jdk8/sun/rmi/server/ActivationGroupImpl.java
Normal file
500
jdkSrc/jdk8/sun/rmi/server/ActivationGroupImpl.java
Normal 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;
|
||||
}
|
||||
}
|
||||
85
jdkSrc/jdk8/sun/rmi/server/ActivationGroupInit.java
Normal file
85
jdkSrc/jdk8/sun/rmi/server/ActivationGroupInit.java
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
jdkSrc/jdk8/sun/rmi/server/DeserializationChecker.java
Normal file
93
jdkSrc/jdk8/sun/rmi/server/DeserializationChecker.java
Normal 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) {}
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/rmi/server/Dispatcher.java
Normal file
50
jdkSrc/jdk8/sun/rmi/server/Dispatcher.java
Normal 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;
|
||||
}
|
||||
50
jdkSrc/jdk8/sun/rmi/server/InactiveGroupException.java
Normal file
50
jdkSrc/jdk8/sun/rmi/server/InactiveGroupException.java
Normal 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);
|
||||
}
|
||||
}
|
||||
1224
jdkSrc/jdk8/sun/rmi/server/LoaderHandler.java
Normal file
1224
jdkSrc/jdk8/sun/rmi/server/LoaderHandler.java
Normal file
File diff suppressed because it is too large
Load Diff
357
jdkSrc/jdk8/sun/rmi/server/MarshalInputStream.java
Normal file
357
jdkSrc/jdk8/sun/rmi/server/MarshalInputStream.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
jdkSrc/jdk8/sun/rmi/server/MarshalOutputStream.java
Normal file
111
jdkSrc/jdk8/sun/rmi/server/MarshalOutputStream.java
Normal 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);
|
||||
}
|
||||
}
|
||||
519
jdkSrc/jdk8/sun/rmi/server/UnicastRef.java
Normal file
519
jdkSrc/jdk8/sun/rmi/server/UnicastRef.java
Normal 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;
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/sun/rmi/server/UnicastRef2.java
Normal file
80
jdkSrc/jdk8/sun/rmi/server/UnicastRef2.java
Normal 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);
|
||||
}
|
||||
}
|
||||
689
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef.java
Normal file
689
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef2.java
Normal file
114
jdkSrc/jdk8/sun/rmi/server/UnicastServerRef2.java
Normal 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);
|
||||
}
|
||||
}
|
||||
466
jdkSrc/jdk8/sun/rmi/server/Util.java
Normal file
466
jdkSrc/jdk8/sun/rmi/server/Util.java
Normal 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);
|
||||
}
|
||||
}
|
||||
87
jdkSrc/jdk8/sun/rmi/server/WeakClassHashMap.java
Normal file
87
jdkSrc/jdk8/sun/rmi/server/WeakClassHashMap.java
Normal 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() { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user