/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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.
*/
/*
* SunContainerHelper.java
*
* Created on March 12, 2003.
*/
package com.sun.jdo.spi.persistence.support.sqlstore.ejb;
import java.util.Iterator;
import java.util.ResourceBundle;
import javax.ejb.EJBObject;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBContext;
import javax.ejb.EJBException;
import javax.ejb.EntityContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.sun.enterprise.deployment.*;
import com.sun.appserv.connectors.internal.api.ConnectorsUtil; //TODO Dependency on connector-internal-api needs to be removed
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.data.ApplicationInfo;
import com.sun.ejb.Container;
import com.sun.ejb.containers.EjbContainerUtil;
import org.glassfish.persistence.ejb.entitybean.container.spi.CascadeDeleteNotifier;
import com.sun.jdo.api.persistence.support.JDOException;
import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.api.persistence.support.JDOFatalUserException;
import com.sun.jdo.api.persistence.support.PersistenceManager;
import com.sun.jdo.api.persistence.support.PersistenceManagerFactory;
import com.sun.jdo.spi.persistence.support.sqlstore.impl.PersistenceManagerFactoryImpl;
import com.sun.jdo.spi.persistence.support.sqlstore.LogHelperPersistenceManager;
import com.sun.jdo.spi.persistence.support.sqlstore.utility.NumericConverter;
import com.sun.jdo.spi.persistence.utility.logging.Logger;
import org.glassfish.persistence.common.I18NHelper;
import org.glassfish.internal.api.Globals;
/** Implementation for Sun specific CMP and Container interactions as defined
* by the ContainerHelper interface.
*
* IMPORTANT: This class extends SunTransactionHelper class. Any changes to the
* TransactionHelper implementation must be done in the SunTransactionHelper.
*
*/
public class SunContainerHelper extends SunTransactionHelper implements ContainerHelper
{
/** I18N message handler */
private final static ResourceBundle messages = I18NHelper.loadBundle(
"com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
SunContainerHelper.class.getClassLoader());
/** The logger */
private static Logger logger = LogHelperPersistenceManager.getLogger();
/** Garantees singleton.
* Registers itself during initial load
*/
static {
CMPHelper.registerContainerHelper (new SunContainerHelper());
}
/** Default constructor should not be public */
SunContainerHelper() { }
/** Get a Container helper instance that will be passed unchanged to the
* required methods.
* This is SunContainerHelper specific code.
*
* The info argument is an Object array that consistes of a class to use
* for the class loader and concreteImpl bean class name.
* @see getEJBObject(Object, Object)
* @see getEJBLocalObject(Object, Object)
* @see getEJBLocalObject(Object, Object, EJBObject)
* @see removeByEJBLocalObject(EJBLocalObject, Object)
* @see removeByPK(Object, Object)
* @param info Object with the request information that is application server
* specific.
* @return a Container helper instance as an Object.
*/
public Object getContainer(Object info) {
Object[] params = (Object[])info;
String appName = (String)params[0];
ServiceLocator habitat = Globals.getDefaultHabitat();
ApplicationRegistry reg = habitat.getService(ApplicationRegistry.class);
ApplicationInfo appInfo = reg.get(appName);
Application app = appInfo.getMetaData(Application.class);
EjbDescriptor desc = app.getEjbByName((String)params[1]);
return habitat.<EjbContainerUtil>getService(EjbContainerUtil.class).getContainer(desc.getUniqueId());
}
/** Get an EJBObject reference for this primary key and Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param pk the primary key instance.
* @param container a Container instance for the request.
* @return a corresponding EJBObject instance to be used by the client.
*/
public EJBObject getEJBObject(Object pk, Object container) {
try {
return ((Container)container).getEJBObjectForPrimaryKey(pk);
} catch (Exception ex) {
throw new JDOFatalInternalException(ex.getMessage(), ex);
}
}
/** Get an EJBLocalObject reference for this primary key and Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param pk the primary key instance.
* @param container a helper instance for the request.
* @return a corresponding EJBLocalObject instance to be used by the client.
*/
public EJBLocalObject getEJBLocalObject(Object pk, Object container) {
try {
return ((Container)container).getEJBLocalObjectForPrimaryKey(pk);
} catch (Exception ex) {
throw new JDOFatalInternalException(ex.getMessage(), ex);
}
}
/** Get an EJBLocalObject reference for this primary key and Container helper,
* and EJBContext of the calling bean.
* Allows the container to check if this method is called during ejbRemove
* that is part of a cascade-delete remove.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param pk the primary key instance.
* @param container a helper instance for the request.
* @param context an EJBContext of the calling bean.
* @return a corresponding EJBLocalObject instance to be used by the client.
*/
public EJBLocalObject getEJBLocalObject(Object pk, Object container, EJBContext context) {
EJBLocalObject rc = null;
try {
rc = ((Container)container).getEJBLocalObjectForPrimaryKey(pk, context);
} catch (Exception ex) {
processContainerException(ex);
}
return rc;
}
/** Remove a bean for a given EJBLocalObject and Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param ejb the EJBLocalObject for the bean to be removed.
* @param container a Container instance for the request.
*/
public void removeByEJBLocalObject(EJBLocalObject ejb, Object container) {
try {
((Container)container).removeBeanUnchecked(ejb);
} catch (Exception ex) {
processContainerException(ex);
}
}
/** Remove a bean for a given primary key and Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param pk the primary key for the bean to be removed.
* @param container a Container instance for the request.
*/
public void removeByPK(Object pk, Object container) {
try {
((Container)container).removeBeanUnchecked(pk);
} catch (Exception ex) {
processContainerException(ex);
}
}
/** Verify that this instance is of a valid local interface type for
* a given Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param o the instance to be verified.
* @param container a Container instance for the request.
*/
public void assertValidLocalObject(Object o, Object container) {
((Container)container).assertValidLocalObject(o);
}
/** Verify that this instance is of a valid remote interface type for
* a given Container helper.
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param o the instance to be verified.
* @param container a Container instance for the request.
*/
public void assertValidRemoteObject(Object o, Object container) {
((Container)container).assertValidRemoteObject(o);
}
/** Mark the bean as already removed during cascade-delete
* operation for a given EntityContext.
* Called by the generated ejbRemove method before calling ejbRemove of the
* related beans (via removeByEJBLocalObject) that are to be cascade-deleted.
*
* This is SunContainerHelper specific code.
*
* @param context the EntityContext of the bean beeing removed.
*/
public void setCascadeDeleteAfterSuperEJBRemove(EntityContext context) {
try {
((CascadeDeleteNotifier)context).setCascadeDeleteAfterSuperEJBRemove(true);
} catch (Exception ex) {
processContainerException(ex);
}
}
/** Called in a CMP supported environment. Notifies the container that
* ejbSelect had been called.
*
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param container a Container instance for the request.
*/
public void preSelect(Object container) {
((Container)container).preSelect();
}
/** Called in a CMP environment to lookup PersistenceManagerFactory
* referenced by this Container instance as the CMP resource.
*
* This is SunContainerHelper specific code.
*
* @see getContainer(Object)
* @param container a Container instance for the request.
*/
public PersistenceManagerFactory getPersistenceManagerFactory(Object container) {
Object rc = null;
PersistenceManagerFactoryImpl pmf = null;
ResourceReferenceDescriptor cmpResource = ((Container)container).getEjbDescriptor().
getEjbBundleDescriptor().getCMPResourceReference();
String name = cmpResource.getJndiName();
try {
InitialContext ic = new InitialContext();
rc = ic.lookup(name);
if (rc instanceof PersistenceManagerFactoryImpl) {
pmf = (PersistenceManagerFactoryImpl)rc;
} else if (rc instanceof javax.sql.DataSource) {
pmf = new PersistenceManagerFactoryImpl();
pmf.setConnectionFactoryName(ConnectorsUtil.getPMJndiName(name));
Iterator it = cmpResource.getProperties();
if (it != null) {
while (it.hasNext()) {
NameValuePairDescriptor prop = (NameValuePairDescriptor)it.next();
String n = prop.getName();
// Any value that is not "true" is treated as "false":
boolean value = Boolean.valueOf(prop.getValue()).booleanValue();
pmf.setBooleanProperty(n, value);
}
}
} else {
RuntimeException e = new JDOFatalUserException(I18NHelper.getMessage(
messages, "ejb.jndi.unexpectedinstance", //NOI18N
name, rc.getClass().getName()));
logger.severe(e.toString());
throw e;
}
} catch (javax.naming.NamingException ex) {
RuntimeException e = new JDOFatalUserException(I18NHelper.getMessage(
messages, "ejb.jndi.lookupfailed", name), ex); //NOI18N
logger.severe(e.toString());
throw e;
}
return pmf;
}
/**
* Called in CMP environment to get NumericConverter policy referenced
* by this Container instance.
* @see getContainer(Object)
* @param container a Container instance for the request
* @return a valid NumericConverter policy type
*/
public int getNumericConverterPolicy(Object container) {
return NumericConverter.DEFAULT_POLICY;
}
/** Called in a unspecified transaction context of a managed environment.
* According to p.364 of EJB 2.0 spec, CMP may need to manage
* its own transaction when its transaction attribute is
* NotSupported, Never, Supports.
* This is a generic implementation.
* Application server may like to overwrite this if necessary.
*
* @param pm PersistenceManager
*/
public void beginInternalTransaction(PersistenceManager pm) {
pm.currentTransaction().begin();
}
/** Called in a unspecified transaction context of a managed environment.
* According to p.364 of EJB 2.0 spec, CMP may need to manage
* its own transaction when its transaction attribute is
* NotSupported, Never, Supports.
* This is a generic implementation.
* Application server may like to overwrite this if necessary.
*
* @param pm PersistenceManager
*/
public void commitInternalTransaction(PersistenceManager pm) {
pm.currentTransaction().commit();
}
/** Called in a unspecified transaction context of a managed environment.
* According to p.364 of EJB 2.0 spec, CMP may need to manage
* its own transaction when its transaction attribute is
* NotSupported, Never, Supports.
* This is a generic implementation.
* Application server may like to overwrite this if necessary.
*
* @param pm PersistenceManager
*/
public void rollbackInternalTransaction(PersistenceManager pm) {
pm.currentTransaction().rollback();
}
/** Called from read-only beans to suspend current transaction.
* This will guarantee that PersistenceManager is not bound to
* any transaction.
*
* @return javax.transaction.Transaction object representing
* the suspended transaction.
* Returns null if the calling thread is not associated
* with a transaction.
*/
public javax.transaction.Transaction suspendCurrentTransaction() {
javax.transaction.Transaction tx = null;
try {
tx = getLocalTransactionManager().suspend();
} catch (Exception ex) {
processContainerException(ex);
}
return tx;
}
/** Called from read-only beans to resume current transaction.
* This will guarantee that the transaction continues to run after
* read-only bean accessed its PersistenceManager.
*
* @param tx - The javax.transaction.Transaction object that
* represents the transaction to be resumed. If this object had been
* returned by #suspendCurrentTransaction() call it will be null in
* case calling thread was not associated with a transaction.
*/
public void resumeCurrentTransaction(javax.transaction.Transaction tx) {
try {
// Resume only real (i.e. not null transaction)
if (tx != null) {
getLocalTransactionManager().resume(tx);
}
} catch (Exception ex) {
processContainerException(ex);
}
}
/**
* Checks the caught Exception, and rethrows it if it is
* of one of known types, or converts to an EJBException
* otherwise.
*
* @param ex the Exception to process.
* @throws RuntimeException of the appropriate type.
*/
private void processContainerException(Exception ex) {
if (ex instanceof EJBException) {
throw (EJBException)ex;
} else if (ex instanceof IllegalArgumentException
|| ex instanceof IllegalStateException) {
throw (RuntimeException)ex;
} else if (ex instanceof JDOException) {
throw (JDOException)ex;
} else {
throw new EJBException(ex);
}
}
}