/*
* 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.ejb.base.io;
import java.io.*;
import java.security.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
import java.util.logging.*;
import com.sun.logging.*;
import com.sun.ejb.base.sfsb.util.SimpleKeyGenerator;
import com.sun.ejb.containers.BaseContainer;
import com.sun.ejb.containers.RemoteBusinessWrapperBase;
import com.sun.ejb.containers.StatefulSessionContainer;
import com.sun.ejb.spi.io.IndirectlySerializable;
import com.sun.ejb.spi.io.SerializableObjectFactory;
import com.sun.ejb.spi.io.NonSerializableObjectHandler;
import com.sun.ejb.EJBUtils;
import com.sun.enterprise.Switch;
import com.sun.enterprise.NamingManager;
import com.sun.corba.ee.spi.ior.IOR;
import com.sun.corba.ee.spi.ior.IORFactories;
import com.sun.corba.ee.spi.ior.ObjectKey;
import com.sun.corba.ee.spi.ior.TaggedProfile ;
import com.sun.enterprise.iiop.SFSBClientVersionManager;
import com.sun.enterprise.util.Utility;
import com.sun.enterprise.util.ORBManager;
import com.sun.corba.ee.spi.presentation.rmi.StubAdapter;
/**
* A class that is used to passivate SFSB conversational state
*
* @author Mahesh Kannan
*/
class EJBObjectOutputStream
extends java.io.ObjectOutputStream
{
protected static final Logger _ejbLogger =
LogDomains.getLogger(LogDomains.EJB_LOGGER);
protected NonSerializableObjectHandler handler;
static final int EJBID_OFFSET = 0;
static final int INSTANCEKEYLEN_OFFSET = 8;
static final int INSTANCEKEY_OFFSET = 12;
private static final byte HOME_KEY = (byte)0xff;
EJBObjectOutputStream(OutputStream out,
boolean replaceObject,
NonSerializableObjectHandler handler)
throws IOException
{
super(out);
if (replaceObject == true) {
enableReplaceObject(replaceObject);
}
this.handler = handler;
}
/**
* This code is needed to serialize non-Serializable objects that
* can be part of a bean's state. See EJB2.0 section 7.4.1.
*/
protected Object replaceObject(Object obj)
throws IOException
{
Object result = obj;
if (obj instanceof IndirectlySerializable) {
result = ((IndirectlySerializable) obj).getSerializableObjectFactory();
} else if (obj instanceof RemoteBusinessWrapperBase) {
result = getRemoteBusinessObjectFactory
((RemoteBusinessWrapperBase)obj);
} else if (StubAdapter.isStub(obj) && StubAdapter.isLocal(obj)) {
org.omg.CORBA.Object target = (org.omg.CORBA.Object) obj;
// If we're here, it's always for the 2.x RemoteHome view.
// There is no remote business wrapper class.
result = getSerializableEJBReference(target, null);
} else if ( obj instanceof Serializable ) {
result = obj;
} else if (obj instanceof Context) {
result = new SerializableJNDIContext((Context) obj);
} else {
if (_ejbLogger.isLoggable(Level.FINE)) {
_ejbLogger.log(Level.FINE,
"EJBObjectInputStream_handling_non_serializable_object",
obj.getClass().getName());
}
result = (handler == null)
? obj
: handler.handleNonSerializableObject(obj);
}
return result;
}
private Serializable getRemoteBusinessObjectFactory
(RemoteBusinessWrapperBase remoteBusinessWrapper)
throws IOException {
// Create a serializable object with the remote delegate and
// the name of the client wrapper class.
org.omg.CORBA.Object target = (org.omg.CORBA.Object)
remoteBusinessWrapper.getStub();
return getSerializableEJBReference(target,
remoteBusinessWrapper.getBusinessInterfaceName());
}
private Serializable getSerializableEJBReference(org.omg.CORBA.Object obj,
String remoteBusinessInterface)
throws IOException
{
Serializable result = (Serializable) obj;
try {
IOR ior = ((com.sun.corba.ee.spi.orb.ORB)ORBManager.getORB()).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();
}
long containerId = -1;
int keyLength = -1;
if ((oid != null) && (oid.length > INSTANCEKEY_OFFSET)) {
containerId = Utility.bytesToLong(oid, EJBID_OFFSET);
//To be really sure that is indeed a ref generated
// by our container we do the following checks
keyLength = Utility.bytesToInt(oid, INSTANCEKEYLEN_OFFSET);
if (oid.length == keyLength + INSTANCEKEY_OFFSET) {
boolean isHomeReference =
((keyLength == 1) && (oid[INSTANCEKEY_OFFSET] == HOME_KEY));
if (isHomeReference) {
result = new SerializableS1ASEJBHomeReference(containerId);
} else {
SerializableS1ASEJBObjectReference serRef =
new SerializableS1ASEJBObjectReference(containerId,
oid, keyLength, remoteBusinessInterface);
result = serRef;
if (serRef.isHAEnabled()) {
SimpleKeyGenerator gen = new SimpleKeyGenerator();
Object key = gen.byteArrayToKey(oid, INSTANCEKEY_OFFSET, 20);
long version = SFSBClientVersionManager.getClientVersion(
containerId, key);
serRef.setSFSBClientVersion(key, version);
}
}
}
}
} catch (Exception ex) {
_ejbLogger.log(Level.WARNING, "Exception while getting serializable object", ex);
IOException ioEx = new IOException("Exception during extraction of instance key");
ioEx.initCause(ex);
throw ioEx;
}
return result;
}
}
final class SerializableJNDIContext
implements SerializableObjectFactory
{
private String name;
SerializableJNDIContext(Context ctx)
throws IOException
{
try {
// Serialize state for a jndi context. The spec only requires
// support for serializing contexts pointing to java:comp/env
// or one of its subcontexts. We also support serializing the
// references to the the default no-arg InitialContext, as well
// as references to the the contexts java: and java:comp. All
// other contexts will either not serialize correctly or will
// throw an exception during deserialization.
this.name = ctx.getNameInNamespace();
} catch (NamingException ex) {
IOException ioe = new IOException();
ioe.initCause(ex);
throw ioe;
}
}
public Object createObject()
throws IOException
{
try {
if ((name == null) || (name.length() == 0)) {
return new InitialContext();
} else {
NamingManager nm = Switch.getSwitch().getNamingManager();
return nm.restoreJavaCompEnvContext(name);
}
} catch (NamingException namEx) {
IOException ioe = new IOException();
ioe.initCause(namEx);
throw ioe;
}
}
}
abstract class AbstractSerializableS1ASEJBReference
implements SerializableObjectFactory
{
protected long containerId;
protected String debugStr; //used for loggin purpose only
protected static Logger _ejbLogger =
LogDomains.getLogger(LogDomains.EJB_LOGGER);
AbstractSerializableS1ASEJBReference(long containerId) {
this.containerId = containerId;
BaseContainer container = (BaseContainer) Switch.getSwitch().
getContainerFactory().getContainer(containerId);
//container can be null if the app has been undeployed
// after this was serialized
if (container == null) {
_ejbLogger.log(Level.WARNING, "ejb.base.io.EJBOutputStream.null_container: "
+ containerId);
debugStr = "" + containerId;
} else {
debugStr = container.toString();
}
}
protected static java.rmi.Remote doRemoteRefClassLoaderConversion
(java.rmi.Remote reference) throws IOException {
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader =
currentThread.getContextClassLoader();
java.rmi.Remote returnReference = reference;
if( reference.getClass().getClassLoader() !=
contextClassLoader) {
try {
byte[] serializedRef = IOUtils.serializeObject
(reference, false);
returnReference = (java.rmi.Remote)
IOUtils.deserializeObject(serializedRef, false,
contextClassLoader);
StubAdapter.connect
(returnReference,
(com.sun.corba.ee.spi.orb.ORB) ORBManager.getORB());
} catch(IOException ioe) {
throw ioe;
} catch(Exception e) {
IOException ioEx = new IOException(e.getMessage());
ioEx.initCause(e);
throw ioEx;
}
}
return returnReference;
}
}
final class SerializableS1ASEJBHomeReference
extends AbstractSerializableS1ASEJBReference
{
SerializableS1ASEJBHomeReference(long containerId) {
super(containerId);
}
public Object createObject()
throws IOException
{
Object result = null;
BaseContainer container = (BaseContainer) Switch.getSwitch().
getContainerFactory().getContainer(containerId);
//container can be null if the app has been undeployed
// after this was serialized
if (container == null) {
_ejbLogger.log(Level.WARNING, "ejb.base.io.EJBOutputStream.null_container "
+ debugStr);
result = null;
} else {
// Note that we can assume it's a RemoteHome stub because an
// application never sees a reference to the internal
// Home for the Remote Business view.
result = AbstractSerializableS1ASEJBReference.
doRemoteRefClassLoaderConversion(container.getEJBHomeStub());
}
return result;
}
}
final class SerializableS1ASEJBObjectReference
extends AbstractSerializableS1ASEJBReference
{
private byte[] instanceKey;
private Object sfsbKey;
protected long sfsbClientVersion;
protected boolean haEnabled;
// If 3.0 Remote business view, the name of the remote business
// interface to which this stub corresponds.
private String remoteBusinessInterface;
SerializableS1ASEJBObjectReference(long containerId, byte[] objKey,
int keySize, String remoteBusinessInterfaceName) {
super(containerId);
BaseContainer container = (BaseContainer) Switch.getSwitch()
.getContainerFactory().getContainer(containerId);
if (container != null) {
this.haEnabled = container.isHAEnabled();
}
remoteBusinessInterface = remoteBusinessInterfaceName;
instanceKey = new byte[keySize];
System.arraycopy(objKey, EJBObjectOutputStream.INSTANCEKEY_OFFSET,
instanceKey, 0, keySize);
}
void setSFSBClientVersion(Object key, long val) {
this.sfsbKey = key;
this.sfsbClientVersion = val;
}
boolean isHAEnabled() {
return haEnabled;
}
public Object createObject()
throws IOException
{
Object result = null;
BaseContainer container = (BaseContainer) Switch.getSwitch().
getContainerFactory().getContainer(containerId);
//container can be null if the app has been undeployed
// after this was serialized
if (container == null) {
_ejbLogger.log(Level.WARNING,
"ejb.base.io.EJBOutputStream.null_container: "
+ debugStr);
result = null;
} else {
try {
if( remoteBusinessInterface == null ) {
java.rmi.Remote reference = container.
createRemoteReferenceWithId(instanceKey, null);
result = AbstractSerializableS1ASEJBReference.
doRemoteRefClassLoaderConversion(reference);
} else {
String generatedRemoteIntfName = EJBUtils.
getGeneratedRemoteIntfName(remoteBusinessInterface);
java.rmi.Remote remoteRef = container.
createRemoteReferenceWithId(instanceKey,
generatedRemoteIntfName);
java.rmi.Remote newRemoteRef =
AbstractSerializableS1ASEJBReference.
doRemoteRefClassLoaderConversion(remoteRef);
Thread currentThread = Thread.currentThread();
ClassLoader contextClassLoader =
currentThread.getContextClassLoader();
result = EJBUtils.createRemoteBusinessObject
(contextClassLoader, remoteBusinessInterface,
newRemoteRef);
}
if (haEnabled) {
SFSBClientVersionManager.setClientVersion(
containerId, sfsbKey, sfsbClientVersion);
}
} catch(Exception e) {
IOException ioex = new IOException("remote ref create error");
ioex.initCause(e);
throw ioex;
}
}
return result;
}
}
|