// Copyright 2013 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.cdi; import static org.apache.tapestry5.cdi.BeanHelper.getInstance; import static org.apache.tapestry5.cdi.BeanHelper.getQualifiers; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.tapestry5.cdi.internal.utils.InternalUtils; import org.apache.tapestry5.internal.services.ComponentClassCache; import org.apache.tapestry5.ioc.AnnotationProvider; import org.apache.tapestry5.ioc.ObjectLocator; import org.apache.tapestry5.ioc.annotations.PostInjection; import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration; import org.apache.tapestry5.ioc.services.RegistryShutdownHub; import org.apache.tapestry5.model.MutableComponentModel; import org.apache.tapestry5.plastic.PlasticField; import org.apache.tapestry5.services.transform.InjectionProvider2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An InjectionProvider implementation that handles CDI beans * Check first that the bean is not managed by tapestry-ioc * If so, it is ignored by CDI */ @UsesOrderedConfiguration(InjectionProvider2.class) public final class CDIInjectionProvider implements InjectionProvider2 { private final ComponentClassCache cache; private final ObjectLocator locator; @SuppressWarnings("rawtypes") private final Map<Class, Annotation[]> annotationsCache = new HashMap<Class, Annotation[]>(); private final Collection<BeanInstance> instancesToRelease = new ArrayList<BeanInstance>(); private static Logger logger = LoggerFactory.getLogger(CDIInjectionProvider.class); public CDIInjectionProvider(final ObjectLocator locator, final ComponentClassCache cache) { this.locator = locator; this.cache = cache; } /* (non-Javadoc) * @see org.apache.tapestry5.services.transform.InjectionProvider2#provideInjection(org.apache.tapestry5.plastic.PlasticField, org.apache.tapestry5.ioc.ObjectLocator, org.apache.tapestry5.model.MutableComponentModel) */ @SuppressWarnings("rawtypes") public boolean provideInjection(final PlasticField field, final ObjectLocator locator, final MutableComponentModel componentModel) { Class type = cache.forName(field.getTypeName()); if(InternalUtils.isManagedByTapestry( type, new AnnotationProvider(){ public <T extends Annotation> T getAnnotation( Class<T> annotationClass) { return field.getAnnotation(annotationClass); }}, locator)){ logger.debug("Field "+field.getName()+" of type "+field.getTypeName()+" is managed by Tapestry"); return false; } logger.debug("Field "+field.getName()+" of type "+field.getTypeName()+" will be managed by CDI"); final Class<?> fieldClass = load(field.getTypeName()); final Annotation[] qualifiers = InternalUtils.getFieldQualifiers(type, new AnnotationProvider(){ public <T extends Annotation> T getAnnotation( Class<T> annotationClass) { return field.getAnnotation(annotationClass); }}); logger.debug("["+field.getName()+"]["+componentModel.getComponentClassName()+"] Qualifiers : "); for (Annotation annotation : qualifiers) { logger.debug("==> "+annotation.toString()); } try { final BeanInstance instance = getInstance(fieldClass, qualifiers); final boolean resolved = instance != null && instance.isResolved(); if (resolved) { field.inject(instance.getBean()); } if (instance != null && instance.isReleasable()) { synchronized (instancesToRelease) { instancesToRelease.add(instance); } } logger.debug("Is field "+field.getName()+" of type "+field.getTypeName()+" has been succesfully managed by CDI ? "+resolved); return resolved; } catch (IllegalStateException isa) { logger.debug("CDI failed to manage the field "+field.getName()+" of type "+field.getTypeName()); return false; } } private Class<?> load(String typeName) { try { return cache.forName(typeName); } catch (RuntimeException re) { try { return Thread.currentThread().getContextClassLoader().loadClass(typeName); } catch (ClassNotFoundException e) { throw re; } } } @PostInjection public void startupService(final RegistryShutdownHub shutdownHub) { shutdownHub.addRegistryShutdownListener(new ShutdownCleanUpListener(instancesToRelease)); } private static class ShutdownCleanUpListener implements Runnable { private final Collection<BeanInstance> releasables; public ShutdownCleanUpListener(final Collection<BeanInstance> instancesToRelease) { releasables = instancesToRelease; } public void run() { synchronized (releasables) { // should be useless but just to be sure for (BeanInstance instance : releasables) { instance.release(); } releasables.clear(); } } } }