Package org.apache.openejb.config

Source Code of org.apache.openejb.config.AutoConfig

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

import org.apache.openejb.OpenEJBException;
import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.assembler.classic.ContainerInfo;
import org.apache.openejb.assembler.classic.ResourceInfo;
import org.apache.openejb.util.LinkResolver;
import org.apache.openejb.util.UniqueDefaultLinkResolver;
import org.apache.openejb.jee.MessageDrivenBean;
import org.apache.openejb.jee.ActivationConfig;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.MessageDestination;
import org.apache.openejb.jee.AssemblyDescriptor;
import org.apache.openejb.jee.PersistenceType;
import org.apache.openejb.jee.SessionType;
import org.apache.openejb.jee.MessageDestinationRef;
import org.apache.openejb.jee.JndiReference;
import org.apache.openejb.jee.ResourceRef;
import org.apache.openejb.jee.JndiConsumer;
import org.apache.openejb.jee.Connector;
import org.apache.openejb.jee.ResourceAdapter;
import org.apache.openejb.jee.OutboundResourceAdapter;
import org.apache.openejb.jee.ConnectionDefinition;
import org.apache.openejb.jee.InboundResource;
import org.apache.openejb.jee.MessageListener;
import org.apache.openejb.jee.AdminObject;
import org.apache.openejb.jee.PersistenceContextRef;
import org.apache.openejb.jee.PersistenceRef;
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.jee.oejb3.ResourceLink;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.URISupport;
import static org.apache.openejb.util.Join.join;

import javax.sql.DataSource;
import javax.jms.Queue;
import javax.jms.Topic;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.net.URI;

public class AutoConfig implements DynamicDeployer {

    public static Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, AutoConfig.class);

    private static Set<String> ignoredReferenceTypes = new TreeSet<String>();
    static{
        // Context objects are automatically handled
        ignoredReferenceTypes.add("javax.ejb.SessionContext");
        ignoredReferenceTypes.add("javax.ejb.EntityContext");
        ignoredReferenceTypes.add("javax.ejb.MessageDrivenContext");
        ignoredReferenceTypes.add("javax.xml.ws.WebServiceContext");
        // URLs are automatically handled
        ignoredReferenceTypes.add("java.net.URL");
        // User transaction is automatically handled
        ignoredReferenceTypes.add("javax.transaction.UserTransaction");
        ignoredReferenceTypes.add("javax.ejb.TimerService");
    }

    private final ConfigurationFactory configFactory;
    private boolean autoCreateContainers = true;
    private boolean autoCreateResources = true;

    public AutoConfig(ConfigurationFactory configFactory) {
        this.configFactory = configFactory;
    }

    public synchronized boolean autoCreateResources() {
        return autoCreateResources;
    }

    public synchronized void autoCreateResources(boolean autoCreateResources) {
        this.autoCreateResources = autoCreateResources;
    }

    public synchronized boolean autoCreateContainers() {
        return autoCreateContainers;
    }

    public synchronized void autoCreateContainers(boolean autoCreateContainers) {
        this.autoCreateContainers = autoCreateContainers;
    }

    public void init() throws OpenEJBException {
    }

    public synchronized AppModule deploy(AppModule appModule) throws OpenEJBException {
        AppResources appResources = new AppResources(appModule);

        for (EjbModule ejbModule : appModule.getEjbModules()) {
            processActivationConfig(ejbModule);
        }
        resolveDestinationLinks(appModule);

        resolvePersistenceRefs(appModule);

        for (EjbModule ejbModule : appModule.getEjbModules()) {
            deploy(ejbModule, appResources);
        }
        for (ClientModule clientModule : appModule.getClientModules()) {
            deploy(clientModule, appResources);
        }
        for (ConnectorModule connectorModule : appModule.getResourceModules()) {
            deploy(connectorModule);
        }
        for (WebModule webModule : appModule.getWebModules()) {
            deploy(webModule, appResources);
        }
        for (PersistenceModule persistenceModule : appModule.getPersistenceModules()) {
            deploy(persistenceModule);
        }
        return appModule;
    }

    private void resolvePersistenceRefs(AppModule appModule) {
        LinkResolver<PersistenceUnit> persistenceUnits = new UniqueDefaultLinkResolver<PersistenceUnit>();

        for (PersistenceModule module : appModule.getPersistenceModules()) {
            String rootUrl = module.getRootUrl();
            for (PersistenceUnit unit : module.getPersistence().getPersistenceUnit()) {
                unit.setId(unit.getName() + " " + rootUrl.hashCode());
                persistenceUnits.add(rootUrl, unit.getName(), unit);
            }
        }

        for (EjbModule ejbModule : appModule.getEjbModules()) {
            URI moduleURI = URI.create(ejbModule.getModuleId());

            for (JndiConsumer component : ejbModule.getEjbJar().getEnterpriseBeans()) {
                processPersistenceRefs(component, appModule, persistenceUnits, moduleURI);
            }

        }

        for (ClientModule clientModule : appModule.getClientModules()) {
            URI moduleURI = URI.create(clientModule.getModuleId());
            processPersistenceRefs(clientModule.getApplicationClient(), appModule, persistenceUnits, moduleURI);
        }

        for (WebModule webModule : appModule.getWebModules()) {
            URI moduleURI = URI.create(webModule.getModuleId());
            processPersistenceRefs(webModule.getWebApp(), appModule, persistenceUnits, moduleURI);
        }
    }

    private void processPersistenceRefs(JndiConsumer component, AppModule appModule, LinkResolver<PersistenceUnit> persistenceUnits, URI moduleURI) {

        String componentName = component.getJndiConsumerName();

        ValidationContext validation = appModule.getValidation();

        for (PersistenceRef ref : component.getPersistenceUnitRef()) {

            processPersistenceRef(persistenceUnits, ref, moduleURI, componentName, validation);
        }

        for (PersistenceRef ref : component.getPersistenceContextRef()) {

            processPersistenceRef(persistenceUnits, ref, moduleURI, componentName, validation);
        }
    }

    private PersistenceUnit processPersistenceRef(LinkResolver<PersistenceUnit> persistenceUnits, PersistenceRef ref, URI moduleURI, String componentName, ValidationContext validation) {

        if (ref.getMappedName() != null && ref.getMappedName().startsWith("jndi:")){
            return null;
        }

        PersistenceUnit unit = persistenceUnits.resolveLink(ref.getPersistenceUnitName(), moduleURI);

        // Explicitly check if we messed up the "if there's only one,
        // that's what you get" rule by adding our "cmp" unit.
        Collection<PersistenceUnit> cmpUnits = persistenceUnits.values("cmp");
        if (unit == null && cmpUnits.size() > 0 && persistenceUnits.values().size() - cmpUnits.size() == 1) {
            // We did, there is exactly one non-cmp unit.  Let's find it.
            for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
                if (!persistenceUnit.getName().equals("cmp")){
                    // Found it
                    unit = persistenceUnit;
                    break;
                }
            }
        }


        // try again using the ref name
        if (unit == null){
            unit = persistenceUnits.resolveLink(ref.getName(), moduleURI);
        }

        // try again using the ref name with any prefix removed
        if (unit == null){
            String shortName = ref.getName().replaceFirst(".*/", "");
            unit = persistenceUnits.resolveLink(shortName, moduleURI);
        }

        if (unit != null){
            ref.setMappedName(unit.getId());
        } else {

            // ----------------------------------------------
            //  Nothing was found.  Let's try and figure out
            //  what went wrong and log a validation message
            // ----------------------------------------------

            String refType = "persistence";
            if (ref instanceof PersistenceContextRef){
                refType += "ContextRef";
            } else refType += "UnitRef";

            String refShortName = ref.getName();
            if (refShortName.matches(".*\\..*/.*")){
                refShortName = refShortName.replaceFirst(".*/", "");
            }

            List<String> availableUnits = new ArrayList<String>();
            for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
                availableUnits.add(persistenceUnit.getName());
            }

            Collections.sort(availableUnits);

            String unitName = ref.getPersistenceUnitName();

            if (availableUnits.size() == 0){
                // Print a sample persistence.xml using their data
                if (unitName == null){
                    unitName = refShortName;
                }
                validation.fail(componentName, refType + ".noPersistenceUnits", refShortName, unitName);
            } else if (ref.getPersistenceUnitName() == null && availableUnits.size() > 1) {
                // Print a correct example of unitName in a ref
                // DMB: Idea, the ability to set a default unit-name in openejb-jar.xml via a property
                String sampleUnitName = availableUnits.get(0);
                validation.fail(componentName, refType + ".noUnitName", refShortName, join(", ", availableUnits), sampleUnitName );
            } else {
                Collection<PersistenceUnit> vagueMatches = persistenceUnits.values(ref.getPersistenceUnitName());
                if (vagueMatches.size() != 0) {
                    // Print the full rootUrls

                    List<String> possibleUnits = new ArrayList<String>();
                    for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
                        URI unitURI = URI.create(persistenceUnit.getId());
                        unitURI = URISupport.relativize(moduleURI, unitURI);
                        possibleUnits.add(unitURI.toString());
                    }

                    Collections.sort(possibleUnits);

                    validation.fail(componentName, refType + ".vagueMatches", refShortName, unitName, possibleUnits.size(), join("\n", possibleUnits));
                } else {
                    validation.fail(componentName, refType + ".noMatches", refShortName, unitName, join(", ", availableUnits));
                }
            }
        }
        return unit;
    }


    /**
     * Set destination, destinationType, clientId and subscriptionName in the MDB activation config.
     */
    private void processActivationConfig(EjbModule ejbModule) throws OpenEJBException {
        OpenejbJar openejbJar;
        if (ejbModule.getOpenejbJar() != null) {
            openejbJar = ejbModule.getOpenejbJar();
        } else {
            openejbJar = new OpenejbJar();
            ejbModule.setOpenejbJar(openejbJar);
        }

        Map<String, EjbDeployment> deployments = openejbJar.getDeploymentsByEjbName();

        for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
            if (bean instanceof MessageDrivenBean) {
                MessageDrivenBean mdb = (MessageDrivenBean) bean;

                EjbDeployment ejbDeployment = deployments.get(bean.getEjbName());
                if (ejbDeployment == null) {
                    throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
                }

                if (mdb.getActivationConfig() == null) {
                    mdb.setActivationConfig(new ActivationConfig());
                }

                Properties properties = mdb.getActivationConfig().toProperties();

                // destination
                String destination = properties.getProperty("destination", properties.getProperty("destinationName"));
                if (destination == null) {
                    destination = ejbDeployment.getDeploymentId();
                    mdb.getActivationConfig().addProperty("destination", destination);
                }

                // destination identifier
                ResourceLink link = ejbDeployment.getResourceLink("openejb/destination");
                if (link == null && mdb.getMessageDestinationLink() == null) {
                    link = new ResourceLink();
                    link.setResId(destination);
                    link.setResRefName("openejb/destination");
                    ejbDeployment.addResourceLink(link);
                }

                // destination type
                String destinationType = properties.getProperty("destinationType");
                if (destinationType == null && mdb.getMessageDestinationType() != null) {
                    destinationType = mdb.getMessageDestinationType();
                    mdb.getActivationConfig().addProperty("destinationType", destinationType);
                }
                if (mdb.getMessageDestinationType() == null) {
                    mdb.setMessageDestinationType(destinationType);
                }

                // topics need a clientId and subscriptionName
                if ("javax.jms.Topic".equals(destinationType)) {
                    if (!properties.containsKey("clientId")) {
                        mdb.getActivationConfig().addProperty("clientId", ejbDeployment.getDeploymentId());
                    }
                    if (!properties.containsKey("subscriptionName")) {
                        mdb.getActivationConfig().addProperty("subscriptionName", ejbDeployment.getDeploymentId() + "_subscription");
                    }
                }
            }
        }
    }

    /**
     * Set resource id in all message-destination-refs and MDBs that are using message destination links.
     */
    private void resolveDestinationLinks(AppModule appModule) throws OpenEJBException {
        // build up a link resolver
        LinkResolver<MessageDestination> destinationResolver = new LinkResolver<MessageDestination>();
        for (EjbModule ejbModule : appModule.getEjbModules()) {
            AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
            if (assembly != null) {
                String moduleId = ejbModule.getModuleId();
                for (MessageDestination destination : assembly.getMessageDestination()) {
                    destinationResolver.add(moduleId, destination.getMessageDestinationName(), destination);
                }
            }
        }
        for (ClientModule clientModule : appModule.getClientModules()) {
            String moduleId = appModule.getModuleId();
            for (MessageDestination destination : clientModule.getApplicationClient().getMessageDestination()) {
                destinationResolver.add(moduleId, destination.getMessageDestinationName(), destination);
            }
        }
        for (WebModule webModule : appModule.getWebModules()) {
            String moduleId = appModule.getModuleId();
            for (MessageDestination destination : webModule.getWebApp().getMessageDestination()) {
                destinationResolver.add(moduleId, destination.getMessageDestinationName(), destination);
            }
        }

        // remember the type of each destination so we can use it to fillin MDBs that don't declare destination type
        Map<MessageDestination,String> destinationTypes = new HashMap<MessageDestination,String>();

        // resolve all MDBs with destination links
        // if MessageDestination does not have a mapped name assigned, give it the destination from the MDB
        for (EjbModule ejbModule : appModule.getEjbModules()) {
            AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
            if (assembly == null) {
                continue;
            }

            URI moduleUri = URI.create(appModule.getModuleId());
            OpenejbJar openejbJar = ejbModule.getOpenejbJar();

            for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
                // MDB destination is deploymentId if none set
                if (bean instanceof MessageDrivenBean) {
                    MessageDrivenBean mdb = (MessageDrivenBean) bean;

                    EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
                    if (ejbDeployment == null) {
                        throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
                    }

                    // skip destination refs without a destination link
                    String link = mdb.getMessageDestinationLink();
                    if (link == null || link.length() == 0) {
                        continue;
                    }

                    // resolve the destination... if we don't find one it is a configuration bug
                    MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
                    if (destination == null) {
                        throw new OpenEJBException("Message destination " + link + " for message driven bean " + mdb.getEjbName()  + " not found");
                    }

                    // get the destinationId is the mapped name
                    String destinationId = destination.getMappedName();
                    if (destinationId == null) {
                        // if we don't have a mapped name use the destination of the mdb
                        Properties properties = mdb.getActivationConfig().toProperties();
                        destinationId = properties.getProperty("destination");
                        destination.setMappedName(destinationId);
                    }

                    if (mdb.getMessageDestinationType() != null && !destinationTypes.containsKey(destination)) {
                        destinationTypes.put(destination, mdb.getMessageDestinationType());
                    }

                    // destination identifier
                    ResourceLink resourceLink = ejbDeployment.getResourceLink("openejb/destination");
                    if (resourceLink == null) {
                        resourceLink = new ResourceLink();
                        resourceLink.setResRefName("openejb/destination");
                        ejbDeployment.addResourceLink(resourceLink);
                    }
                    resourceLink.setResId(destinationId);
                }
            }
        }

        // resolve all message destination refs with links and assign a ref id to the reference
        for (EjbModule ejbModule : appModule.getEjbModules()) {
            AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
            if (assembly == null) {
                continue;
            }

            URI moduleUri = URI.create(appModule.getModuleId());
            OpenejbJar openejbJar = ejbModule.getOpenejbJar();

            for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
                EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
                if (ejbDeployment == null) {
                    throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
                }

                for (MessageDestinationRef ref : bean.getMessageDestinationRef()) {
                    // skip destination refs with a resource link already assigned
                    if (ref.getMappedName() == null && ejbDeployment.getResourceLink(ref.getName()) == null) {
                        String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
                        if (destinationId != null) {
                            // build the link and add it
                            ResourceLink resourceLink = new ResourceLink();
                            resourceLink.setResId(destinationId);
                            resourceLink.setResRefName(ref.getName());
                            ejbDeployment.addResourceLink(resourceLink);
                        }

                    }
                }
            }
        }

        for (ClientModule clientModule : appModule.getClientModules()) {
            URI moduleUri = URI.create(appModule.getModuleId());
            for (MessageDestinationRef ref : clientModule.getApplicationClient().getMessageDestinationRef()) {
                String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
                if (destinationId != null) {
                    // for client modules we put the destinationId in the mapped name
                    ref.setMappedName(destinationId);
                }
            }
        }

        for (WebModule webModule : appModule.getWebModules()) {
            URI moduleUri = URI.create(appModule.getModuleId());
            for (MessageDestinationRef ref : webModule.getWebApp().getMessageDestinationRef()) {
                String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
                if (destinationId != null) {
                    // for web modules we put the destinationId in the mapped name
                    ref.setMappedName(destinationId);
                }
            }
        }

        // Process MDBs one more time...
        // this time fill in the destination type (if not alreday specified) with
        // the info from the destination (which got filled in from the references)
        for (EjbModule ejbModule : appModule.getEjbModules()) {
            AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
            if (assembly == null) {
                continue;
            }

            URI moduleUri = URI.create(appModule.getModuleId());
            OpenejbJar openejbJar = ejbModule.getOpenejbJar();

            for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
                // MDB destination is deploymentId if none set
                if (bean instanceof MessageDrivenBean) {
                    MessageDrivenBean mdb = (MessageDrivenBean) bean;

                    EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
                    if (ejbDeployment == null) {
                        throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
                    }

                    // if destination type is already set in, continue
                    String destinationType = mdb.getMessageDestinationType();
                    if (destinationType != null) {
                        continue;
                    }

                    String link = mdb.getMessageDestinationLink();
                    if (link != null && link.length() != 0) {
                        // resolve the destination... if we don't find one it is a configuration bug
                        MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
                        if (destination == null) {
                            throw new OpenEJBException("Message destination " + link + " for message driven bean " + mdb.getEjbName()  + " not found");
                        }
                        destinationType = destinationTypes.get(destination);
                    }

                    if (destinationType == null) {
                        // couldn't determine type... we'll have to guess

                        // if destination name contains the string "queue" or "topic" we use that
                        Properties properties = mdb.getActivationConfig().toProperties();
                        String destination = properties.getProperty("destination").toLowerCase();
                        if (destination.indexOf("queue") >= 0) {
                            destinationType = Queue.class.getName();
                        } else if (destination.indexOf("topic") >= 0) {
                            destinationType = Topic.class.getName();
                        } else {
                            // Queue is the default
                            destinationType = Queue.class.getName();
                        }
                        logger.info("Auto-configuring a message driven bean " + ejbDeployment.getDeploymentId() + " destination " + properties.getProperty("destination") + " to be destinationType " + destinationType);
                    }

                    if (destinationType != null) {
                        mdb.getActivationConfig().addProperty("destinationType", destinationType);
                        mdb.setMessageDestinationType(destinationType);

                        // topics need a clientId and subscriptionName
                        if ("javax.jms.Topic".equals(destinationType)) {
                            Properties properties = mdb.getActivationConfig().toProperties();
                            if (!properties.containsKey("clientId")) {
                                mdb.getActivationConfig().addProperty("clientId", ejbDeployment.getDeploymentId());
                            }
                            if (!properties.containsKey("subscriptionName")) {
                                mdb.getActivationConfig().addProperty("subscriptionName", ejbDeployment.getDeploymentId() + "_subscription");
                            }
                        }
                    }
                }
            }
        }

    }

    private String resolveDestinationId(MessageDestinationRef ref, URI moduleUri, LinkResolver<MessageDestination> destinationResolver, Map<MessageDestination,String> destinationTypes) throws OpenEJBException {
        // skip destination refs without a destination link
        String link = ref.getMessageDestinationLink();
        if (link == null || link.length() == 0) {
            return null;
        }

        // resolve the destination... if we don't find one it is a configuration bug
        MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
        if (destination == null) {
            throw new OpenEJBException("Message destination " + link + " for message-destination-ref " + ref.getMessageDestinationRefName()  + " not found");
        }

        // remember the type of each destination so we can use it to fillin MDBs that don't declare destination type
        if (ref.getMessageDestinationType() != null && !destinationTypes.containsKey(destination)) {
            destinationTypes.put(destination, ref.getMessageDestinationType());
        }

        // get the destinationId
        String destinationId = destination.getMappedName();
        if (destinationId == null) destination.getMessageDestinationName();
        return destinationId;
    }

    private void deploy(ClientModule clientModule, AppResources appResources) throws OpenEJBException {
        processJndiRefs(clientModule.getModuleId(), clientModule.getApplicationClient(), appResources);
    }

    @SuppressWarnings({"UnusedDeclaration"})
    private void deploy(ConnectorModule connectorModule) throws OpenEJBException {
        // Nothing to process for resource modules
    }

    private void deploy(WebModule webModule, AppResources appResources) throws OpenEJBException {
        processJndiRefs(webModule.getModuleId(), webModule.getWebApp(), appResources);
    }

    private void processJndiRefs(String moduleId, JndiConsumer jndiConsumer, AppResources appResources) throws OpenEJBException {
        // Resource reference
        for (ResourceRef ref : jndiConsumer.getResourceRef()) {
            // skip references such as URLs which are automatically handled by the server
            if (ignoredReferenceTypes.contains(ref.getType())) {
                continue;
            }

            // skip destinations with a global jndi name
            String mappedName = ref.getMappedName();
            if (mappedName == null) mappedName = "";
            if (mappedName.startsWith("jndi:")){
                continue;
            }

            String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
            destinationId = getResourceId(moduleId, destinationId, ref.getType(), appResources);
            ref.setMappedName(destinationId);
        }

        // Resource env reference
        for (JndiReference ref : jndiConsumer.getResourceEnvRef()) {
            // skip references such as URLs which are automatically handled by the server
            if (ignoredReferenceTypes.contains(ref.getType())) {
                continue;
            }

            // skip destinations with a global jndi name
            String mappedName = ref.getMappedName();
            if (mappedName == null) mappedName = "";
            if (mappedName.startsWith("jndi:")){
                continue;
            }

            String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
            destinationId = getResourceEnvId(moduleId, destinationId, ref.getType(), appResources);
            ref.setMappedName(destinationId);
        }

        // Message destination reference
        for (MessageDestinationRef ref : jndiConsumer.getMessageDestinationRef()) {
            // skip destinations with a global jndi name
            String mappedName = ref.getMappedName() + "";
            if (mappedName.startsWith("jndi:")){
                continue;
            }

            String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
            destinationId = getResourceEnvId(moduleId, destinationId, ref.getType(), appResources);
            ref.setMappedName(destinationId);
        }
    }

    private void deploy(EjbModule ejbModule, AppResources appResources) throws OpenEJBException {
        OpenejbJar openejbJar;
        if (ejbModule.getOpenejbJar() != null) {
            openejbJar = ejbModule.getOpenejbJar();
        } else {
            openejbJar = new OpenejbJar();
            ejbModule.setOpenejbJar(openejbJar);
        }

        Map<String, EjbDeployment> deployments = openejbJar.getDeploymentsByEjbName();

        for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
            EjbDeployment ejbDeployment = deployments.get(bean.getEjbName());
            if (ejbDeployment == null) {
                throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
            }

            Class<? extends ContainerInfo> containerInfoType = ConfigurationFactory.getContainerInfoType(getType(bean));
            if (ejbDeployment.getContainerId() == null && !skipMdb(bean)) {
                String containerId = getUsableContainer(containerInfoType, bean, appResources);
                if (containerId == null){
                    containerId = createContainer(containerInfoType, ejbDeployment, bean);
                }
                ejbDeployment.setContainerId(containerId);
            }

            // create the container if it doesn't exist
            if (!configFactory.getContainerIds().contains(ejbDeployment.getContainerId()) && !skipMdb(bean)) {
                createContainer(containerInfoType, ejbDeployment, bean);
            }

            // Resource reference
            for (ResourceRef ref : bean.getResourceRef()) {
                processResourceRef(ref, ejbDeployment, appResources);
            }

            // Resource env reference
            for (JndiReference ref : bean.getResourceEnvRef()) {
                processResourceEnvRef(ref, ejbDeployment, appResources);
            }

            // Message destination reference
            for (MessageDestinationRef ref : bean.getMessageDestinationRef()) {
                processResourceEnvRef(ref, ejbDeployment, appResources);
            }


            // mdb message destination id
            if (autoCreateResources && bean instanceof MessageDrivenBean) {
                MessageDrivenBean mdb = (MessageDrivenBean) bean;

                ResourceLink resourceLink = ejbDeployment.getResourceLink("openejb/destination");
                if (resourceLink != null) {
                    try {
                        String destinationId = getResourceEnvId(bean.getEjbName(), resourceLink.getResId(), mdb.getMessageDestinationType(), appResources);
                        resourceLink.setResId(destinationId);
                    } catch (OpenEJBException e) {
                        // The MDB doesn't need the auto configured "openejb/destination" env entry
                        ejbDeployment.removeResourceLink("openejb/destination");
                    }
                }
            }

        }
    }

    private String createContainer(Class<? extends ContainerInfo> containerInfoType, EjbDeployment ejbDeployment, EnterpriseBean bean) throws OpenEJBException {
        if (!autoCreateContainers) {
            throw new OpenEJBException("A container of type " + getType(bean) + " must be declared in the configuration file for bean: " + bean.getEjbName());
        }

        // get the container info (data used to build the container)
        ContainerInfo containerInfo = configFactory.configureService(containerInfoType);
        logger.info("Auto-creating a container for bean " + ejbDeployment.getDeploymentId() + ": Container(type=" + getType(bean) + ", id=" + containerInfo.id + ")");

        // if the is an MDB container we need to resolve the resource adapter
        String resourceAdapterId = containerInfo.properties.getProperty("ResourceAdapter");
        if (resourceAdapterId != null) {
            String newResourceId = getResourceId(ejbDeployment.getDeploymentId(), resourceAdapterId, null, null);
            if (resourceAdapterId != newResourceId) {
                containerInfo.properties.setProperty("ResourceAdapter", newResourceId);
            }
        }

        // install the container
        configFactory.install(containerInfo);
        return containerInfo.id;
    }

    private void processResourceRef(ResourceRef ref, EjbDeployment ejbDeployment, AppResources appResources) throws OpenEJBException {
        // skip destinations with a global jndi name
        String mappedName = ref.getMappedName();
        if (mappedName == null) mappedName = "";
        if ((mappedName).startsWith("jndi:")){
            return;
        }

        String refName = ref.getName();
        String refType = ref.getType();

        // skip references such as URLs which are automatically handled by the server
        if (ignoredReferenceTypes.contains(refType)) {
            return;
        }

        ResourceLink link = ejbDeployment.getResourceLink(refName);
        if (link == null) {
            String id = (mappedName.length() == 0) ? ref.getName() : mappedName;
            id = getResourceId(ejbDeployment.getDeploymentId(), id, refType, appResources);
            logger.info("Auto-linking resource-ref '" + refName + "' in bean " + ejbDeployment.getDeploymentId() + " to Resource(id=" + id + ")");

            link = new ResourceLink();
            link.setResId(id);
            link.setResRefName(refName);
            ejbDeployment.addResourceLink(link);
        } else {
            String id = getResourceId(ejbDeployment.getDeploymentId(), link.getResId(), refType, appResources);
            link.setResId(id);
            link.setResRefName(refName);
        }
    }

    private void processResourceEnvRef(JndiReference ref, EjbDeployment ejbDeployment, AppResources appResources) throws OpenEJBException {
        // skip destinations with a global jndi name
        String mappedName = (ref.getMappedName() == null)? "": ref.getMappedName();
        if (mappedName.startsWith("jndi:")){
            return;
        }

        String refName = ref.getName();
        String refType = ref.getType();

        // skip references such as SessionContext which are automatically handled by the server
        if (ignoredReferenceTypes.contains(refType)) {
            return;
        }

        ResourceLink link = ejbDeployment.getResourceLink(refName);
        if (link == null) {

            String id = (mappedName.length() == 0) ? refName : mappedName;
            id = getResourceEnvId(ejbDeployment.getDeploymentId(), id, refType, appResources);
            if (id == null) {
                // could be a session context ref
                return;
            }
            logger.info("Auto-linking resource-env-ref '" + refName + "' in bean " + ejbDeployment.getDeploymentId() + " to Resource(id=" + id + ")");

            link = new ResourceLink();
            link.setResId(id);
            link.setResRefName(refName);
            ejbDeployment.addResourceLink(link);
        } else {
            String id = getResourceEnvId(ejbDeployment.getDeploymentId(), link.getResId(), refType, appResources);
            link.setResId(id);
            link.setResRefName(refName);
        }
    }

    private static boolean skipMdb(Object bean) {
        return bean instanceof MessageDrivenBean && System.getProperty("duct tape") != null;
    }

    private static String getType(EnterpriseBean enterpriseBean) throws OpenEJBException {
        if (enterpriseBean instanceof org.apache.openejb.jee.EntityBean) {
            if (((org.apache.openejb.jee.EntityBean)enterpriseBean).getPersistenceType() == PersistenceType.CONTAINER) {
                return BeanTypes.CMP_ENTITY;
            } else {
                return BeanTypes.BMP_ENTITY;
            }
        } else if (enterpriseBean instanceof org.apache.openejb.jee.SessionBean) {
            if (((org.apache.openejb.jee.SessionBean) enterpriseBean).getSessionType() == SessionType.STATEFUL) {
                return BeanTypes.STATEFUL;
            } else {
                return BeanTypes.STATELESS;
            }
        } else if (enterpriseBean instanceof org.apache.openejb.jee.MessageDrivenBean) {
            return BeanTypes.MESSAGE;
        }
        throw new OpenEJBException("Unknown enterprise bean type " + enterpriseBean.getClass().getName());
    }

    private void deploy(PersistenceModule persistenceModule) throws OpenEJBException {
        if (!autoCreateResources) {
            return;
        }

        Persistence persistence = persistenceModule.getPersistence();
        for (PersistenceUnit persistenceUnit : persistence.getPersistenceUnit()) {
            Properties required = new Properties();

            required.put("JtaManaged", "true");
            String jtaDataSourceId = getResourceId(persistenceUnit.getName(), persistenceUnit.getJtaDataSource(), DataSource.class.getName(), null, required);
            if (jtaDataSourceId != null) {
                persistenceUnit.setJtaDataSource("java:openejb/Resource/" + jtaDataSourceId);
            }

            required.put("JtaManaged", "false");
            String nonJtaDataSourceId = getResourceId(persistenceUnit.getName(), persistenceUnit.getNonJtaDataSource(), DataSource.class.getName(), null, required);
            if (nonJtaDataSourceId != null) {
                persistenceUnit.setNonJtaDataSource("java:openejb/Resource/" + nonJtaDataSourceId);
            }
        }
    }

    private String getResourceId(String beanName, String resourceId, String type, AppResources appResources) throws OpenEJBException {
        return getResourceId(beanName, resourceId, type, appResources, null);
    }

    private String getResourceId(String beanName, String resourceId, String type, AppResources appResources, Properties required) throws OpenEJBException {
        if(resourceId == null){
            return null;
        }

        if (appResources == null) appResources = new AppResources();

        // skip references such as URL which are automatically handled by the server
        if (type != null && ignoredReferenceTypes.contains(type)) {
            return null;
        }

        // strip off "java:comp/env"
        if (resourceId.startsWith("java:comp/env")) {
            resourceId = resourceId.substring("java:comp/env".length());
        }

        // check for existing resource with specified resourceId
        List<String> resourceIds = new ArrayList<String>();
        resourceIds.addAll(appResources.getResourceIds(type));
        resourceIds.addAll(configFactory.getResourceIds(type, required));
        for (String id : resourceIds) {
            if (id.equalsIgnoreCase(resourceId)) return id;
        }

        // check for an existing resource using the short name (everything ever the final '/')
        String shortName = resourceId.replaceFirst(".*/", "");
        for (String id : resourceIds) {
            if (id.equalsIgnoreCase(shortName)) return id;
        }

        // expand search to any type -- may be asking for a reference to a sub-type
        List<String> allResourceIds = new ArrayList<String>();
        allResourceIds.addAll(appResources.getResourceIds(null));
        allResourceIds.addAll(configFactory.getResourceIds(null, required));
        for (String id : allResourceIds) {
            if (id.equalsIgnoreCase(resourceId)) return id;
        }
        for (String id : allResourceIds) {
            if (id.equalsIgnoreCase(shortName)) return id;
        }

        // throw an exception or log an error
        String message = "No existing resource found while attempting to Auto-link unmapped resource-ref '" + resourceId + "' of type '" + type  + "' for '" + beanName + "'.  Looked for Resource(id=" + resourceId + ") and Resource(id=" + shortName + ")";
        if (!autoCreateResources){
            throw new OpenEJBException(message);
        }
        logger.debug(message);

        // if there is a provider with the specified name. use it
        if (ServiceUtils.hasServiceProvider(resourceId)) {
            ResourceInfo resourceInfo = configFactory.configureService(resourceId, ResourceInfo.class);
            return installResource(beanName, resourceInfo);
        } else if (ServiceUtils.hasServiceProvider(shortName)) {
            ResourceInfo resourceInfo = configFactory.configureService(shortName, ResourceInfo.class);
            return installResource(beanName, resourceInfo);
        }

        // if there are any resources of the desired type, use the first one
        if (resourceIds.size() > 0) {
            return resourceIds.get(0);
        }

        // Auto create a resource using the first provider that can supply a resource of the desired type
        resourceId = ServiceUtils.getServiceProviderId(type, required);
        if (resourceId == null) {
            throw new OpenEJBException("No provider available for resource-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'.");
        }
        ResourceInfo resourceInfo = configFactory.configureService(resourceId, ResourceInfo.class);

        logger.info("Auto-creating a resource with id '" + resourceInfo.id +  "' of type '" + type  + " for '" + beanName + "'.");
        return installResource(beanName, resourceInfo);
    }

    private String installResource(String beanName, ResourceInfo resourceInfo) throws OpenEJBException {
        String resourceAdapterId = resourceInfo.properties.getProperty("ResourceAdapter");
        if (resourceAdapterId != null) {
            String newResourceId = getResourceId(beanName, resourceAdapterId, null, null);
            if (resourceAdapterId != newResourceId) {
                resourceInfo.properties.setProperty("ResourceAdapter", newResourceId);
            }
        }
        String dataSourceId = resourceInfo.properties.getProperty("DataSource");
        if (dataSourceId != null) {
            String newResourceId = getResourceId(beanName, dataSourceId, null, null);
            if (dataSourceId != newResourceId) {
                resourceInfo.properties.setProperty("DataSource", newResourceId);
            }
        }

        configFactory.install(resourceInfo);
        return resourceInfo.id;
    }

    private String getResourceEnvId(String beanName, String resourceId, String type, AppResources appResources) throws OpenEJBException {
        if(resourceId == null){
            return null;
        }
        if (appResources == null) appResources = new AppResources();

        // skip references such as URLs which are automatically handled by the server
        if (ignoredReferenceTypes.contains(type)) {
            return null;
        }

        // strip off "java:comp/env"
        if (resourceId.startsWith("java:comp/env")) {
            resourceId = resourceId.substring("java:comp/env".length());
        }

        // check for existing resource with specified resourceId
        List<String> resourceEnvIds = new ArrayList<String>();
        resourceEnvIds.addAll(appResources.getResourceIds(type));
        resourceEnvIds.addAll(configFactory.getResourceIds(type));
        for (String id : resourceEnvIds) {
            if (id.equalsIgnoreCase(resourceId)) return id;
        }

        // throw an exception or log an error
        String message = "No existing resource found while attempting to Auto-link unmapped resource-env-ref '" + resourceId + "' of type '" + type  + "' for '" + beanName + "'.  Looked for Resource(id=" + resourceId + ")";
        if (!autoCreateResources){
            throw new OpenEJBException(message);
        }
        logger.debug(message);


        // Auto create a resource using the first provider that can supply a resource of the desired type
        String providerId = ServiceUtils.getServiceProviderId(type);
        if (providerId == null) {
            // if there are any existing resources of the desired type, use the first one
            if (resourceEnvIds.size() > 0) {
                return resourceEnvIds.get(0);
            }
            throw new OpenEJBException("No provider available for resource-env-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'.");
        }

        Resource resource = new Resource(resourceId, null, providerId);
        resource.getProperties().setProperty("destination", resourceId);

        ResourceInfo resourceInfo = configFactory.configureService(resource, ResourceInfo.class);
        logger.info("Auto-creating a resource with id '" + resourceInfo.id +  "' of type '" + type  + " for '" + beanName + "'.");
        return installResource(beanName, resourceInfo);
    }

    private String getUsableContainer(Class<? extends ContainerInfo> containerInfoType, Object bean, AppResources appResources) {
        if (bean instanceof MessageDrivenBean) {
            MessageDrivenBean messageDrivenBean = (MessageDrivenBean) bean;
            String messagingType = messageDrivenBean.getMessagingType();
            List<String> containerIds = appResources.containerIdsByType.get(messagingType);
            if (containerIds != null && !containerIds.isEmpty()) {
                return containerIds.get(0);
            }
        }

        for (ContainerInfo containerInfo : configFactory.getContainerInfos()) {
            if (containerInfo.getClass().equals(containerInfoType)){
                // MDBs must match message listener interface type
                if (bean instanceof MessageDrivenBean) {
                    MessageDrivenBean messageDrivenBean = (MessageDrivenBean) bean;
                    String messagingType = messageDrivenBean.getMessagingType();
                    if (containerInfo.properties.get("MessageListenerInterface").equals(messagingType)) {
                        return containerInfo.id;
                    }
                } else {
                    return containerInfo.id;
                }
            }
        }

        return null;
    }

    private static class AppResources {
        @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
        private final Set<String> resourceAdapterIds = new TreeSet<String>();
        private final Map<String,List<String>> resourceIdsByType = new TreeMap<String,List<String>>();
        private final Map<String,List<String>> resourceEnvIdsByType = new TreeMap<String,List<String>>();
        private final Map<String,List<String>> containerIdsByType = new TreeMap<String,List<String>>();

        public AppResources() {
        }

        public AppResources(AppModule appModule) {

            //
            // DEVELOPERS NOTE:  if you change the id generation code here, you must change
            // the id generation code in ConfigurationFactory.configureApplication(AppModule appModule)
            //

            for (ConnectorModule connectorModule : appModule.getResourceModules()) {
                Connector connector = connectorModule.getConnector();

                ResourceAdapter resourceAdapter = connector.getResourceAdapter();
                if (resourceAdapter.getResourceAdapterClass() != null) {
                    String resourceAdapterId;
                    if (resourceAdapter.getId() != null) {
                        resourceAdapterId = resourceAdapter.getId();
                    } else {
                        resourceAdapterId = connectorModule.getModuleId() + "RA";
                    }
                    resourceAdapterIds.add(resourceAdapterId);
                }

                OutboundResourceAdapter outbound = resourceAdapter.getOutboundResourceAdapter();
                if (outbound != null) {
                    for (ConnectionDefinition connection : outbound.getConnectionDefinition()) {
                        String type = connection.getConnectionFactoryInterface();

                        String resourceId;
                        if (connection.getId() != null) {
                            resourceId = connection.getId();
                        } else if (outbound.getConnectionDefinition().size() == 1) {
                            resourceId = connectorModule.getModuleId();
                        } else {
                            resourceId = connectorModule.getModuleId() + "-" + type;
                        }

                        List<String> resourceIds = resourceIdsByType.get(type);
                        if (resourceIds == null) {
                            resourceIds = new ArrayList<String>();
                            resourceIdsByType.put(type, resourceIds);
                        }
                        resourceIds.add(resourceId);
                    }
                }

                InboundResource inbound = resourceAdapter.getInboundResourceAdapter();
                if (inbound != null) {
                    for (MessageListener messageListener : inbound.getMessageAdapter().getMessageListener()) {
                        String type = messageListener.getMessageListenerType();

                        String containerId;
                        if (messageListener.getId() != null) {
                            containerId = messageListener.getId();
                        } else if (inbound.getMessageAdapter().getMessageListener().size() == 1) {
                            containerId = connectorModule.getModuleId();
                        } else {
                            containerId = connectorModule.getModuleId() + "-" + type;
                        }

                        List<String> containerIds = containerIdsByType.get(type);
                        if (containerIds == null) {
                            containerIds = new ArrayList<String>();
                            containerIdsByType.put(type, containerIds);
                        }
                        containerIds.add(containerId);
                    }
                }

                for (AdminObject adminObject : resourceAdapter.getAdminObject()) {
                    String type = adminObject.getAdminObjectInterface();

                    String resourceEnvId;
                    if (adminObject.getId() != null) {
                        resourceEnvId = adminObject.getId();
                    } else if (resourceAdapter.getAdminObject().size() == 1) {
                        resourceEnvId = connectorModule.getModuleId();
                    } else {
                        resourceEnvId = connectorModule.getModuleId() + "-" + type;
                    }

                    List<String> resourceEnvIds = resourceEnvIdsByType.get(type);
                    if (resourceEnvIds == null) {
                        resourceEnvIds = new ArrayList<String>();
                        resourceEnvIdsByType.put(type, resourceEnvIds);
                    }
                    resourceEnvIds.add(resourceEnvId);
                }
            }

        }

        public List<String> getResourceIds(String type) {
            if (type == null) {
                List<String> allResourceIds = new ArrayList<String>();
                for (List<String> resourceIds : resourceIdsByType.values()) {
                    allResourceIds.addAll(resourceIds);
                }
                return allResourceIds;
            }

            List<String> resourceIds = resourceIdsByType.get(type);
            if (resourceIds != null) {
                return resourceIds;
            }
            return Collections.emptyList();
        }

        public List<String> getResourceEnvIds(String type) {
            if (type != null) {
                List<String> resourceIds = resourceEnvIdsByType.get(type);
                if (resourceIds != null) {
                    return resourceIds;
                }
            }
            return Collections.emptyList();
        }
    }
}
TOP

Related Classes of org.apache.openejb.config.AutoConfig

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.