| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.yoko.rmi.impl; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.rmi.Remote; |
| import java.rmi.RemoteException; |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.logging.Logger; |
| import java.util.logging.Level; |
| |
| import javax.rmi.CORBA.PortableRemoteObjectDelegate; |
| import javax.rmi.CORBA.Stub; |
| import javax.rmi.CORBA.Tie; |
| import javax.rmi.CORBA.Util; |
| |
| import org.apache.yoko.rmi.util.ClientUtil; |
| import org.apache.yoko.rmi.util.GetSystemPropertyAction; |
| import org.apache.yoko.rmi.util.stub.MethodRef; |
| import org.apache.yoko.rmi.util.stub.StubClass; |
| import org.apache.yoko.rmi.util.stub.StubInitializer; |
| import org.apache.yoko.rmispec.util.UtilLoader; |
| import org.omg.CORBA.BAD_INV_ORDER; |
| import org.omg.CORBA.portable.IDLEntity; |
| import org.omg.CORBA.portable.ObjectImpl; |
| |
| |
| public class PortableRemoteObjectImpl implements PortableRemoteObjectDelegate { |
| static final Logger LOGGER = Logger |
| .getLogger(PortableRemoteObjectImpl.class.getName()); |
| |
| static { |
| // Initialize the stub handler factory when first loaded to ensure we have |
| // class loading visibility to the factory. |
| getRMIStubInitializer(); |
| } |
| |
| static org.omg.CORBA.ORB getORB() { |
| return RMIState.current().getORB(); |
| } |
| |
| static org.omg.PortableServer.POA getPOA() { |
| return RMIState.current().getPOA(); |
| } |
| |
| static ClassLoader getClassLoader() { |
| return RMIState.current().getClassLoader(); |
| } |
| |
| public void connect(Remote target, Remote source) |
| throws java.rmi.RemoteException { |
| if (!(source instanceof javax.rmi.CORBA.Stub)) |
| source = toStub(source); |
| |
| ObjectImpl obj; |
| if (target instanceof ObjectImpl) { |
| obj = (ObjectImpl) target; |
| |
| } else { |
| |
| try { |
| exportObject(target); |
| } catch (RemoteException ex) { |
| // ignore "already exported test" // |
| } |
| |
| try { |
| obj = (ObjectImpl) toStub(target); |
| } catch (java.rmi.NoSuchObjectException ex) { |
| throw (RemoteException)new RemoteException("cannot convert to stub!").initCause(ex); |
| } |
| } |
| |
| try { |
| ((javax.rmi.CORBA.Stub) source).connect(((ObjectImpl) obj)._orb()); |
| } catch (org.omg.CORBA.BAD_OPERATION bad_operation) { |
| throw (RemoteException)new RemoteException(bad_operation.getMessage()) |
| .initCause(bad_operation); |
| } |
| } |
| |
| private Object narrowRMI(ObjectImpl narrowFrom, Class<?> narrowTo) { |
| if (LOGGER.isLoggable(Level.FINE)) |
| LOGGER.fine(String.format("RMI narrowing %s => %s", narrowFrom.getClass().getName(), narrowTo.getName())); |
| ObjectImpl object = narrowFrom; |
| |
| final String codebase = getCodebase(narrowFrom); |
| |
| RMIState state = RMIState.current(); |
| |
| javax.rmi.CORBA.Stub stub; |
| try { |
| stub = createStub(state, codebase, narrowTo); |
| } catch (ClassNotFoundException ex) { |
| throw (ClassCastException)new ClassCastException(narrowTo.getName()).initCause(ex); |
| } |
| |
| org.omg.CORBA.portable.Delegate delegate; |
| try { |
| // let the stub adopt narrowFrom's identity |
| delegate = object._get_delegate(); |
| |
| } catch (org.omg.CORBA.BAD_OPERATION ex) { |
| // ignore |
| delegate = null; |
| } |
| |
| stub._set_delegate(delegate); |
| |
| return stub; |
| } |
| |
| private String getCodebase(ObjectImpl narrowFrom) { |
| String codebase; |
| if (narrowFrom instanceof org.omg.CORBA_2_3.portable.ObjectImpl) { |
| org.omg.CORBA_2_3.portable.ObjectImpl object_2_3 = (org.omg.CORBA_2_3.portable.ObjectImpl) narrowFrom; |
| |
| try { |
| codebase = object_2_3._get_codebase(); |
| } catch (org.omg.CORBA.BAD_OPERATION ex) { |
| codebase = null; |
| } |
| } else { |
| codebase = null; |
| } |
| return codebase; |
| } |
| |
| private Object narrowIDL(ObjectImpl narrowFrom, Class<?> narrowTo) { |
| if (LOGGER.isLoggable(Level.FINE)) |
| LOGGER.fine(String.format("IDL narrowing %s => %s", narrowFrom.getClass().getName(), narrowTo.getName())); |
| final ClassLoader idlClassLoader = UtilImpl.getClassLoader(narrowTo); |
| final String codebase = getCodebase(narrowFrom); |
| final String helperClassName = narrowTo.getName() + "Helper"; |
| |
| try { |
| final Class<?> helperClass = Util.loadClass(helperClassName, codebase, idlClassLoader); |
| final Method helperNarrow = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { |
| @Override |
| public Method run() throws Exception { |
| return helperClass.getMethod("narrow", org.omg.CORBA.Object.class); |
| } |
| }); |
| return helperNarrow.invoke(null, narrowFrom); |
| } catch (PrivilegedActionException e) { |
| throw (ClassCastException)new ClassCastException(narrowTo.getName()).initCause(e.getCause()); |
| } catch (Exception e) { |
| throw (ClassCastException)new ClassCastException(narrowTo.getName()).initCause(e); |
| } |
| } |
| |
| public Object narrow(Object narrowFrom, @SuppressWarnings("rawtypes") Class narrowTo) |
| throws ClassCastException { |
| if (narrowFrom == null) |
| return null; |
| |
| if (narrowTo.isInstance(narrowFrom)) |
| return narrowFrom; |
| |
| final String fromClassName = narrowFrom.getClass().getName(); |
| final String toClassName = narrowTo.getName(); |
| if (LOGGER.isLoggable(Level.FINE)) |
| LOGGER.finer(String.format("narrow %s => %s", fromClassName, toClassName)); |
| |
| if (!(narrowFrom instanceof org.omg.CORBA.portable.ObjectImpl)) |
| throw new ClassCastException(String.format( |
| "object to narrow (runtime type %s) is not an instance of %s", |
| fromClassName, ObjectImpl.class.getName())); |
| if (!narrowTo.isInterface()) |
| throw new ClassCastException(String.format("%s is not an interface", toClassName)); |
| |
| final boolean isRemote = Remote.class.isAssignableFrom(narrowTo); |
| final boolean isIDLEntity = IDLEntity.class.isAssignableFrom(narrowTo); |
| |
| if (isRemote && isIDLEntity) |
| throw new ClassCastException(String.format( |
| "%s invalidly extends both %s and %s", |
| toClassName, Remote.class.getName(), IDLEntity.class.getName())); |
| if (isRemote) |
| return narrowRMI((ObjectImpl) narrowFrom, narrowTo); |
| if (isIDLEntity) |
| return narrowIDL((ObjectImpl) narrowFrom, narrowTo); |
| |
| throw new ClassCastException(String.format( |
| "%s extends neither %s nor %s", |
| toClassName, Remote.class.getName(), IDLEntity.class.getName())); |
| } |
| |
| static java.rmi.Remote narrow1(RMIState state, ObjectImpl object, Class<?> narrowTo) throws ClassCastException { |
| Stub stub; |
| |
| try { |
| stub = createStub(state, null, narrowTo); |
| } catch (ClassNotFoundException ex) { |
| throw (ClassCastException)new ClassCastException(narrowTo.getName()).initCause(ex); |
| } |
| |
| org.omg.CORBA.portable.Delegate delegate; |
| try { |
| // let the stub adopt narrowFrom's identity |
| delegate = object._get_delegate(); |
| |
| } catch (org.omg.CORBA.BAD_OPERATION ex) { |
| // ignore |
| delegate = null; |
| } |
| |
| stub._set_delegate(delegate); |
| |
| return (java.rmi.Remote) stub; |
| } |
| |
| static private Stub createStub(RMIState state, String codebase, Class<?> type) throws ClassNotFoundException { |
| if (Remote.class == type) { |
| return new RMIRemoteStub(); |
| } |
| |
| if (ClientUtil.isRunningAsClientContainer()) { |
| Stub stub = state.getStaticStub(codebase, type); |
| if (stub != null) { |
| return stub; |
| } |
| } |
| |
| return createRMIStub(state, type); |
| } |
| |
| static Object[] NO_ARG = new Object[0]; |
| |
| static Stub createRMIStub(RMIState state, Class<?> type) throws ClassNotFoundException { |
| if (!type.isInterface()) { |
| throw new RuntimeException("non-interfaces not supported"); |
| } |
| |
| LOGGER.fine("Creating RMI stub for class " + type.getName()); |
| |
| Constructor<? extends Stub> cons = getRMIStubClassConstructor(state, type); |
| |
| try { |
| Stub result = cons.newInstance(NO_ARG); |
| return result; |
| } catch (InstantiationException ex) { |
| throw new RuntimeException( |
| "internal problem: cannot instantiate stub", ex); |
| } catch (InvocationTargetException ex) { |
| throw new RuntimeException( |
| "internal problem: cannot instantiate stub", ex.getCause()); |
| } catch (IllegalAccessException ex) { |
| throw new RuntimeException( |
| "internal problem: cannot instantiate stub", ex); |
| } |
| } |
| |
| private static java.lang.reflect.Method stub_write_replace; |
| |
| static { |
| try { |
| stub_write_replace = RMIStub.class.getDeclaredMethod( |
| "writeReplace", new Class[0]); |
| |
| } catch (Throwable ex) { |
| LOGGER.log(Level.WARNING, "cannot initialize: \n" + ex.getMessage(), ex); |
| throw new Error("cannot initialize", ex); |
| } |
| } |
| |
| static synchronized Class<?> getRMIStubClass(RMIState state, Class<?> type) throws ClassNotFoundException { |
| return getRMIStubClassConstructor(state, type).getDeclaringClass(); |
| } |
| |
| static Constructor<? extends Stub> getRMIStubClassConstructor(RMIState state, Class<?> type) throws ClassNotFoundException { |
| LOGGER.fine("Requesting stub constructor of class " + type.getName()); |
| @SuppressWarnings("unchecked") |
| Constructor<? extends Stub> cons = (Constructor<? extends Stub>) state.stub_map.get(type); |
| |
| if (cons != null) { |
| LOGGER.fine("Returning cached constructor of class " + cons.getDeclaringClass().getName()); |
| return cons; |
| } |
| |
| TypeRepository repository = state.getTypeRepository(); |
| RemoteDescriptor desc = (RemoteDescriptor) repository.getRemoteDescriptor(type); |
| |
| MethodDescriptor[] mdesc = desc.getMethods(); |
| MethodDescriptor[] descriptors = new MethodDescriptor[mdesc.length + 1]; |
| for (int i = 0; i < mdesc.length; i++) { |
| descriptors[i] = mdesc[i]; |
| } |
| |
| LOGGER.finer("TYPE ----> " + type); |
| LOGGER.finer("LOADER --> " + UtilImpl.getClassLoader(type)); |
| LOGGER.finer("CONTEXT -> " + getClassLoader()); |
| |
| MethodRef[] methods = new MethodRef[descriptors.length]; |
| |
| for (int i = 0; i < mdesc.length; i++) { |
| Method m = descriptors[i].getReflectedMethod(); |
| LOGGER.finer("Method ----> " + m); |
| methods[i] = new MethodRef(m); |
| } |
| methods[mdesc.length] = new MethodRef(stub_write_replace); |
| |
| |
| Class<?> clazz = null; |
| |
| try { |
| /* Construct class! */ |
| clazz = StubClass.make(/* the class loader to use */ |
| UtilImpl.getClassLoader(type), |
| |
| /* the bean developer's bean class */ |
| RMIStub.class, |
| |
| /* interfaces */ |
| new Class[] { type }, |
| |
| /* the methods */ |
| methods, |
| |
| /* contains only ejbCreate */ |
| null, |
| |
| /* our data objects */ |
| descriptors, |
| |
| /* the handler method */ |
| getPOAStubInvokeMethod(), |
| |
| /* package name (use superclass') */ |
| getPackageName(type), |
| |
| /* provider of handlers */ |
| getRMIStubInitializer()); |
| } catch (java.lang.NoClassDefFoundError ex) { |
| /* Construct class! */ |
| clazz = StubClass.make(/* the class loader to use */ |
| getClassLoader(), |
| |
| /* the bean developer's bean class */ |
| RMIStub.class, |
| |
| /* interfaces */ |
| new Class[] { type }, |
| |
| /* the methods */ |
| methods, |
| |
| /* contains only ejbCreate */ |
| null, |
| |
| /* our data objects */ |
| descriptors, |
| |
| /* the handler method */ |
| getPOAStubInvokeMethod(), |
| |
| /* package name (use superclass') */ |
| getPackageName(type), |
| |
| /* provider of handlers */ |
| getRMIStubInitializer()); |
| |
| } |
| |
| if (clazz != null) { |
| try { |
| cons = (Constructor<? extends Stub>) clazz.getConstructor(); |
| state.stub_map.put(type, cons); |
| } catch (NoSuchMethodException e) { |
| LOGGER.log(Level.FINER, "constructed stub has no default constructor", e); |
| } |
| } |
| |
| return cons; |
| } |
| |
| static String getPackageName(Class clazz) { |
| String class_name = clazz.getName(); |
| int idx = class_name.lastIndexOf('.'); |
| if (idx == -1) { |
| return null; |
| } else { |
| return class_name.substring(0, idx); |
| } |
| } |
| |
| private static Method poa_stub_invoke_method; |
| |
| static Method getPOAStubInvokeMethod() { |
| if (poa_stub_invoke_method == null) { |
| |
| // NYI: PrivilegedAction |
| try { |
| // get the interface method used to invoke the stub handler |
| poa_stub_invoke_method = (StubHandler.class) |
| .getDeclaredMethod("invoke", new Class[] { |
| RMIStub.class, MethodDescriptor.class, |
| Object[].class }); |
| } catch (NoSuchMethodException ex) { |
| throw new Error("cannot find RMI Stub handler invoke method", ex); |
| } |
| |
| } |
| |
| return poa_stub_invoke_method; |
| |
| } |
| |
| public java.rmi.Remote toStub(java.rmi.Remote value) |
| throws java.rmi.NoSuchObjectException { |
| if (value instanceof javax.rmi.CORBA.Stub) |
| return value; |
| |
| javax.rmi.CORBA.Tie tie = javax.rmi.CORBA.Util.getTie(value); |
| if (tie == null) { |
| throw new java.rmi.NoSuchObjectException("object not exported"); |
| } |
| |
| RMIServant servant = (RMIServant) tie; |
| |
| try { |
| org.omg.PortableServer.POA poa = servant.getRMIState().getPOA(); |
| org.omg.CORBA.Object ref = poa.servant_to_reference(servant); |
| return (java.rmi.Remote) narrow(ref, servant.getJavaClass()); |
| } catch (org.omg.PortableServer.POAPackage.ServantNotActive ex) { |
| throw new RuntimeException("internal error: " + ex.getMessage(), ex); |
| } catch (org.omg.PortableServer.POAPackage.WrongPolicy ex) { |
| throw new RuntimeException("internal error: " + ex.getMessage(), ex); |
| } |
| } |
| |
| public void exportObject(Remote obj) throws java.rmi.RemoteException { |
| RMIState state = RMIState.current(); |
| |
| try { |
| state.checkShutDown(); |
| } catch (BAD_INV_ORDER ex) { |
| throw new RemoteException("RMIState is deactivated", ex); |
| } |
| |
| Tie tie = javax.rmi.CORBA.Util.getTie(obj); |
| |
| if (tie != null) |
| throw new java.rmi.RemoteException("object already exported"); |
| |
| RMIServant servant = new RMIServant(state); |
| javax.rmi.CORBA.Util.registerTarget(servant, obj); |
| |
| LOGGER.finer("exporting instance of " + obj.getClass().getName() |
| + " in " + state.getName()); |
| |
| try { |
| servant._id = state.getPOA().activate_object(servant); |
| } catch (org.omg.PortableServer.POAPackage.ServantAlreadyActive ex) { |
| throw new java.rmi.RemoteException("internal error: " + ex.getMessage(), ex); |
| } catch (org.omg.PortableServer.POAPackage.WrongPolicy ex) { |
| throw new java.rmi.RemoteException("internal error: " + ex.getMessage(), ex); |
| } |
| } |
| |
| public void unexportObject(Remote obj) |
| throws java.rmi.NoSuchObjectException { |
| javax.rmi.CORBA.Util.unexportObject(obj); |
| } |
| |
| // the factory object used for creating stub initializers |
| static private StubInitializer initializer = null; |
| // the default stub handler, which is ours without overrides. |
| private static final String defaultInitializer = "org.apache.yoko.rmi.impl.RMIStubInitializer"; |
| |
| /** |
| * Get the RMI stub handler initializer to use for RMI invocation |
| * stubs. The Class in question must implement the StubInitializer method. |
| * |
| * @return The class used to create StubHandler instances. |
| */ |
| private static StubInitializer getRMIStubInitializer() { |
| if (initializer == null) { |
| String factory = (String)AccessController.doPrivileged(new GetSystemPropertyAction("org.apache.yoko.rmi.RMIStubInitializerClass", defaultInitializer)); |
| try { |
| initializer = (StubInitializer)(UtilLoader.loadServiceClass(factory, "org.apache.yoko.rmi.RMIStubInitializerClass").newInstance()); |
| } catch (Exception e) { |
| throw (org.omg.CORBA.INITIALIZE)new org.omg.CORBA.INITIALIZE( |
| "Can not create RMIStubInitializer: " + factory).initCause(e); |
| } |
| } |
| return initializer; |
| } |
| } |