/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.iiop;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.net.URL;
import java.io.File;
import java.util.*;
import java.util.logging.*;
import java.lang.reflect.Method;
import javax.rmi.PortableRemoteObject;
import javax.rmi.CORBA.*;
import javax.transaction.*;
import javax.ejb.EJBHome;
import javax.ejb.EJBObject;
import javax.ejb.NoSuchObjectLocalException;
import javax.naming.*;
import org.omg.CORBA.*;
import org.omg.CORBA.portable.Delegate;
import org.omg.CosNaming.NamingContext;
import org.omg.PortableServer.POA ;
import org.omg.PortableServer.Servant ;
import org.omg.PortableServer.ServantLocator ;
import org.omg.PortableServer.ServantLocatorPackage.CookieHolder ;
import com.sun.logging.LogDomains;
import com.sun.enterprise.*;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.util.*;
import com.sun.enterprise.server.*;
import com.sun.enterprise.deployment.runtime.IASEjbExtraDescriptors;
import com.sun.ejb.*;
import com.sun.ejb.base.sfsb.util.EJBServerConfigLookup;
import com.sun.ejb.containers.StatefulSessionContainer;
import com.sun.corba.ee.spi.ior.*;
import com.sun.corba.ee.spi.extension.ServantCachingPolicy;
import com.sun.corba.ee.spi.extension.ZeroPortPolicy;
import com.sun.corba.ee.spi.extension.CopyObjectPolicy;
import com.sun.corba.ee.spi.extension.RequestPartitioningPolicy;
import com.sun.corba.ee.spi.orbutil.threadpool.ThreadPoolManager;
import com.sun.corba.ee.spi.orbutil.threadpool.NoSuchThreadPoolException;
import com.sun.corba.ee.spi.presentation.rmi.PresentationManager ;
import com.sun.corba.ee.spi.presentation.rmi.DynamicStub;
import com.sun.corba.ee.spi.presentation.rmi.StubAdapter;
import com.sun.corba.ee.spi.oa.rfm.ReferenceFactory ;
import com.sun.corba.ee.spi.oa.rfm.ReferenceFactoryManager ;
import com.sun.corba.ee.impl.orbutil.ORBConstants;
import com.sun.corba.ee.impl.naming.cosnaming.TransientNameService;
import com.sun.corba.ee.impl.util.SUNVMCID;
import com.sun.enterprise.util.Utility;
/**
* This class implements the RemoteReferenceFactory interface for the
* RMI/IIOP ORB with POA (Portable Object Adapter).
* There is one instance of the POARemoteReferenceFactory for each
* EJB type.
*
* It also implements the preinvoke/postinvoke APIs in the
* POA's ServantLocator interface, which are called before/after
* every invocation (local or remote).
* It creates a RMI-IIOP-POA object reference (a stub) for every EJBObject
* and EJBHome in the EJB container.
*
* @author Kenneth Saks
*/
public final class POARemoteReferenceFactory extends org.omg.CORBA.LocalObject
implements RemoteReferenceFactory, ServantLocator
{
static final int PASS_BY_VALUE_ID = 0;
static final int PASS_BY_REFERENCE_ID = 1;
static final int OTS_POLICY_TYPE = SUNVMCID.value + 123;
static final int CSIv2_POLICY_TYPE = SUNVMCID.value + 124;
static final int REQUEST_DISPATCH_POLICY_TYPE = SUNVMCID.value + 125;
static final int SFSB_VERSION_POLICY_TYPE = SUNVMCID.value + 126;
private static final java.util.logging.Logger logger =
java.util.logging.Logger.getLogger(LogDomains.CORBA_LOGGER);
private static final int GET_TIE_EXCEPTION_CODE = 9999;
private Container container;
private EjbDescriptor ejbDescriptor;
private ORB orb;
private POAProtocolMgr protocolMgr;
private PresentationManager presentationMgr;
private ReferenceFactory ejbHomeReferenceFactory ;
private PresentationManager.StubFactory ejbHomeStubFactory;
private String ejbHomeRepositoryId;
private ReferenceFactory ejbObjectReferenceFactory ;
private PresentationManager.StubFactory ejbObjectStubFactory;
private String ejbObjectRepositoryId;
private String remoteBusinessIntf;
// true if remote home view. false if remote business view.
// Used when getting target object for an invocation.
private boolean isRemoteHomeView;
private String poaId_EJBHome;
private String poaId_EJBObject;
// The EJB key format with field-name(size in bytes):
// -----------------------------------------
// | EJB ID(8) | INSTANCEKEY | INSTANCEKEY |
// | | LENGTH(4) | (unknown) |
// -----------------------------------------
// The following are the offsets for the fields in the EJB key.
static final int EJBID_OFFSET = 0;
private static final int INSTANCEKEYLEN_OFFSET = 8;
private static final int INSTANCEKEY_OFFSET = 12;
POARemoteReferenceFactory(Container container, POAProtocolMgr protocolMgr,
ORB orb, boolean remoteHomeView, String id) {
this.protocolMgr = protocolMgr;
this.orb = orb;
this.poaId_EJBHome = id + "-EJBHome";
this.poaId_EJBObject = id + "-EJBObject";
this.presentationMgr =
((com.sun.corba.ee.spi.orb.ORB) orb).getPresentationManager();
this.container = container;
this.ejbDescriptor = container.getEjbDescriptor();
this.isRemoteHomeView = remoteHomeView;
ClassLoader loader = container.getClassLoader();
// NOTE: ReferenceFactory creation happens in setRepositoryIds.
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
"POARemoteReferenceFactory:"
+ " " + poaId_EJBHome
+ " " + poaId_EJBObject
+ " " + ejbDescriptor);
}
}
private String getRepositoryId(Class c) throws Exception {
// Using PresentationManager to get repository ID will always work,
// independent of whether we have generated static RMI-IIOP stubs.
PresentationManager.ClassData cData = presentationMgr.getClassData(c);
String[] typeIds = cData.getTypeIds();
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, ".getRepositoryId: " + typeIds[0]);
}
// Repository id is always 1st element in array.
return typeIds[0];
}
public void setRepositoryIds(Class homeIntf, Class remoteIntf)
{
ClassLoader appClassLoader = container.getClassLoader();
PresentationManager.StubFactoryFactory sff =
((com.sun.corba.ee.spi.orb.ORB) orb).getStubFactoryFactory();
// Home
ejbHomeStubFactory =
sff.createStubFactory( homeIntf.getName(), false,
"", null, appClassLoader);
String[] ejbHomeTypeIds = ejbHomeStubFactory.getTypeIds();
ejbHomeRepositoryId = ejbHomeTypeIds[0];
ejbObjectStubFactory =
sff.createStubFactory( remoteIntf.getName(), false,
"", null, appClassLoader);
String[] ejbObjectTypeIds = ejbObjectStubFactory.getTypeIds();
ejbObjectRepositoryId = ejbObjectTypeIds[0];
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,
".setRepositoryIds:"
+ " " + ejbHomeRepositoryId
+ " " + ejbObjectRepositoryId);
}
try {
ejbHomeReferenceFactory
= createReferenceFactory(poaId_EJBHome, ejbHomeRepositoryId);
ejbObjectReferenceFactory
= createReferenceFactory(poaId_EJBObject, ejbObjectRepositoryId);
} catch (Exception e) {
throw new RuntimeException(e);
}
if( !isRemoteHomeView ) {
remoteBusinessIntf = remoteIntf.getName();
}
}
public void cleanupClass(Class clazz) {
try {
presentationMgr.flushClass(clazz);
} catch(Exception e) {
logger.log(Level.FINE, "cleanupClass error", e);
}
}
private ReferenceFactory createReferenceFactory(String poaId, String repoid ) throws Exception {
try {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.WARNING,
".createReferenceFactory->: " + poaId + " " + repoid);
}
ReferenceFactoryManager rfm =
(ReferenceFactoryManager)orb.resolve_initial_references(
ORBConstants.REFERENCE_FACTORY_MANAGER ) ;
List<Policy> policies = new ArrayList<Policy>();
// Servant caching for local RMI-IIOP invocation performance
policies.add(ServantCachingPolicy.getPolicy());
// OTS Policy
policies.add(new OTSPolicy());
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.WARNING,
".createReferenceFactory: " + poaId + " " + repoid
+ ": " + ejbDescriptor);
}
// CSIv2 Policy
policies.add(new CSIv2Policy(ejbDescriptor));
IASEjbExtraDescriptors extraDesc
= ejbDescriptor.getIASEjbExtraDescriptors();
String threadPoolName = extraDesc.getUseThreadPoolId();
int threadPoolNumericID = 0;
boolean usePassByReference = extraDesc.getPassByReference();
if (usePassByReference) {
policies.add(new CopyObjectPolicy(PASS_BY_REFERENCE_ID));
}
if (threadPoolName != null) {
ThreadPoolManager threadPoolManager
= S1ASThreadPoolManager.getThreadPoolManager();
try {
threadPoolNumericID = threadPoolManager.getThreadPoolNumericId(
threadPoolName);
policies.add(new RequestPartitioningPolicy(threadPoolNumericID));
} catch (Exception ex) {
logger.log(Level.WARNING, "Not using threadpool-request-partitioning...", ex);
}
}
logger.log(Level.INFO, "POARemoteRefFactory checking if SFSBVersionPolicy need to be added");
EJBServerConfigLookup ejbConfigLookup =
new EJBServerConfigLookup(ejbDescriptor);
boolean addSFSBVersionPolicy = EJBServerConfigLookup.needToAddSFSBVersionInterceptors();
logger.log(Level.INFO, "POARemoteRefFactory addSFSBVersionPolicy? " + addSFSBVersionPolicy);
if (addSFSBVersionPolicy) {
if (container instanceof StatefulSessionContainer) {
StatefulSessionContainer sfsbCon = (StatefulSessionContainer) container;
if (sfsbCon.isHAEnabled()) {
policies.add(new SFSBVersionPolicy(ejbDescriptor.getUniqueId()));
}
}
}
if (logger.isLoggable(Level.FINE)) {
String jndiName = ejbDescriptor.getJndiName();
logger.log(Level.FINE, "Using Thread-Pool: ["
+ threadPoolName + " ==> " + threadPoolNumericID
+ "] for jndi name: " + jndiName);
logger.log(Level.FINE, "Pass by reference: ["
+ usePassByReference
+ "] for jndi name: " + usePassByReference);
}
// DisableClearTextIIOP policy which sets IIOP Profile port to 0
// if EJB allows only SSL invocations
CSIV2TaggedComponentInfo ctc = new CSIV2TaggedComponentInfo(orb);
Set iorDescSet = ejbDescriptor.getIORConfigurationDescriptors();
if ( ctc.allMechanismsRequireSSL(iorDescSet) ) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.WARNING,
".createReferenceFactory: " + poaId + " " + repoid
+ ": adding ZeroPortPolicy");
}
policies.add(ZeroPortPolicy.getPolicy());
}
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.WARNING,
".createReferenceFactory: " + poaId + " " + repoid
+ ": policies: " + policies);
}
ReferenceFactory rf = rfm.create( poaId, repoid, policies, this ) ;
return rf ;
} finally {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.WARNING,
".createReferenceFactory<-: " + poaId + " " + repoid);
}
}
}
public java.rmi.Remote createRemoteReference(byte[] instanceKey)
{
return createRef(instanceKey, ejbObjectReferenceFactory,
ejbObjectStubFactory, ejbObjectRepositoryId );
}
public EJBHome createHomeReference(byte[] homeKey)
{
return (EJBHome)createRef(homeKey, ejbHomeReferenceFactory,
ejbHomeStubFactory, ejbHomeRepositoryId ) ;
}
private Remote createRef(byte[] instanceKey, ReferenceFactory rf,
PresentationManager.StubFactory stubFactory, String repoid )
{
try {
PresentationManager.StubFactory stubFact = stubFactory;
org.omg.CORBA.Object ref = _createRef(rf, instanceKey,repoid);
org.omg.CORBA.Object stub = stubFact.makeStub();
Delegate delegate = StubAdapter.getDelegate(ref);
StubAdapter.setDelegate(stub, delegate);
return (Remote) stub;
} catch(Exception e) {
logger.log(Level.SEVERE, "iiop.createreference_exception",
e.toString());
throw new RuntimeException("Unable to create reference ",e);
}
}
// NOTE: The repoid is only needed for logging.
private org.omg.CORBA.Object _createRef( ReferenceFactory rf,
byte[] instanceKey, String repoid ) throws Exception {
if ( logger.isLoggable(Level.FINE) ) {
logger.info("\t\tIn POARemoteReferenceFactory._createRef, " +
"repositoryId = " + repoid);
}
// Create the ejbKey using EJB's unique id + instanceKey
byte[] ejbKey = createEJBKey(ejbDescriptor.getUniqueId(),
instanceKey);
org.omg.CORBA.Object obj = rf.createReference( ejbKey ) ;
return obj;
}
private byte[] createEJBKey(long ejbId, byte[] instanceKey)
{
byte[] ejbkey = new byte[INSTANCEKEY_OFFSET+instanceKey.length];
Utility.longToBytes(ejbId, ejbkey, EJBID_OFFSET);
Utility.intToBytes(instanceKey.length, ejbkey, INSTANCEKEYLEN_OFFSET);
System.arraycopy(instanceKey, 0, ejbkey, INSTANCEKEY_OFFSET,
instanceKey.length);
return ejbkey;
}
/**
* Disconnect an EJBObject or EJBHome from the ORB.
*/
public void destroyReference(Remote remoteRef, Remote remoteObj)
{
// Note: the POAs have the NON_RETAIN policy so they dont maintain
// any state for objects. We only need to unexport the object from
// the RMI/IIOP machinery.
// The following call also does tie.deactivate() for the remoteObj's tie
try {
Util.unexportObject(remoteObj);
} catch ( RuntimeException ex ) {
// A bug in Util.unexportObject causes this exception
// Ignore it.
} catch ( java.lang.Exception nsoe ){
// eat it and ignore it.
}
}
/**
* This is the implementation of ServantLocator.preinvoke()
* It is called from the POA before every remote invocation.
* Return a POA Servant (which is the RMI/IIOP Tie for EJBObject/EJBHome).
*/
public Servant preinvoke(byte[] ejbKey, POA adapter, String operation,
CookieHolder cookieHolder)
throws org.omg.PortableServer.ForwardRequest
{
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,"In preinvoke for operation:" + operation);
}
// get instance key
int keyLen = Utility.bytesToInt(ejbKey, INSTANCEKEYLEN_OFFSET);
byte[] instanceKey = new byte[keyLen];
System.arraycopy(ejbKey, INSTANCEKEY_OFFSET, instanceKey, 0, keyLen);
Servant servant = null;
try {
while ( servant == null ) {
// get the EJBObject / EJBHome
Remote targetObj =
container.getTargetObject(instanceKey,
(isRemoteHomeView ? null :
remoteBusinessIntf));
// This could be null in rare cases for sfsbs and entity
// beans. It would be preferable to push the retry logic
// within the sfsb container and entity container
// implementations of getTargetObject, but for now let's keep
// the looping logic the same as it has always been.
if( targetObj != null ) {
// get the Tie which is the POA Servant
//fix for bug 6484935
Tie tie = (Tie)java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Tie run() {
return presentationMgr.getTie();
}
});
tie.setTarget(targetObj);
servant = (Servant) tie;
}
}
} catch (NoSuchObjectLocalException e) {
logger.log(Level.SEVERE,"iiop.gettie_exception", e);
throw new OBJECT_NOT_EXIST( GET_TIE_EXCEPTION_CODE,
CompletionStatus.COMPLETED_NO);
} catch (RuntimeException e) {
logger.log(Level.SEVERE,"iiop.runtime_exception", e);
throw e;
}
return servant;
}
public void postinvoke(byte[] ejbKey, POA adapter, String operation,
java.lang.Object cookie, Servant servant)
{
Remote target = null;
if ( servant != null ) {
target = ((Tie)servant).getTarget();
}
// Always release, since that restores the previous context class
// loader.
container.releaseTargetObject(target);
}
public void destroy() {
try {
ejbHomeReferenceFactory.destroy() ;
ejbObjectReferenceFactory.destroy() ;
ejbHomeReferenceFactory = null ;
ejbObjectReferenceFactory = null ;
container = null;
ejbDescriptor = null;
orb = null;
protocolMgr = null;
} catch (Throwable th) {
logger.log(Level.SEVERE, "Exception during "
+ "POARemoteRefFactory::destroy()", th);
}
}
public boolean hasSameContainerID(org.omg.CORBA.Object obj)
throws Exception
{
boolean result = false;
try {
IOR ior = ((com.sun.corba.ee.spi.orb.ORB)orb).getIOR(obj, false);
java.util.Iterator iter = ior.iterator();
byte[] oid = null;
if (iter.hasNext()) {
TaggedProfile profile = (TaggedProfile) iter.next();
ObjectKey objKey = profile.getObjectKey();
oid = objKey.getId().getId();
}
if ((oid != null) && (oid.length > INSTANCEKEY_OFFSET)) {
long cid = Utility.bytesToLong(oid, EJBID_OFFSET);
//To be really sure that is indeed a ref generated
// by our container we do the following checks
int keyLen = Utility.bytesToInt(oid, INSTANCEKEYLEN_OFFSET);
if (oid.length == keyLen + INSTANCEKEY_OFFSET) {
result = (cid == ejbDescriptor.getUniqueId());
}
if (logger.isLoggable(Level.FINE)) {
StringBuffer sbuf = new StringBuffer();
sbuf.append("hasSameContainerID() result: ").append(result)
.append("; because ==> oid.length: ").append(oid.length)
.append("; instance-key-length: ").append(keyLen)
.append("; expected oid.length: ")
.append(keyLen).append("+").append(INSTANCEKEY_OFFSET)
.append("; myContainrID: ")
.append(ejbDescriptor.getUniqueId())
.append("; obj.containerID: ")
.append(cid);
logger.log(Level.FINE, sbuf.toString());
}
} else {
if (logger.isLoggable(Level.FINE)) {
if (oid == null) {
logger.log(Level.FINE, "hasSameContainerID() failed because oid=null");
} else {
logger.log(Level.FINE, "hasSameContainerID() failed because "
+ "oid.length= " + oid.length
+ "; but INSTANCE_KEY_OFFSET= " + INSTANCEKEY_OFFSET);
}
}
}
} catch (Exception ex) {
logger.log(Level.FINE, "Exception while checking for same containerID", ex);
throw ex;
}
return result;
}
}
|