FileDocCategorySizeDatePackage
ResourceAdapterAdminServiceImpl.javaAPI DocGlassfish v2 API27365Fri May 04 22:34:24 BST 2007com.sun.enterprise.connectors

ResourceAdapterAdminServiceImpl.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.connectors;

import com.sun.enterprise.connectors.util.ResourcesUtil;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.*;
import javax.naming.*;
import com.sun.enterprise.connectors.util.*;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.util.*;
import com.sun.enterprise.server.*;
import com.sun.enterprise.*;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.config.*;
import com.sun.enterprise.util.ConnectorClassLoader;


/**
 * This is resource adapter admin service. It creates, deletes Resource adapter
 * and also the resource adapter configuration updation.
 * 
 * @author Binod P.G, Srikanth P and Aditya Gore
 */

public class ResourceAdapterAdminServiceImpl
    extends ConnectorServiceImpl
    implements ConnectorAdminService {

    private JmsRaMapping ramap= null;

    private int resource_adapter_shutdown_timeout = 0;

    //Resource-Adapter-Name vs Boolean(shutdownStatus)
    private final Hashtable raShutdownStatusTable = new Hashtable();
    
    /**
	 * Default constructor
	 */

    public ResourceAdapterAdminServiceImpl() {
        super();
        ramap= new JmsRaMapping();
    }


    /**
	 * Destroys/deletes the Active resource adapter object from the connector
	 * container. Active resource adapter abstracts the rar deployed. It checks
	 * whether any resources (pools and connector resources) are still present.
	 * If they are present the deletion fails and all the objects and
	 * datastructures pertaining to to the resource adapter are left untouched.
	 * 
	 * @param moduleName
	 *                     Name of the rarModule to destroy/delete
	 * @throws ConnectorRuntimeException
	 *                      if the deletion fails
	 */

    public void destroyActiveResourceAdapter(String moduleName)
        throws ConnectorRuntimeException {
        destroyActiveResourceAdapter(moduleName, false);

    }

    /**
	 * Destroys/deletes the Active resource adapter object from the connector
	 * container. Active resource adapter abstracts the rar deployed. It checks
	 * whether any resources (pools and connector resources) are still present.
	 * If they are present and cascade option is false the deletion fails and
	 * all the objects and datastructures pertaining to the resource adapter
	 * are left untouched. If cascade option is true, even if resources are
	 * still present, they are also destroyed with the active resource adapter
	 * 
	 * @param moduleName
	 *                     Name of the rarModule to destroy/delete
	 * @param cascade
	 *                     If true all the resources belonging to the rar are destroyed
	 *                     recursively. If false, and if resources pertaining to
	 *                     resource adapter /rar are present deletetion is failed. Then
	 *                     cascade should be set to true or all the resources have to
	 *                     deleted explicitly before destroying the rar/Active resource
	 *                     adapter.
	 * @throws ConnectorRuntimeException
	 *                      if the deletion fails
	 */

    public void destroyActiveResourceAdapter(
        String moduleName,
        boolean cascade)
        throws ConnectorRuntimeException {

        ResourcesUtil resutil= ResourcesUtil.createInstance();
        if (resutil == null) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Failed to get ResourcesUtil object");
            _logger.log(Level.SEVERE, "resourcesutil_get_failure", moduleName);
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        }
        Object[][] resources= null;
        try {
            resources= resutil.getAllConnectorResourcesForRar(moduleName);
        } catch (ConfigException ce) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Failed to get Resources from domain.xml");
            ce.initCause(ce);
            _logger.log(
                Level.SEVERE,
                "rardeployment.resources_list_error",
                cre);
            throw cre;
        }

        boolean errrorOccured= false;

        com.sun.enterprise.config.serverbeans.ConnectorConnectionPool ccp= null;
        if (cascade == true && resources != null) {
            for (int i= 0;
                resources[0] != null && i < resources[0].length;
                ++i) {
                ccp=
                    (com
                        .sun
                        .enterprise
                        .config
                        .serverbeans
                        .ConnectorConnectionPool) resources[0][i];
                try {
                    getRuntime().deleteConnectorConnectionPool(
                        ccp.getName(),
                        cascade);
                } catch (ConnectorRuntimeException cre) {
                    errrorOccured= true;
                }
            }
            for (int i= 0;
                resources[2] != null && i < resources[2].length;
                ++i) {
                try {
                    AdminObjectResource aor=
                        (AdminObjectResource) resources[2][i];
                    getRuntime().deleteAdminObject(aor.getJndiName());
                } catch (ConnectorRuntimeException cre) {
                    errrorOccured= true;
                }
            }
        } else if (
            (resources[0] != null && resources[0].length != 0)
                || (resources[1] != null && resources[1].length != 0)
                || (resources[2] != null && resources[2].length != 0)) {
            _logger.log(
                Level.SEVERE,
                "rardeployment.pools_and_resources_exist",
                moduleName);
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Error: Connector Connection Pools/resources exist.");
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        }

        if (!stopAndRemoveActiveResourceAdapter(moduleName)) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Failed to remove Active Resource Adapter");
            _logger.log(
                Level.SEVERE,
                "rardeployment.ra_removal_registry_failure",
                moduleName);
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        }

        //Embedded RARs are handled by the application classloader
        if (!(ResourcesUtil.createInstance().belongToEmbeddedRar(moduleName))) {
			ConnectorClassLoader.getInstance().removeResourceAdapter(moduleName);
        }

        
        if (errrorOccured == true) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Failed to remove all connector resources/pools");
            _logger.log(
                Level.SEVERE,
                "rardeployment.ra_resource_removal",
                moduleName);
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        }
    }

    /**
	 * Creates Active resource Adapter which abstracts the rar module. During
	 * the creation of ActiveResourceAdapter, default pools and resources also
	 * are created.
	 * 
	 * @param connectorDescriptor
	 *                     object which abstracts the connector deployment descriptor
	 *                     i.e rar.xml and sun-ra.xml.
	 * @param moduleName
	 *                     Name of the module
	 * @param moduleDir
	 *                     Directory where rar module is exploded.
	 * @param writeSunDescriptor
	 *                     If true write the sun-ra.xml props to domain.xml and if false
	 *                     it doesnot write to domain.xml
	 * @throws ConnectorRuntimeException
	 *                      if creation fails.
	 */

    public synchronized void createActiveResourceAdapter(
        ConnectorDescriptor connectorDescriptor,
        String moduleName,
        String moduleDir)
        throws ConnectorRuntimeException {
        _logger.fine("ResourceAdapterAdminServiceImpl :: createActiveRA " 
                        + moduleName + " at " + moduleDir  );

        ActiveResourceAdapter activeResourceAdapter=
            _registry.getActiveResourceAdapter(moduleName);
        if (activeResourceAdapter != null) {
            _logger.log(
                Level.FINE,
                "rardeployment.resourceadapter.already.started",
                moduleName);
            return;
        }

        ClassLoader loader= null;
        try {
            loader= connectorDescriptor.getClassLoader();
        } catch (Exception ex) {
            _logger.log(
                Level.FINE,
                "No classloader available with connector descriptor");
            loader= null;
        }
        ModuleDescriptor moduleDescriptor= null;
        Application application = null;
        _logger.fine("ResourceAdapterAdminServiceImpl :: createActiveRA " 
                        + moduleName + " at " + moduleDir  + " loader :: " + loader);
        if (loader == null) {
            if (environment == SERVER) {
                ConnectorClassLoader.getInstance().addResourceAdapter(moduleName, moduleDir);
                loader = ConnectorClassLoader.getInstance();
                if (loader == null) {
                    ConnectorRuntimeException cre=
                        new ConnectorRuntimeException("Failed to obtain the class loader");
                    _logger.log(
                        Level.SEVERE,
                        "rardeployment.failed_toget_classloader");
                    _logger.log(Level.SEVERE, "", cre);
                    throw cre;
                }
            }
        } else {
            connectorDescriptor.setClassLoader(null);
            moduleDescriptor= connectorDescriptor.getModuleDescriptor();
            application = connectorDescriptor.getApplication();
            connectorDescriptor.setModuleDescriptor(null);
            connectorDescriptor.setApplication(null);
        }
        try {
            activeResourceAdapter=
                ActiveRAFactory.createActiveResourceAdapter(
                    connectorDescriptor,
                    moduleName,
                    loader);
            _logger.fine("ResourceAdapterAdminServiceImpl :: createActiveRA " + 
                            moduleName + " at " + moduleDir  + 
                            " ADDING to registry " + activeResourceAdapter);
            _registry.addActiveResourceAdapter(
                moduleName,
                activeResourceAdapter);
            _logger.fine("ResourceAdapterAdminServiceImpl:: createActiveRA " + 
                            moduleName + " at " + moduleDir  
                            + " env =server ? " + (environment==SERVER));
            
            if (environment == SERVER) {
                activeResourceAdapter.setup();
                String descriptorJNDIName = ConnectorAdminServiceUtils.
                            getReservePrefixedJNDINameForDescriptor(moduleName);
                _logger.fine("ResourceAdapterAdminServiceImpl :: createActiveRA " 
                                + moduleName + " at " + moduleDir  
                                + " publishing descriptor " +  descriptorJNDIName);
                //Update RAConfig in Connector Descriptor and bind in JNDI
                //so that ACC clients could use RAConfig
                updateRAConfigInDescriptor(connectorDescriptor, moduleName);
                Switch.getSwitch().getNamingManager().publishObject(
                    descriptorJNDIName, connectorDescriptor, true);
                String securityWarningMessage=
                    getRuntime().getSecurityPermissionSpec(moduleName);
                // To i18N.
                if (securityWarningMessage != null) {
                    _logger.log(Level.WARNING, securityWarningMessage);
                }
            }

        } catch (NullPointerException npEx) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Error in creating active RAR");
            cre.initCause(npEx);
            _logger.log(
                Level.SEVERE,
                "rardeployment.nullPointerException",
                moduleName);
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        } catch (NamingException ne) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Error in creating active RAR");
            cre.initCause(ne);
            _logger.log(Level.SEVERE, "rardeployment.jndi_publish_failure");
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        } finally {
            if (moduleDescriptor != null) {
                connectorDescriptor.setModuleDescriptor(moduleDescriptor);
                connectorDescriptor.setApplication(application);
                connectorDescriptor.setClassLoader(loader);
            }
        }
    }

    /*
     * Updates the connector descriptor of the connector module, with the 
     * contents of a resource adapter config if specified.
     * 
     * This modified ConnectorDescriptor is then bound to JNDI so that ACC 
     * clients while configuring a non-system RAR could get the correct merged
     * configuration. Any updates to resource-adapter config while an ACC client
     * is in use is not transmitted to the client dynamically. All such changes 
     * would be visible on ACC client restart. 
     */
    private void updateRAConfigInDescriptor(ConnectorDescriptor connectorDescriptor, 
                    String moduleName) {

        ResourceAdapterConfig raConfig = 
            ConnectorRegistry.getInstance().getResourceAdapterConfig(moduleName);

        ElementProperty[] raConfigProps = null;
        if(raConfig != null) {
            raConfigProps = raConfig.getElementProperty();
        }

        _logger.fine("current RAConfig In Descriptor " + connectorDescriptor.getConfigProperties());

        if(raConfigProps != null) {
            Set mergedProps = ConnectorDDTransformUtils.mergeProps(
                    raConfigProps, connectorDescriptor.getConfigProperties());
            Set actualProps = connectorDescriptor.getConfigProperties();
            actualProps.clear();
            actualProps.addAll(mergedProps);
            _logger.fine("updated RAConfig In Descriptor " + connectorDescriptor.getConfigProperties());
        } 

    }


    /**
	 * Creates Active resource Adapter which abstracts the rar module. During
	 * the creation of ActiveResourceAdapter, default pools and resources also
	 * are created.
	 * 
	 * @param moduleDir
	 *                     Directory where rar module is exploded.
	 * @param moduleName
	 *                     Name of the module
	 * @param writeSunDescriptor
	 *                     If true write the sun-ra.xml props to domain.xml and if false
	 *                     it doesnot write to domain.xml
	 * @throws ConnectorRuntimeException
	 *                      if creation fails.
	 */

    public synchronized void createActiveResourceAdapter(
        String moduleDir,
        String moduleName)
        throws ConnectorRuntimeException {

        ActiveResourceAdapter activeResourceAdapter=
            _registry.getActiveResourceAdapter(moduleName);
        if (activeResourceAdapter != null) {
            _logger.log(
                Level.FINE,
                "rardeployment.resourceadapter.already.started",
                moduleName);
            return;
        }

        if (ResourcesUtil.createInstance().belongToSystemRar(moduleName)) {
            moduleDir = Switch.getSwitch().getResourceInstaller().
                        getSystemModuleLocation(moduleName);
        }

        ConnectorDescriptor connectorDescriptor= null;
        connectorDescriptor=
            ConnectorDDTransformUtils.getConnectorDescriptor(moduleDir);
        if (connectorDescriptor == null) {
            ConnectorRuntimeException cre=
                new ConnectorRuntimeException("Failed to obtain the connectorDescriptor");
            _logger.log(
                Level.SEVERE,
                "rardeployment.connector_descriptor_notfound",
                moduleName);
            _logger.log(Level.SEVERE, "", cre);
            throw cre;
        }
        createActiveResourceAdapter(
            connectorDescriptor,
            moduleName,
            moduleDir);
    }

    /**
	 * The ActiveResourceAdapter object which abstract the rar module is
	 * recreated in the connector container/registry. All the pools and
	 * resources are killed. But the infrastructure to create the pools and and
	 * resources is untouched. Only the actual pool is killed.
	 * 
	 * @param moduleName
	 *                     rar module Name.
	 * @throws ConnectorRuntimeException
	 *                      if recreation fails.
	 */

    public void reCreateActiveResourceAdapter(String moduleName)
        throws ConnectorRuntimeException {
        String moduleDir= null;
        if (isRarDeployed(moduleName)) {
            getRuntime().killAllPools(moduleName);
            stopAndRemoveActiveResourceAdapter(moduleName);
            moduleDir= ResourcesUtil.createInstance().getLocation(moduleName);
            createActiveResourceAdapter(moduleDir, moduleName);
        } else {
            moduleDir= ResourcesUtil.createInstance().getLocation(moduleName);
            if (moduleDir != null) {
                createActiveResourceAdapter(moduleDir, moduleName);
            }
        }
    }

    /**
	 * Stops the resourceAdapter and removes it from connector container/
	 * registry.
	 * 
	 * @param moduleName
	 *                     Rarmodule name.
	 * @return true it is successful stop and removal of ActiveResourceAdapter
	 *                false it stop and removal fails.
	 */

    public boolean stopAndRemoveActiveResourceAdapter(String moduleName) {

        ActiveResourceAdapter acr= null;
        if (moduleName != null) {
            acr= _registry.getActiveResourceAdapter(moduleName);
        }
        if (acr != null) {
            acr.destroy();
            boolean ret= _registry.removeActiveResourceAdapter(moduleName);
            return ret;
        }
        return false;
    }

    public void addResourceAdapterConfig(
        String rarName,
        ResourceAdapterConfig raConfig)
        throws ConnectorRuntimeException {
        if (rarName != null && raConfig != null) {
            _registry.addResourceAdapterConfig(rarName, raConfig);
            reCreateActiveResourceAdapter(rarName);
        }
    }

    /**
	 * Delete the resource adapter configuration to the connector registry
	 * 
	 * @param rarName
	 *                     rarmodule
	 */

    public void deleteResourceAdapterConfig(String rarName) {
        if (rarName != null) {
            _registry.removeResourceAdapterConfig(rarName);
        }
    }

    public static boolean isJmsRa() {
        //return System.getProperty("jms.ra").equals("true");
        return true;
    }

    public JmsRaMapping getJmsRaMapping() {
        return ramap;
    }

    /**
	 * Checks if the rar module is already reployed.
	 * 
	 * @param moduleName
	 *                     Rarmodule name
	 * @return true if it is already deployed. false if it is not deployed.
	 */

    public boolean isRarDeployed(String moduleName) {

        ActiveResourceAdapter activeResourceAdapter=
            _registry.getActiveResourceAdapter(moduleName);
        if (activeResourceAdapter != null) {
            return true;
        } else {
            return false;
        }
    }
    
    /**
     * Calls the stop method for all J2EE Connector 1.5 spec compliant RARs
     */
    public void stopAllActiveResourceAdapters() {
        try {
            resource_adapter_shutdown_timeout = 
                ResourcesUtil.createInstance().getShutdownTimeout();
        } catch (ConnectorRuntimeException e) {
            _logger.log(Level.WARNING, "error_reading_connectorservice_elt", e);
            //Going ahead with the default timeout value 
            resource_adapter_shutdown_timeout 
            = ConnectorConstants.DEFAULT_RESOURCE_ADAPTER_SHUTDOWN_TIMEOUT;
        }
        ActiveResourceAdapter[] resourceAdapters = 
            ConnectorRegistry.getInstance().getAllActiveResourceAdapters();

        //find all Connector 1.5 Spec Compliant resource adapters
        ArrayList resourceAdaptersToStop = new ArrayList();
        for (int i = 0; i < resourceAdapters.length; i++) {
            if (resourceAdapters[i] instanceof ActiveInboundResourceAdapter){
                _logger.log(Level.FINE, "Connector 1.5 spec compliant RA", 
                        resourceAdapters[i].getModuleName());
                raShutdownStatusTable.put(
                      resourceAdapters[i].getModuleName(), new Boolean(false));
                resourceAdaptersToStop.add(resourceAdapters[i]);
            } else {
                _logger.log(Level.FINE, "Connector 1.0 spec compliant RA", 
                        resourceAdapters[i].getModuleName());
            }
        }
        ActiveResourceAdapter[] raToStop = (ActiveResourceAdapter[])
            resourceAdaptersToStop.toArray(new ActiveResourceAdapter[]{});
        sendStopToAllResourceAdapters(raToStop);
    }

    
    
    /**
     * Calls the stop method for all J2EE Connector 1.5 spec compliant RARs
     * @param resourceAdapters
     */
    private void sendStopToAllResourceAdapters(ActiveResourceAdapter[] 
                                                       resourceAdaptersToStop) {
        //Only J2EE Connector 1.5 compliant RAs needs to be stopped
        int numberOfResourceAdaptersToStop = 0;

        numberOfResourceAdaptersToStop = resourceAdaptersToStop.length;
       
        Thread[] raShutDownThreads = new Thread[numberOfResourceAdaptersToStop];
        Thread[] joinerThreads = new Thread[numberOfResourceAdaptersToStop];

        //Start ResourceAdapter shutdownthreads and then 
        //Start Threads to join the resource adapter shutdownThreads
        for (int i = 0; i < numberOfResourceAdaptersToStop; i++) {
            
            _logger.log(Level.FINE, "Starting RA shutdown thread for " 
                    + ( (ActiveInboundResourceAdapter)resourceAdaptersToStop[i] )
                            .getModuleName() );
            Thread rast = new RAShutdownThread(
                  (ActiveInboundResourceAdapter)resourceAdaptersToStop[i]);
            raShutDownThreads[i] = rast;
            rast.start();
            
            _logger.log(Level.FINE, "Starting Thread to join time-out " +
                    "shutdown of " + 
                    ( ( ActiveInboundResourceAdapter )resourceAdaptersToStop[i]).getModuleName() );
            Thread joiner = new JoinerThread(raShutDownThreads[i]);
            joinerThreads[i] = joiner;
            joiner.start();
        }
        
        //Join all the Joiner threads
        for (int i = 0; i < joinerThreads.length; i++) {
            try {
                _logger.log(Level.FINE, "Joining joiner thread of " 
                       + ((ActiveResourceAdapter)resourceAdaptersToStop[i])
                                .getModuleName() );
                joinerThreads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        _logger.log(Level.FINE, "stop() Complete for all " +
                "active 1.5 compliant RARs");

        //Log the status of the stop() call
        if (resourceAdaptersToStop.length != 0) {
            _logger.log(Level.FINE, "resource_adapter_stop_status");
        }
        
        for (Iterator iter = raShutdownStatusTable.keySet().iterator(); 
                                            iter.hasNext();) {
            String raName = (String) iter.next();
            if(((Boolean)raShutdownStatusTable.get(raName)).booleanValue()) {
                _logger.log(Level.INFO, "ra.stop-successful", raName);
            } else {
                _logger.log(Level.WARNING, "ra.stop-unsuccessful", raName);
            }
        }
    }

    private class JoinerThread extends Thread {
        private Thread threadToJoin;
        
        public JoinerThread(Thread threadToJoin) {
            this.threadToJoin = threadToJoin;
        }
        
        public void run() {
            try {
                this.threadToJoin.join(ResourceAdapterAdminServiceImpl.this.
                        resource_adapter_shutdown_timeout * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private class RAShutdownThread extends Thread {
        private ActiveInboundResourceAdapter ra;

        public RAShutdownThread(ActiveInboundResourceAdapter ratoBeShutDown){
            super();
            this.ra = ratoBeShutDown;
            //This thread is a daemon thread
            this.setDaemon(true);
        }

        public void run() {
            _logger.log(Level.FINE, "Calling" + ra.getModuleName() 
                    + " shutdown ");
            this.ra.destroy();
            ResourceAdapterAdminServiceImpl.this.raShutdownStatusTable.put(
                    ra.getModuleName(), new Boolean(true));
        }
    }    

}