Package org.apache.openejb

Source Code of org.apache.openejb.OpenEjbContainer$NoInjectionMetaDataException

/*
* 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.openejb;

import org.apache.openejb.assembler.classic.AppInfo;
import org.apache.openejb.assembler.classic.Assembler;
import org.apache.openejb.cdi.OWBInjector;
import org.apache.openejb.config.AppModule;
import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.config.ConnectorModule;
import org.apache.openejb.config.EjbModule;
import org.apache.openejb.config.NewLoaderLogic;
import org.apache.openejb.config.PersistenceModule;
import org.apache.openejb.config.ValidationFailedException;
import org.apache.openejb.jee.Application;
import org.apache.openejb.jee.Beans;
import org.apache.openejb.jee.Connector;
import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.ManagedBean;
import org.apache.openejb.jee.TransactionType;
import org.apache.openejb.jee.jpa.unit.Persistence;
import org.apache.openejb.jee.jpa.unit.PersistenceUnit;
import org.apache.openejb.jee.oejb3.EjbDeployment;
import org.apache.openejb.jee.oejb3.OpenejbJar;
import org.apache.openejb.loader.Options;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.spi.ContainerSystem;
import org.apache.openejb.util.Exceptions;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.OptionsLog;
import org.apache.openejb.util.ServiceManagerProxy;
import org.apache.xbean.naming.context.ContextFlyweight;

import javax.ejb.EJBException;
import javax.ejb.embeddable.EJBContainer;
import javax.ejb.spi.EJBContainerProvider;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.validation.ValidationException;
import java.io.File;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
* @version $Rev$ $Date$
*/
public class OpenEjbContainer extends EJBContainer {

    public static final String OPENEJB_EMBEDDED_REMOTABLE = "openejb.embedded.remotable";
    static Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, OpenEjbContainer.class);

    private static OpenEjbContainer instance;

    private final AppContext appContext;

    private ServiceManagerProxy serviceManager;
    private Options options;
    private OpenEjbContainer.GlobalContext globalJndiContext;

    private OpenEjbContainer(Map<?, ?> map, AppContext appContext) {
        this.appContext = appContext;
        this.globalJndiContext = new GlobalContext(appContext.getGlobalJndiContext());

        final Properties properties = new Properties();
        properties.putAll(map);

        options = new Options(properties);

        startNetworkServices();
    }

    @Override
    public void close() {
        if (serviceManager != null) {
            serviceManager.stop();
        }
        try {
            globalJndiContext.close();
        } catch (NamingException e) {
            throw new IllegalStateException(e);
        }
        OpenEJB.destroy();
        instance = null;
    }

    @Override
    public Context getContext() {
        return globalJndiContext;
    }

    public <T> T inject(T object) {

        assert object != null;

        final Class<?> clazz = object.getClass();

        final BeanContext context = resolve(clazz);

        if (context == null) throw new NoInjectionMetaDataException(clazz.getName());

        final InjectionProcessor processor = new InjectionProcessor(object, context.getInjections(), context.getJndiContext());

        try {
            OWBInjector beanInjector = new OWBInjector(appContext.getWebBeansContext());
            beanInjector.inject(object);
        } catch (Throwable t) {
            // TODO handle this differently
            // this is temporary till the injector can be rewritten
        }

        try {
            return (T) processor.createInstance();
        } catch (OpenEJBException e) {
            throw new InjectionException(clazz.getName(), e);
        }
    }

    private <T> BeanContext resolve(Class<?> clazz) {

        final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);

        while (clazz != null && clazz != Object.class) {

            {
                final BeanContext context = containerSystem.getBeanContext(clazz.getName());

                if (context != null) return context;
            }

            for (BeanContext context : containerSystem.deployments()) {

                if (clazz == context.getBeanClass()) return context;

            }

            clazz = clazz.getSuperclass();
        }

        return null;
    }


    private void startNetworkServices() {
        if (!options.get(OPENEJB_EMBEDDED_REMOTABLE, false)) {
            return;
        }

        try {
            serviceManager = new ServiceManagerProxy();
            serviceManager.start();
        } catch (ServiceManagerProxy.AlreadyStartedException e) {
            logger.debug("Network services already started.  Ignoring option " + OPENEJB_EMBEDDED_REMOTABLE);
        }
    }


    public static class NoInjectionMetaDataException extends IllegalStateException {
        public NoInjectionMetaDataException(String s) {
            super(s);
        }
    }

    public static class InjectionException extends IllegalStateException {
        public InjectionException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public static class Provider implements EJBContainerProvider {
        public static final String OPENEJB_ADDITIONNAL_CALLERS_KEY = "openejb.additionnal.callers";

        @Override
        public EJBContainer createEJBContainer(Map<?, ?> map) {
            if (isOtherProvider(map)) return null;

            if (instance != null || OpenEJB.isInitialized()) {
                logger.info("EJBContainer already initialized.  Call ejbContainer.close() to allow reinitialization");
                return instance;
            }


            try {
                // reset to be able to run this container then tomee one etc...
                if (System.getProperties().containsKey(Context.URL_PKG_PREFIXES)) {
                    System.getProperties().remove(Context.URL_PKG_PREFIXES);
                }

                Properties properties = new Properties();
                properties.putAll(map);

                SystemInstance.reset();
                SystemInstance.init(properties);
                SystemInstance.get().setProperty("openejb.embedded", "true");
                SystemInstance.get().setProperty(EJBContainer.class.getName(), "true");

                OptionsLog.install();

                OpenEJB.init(properties);


                final ConfigurationFactory configurationFactory = new ConfigurationFactory();


                final AppModule appModule = load(map, configurationFactory);

                final Set<String> callers;
                if (map.containsKey(OPENEJB_ADDITIONNAL_CALLERS_KEY)) {
                    callers = new LinkedHashSet<String>();
                    callers.addAll(Arrays.asList(((String) map.get(OPENEJB_ADDITIONNAL_CALLERS_KEY)).split(",")));
                } else {
                    callers = NewLoaderLogic.callers();
                }

                final EjbJar ejbJar = new EjbJar();
                final OpenejbJar openejbJar = new OpenejbJar();

                for (String caller : callers) {

                    if (!isValid(caller)) continue;

                    final ManagedBean bean = ejbJar.addEnterpriseBean(new ManagedBean(caller, caller, true));

                    // set it to bean so it can get UserTransaction injection
                    bean.setTransactionType(TransactionType.BEAN);

                    final EjbDeployment ejbDeployment = openejbJar.addEjbDeployment(bean);

                    // important in case any other deploment id formats are specified
                    ejbDeployment.setDeploymentId(caller);
                }

                appModule.getEjbModules().add(new EjbModule(ejbJar, openejbJar));


                final AppInfo appInfo;
                try {

                    appInfo = configurationFactory.configureApplication(appModule);

                } catch (ValidationFailedException e) {

                    logger.warning("configureApplication.loadFailed", appModule.getModuleId(), e.getMessage()); // DO not include the stacktrace in the message

                    throw new InvalidApplicationException(e);

                } catch (OpenEJBException e) {
                    // DO NOT REMOVE THE EXCEPTION FROM THIS LOG MESSAGE
                    // removing this message causes NO messages to be printed when embedded
                    logger.warning("configureApplication.loadFailed", e, appModule.getModuleId(), e.getMessage());

                    throw new ConfigureApplicationException(e);
                }

                final Assembler assembler = SystemInstance.get().getComponent(Assembler.class);

                final AppContext appContext;

                try {
                    appContext = assembler.createApplication(appInfo, appModule.getClassLoader());
                } catch (ValidationException ve) {
                    throw ve;
                } catch (Exception e) {
                    throw new AssembleApplicationException(e);
                }


                return instance = new OpenEjbContainer(map, appContext);

            } catch (OpenEJBException e) {

                throw new EJBException(e);

            } catch (MalformedURLException e) {

                throw new EJBException(e);

            } catch (ValidationException ve) {
                throw ve;
            } catch (Exception e) {

                if (e instanceof EJBException) {

                    throw (EJBException) e;
                }

                throw new InitializationException(e);
            } finally {
                if (instance == null && OpenEJB.isInitialized()) {
                    try {
                        OpenEJB.destroy();
                    } catch (Exception e) {
                    }
                }
            }
        }

        private boolean isValid(String caller) {
            try {
                final ClassLoader loader = Thread.currentThread().getContextClassLoader();

                final Class<?> clazz = loader.loadClass(caller);

                if (clazz.isEnum()) return false;
                if (clazz.isInterface()) return false;
                if (Modifier.isAbstract(clazz.getModifiers())) return false;

                return true;
            } catch (ClassNotFoundException e) {
                return false;
            }
        }

        private AppModule load(Map<?, ?> map, ConfigurationFactory configurationFactory) throws MalformedURLException, OpenEJBException {
            final List<File> moduleLocations;

            String appId = (String) map.get(EJBContainer.APP_NAME);


            final Object modules = map.get(EJBContainer.MODULES);

            // will be updated if needed

            ClassLoader classLoader = getClass().getClassLoader();

            if (modules instanceof String) {

                moduleLocations = configurationFactory.getModulesFromClassPath(null, classLoader);
                for (Iterator<File> i = moduleLocations.iterator(); i.hasNext(); ) {
                    File file = i.next();
                    if (!match((String) modules, file)) {
                        i.remove();
                    }
                }

            } else if (modules instanceof String[]) {

                // TODO Optimize this so we look specifically for modules by name
                moduleLocations = configurationFactory.getModulesFromClassPath(null, classLoader);

                int matched = 0;

                for (Iterator<File> i = moduleLocations.iterator(); i.hasNext(); ) {
                    File file = i.next();
                    boolean remove = true;
                    for (String s : (String[]) modules) {
                        if (match(s, file)) {
                            remove = false;
                            matched++;
                            break;
                        }
                    }
                    if (remove) {
                        i.remove();
                    }
                }

                if (matched != ((String[]) modules).length) {

                    throw specifiedModulesNotFound();

                }

            } else if (modules instanceof File) {

                URL url = ((File) modules).toURI().toURL();
                classLoader = new URLClassLoader(new URL[]{url}, classLoader);
                moduleLocations = Collections.singletonList((File) modules);

            } else if (modules instanceof File[]) {

                File[] files = (File[]) modules;
                URL[] urls = new URL[files.length];
                for (int i = 0; i < urls.length; i++) {
                    urls[i] = files[i].toURI().toURL();
                }
                classLoader = new URLClassLoader(urls, classLoader);
                moduleLocations = Arrays.asList((File[]) modules);

            } else if (modules == null) {

                moduleLocations = configurationFactory.getModulesFromClassPath(null, classLoader);

            } else {

                AppModule appModule = load(map);

                if (appModule != null) return appModule;

                throw invalidModulesValue(modules);

            }


            if (moduleLocations.isEmpty()) {
                throw Exceptions.newNoModulesFoundException();

            }

            // TODO With this load method we can finally do some checking on module ids to really implement EJBContainer.MODULES String/String[]
            return configurationFactory.loadApplication(classLoader, appId, moduleLocations);
        }

        private AppModule load(Map<?, ?> map) {

            String appId = (String) map.get(EJBContainer.APP_NAME);


            final Object modules = map.get(EJBContainer.MODULES);

            map.size();
            AppModule m;

            {
                final Object obj = modules;
                Application application = null;
                AppModule appModule = new AppModule(this.getClass().getClassLoader(), appId);

                {
                    if (obj instanceof EjbJar) {

                        final EjbJar ejbJar = (EjbJar) obj;
                        appModule.getEjbModules().add(new EjbModule(ejbJar));

                    } else if (obj instanceof EnterpriseBean) {

                        final EnterpriseBean bean = (EnterpriseBean) obj;
                        final EjbJar ejbJar = new EjbJar();
                        ejbJar.addEnterpriseBean(bean);
                        appModule.getEjbModules().add(new EjbModule(ejbJar));

                    } else if (obj instanceof Application) {

                        application = (Application) obj;

                    } else if (obj instanceof Connector) {

                        final Connector connector = (Connector) obj;
                        appModule.getConnectorModules().add(new ConnectorModule(connector));

                    } else if (obj instanceof Persistence) {

                        final Persistence persistence = (Persistence) obj;
                        appModule.getPersistenceModules().add(new PersistenceModule("", persistence));

                    } else if (obj instanceof PersistenceUnit) {

                        final PersistenceUnit unit = (PersistenceUnit) obj;
                        appModule.getPersistenceModules().add(new PersistenceModule("", new Persistence(unit)));

                    } else if (obj instanceof Beans) {

                        final Beans beans = (Beans) obj;
                        final EjbModule ejbModule = new EjbModule(new EjbJar());
                        ejbModule.setBeans(beans);
                        appModule.getEjbModules().add(ejbModule);
                    }
                }

                // Application is final in AppModule, which is fine, so we'll create a new one and move everything
                if (application != null) {
                    final AppModule newModule = new AppModule(appModule.getClassLoader(), appModule.getModuleId(), application, false);
                    newModule.getClientModules().addAll(appModule.getClientModules());
                    newModule.getPersistenceModules().addAll(appModule.getPersistenceModules());
                    newModule.getEjbModules().addAll(appModule.getEjbModules());
                    newModule.getConnectorModules().addAll(appModule.getConnectorModules());
                    appModule = newModule;
                }

                m = appModule;
            }
            return m;
        }

        // TODO, report some information

        private EJBException specifiedModulesNotFound() {
            return new NoSuchModuleException("some modules not matched on classpath");
        }

        private InvalidModulesPropertyException invalidModulesValue(Object value) {
            String[] spec = {"java.lang.String", "java.lang.String[]", "java.io.File", "java.io.File[]"};
//            TODO
//            String[] vendor = {"java.lang.Class","java.lang.Class[]", "java.net.URL", "java.io.URL[]"};
            String type = (value == null) ? null : value.getClass().getName();
            return new InvalidModulesPropertyException(String.format("Invalid '%s' value '%s'. Valid values are: %s", EJBContainer.MODULES, type, Join.join(", ", spec)));
        }

        private static boolean isOtherProvider(Map<?, ?> properties) {
            Object provider = properties.get(EJBContainer.PROVIDER);

            if (provider != null && !provider.equals(OpenEjbContainer.class) && !provider.equals(OpenEjbContainer.class.getName())) {

                return true;

            }
            return false;
        }

        private boolean match(String s, File file) {
            String s2 = file.getName();
            boolean matches;
            if (file.isDirectory()) {
                matches = s2.equals(s) || s2.equals(s + ".jar");
            } else {
                matches = s2.equals(s + ".jar");
            }
            if (!matches) {
                //TODO look for ejb-jar.xml with matching module name
            }
            return matches;
        }
    }

    private class GlobalContext extends ContextFlyweight {
        private final Context globalJndiContext;

        public GlobalContext(Context globalJndiContext) {
            this.globalJndiContext = globalJndiContext;
        }

        @Override
        protected Context getContext() throws NamingException {
            return globalJndiContext;
        }

        @Override
        protected Name getName(Name name) throws NamingException {
            String first = name.get(0);
            if (!first.startsWith("java:")) throw new NameNotFoundException("Name must be in java: namespace");
            first = first.substring("java:".length());
            name = name.getSuffix(1);
            return name.add(0, first);
        }

        @Override
        protected String getName(String name) throws NamingException {
            if ("inject".equals(name)) return name;
            if (!name.startsWith("java:")) throw new NameNotFoundException("Name must be in java: namespace");
            return name.substring("java:".length());
        }

        @Override
        public void bind(Name name, Object obj) throws NamingException {
            if (name.size() == 1 && "inject".equals(name.get(0))) inject(obj);
            else super.bind(name, obj);
        }

        @Override
        public void bind(String name, Object obj) throws NamingException {
            if (name != null && "inject".equals(name)) inject(obj);
            else super.bind(name, obj);
        }
    }


    public static class InitializationException extends EJBException {
        public InitializationException(String s) {
            super(s);
        }

        public InitializationException(Exception cause) {
            super(cause);
        }
    }

    public static class InvalidModulesPropertyException extends InitializationException {
        public InvalidModulesPropertyException(String s) {
            super(s);
        }
    }

    public static class NoSuchModuleException extends InitializationException {
        public NoSuchModuleException(String s) {
            super(s);
        }
    }

    public static class NoModulesFoundException extends InitializationException {
        public NoModulesFoundException(String s) {
            super(s);
        }
    }

    public static class ConfigureApplicationException extends InitializationException {
        public ConfigureApplicationException(Exception cause) {
            super(cause);
        }
    }

    public static class AssembleApplicationException extends InitializationException {
        public AssembleApplicationException(Exception cause) {
            super(cause);
        }
    }

    public static class InvalidApplicationException extends InitializationException {
        public InvalidApplicationException(Exception cause) {
            super(cause);
        }
    }
}
TOP

Related Classes of org.apache.openejb.OpenEjbContainer$NoInjectionMetaDataException

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.