Package org.apache.geronimo.openwebbeans.deployment

Source Code of org.apache.geronimo.openwebbeans.deployment.OpenWebBeansModuleBuilderExtension

/**
* 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 org.apache.geronimo.openwebbeans.deployment;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.enterprise.inject.Produces;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;

import org.apache.geronimo.common.DeploymentException;
import org.apache.geronimo.deployment.ModuleIDBuilder;
import org.apache.geronimo.deployment.service.EnvironmentBuilder;
import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.GBeanData;
import org.apache.geronimo.gbean.annotation.GBean;
import org.apache.geronimo.gbean.annotation.ParamAttribute;
import org.apache.geronimo.gbean.annotation.ParamReference;
import org.apache.geronimo.j2ee.annotation.Holder;
import org.apache.geronimo.j2ee.deployment.EARContext;
import org.apache.geronimo.j2ee.deployment.Module;
import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
import org.apache.geronimo.j2ee.deployment.NamingBuilder;
import org.apache.geronimo.j2ee.deployment.WebModule;
import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
import org.apache.geronimo.kernel.Naming;
import org.apache.geronimo.kernel.config.ConfigurationStore;
import org.apache.geronimo.kernel.repository.Environment;
import org.apache.geronimo.openwebbeans.OpenWebBeansWebAppContext;
import org.apache.geronimo.openwebbeans.OpenWebBeansWebModuleListener;
import org.apache.geronimo.openwebbeans.WebBeansConfigurationListener;
import org.apache.geronimo.web.WebApplicationConstants;
import org.apache.geronimo.web.info.WebAppInfo;
import org.apache.openejb.jee.WebApp;
import org.apache.xbean.finder.AbstractFinder;
import org.apache.xbean.finder.BundleAnnotationFinder;
import org.apache.xbean.finder.ClassFinder;
import org.apache.xbean.osgi.bundle.util.BundleResourceFinder;
import org.apache.xbean.osgi.bundle.util.BundleResourceFinder.ResourceFinderCallback;
import org.apache.xbean.osgi.bundle.util.DiscoveryRange;
import org.apache.xbean.osgi.bundle.util.ResourceDiscoveryFilter;
import org.apache.xmlbeans.XmlObject;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @version $Rev $Date
*/
@GBean(j2eeType = NameFactory.MODULE_BUILDER)
public class OpenWebBeansModuleBuilderExtension implements ModuleBuilderExtension {

    private static final Logger log = LoggerFactory.getLogger(OpenWebBeansModuleBuilderExtension.class);

    private final Environment defaultEnvironment;
    private final Environment jsfPluginEnvironment;
    //only plausible naming builder is ours that adds BeanManager entry
    private final NamingBuilder namingBuilders;

    //this is the geronimo copy
    private static final String CONTEXT_LISTENER_NAME = WebBeansConfigurationListener.class.getName();

    private static final String WEB_MODULE_LISTENER_NAME = OpenWebBeansWebModuleListener.class.getName();

    public OpenWebBeansModuleBuilderExtension(
            @ParamAttribute(name = "defaultEnvironment") Environment defaultEnvironment,
            @ParamAttribute(name = "jsfPluginEnvironment") Environment jsfPluginEnvironment,
            @ParamReference(name = "NamingBuilders", namingType = NameFactory.MODULE_BUILDER) NamingBuilder namingBuilders) {
        this.defaultEnvironment = defaultEnvironment;
        this.jsfPluginEnvironment = jsfPluginEnvironment;
        this.namingBuilders = namingBuilders;
    }

    public void createModule(Module module, Bundle bundle, Naming naming, ModuleIDBuilder idBuilder)
            throws DeploymentException {
        if (!(module instanceof WebModule)) {
            // not a web module, nothing to do
            return;
        }
        if(hasBeanXml(module)){
            EnvironmentBuilder.mergeEnvironments(module.getEnvironment(), defaultEnvironment);
            EnvironmentBuilder.mergeEnvironments(module.getEnvironment(), jsfPluginEnvironment);
        }
    }

    public void createModule(Module module, Object plan, JarFile moduleFile, String targetPath, URL specDDUrl,
            Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming,
            ModuleIDBuilder idBuilder) throws DeploymentException {
        if (!(module instanceof WebModule)) {
            // not a web module, nothing to do
            return;
        }
        if(hasBeanXml(module)){
            EnvironmentBuilder.mergeEnvironments(module.getEnvironment(), defaultEnvironment);
            EnvironmentBuilder.mergeEnvironments(module.getEnvironment(), jsfPluginEnvironment);
        }
    }

    public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores,
            ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
    }

    public void initContext(EARContext earContext, Module module, Bundle bundle) throws DeploymentException {
    }

    public void addGBeans(EARContext earContext, Module module, Bundle bundle, Collection repository)
            throws DeploymentException {
        if (!(module instanceof WebModule)) {
            // not a web module, nothing to do
            return;
        }
        if (!hasBeansXml(bundle)) {
            return;
        }

        WebModule webModule = (WebModule) module;
        EARContext moduleContext = module.getEarContext();
        Map sharedContext = module.getSharedContext();

        GBeanData webAppData = (GBeanData) sharedContext.get(WebModule.WEB_APP_DATA);
        Map<String, Object> deploymentAttributes = (Map<String, Object>)webAppData.getAttribute("deploymentAttributes");
        List<String> webModuleListenerClassNames = (List<String>) deploymentAttributes.get(WebApplicationConstants.WEB_MODULE_LISTENERS);
        if (webModuleListenerClassNames == null) {
            webModuleListenerClassNames = new ArrayList<String>();
            deploymentAttributes.put(WebApplicationConstants.WEB_MODULE_LISTENERS, webModuleListenerClassNames);
        }
        webModuleListenerClassNames.add(WEB_MODULE_LISTENER_NAME);


        // add OpenWebBeans Lifcycle listener
        WebAppInfo webAppInfo = (WebAppInfo) webAppData.getAttribute("webAppInfo");
        if (webAppInfo != null && !webAppInfo.listeners.contains(CONTEXT_LISTENER_NAME)) {
            webAppInfo.listeners.add(0, CONTEXT_LISTENER_NAME);
        }
        AbstractName moduleName = module.getModuleName();
        Map<EARContext.Key, Object> buildingContext = new HashMap<EARContext.Key, Object>();
        buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, moduleName);

        //use the same holder object as the web app.
        Holder holder = NamingBuilder.INJECTION_KEY.get(sharedContext);
        buildingContext.put(NamingBuilder.INJECTION_KEY, holder);

        WebApp webApp = webModule.getSpecDD();
        XmlObject geronimoWebApp = webModule.getVendorDD();

        AbstractFinder originalFinder = webModule.getClassFinder();
        ClassFinder classFinder = createOpenWebBeansClassFinder(webApp, webModule);
        webModule.setClassFinder(classFinder);
        namingBuilders.buildNaming(webApp, geronimoWebApp, webModule, buildingContext);
        webModule.setClassFinder(originalFinder);

        AbstractName openWebBeansWebAppContextGBeanName = moduleContext.getNaming().createChildName(moduleName, "OpenWebBeansWebAppContext", "OpenWebBeansWebAppContext");
        GBeanData openWebBeansWebAppContextGBean = new GBeanData(openWebBeansWebAppContextGBeanName, OpenWebBeansWebAppContext.class);
        try {
            openWebBeansWebAppContextGBean.setAttribute("holder", holder);
            AbstractName sharedOwbContextName = EARContext.APPINFO_GBEAN_NAME_KEY.get(earContext.getGeneralData());
            if (sharedOwbContextName != null) {
                openWebBeansWebAppContextGBean.setReferencePattern("SharedOwbContext", sharedOwbContextName);
            }
            moduleContext.addGBean(openWebBeansWebAppContextGBean);
            webAppData.addDependency(openWebBeansWebAppContextGBeanName);
        } catch (GBeanAlreadyExistsException e) {
            throw new DeploymentException("Duplicate webbean config gbean in web module", e);
        }
    }

    private boolean hasBeansXml(Bundle bundle) {
        return bundle.getEntry("WEB-INF/beans.xml") != null || bundle.getResource("META-INF/beans.xml") != null;
    }

    private boolean hasBeanXml(Module webModule) {
        return webModule.getDeployable().getResource("WEB-INF/beans.xml") != null || webModule.getDeployable().getResource("META-INF/beans.xml") != null;
    }

    protected ClassFinder createOpenWebBeansClassFinder(WebApp webApp, WebModule webModule)
        throws DeploymentException {
        List<Class<?>> classes = getManagedClasses(webApp, webModule);
        return new ClassFinder(classes);
    }

    private List<Class<?>> getManagedClasses(WebApp webApp, WebModule webModule) throws DeploymentException {

        // Technically a CDI jar can never be meta-data complete
        // But without this check we fail some EE TCK tests

        // It would seem we are scanning too much of the classpath in this method
        // we should only be scanning the jars that contain beans.xml files
        // Obviously, this conflicts with the Bundle concept somewhat

       /* if (webApp.isMetadataComplete()) return Collections.EMPTY_LIST;*/


        Bundle bundle = webModule.getEarContext().getDeploymentBundle();
        ServiceReference reference = bundle.getBundleContext().getServiceReference(PackageAdmin.class.getName());
        try {
            PackageAdmin packageAdmin = (PackageAdmin) bundle.getBundleContext().getService(reference);

            //1. Generated the jar file list, which contains META-INF/beans.xml file
            final Set<String> annotationScanRequiredJarFiles = new HashSet<String>();
            String moduleNamePrefix = webModule.isStandAlone() ? "" : webModule.getTargetPath() + "/";
            BundleResourceFinder resourceFinder = new BundleResourceFinder(packageAdmin, bundle, "META-INF/", "beans.xml", new ResourceDiscoveryFilter() {

                @Override
                public boolean directoryDiscoveryRequired(String directoryName) {
                    return false;
                }

                @Override
                public boolean rangeDiscoveryRequired(DiscoveryRange discoveryRange) {
                    return discoveryRange == DiscoveryRange.BUNDLE_CLASSPATH;
                }

                @Override
                public boolean zipFileDiscoveryRequired(String zipFileName) {
                    return zipFileName.endsWith(".jar");
                }

            });
            resourceFinder.find(new ResourceFinderCallback() {

                @Override
                public boolean foundInDirectory(Bundle arg0, String arg1, URL arg2) throws Exception {
                    return false;
                }

                @Override
                public boolean foundInJar(Bundle bundle, String zipFileName, ZipEntry zipEntry, InputStream in) throws Exception {
                    String zipEntryName = zipEntry.getName();
                    if (zipEntryName.equals("META-INF/beans.xml")) {
                        annotationScanRequiredJarFiles.add(zipFileName);
                    }
                    return true;
                }
            });

            final String webInfClassesFolder = moduleNamePrefix + "WEB-INF/classes/";
            final boolean webInfClassesScanRequired = bundle.getEntry(moduleNamePrefix + "WEB-INF/beans.xml") != null;

            //2. Scan annotations
            BundleAnnotationFinder bundleAnnotationFinder = new BundleAnnotationFinder(packageAdmin, bundle, new ResourceDiscoveryFilter() {

                @Override
                public boolean directoryDiscoveryRequired(String directory) {
                    return directory.equals(webInfClassesFolder) && webInfClassesScanRequired;
                }

                @Override
                public boolean rangeDiscoveryRequired(DiscoveryRange discoveryRange) {
                    return discoveryRange.equals(DiscoveryRange.BUNDLE_CLASSPATH);
                }

                @Override
                public boolean zipFileDiscoveryRequired(String jarFile) {
                    return annotationScanRequiredJarFiles.contains(jarFile);
                }
            });

            final List<Member> members = new ArrayList<Member>();



            final Class<? extends Annotation>[] annotation = new Class[]{
                    Produces.class,
                    EJB.class,
                    PersistenceContext.class,
                    PersistenceUnit.class,
                    Resource.class,
            };

            for (Class<? extends Annotation> annotationClass : annotation) {
                members.addAll(bundleAnnotationFinder.findAnnotatedMethods(annotationClass));
                members.addAll(bundleAnnotationFinder.findAnnotatedFields(annotationClass));

            }

            final Set<Class<?>> classes = new HashSet<Class<?>>();
            for (Member member : members) {
                classes.add(member.getDeclaringClass());
            }

            return new ArrayList<Class<?>>(classes);
        } catch (Exception e) {
            throw new DeploymentException("Fail to scan jsr299 annotations", e);
        } finally {
            bundle.getBundleContext().ungetService(reference);
        }
    }

}
TOP

Related Classes of org.apache.geronimo.openwebbeans.deployment.OpenWebBeansModuleBuilderExtension

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.