/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.ejb.session;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.FinderException;
import javax.ejb.NoSuchEJBException;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.Decorator;
import javax.enterprise.inject.spi.SessionBeanType;
import com.caucho.config.ConfigException;
import com.caucho.config.gen.BeanGenerator;
import com.caucho.config.gen.CandiEnhancedBean;
import com.caucho.config.gen.CandiUtil;
import com.caucho.config.inject.CreationalContextImpl;
import com.caucho.config.inject.InjectManager;
import com.caucho.config.inject.ManagedBeanImpl;
import com.caucho.config.inject.OwnerCreationalContext;
import com.caucho.config.j2ee.EJBExceptionWrapper;
import com.caucho.ejb.cfg.EjbLazyGenerator;
import com.caucho.ejb.gen.SingletonGenerator;
import com.caucho.ejb.inject.SessionBeanImpl;
import com.caucho.ejb.manager.EjbManager;
import com.caucho.ejb.server.AbstractContext;
import com.caucho.ejb.server.EjbInjectionTarget;
import com.caucho.ejb.server.SingletonInjectionTarget;
import com.caucho.util.L10N;
/**
* Server container for a session bean.
*/
public class SingletonManager<X> extends AbstractSessionManager<X> {
private static final L10N L = new L10N(SingletonManager.class);
private static final Logger log =
Logger.getLogger(SingletonManager.class.getName());
private AtomicReference<X> _instanceRef = new AtomicReference<X>();
private Object _decoratorClass;
private List<Decorator<?>> _decoratorBeans;
private Object []_delegates;
private Object []_interceptors;
public SingletonManager(EjbManager ejbContainer,
String ejbName,
String moduleName,
AnnotatedType<X> rawAnnType,
AnnotatedType<X> annotatedType,
EjbLazyGenerator<X> lazyGenerator)
{
super(ejbContainer, ejbName, moduleName,
rawAnnType, annotatedType, lazyGenerator);
}
@Override
protected String getType()
{
return "singleton:";
}
@Override
protected SessionBeanType getSessionBeanType()
{
return SessionBeanType.SINGLETON;
}
@Override
protected <T> SingletonContext<X,T> getSessionContext(Class<T> api)
{
return (SingletonContext<X,T>) super.getSessionContext(api);
}
@Override
protected EjbInjectionTarget<X> createInjectionTarget()
{
return new SingletonInjectionTarget<X>(this, getAnnotatedType());
}
/**
* Returns the JNDI proxy object to create instances of the local interface.
*/
@Override
public <T> Object getLocalJndiProxy(Class<T> api)
{
// SingletonContext<X,T> context = getSessionContext(api);
/*
* if (factory != null) return new SingletonFactoryJndiProxy(factory); else
* return null;
*/
throw new UnsupportedOperationException();
}
@Override
public void bind()
{
super.bind();
Class<?> instanceClass = getProxyImplClass();
if (instanceClass != null
&& CandiEnhancedBean.class.isAssignableFrom(instanceClass)) {
try {
Method method = instanceClass.getMethod("__caucho_decorator_init");
_decoratorClass = method.invoke(null);
Annotation []qualifiers = new Annotation[getBean().getQualifiers().size()];
getBean().getQualifiers().toArray(qualifiers);
InjectManager moduleBeanManager = InjectManager.create();
_decoratorBeans = moduleBeanManager.resolveDecorators(getBean().getTypes(), qualifiers);
method = instanceClass.getMethod("__caucho_init_decorators",
List.class);
method.invoke(null, _decoratorBeans);
} catch (InvocationTargetException e) {
throw ConfigException.create(e.getCause());
} catch (Exception e) {
log.log(Level.FINEST, e.toString(), e);
}
}
}
@Override
public X newInstance(CreationalContextImpl<X> env)
{
X instance = _instanceRef.get();
if (instance == null) {
instance = super.newInstance(env);
if (instance == null)
throw new NullPointerException(toString());
_instanceRef.compareAndSet(null, instance);
instance = _instanceRef.get();
}
return instance;
}
@Override
protected void postStart()
{
super.postStart();
CreationalContextImpl<X> env = new OwnerCreationalContext<X>(getBean());
getBean().create(env);
//newInstance(env);
}
public <T> T initProxy(T proxy, CreationalContextImpl<T> env)
{
if (proxy instanceof CandiEnhancedBean) {
CandiEnhancedBean bean = (CandiEnhancedBean) proxy;
try {
if (_delegates == null)
_delegates = createDelegates(env);
_interceptors = bean.__caucho_inject(_delegates, _interceptors, env);
/*
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
}
try {
*/
bean.__caucho_postConstruct();
} catch (RuntimeException e) {
throw e;
} catch (InvocationTargetException e) {
throw new EJBExceptionWrapper(e.getCause());
} catch (Exception e) {
throw new EJBExceptionWrapper(e);
}
}
return proxy;
}
private Object []createDelegates(CreationalContextImpl<?> env)
{
if (_decoratorBeans != null) {
// if (env != null)
// env.setInjectionPoint(oldPoint);
return CandiUtil.generateProxyDelegate(getInjectManager(),
_decoratorBeans,
_decoratorClass,
env);
}
else
return null;
}
@Override
public void destroy(Object instance, CreationalContextImpl<?> env)
{
}
/**
* Destroy an instance
*/
public void destroyInstance(X instance)
{
}
@Override
protected <T> Bean<T> createBean(ManagedBeanImpl<X> mBean,
Class<T> api,
Set<Type> apiList,
AnnotatedType<X> extAnnType)
{
SingletonContext<X,T> context = getSessionContext(api);
if (context == null)
throw new NullPointerException(L.l("'{0}' is an unknown api for {1}",
api, this));
SessionBeanImpl<X,T> statefulBean
= new SessionBeanImpl<X,T>(context, mBean, apiList, extAnnType);
InjectManager manager = getModuleInjectManager();
if (manager.isNormalScope(statefulBean.getScope())
&& ApplicationScoped.class != statefulBean.getScope()) {
throw new ConfigException(L.l("{0} is an invalid @Singleton EJB because it has @{1} scope.",
api.getName(),
statefulBean.getScope()));
}
return statefulBean;
}
@Override
protected <T> SingletonContext<X,T> createSessionContext(Class<T> api)
{
return new SingletonContext<X,T>(this, api);
}
protected Class<?> getContextClass()
{
return SingletonContext.class;
}
/**
* Creates the bean generator for the session bean.
*/
@Override
protected BeanGenerator<X> createBeanGenerator()
{
EjbLazyGenerator<X> lazyGen = getLazyGenerator();
return new SingletonGenerator<X>(getEJBName(), getAnnotatedType(),
lazyGen.getLocalApi(),
lazyGen.getLocalBean(),
lazyGen.getRemoteApi());
}
/**
* Finds the remote bean by its key.
*
* @param key
* the remote key
*
* @return the remote interface of the entity.
*/
@Override
public AbstractContext getContext(Object key, boolean forceLoad)
throws FinderException
{
throw new NoSuchEJBException("no matching object:" + key);
/*
* if (key == null) return null;
*
* StatefulContext cxt = _sessions.get(key);
*
* // ejb/0fe4 if (cxt == null) throw new
* NoSuchEJBException("no matching object:" + key); // XXX ejb/0fe-: needs
* refactoring of 2.1/3.0 interfaces. // throw new
* FinderException("no matching object:" + key);
*
* return cxt;
*/
}
/**
* Cleans up the entity server nicely.
*/
@Override
public void destroy()
{
super.destroy();
log.fine(this + " closed");
}
@Override
public <T> T getRemoteObject(Class<T> api, String protocol)
{
// TODO Auto-generated method stub
return null;
}
}