All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.jersey.ext.cdi1x.internal.AbstractCdiBeanSupplier Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.ext.cdi1x.internal;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.logging.Logger;

import jakarta.enterprise.context.spi.Contextual;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.InjectionPoint;
import jakarta.enterprise.inject.spi.InjectionTarget;
import jakarta.enterprise.inject.spi.InjectionTargetFactory;

import org.glassfish.jersey.internal.inject.DisposableSupplier;
import org.glassfish.jersey.internal.inject.InjectionManager;

/**
 * Abstract supplier to provide CDI components obtained from CDI bean manager.
 * The factory handles CDI managed components as well as non-contextual managed beans.
 * To specify scope of provided CDI beans, an extension of this supplier
 * should implement properly annotated {@link java.util.function.Supplier#get()} method that
 * could just delegate to the existing {@link #_provide()} method.
 *
 * @author Jakub Podlesak
 */
public abstract class AbstractCdiBeanSupplier implements DisposableSupplier {

    private static final Logger LOGGER = Logger.getLogger(AbstractCdiBeanSupplier.class.getName());

    final Class clazz;
    final InstanceManager referenceProvider;
    final Annotation[] qualifiers;
    /**
     * Create new factory instance for given type and bean manager.
     *
     * @param rawType          type of the components to provide.
     * @param injectionManager actual injection manager instance.
     * @param beanManager      current bean manager to get references from.
     * @param cdiManaged       set to {@code true} if the component should be managed by CDI.
     */
    public AbstractCdiBeanSupplier(final Class rawType,
                                     final InjectionManager injectionManager,
                                     final BeanManager beanManager,
                                     final boolean cdiManaged) {

        this.clazz = rawType;
        this.qualifiers = CdiUtil.getQualifiers(clazz.getAnnotations());
        this.referenceProvider = cdiManaged ? new InstanceManager() {

            final Iterator> beans = beanManager.getBeans(clazz, qualifiers).iterator();
            final Bean bean = beans.hasNext() ? beans.next() : null;

            @Override
            public T getInstance(final Class clazz) {
                return (bean != null) ? CdiUtil.getBeanReference(clazz, bean, beanManager) : null;
            }

            @Override
            public void preDestroy(final T instance) {
                // do nothing
            }
        } : new InstanceManager() {

            final AnnotatedType annotatedType = beanManager.createAnnotatedType(clazz);
            final InjectionTargetFactory injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
            final InjectionTarget injectionTarget = injectionTargetFactory.createInjectionTarget(null);

            @Override
            public T getInstance(final Class clazz) {
                final CreationalContext creationalContext = beanManager.createCreationalContext(null);
                final T instance = produce(injectionTarget, creationalContext, injectionManager, clazz);
                final CdiComponentProvider cdiComponentProvider = beanManager.getExtension(CdiComponentProvider.class);
                final CdiComponentProvider.InjectionManagerInjectedCdiTarget hk2managedTarget =
                     cdiComponentProvider.new InjectionManagerInjectedCdiTarget(injectionTarget) {
                        @Override
                        public Set getInjectionPoints() {
                            return injectionTarget.getInjectionPoints();
                        }
                    };
                hk2managedTarget.setInjectionManager(injectionManager);
                hk2managedTarget.inject(instance, creationalContext);
                hk2managedTarget.postConstruct(instance);
                return instance;
            }

            @Override
            public void preDestroy(final T instance) {
                injectionTarget.preDestroy(instance);
            }
        };
    }

    /*
     * Let CDI produce the InjectionTarget. If the constructor contains @Context Args CDI won't be able to produce it.
     * Let the HK2 try to produce the target then.
     */
    private static  T produce(InjectionTarget target, CreationalContext ctx, InjectionManager im, Class clazz) {
        try {
            return target.produce(ctx);
        } catch (Exception e) {
            LOGGER.fine(LocalizationMessages.CDI_FAILED_LOADING(clazz, e.getMessage()));
            try {
                return im.create(clazz);
            } catch (RuntimeException re) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                e.printStackTrace(pw);
                LOGGER.warning(LocalizationMessages.CDI_FAILED_LOADING(clazz, sw.toString()));
                throw re;
            }
        }
    }

    @SuppressWarnings(value = "unchecked")
    /* package */ T _provide() {
        final T instance = referenceProvider.getInstance(clazz);
        if (instance != null) {
            return instance;
        }
        throw new NoSuchElementException(LocalizationMessages.CDI_LOOKUP_FAILED(clazz));
    }

    @Override
    public void dispose(final T instance) {
        referenceProvider.preDestroy(instance);
    }

    private interface InstanceManager {

        /**
         * Get me correctly instantiated and injected instance.
         *
         * @param clazz type of the component to instantiate.
         * @return injected component instance.
         */
        T getInstance(Class clazz);

        /**
         * Do whatever needs to be done before given instance is destroyed.
         *
         * @param instance to be destroyed.
         */
        void preDestroy(T instance);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy