/*
* 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.config.inject;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.ejb.Timer;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.NormalScope;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import com.caucho.config.ConfigException;
import com.caucho.config.Configured;
import com.caucho.config.bytecode.ScopeAdapter;
import com.caucho.config.event.EventManager;
import com.caucho.config.event.ObserverMethodImpl;
import com.caucho.config.timer.ScheduleIntrospector;
import com.caucho.config.timer.TimeoutCaller;
import com.caucho.config.timer.TimerTask;
import com.caucho.inject.Module;
import com.caucho.util.L10N;
/**
* SimpleBean represents a POJO Java bean registered as a WebBean.
*/
@Module
public class ManagedBeanImpl<X> extends AbstractIntrospectedBean<X>
implements ScopeAdapterBean<X>, ScheduleBean
{
private static final L10N L = new L10N(ManagedBeanImpl.class);
private AnnotatedType<X> _annotatedType;
private InjectionTarget<X> _injectionTarget;
private HashSet<ObserverMethodImpl<X,?>> _observerMethods
= new LinkedHashSet<ObserverMethodImpl<X,?>>();
private boolean _isNormalScope;
private Object _scopeAdapter;
public ManagedBeanImpl(InjectManager injectManager,
AnnotatedType<X> beanType,
boolean isSessionBean)
{
super(injectManager, beanType.getBaseType(), beanType);
_annotatedType = beanType;
/*
if (beanType.getType() instanceof Class)
validateType((Class) beanType.getType());
*/
InjectionTargetBuilder<X> target;
target = new InjectionTargetBuilder<X>(injectManager, beanType, this);
if (isSessionBean)
target.setGenerateInterception(false);
_injectionTarget = target;
}
public ManagedBeanImpl(InjectManager webBeans,
AnnotatedType<X> beanType,
InjectionTarget<X> injectionTarget)
{
this(webBeans, beanType, false);
_injectionTarget = injectionTarget;
}
@Override
public AnnotatedType<X> getAnnotatedType()
{
return _annotatedType;
}
@Override
public InjectionTarget<X> getInjectionTarget()
{
return _injectionTarget;
}
public void setInjectionTarget(InjectionTarget<X> target)
{
_injectionTarget = target;
}
@Override
protected boolean isNormalScope()
{
return _isNormalScope;
}
/**
* Creates a new instance of the component.
*/
@Override
public X create(CreationalContext<X> context)
{
X instance = _injectionTarget.produce(context);
if (context != null)
context.push(instance);
_injectionTarget.inject(instance, context);
_injectionTarget.postConstruct(instance);
/*
if (context instanceof CreationalContextImpl<?>) {
CreationalContextImpl<X> env = (CreationalContextImpl<X>) context;
// ioc/0555
if (env.isTop()) {
env.postConstruct();
_injectionTarget.postConstruct(instance);
}
}
else
_injectionTarget.postConstruct(instance);
*/
return instance;
}
/**
* Creates a new instance of the component.
*/
public X createDependent(CreationalContext<X> env)
{
X instance = _injectionTarget.produce(env);
if (env != null) {
env.push(instance);
// env.setInjectionTarget(_injectionTarget);
}
_injectionTarget.inject(instance, env);
_injectionTarget.postConstruct(instance);
// ioc/0555
/*
if (env == null)
_injectionTarget.postConstruct(instance);
*/
return instance;
}
@Override
public X getScopeAdapter(Bean<?> topBean, CreationalContextImpl<X> cxt)
{
// ioc/0520
if (isNormalScope()) {
Object value = _scopeAdapter;
if (value == null) {
ScopeAdapter scopeAdapter = ScopeAdapter.create(getJavaClass());
_scopeAdapter = scopeAdapter.wrap(getBeanManager().createNormalInstanceFactory(topBean));
value = _scopeAdapter;
}
return (X) value;
}
return null;
}
protected boolean isProxiedScope()
{
NormalScope scopeType = getScope().getAnnotation(NormalScope.class);
if (scopeType != null
&& ! getScope().equals(ApplicationScoped.class)) {
return true;
}
else
return false;
}
public Object getScopeAdapter()
{
Object value = _scopeAdapter;
if (value == null) {
ScopeAdapter scopeAdapter = ScopeAdapter.create(getTargetClass());
_scopeAdapter = scopeAdapter.wrap(getBeanManager().createNormalInstanceFactory(this));
value = _scopeAdapter;
}
return value;
}
/**
* Returns the set of injection points, for validation.
*/
@Override
public Set<InjectionPoint> getInjectionPoints()
{
return _injectionTarget.getInjectionPoints();
}
public boolean validate()
{
if (_injectionTarget instanceof InjectionTargetBuilder) {
((InjectionTargetBuilder) _injectionTarget).validate();
return true;
}
else {
return false;
}
}
/*
public Set<Bean<?>> getProducerBeans()
{
return _producerBeans;
}
*/
/**
* Returns the observer methods
*/
public Set<ObserverMethodImpl<X,?>> getObserverMethods()
{
return _observerMethods;
}
/**
* Call post-construct
*/
public void dispose(X instance)
{
}
/**
* Call pre-destroy
*/
@Override
public void destroy(X instance, CreationalContext<X> cxt)
{
_injectionTarget.preDestroy(instance);
if (cxt!= null) {
if (cxt instanceof CreationalContextImpl<?>) {
CreationalContextImpl<?> env = (CreationalContextImpl<?>) cxt;
env.clearTarget();
}
cxt.release();
}
}
//
// introspection
//
@Override
public void introspect()
{
super.introspect();
introspect(_annotatedType);
// ioc/0e13
if (_injectionTarget instanceof PassivationSetter && getId() != null)
((PassivationSetter) _injectionTarget).setPassivationId(getId());
validateBean();
validatePassivation();
_isNormalScope = getScope().isAnnotationPresent(NormalScope.class);
}
private void validateBean()
{
Class<X> javaClass = _annotatedType.getJavaClass();
Class<? extends Annotation> scopeType = getScope();
if (javaClass.getTypeParameters().length != 0) {
if (_annotatedType.isAnnotationPresent(Configured.class)) {
// ioc/2601
}
else if (javax.inject.Singleton.class.equals(scopeType)) {
// ioc/024q - used for ClusterQueue
}
else if (! Dependent.class.equals(scopeType)) {
throw new ConfigException(L.l("'{0}' is an invalid bean because it has a generic type and a non-dependent scope.",
javaClass.getName()));
}
}
}
private void validatePassivation()
{
Class<? extends Annotation> scopeType = getScope();
if (scopeType == null)
return;
if (! getBeanManager().isNormalScope(scopeType))
return;
// boolean isPassivation = getBeanManager().isPassivatingScope(scopeType);
Class<?> cl = _annotatedType.getJavaClass();
if (Modifier.isFinal(cl.getModifiers()))
throw new ConfigException(L.l("'{0}' is an invalid @{1} bean because it is final.",
cl.getName(), scopeType.getName()));
}
/**
* Called for implicit introspection.
*/
protected void introspect(AnnotatedType<X> beanType)
{
// super.introspect(beanType);
// introspectProduces(beanType);
// introspectObservers(beanType);
}
public void introspectProduces()
{
ProducesBuilder builder = new ManagedProducesBuilder(getBeanManager());
builder.introspectProduces(this, getAnnotatedType());
}
/**
* Introspects the methods for any @Observes
*/
void introspectObservers()
{
EventManager eventManager = getBeanManager().getEventManager();
AnnotatedType<X> annType = getAnnotatedType();
// ioc/0b25
/*
if (! getBeanManager().isIntrospectObservers(annType))
return;
*/
for (AnnotatedMethod<? super X> beanMethod : annType.getMethods()) {
int param = EventManager.findObserverAnnotation(beanMethod);
if (param < 0)
continue;
// ioc/0b25
/*
Class<?> declClass = beanMethod.getJavaMember().getDeclaringClass();
if (declClass != annType.getJavaClass()
&& declClass.isAssignableFrom(annType.getJavaClass())
&& ! annType.isAnnotationPresent(Specializes.class)) {
continue;
}
*/
eventManager.addObserver(this, beanMethod);
}
}
/**
*
*/
@Override
public void scheduleTimers(Object value)
{
ScheduleIntrospector introspector = new ScheduleIntrospector();
TimeoutCaller timeoutCaller = new BeanTimeoutCaller(value);
ArrayList<TimerTask> taskList
= introspector.introspect(timeoutCaller, _annotatedType);
if (taskList != null) {
for (TimerTask task : taskList) {
task.start();
}
}
}
static class BeanTimeoutCaller implements TimeoutCaller
{
private Object _bean;
BeanTimeoutCaller(Object bean)
{
_bean = bean;
}
@Override
public void timeout(Method method)
throws InvocationTargetException,
IllegalAccessException
{
method.invoke(_bean);
}
@Override
public void timeout(Method method, Timer timer)
throws InvocationTargetException, IllegalAccessException
{
}
}
}