/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 javax.enterprise.inject.spi; import javax.enterprise.context.spi.CreationalContext; /** * Helper class for manually maintaining CDI created instances * which are not managed by the CDI container. * * Be aware that instances created that way are <i>not</i> * managed by the CDI container and thus need to be * cleaned up manually to not create memory leaks!. * * Normal code shall use {@link javax.enterprise.inject.Instance<T>} if possible. * * The reason for using UnmanagedInstance is for * @Dependent scoped instances which should not pollute the * {@link javax.enterprise.context.spi.CreationalContext} of the containing instance. * * Note that the methods of UnmanagedInstance needs to be called * in a well defined order. * * Please note that this classes are not thread safe! * * @param <T> the type of the CDI instance to create * @since 1.1 */ public class Unmanaged<T> { private BeanManager beanManager; private InjectionTarget<T> injectionTarget; public Unmanaged(Class<T> clazz) { this(CDI.current().getBeanManager(), clazz); } public Unmanaged(BeanManager beanManager, java.lang.Class<T> clazz) { this.beanManager = beanManager; AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(clazz); injectionTarget = beanManager.createInjectionTarget(annotatedType); } public UnmanagedInstance<T> newInstance() { return new UnmanagedInstance<T>(beanManager, injectionTarget); } /** * This basically delegates to the {@link javax.enterprise.inject.spi.InjectionTarget} * interface * @param <T> the type of the CDI instance to create */ public static class UnmanagedInstance<T> { private BeanManager beanManager; private InjectionTarget<T> injectionTarget; private CreationalContext<T> creationalContext; private T instance; private boolean injected = false; private boolean disposed = false; private UnmanagedInstance(BeanManager beanManager, InjectionTarget<T> injectionTarget) { this.injectionTarget = injectionTarget; this.beanManager = beanManager; } /** * Create the CDI instance itself. This internally just calls * {@link javax.enterprise.inject.spi.InjectionTarget#produce(javax.enterprise.context.spi.CreationalContext)} * and performs a few checks upfront. * * @throws java.lang.IllegalStateException if the instance already got created * @throws java.lang.IllegalStateException if the instance already got disposed */ public UnmanagedInstance<T> produce() { if (creationalContext != null) { throw new IllegalStateException("UnmanagedInstance is already produced"); } if (disposed) { throw new IllegalStateException("UnmanagedInstance is already disposed"); } creationalContext = beanManager.createCreationalContext(null); instance = injectionTarget.produce(creationalContext); return this; } /** * Fill @inject field, constructor and methods. * * @throws java.lang.IllegalStateException if the instance was not yet created * @throws java.lang.IllegalStateException if the instance already got injected * @throws java.lang.IllegalStateException if the instance already got disposed * @see javax.enterprise.inject.spi.InjectionTarget#inject(Object, javax.enterprise.context.spi.CreationalContext) */ public UnmanagedInstance<T> inject() { basicCheck(); if (injected) { throw new IllegalStateException("UnmanagedInstance is already injected"); } injectionTarget.inject(instance, creationalContext); injected = true; return this; } /** * Invoke any @PostConstruct methods. * @see javax.enterprise.inject.spi.InjectionTarget#postConstruct(Object) */ public UnmanagedInstance<T> postConstruct() { basicCheck(); injectionTarget.postConstruct(instance); return this; } /** * This method should only get called after the * CDI instance got properly produced and initialized * via * {@link #produce()} * {@link #inject()} * {@link #postConstruct()} * * @return the filled cdi instance */ public T get() { basicCheck(); return instance; } /** * Invoke any @PreDestroy annotated methods * and interceptors of the given CDI instance. */ public UnmanagedInstance<T> preDestroy() { basicCheck(); injectionTarget.preDestroy(instance); return this; } /** * Dispose the CDI instance. One should call {@link #preDestroy()} before * this method. * @see javax.enterprise.inject.spi.InjectionTarget#dispose(Object) */ public UnmanagedInstance<T> dispose() { basicCheck(); injectionTarget.dispose(instance); creationalContext.release(); return this; } /** * Check whether the UnmanagedInstance is already initialized and not yet disposed. */ private void basicCheck() { if (creationalContext == null) { throw new IllegalStateException("UnmanagedInstance is not yet initialized. Invoke #produce() first!"); } if (disposed) { throw new IllegalStateException("UnmanagedInstance is already disposed"); } } } }