Package org.apache.avalon.phoenix.components.deployer

Source Code of org.apache.avalon.phoenix.components.deployer.DefaultDeployer

/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.avalon.phoenix.components.deployer;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.excalibur.io.FileUtil;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.phoenix.components.deployer.installer.Installation;
import org.apache.avalon.phoenix.components.deployer.installer.InstallationException;
import org.apache.avalon.phoenix.components.deployer.installer.Installer;
import org.apache.avalon.phoenix.interfaces.Application;
import org.apache.avalon.phoenix.interfaces.ClassLoaderManager;
import org.apache.avalon.phoenix.interfaces.ConfigurationRepository;
import org.apache.avalon.phoenix.interfaces.ConfigurationValidator;
import org.apache.avalon.phoenix.interfaces.Deployer;
import org.apache.avalon.phoenix.interfaces.DeployerMBean;
import org.apache.avalon.phoenix.interfaces.DeploymentException;
import org.apache.avalon.phoenix.interfaces.Kernel;
import org.apache.avalon.phoenix.interfaces.LogManager;
import org.apache.avalon.phoenix.metadata.BlockListenerMetaData;
import org.apache.avalon.phoenix.metadata.BlockMetaData;
import org.apache.avalon.phoenix.metadata.SarMetaData;
import org.apache.avalon.phoenix.metainfo.BlockDescriptor;
import org.apache.avalon.phoenix.tools.assembler.Assembler;
import org.apache.avalon.phoenix.tools.assembler.AssemblyException;
import org.apache.avalon.phoenix.tools.configuration.ConfigurationBuilder;
import org.apache.avalon.phoenix.tools.verifier.SarVerifier;
import org.apache.avalon.phoenix.tools.verifier.VerifyException;

/**
* Deploy .sar files into a kernel using this class.
*
* @author <a href="mailto:peter at apache.org">Peter Donald</a>
*/
public class DefaultDeployer
    extends AbstractLogEnabled
    implements Deployer, Parameterizable, Serviceable, Initializable, Disposable, DeployerMBean
{
    private static final Resources REZ =
        ResourceManager.getPackageResources( DefaultDeployer.class );

    private final Assembler m_assembler = new Assembler();
    private final SarVerifier m_verifier = new SarVerifier();
    private final Installer m_installer = new Installer();
    private final Map m_installations = new Hashtable();
    private LogManager m_logManager;
    private Kernel m_kernel;
    private ConfigurationRepository m_repository;
    private ClassLoaderManager m_classLoaderManager;
    private ConfigurationValidator m_validator;

    /**
     * The directory which is used as the base for
     * extracting all temporary files from archives. It is
     * expected that the temporary files will be deleted when
     * the .sar file is undeployed.
     */
    private File m_baseWorkDirectory;

    /**
     * The base directory in which applications are deployed.
     */
    private File m_baseDirectory;

    /**
     * Retrieve parameter that specifies work directory.
     *
     * @param parameters the parameters to read
     * @throws ParameterException if invlaid work directory
     */
    public void parameterize( final Parameters parameters )
        throws ParameterException
    {
        final String phoenixHome = parameters.getParameter( "phoenix.home" );
        final String defaultWorkDir = phoenixHome + File.separator + "work";
        final String defaultAppsDir = phoenixHome + File.separator + "apps";
        final String rawWorkDir =
            parameters.getParameter( "phoenix.work.dir", defaultWorkDir );
        final String rawAppsDir =
            parameters.getParameter( "phoenix.apps.dir", defaultAppsDir );

        final File workDir = new File( rawWorkDir );
        try
        {
            m_baseWorkDirectory = workDir.getCanonicalFile();
        }
        catch( final IOException ioe )
        {
            m_baseWorkDirectory = workDir.getAbsoluteFile();
        }

        final File appsDir = new File( rawAppsDir );
        try
        {
            m_baseDirectory = appsDir.getCanonicalFile();
        }
        catch( final IOException ioe )
        {
            m_baseDirectory = appsDir.getAbsoluteFile();
        }
    }

    /**
     * Retrieve relevant services needed to deploy.
     *
     * @param serviceManager the ComponentManager
     * @throws ServiceException if an error occurs
     */
    public void service( final ServiceManager serviceManager )
        throws ServiceException
    {
        m_kernel = (Kernel)serviceManager.lookup( Kernel.ROLE );
        m_repository = (ConfigurationRepository)serviceManager.
            lookup( ConfigurationRepository.ROLE );
        m_classLoaderManager = (ClassLoaderManager)serviceManager.
            lookup( ClassLoaderManager.ROLE );
        m_logManager = (LogManager)serviceManager.lookup( LogManager.ROLE );
        m_validator = (ConfigurationValidator)serviceManager.lookup( ConfigurationValidator.ROLE );
    }

    public void initialize()
        throws Exception
    {
        initWorkDirectory();
        try
        {
            FileUtil.cleanDirectory( m_baseWorkDirectory );
        }
        catch( final IOException ioe )
        {
            final String message =
                REZ.getString( "nodelete-workdir.error",
                               m_baseWorkDirectory,
                               ioe.getMessage() );
            getLogger().warn( message, ioe );
        }

        setupLogger( m_installer );
        setupLogger( m_assembler );
        setupLogger( m_verifier );
        m_installer.setBaseDirectory( m_baseDirectory );
        m_installer.setBaseWorkDirectory( m_baseWorkDirectory );
    }

    /**
     * Dispose the dpeloyer which effectively means undeploying
     * all the currently deployed apps.
     */
    public void dispose()
    {
        final Set set = m_installations.keySet();
        final String[] applications =
            (String[])set.toArray( new String[ set.size() ] );
        for( int i = 0; i < applications.length; i++ )
        {
            final String name = applications[ i ];
            try
            {
                undeploy( name );
            }
            catch( final DeploymentException de )
            {
                final String message =
                    REZ.getString( "deploy.undeploy-indispose.error",
                                   name,
                                   de.getMessage() );
                getLogger().error( message, de );
            }
        }
    }

    /**
     * Redeploy an application.
     *
     * @param name the name of deployment
     * @throws DeploymentException if an error occurs
     */
    public void redeploy( final String name )
        throws DeploymentException
    {
        final Installation installation =
            (Installation)m_installations.get( name );
        if( null == installation )
        {
            final String message =
                REZ.getString( "deploy.no-deployment.error", name );
            throw new DeploymentException( message );
        }
        try
        {
            final URL location = installation.getSource().toURL();
            undeploy( name );
            deploy( name, location );
        }
        catch( final Exception e )
        {
            throw new DeploymentException( e.getMessage(), e );
        }
    }

    /**
     * Undeploy an application.
     *
     * @param name the name of deployment
     * @throws DeploymentException if an error occurs
     */
    public void undeploy( final String name )
        throws DeploymentException
    {
        final Installation installation =
            (Installation)m_installations.remove( name );
        if( null == installation )
        {
            final String message =
                REZ.getString( "deploy.no-deployment.error", name );
            throw new DeploymentException( message );
        }
        try
        {
            final Application application = m_kernel.getApplication( name );
            final String[] blocks = application.getBlockNames();

            m_kernel.removeApplication( name );

            for( int i = 0; i < blocks.length; i++ )
            {
                //remove configuration and schema from repository and validator
                m_repository.removeConfiguration( name, blocks[ i ] );
                m_validator.removeSchema( name, blocks[ i ] );
            }

            m_installer.uninstall( installation );
        }
        catch( final Exception e )
        {
            throw new DeploymentException( e.getMessage(), e );
        }
    }

    /**
     * Deploy an application from an installation.
     *
     * @param name the name of application
     * @param sarURL the location to deploy from represented as String
     * @throws DeploymentException if an error occurs
     */
    public void deploy( final String name, final String sarURL )
        throws DeploymentException
    {
        try
        {
            try
            {
                deploy( name, new URL( sarURL ) );
            }
            catch( DeploymentException e )
            {
                e.printStackTrace();
            }
        }
        catch( MalformedURLException mue )
        {
            mue.printStackTrace();
            throw new DeploymentException( mue.getMessage(), mue );
        }
    }

    /**
     * Deploy an application from an installation.
     *
     * @param name the name of application
     * @param location the location to deploy from
     * @throws DeploymentException if an error occurs
     */
    public void deploy( final String name, final URL location )
        throws DeploymentException
    {
        if( m_installations.containsKey( name ) )
        {
            final String message =
                REZ.getString( "deploy.already-deployed.error",
                               name );
            throw new DeploymentException( message );
        }

        /*
         * Clear all the reosurces out of ResourceManager cache
         * so that reloaded applications will have their i18n bundles
         * reloaded.
         */
        ResourceManager.clearResourceCache();

        Installation installation = null;
        boolean success = false;
        try
        {
            //m_baseWorkDirectory
            installation = m_installer.install( name, location );

            final Configuration config = getConfigurationFor( installation.getConfig() );
            final Configuration environment = getConfigurationFor( installation.getEnvironment() );
            final Configuration assembly = getConfigurationFor( installation.getAssembly() );

            final File directory = installation.getDirectory();

            final ClassLoader classLoader =
                m_classLoaderManager.createClassLoader( environment,
                                                        installation.getSource(),
                                                        installation.getDirectory(),
                                                        installation.getWorkDirectory(),
                                                        installation.getClassPath() );
            //assemble all the blocks for application
            final SarMetaData metaData =
                m_assembler.assembleSar( name, assembly, directory, classLoader );

            storeConfigurationSchemas( metaData, classLoader );

            verify( metaData, classLoader );

            //Setup configuration for all the applications blocks
            setupConfiguration( metaData, config.getChildren() );

            final Configuration logs = environment.getChild( "logs" );
            final Logger logger =
                m_logManager.createHierarchy( metaData, logs, classLoader );

            //Finally add application to kernel
            m_kernel.addApplication( metaData,
                                     installation.getWorkDirectory(),
                                     classLoader,
                                     logger,
                                     environment );

            m_installations.put( metaData.getName(), installation );

            final String message =
                REZ.getString( "deploy.notice.sar.add",
                               metaData.getName(),
                               Arrays.asList( installation.getClassPath() ) );
            getLogger().debug( message );
            success = true;
        }
        catch( final DeploymentException de )
        {
            throw de;
        }
        catch( final AssemblyException ae )
        {
            throw new DeploymentException( ae.getMessage(), ae );
        }
        catch( final Exception e )
        {
            //From classloaderManager/kernel
            throw new DeploymentException( e.getMessage(), e );
        }
        finally
        {
            if( !success && null != installation )
            {
                try
                {
                    m_installer.uninstall( installation );
                }
                catch( final InstallationException ie )
                {
                    getLogger().error( ie.getMessage(), ie );
                }
            }
        }
    }

    /**
     * Verify that the application conforms to our requirements.
     *
     * @param metaData the application metaData
     * @param classLoader the ClassLoader associated with app
     * @throws VerifyException on error
     */
    protected void verify( final SarMetaData metaData,
                           final ClassLoader classLoader )
        throws VerifyException
    {
        m_verifier.verifySar( metaData, classLoader );
    }

    /**
     * Store the configuration schemas for this application
     *
     * @param metaData the application metaData
     * @throws DeploymentException upon invalid schema
     */
    private void storeConfigurationSchemas( final SarMetaData metaData, ClassLoader classLoader )
        throws DeploymentException
    {
        final BlockMetaData[] blocks = metaData.getBlocks();
        int i = 0;

        try
        {
            for( i = 0; i < blocks.length; i++ )
            {
                final String name = blocks[ i ].getName();
                final BlockDescriptor descriptor = blocks[ i ].getBlockInfo().getBlockDescriptor();
                final String type = descriptor.getSchemaType();

                if( null != type )
                {
                    m_validator.addSchema( metaData.getName(),
                                           name,
                                           type,
                                           getConfigurationSchemaURL( name,
                                                                      descriptor.getImplementationKey(),
                                                                      classLoader )
                    );
                }
            }
        }
        catch( ConfigurationException e )
        {
            //uh-oh, bad schema bad bad!
            final String message = REZ.getString( "deploy.error.config.schema.invalid",
                                                  blocks[ i ].getName() );

            //back out any schemas that we have already stored for this app
            while( --i >= 0 )
            {
                m_validator.removeSchema( metaData.getName(),
                                          blocks[ i ].getName() );
            }

            throw new DeploymentException( message, e );
        }
    }

    private String getConfigurationSchemaURL( final String name,
                                              final String classname,
                                              final ClassLoader classLoader )
        throws DeploymentException
    {
        final String resourceName = classname.replace( '.', '/' ) + "-schema.xml";

        final URL resource = classLoader.getResource( resourceName );
        if( null == resource )
        {

            throw new DeploymentException( REZ.getString( "deploy.error.config.schema.missing",
                                                          name,
                                                          resourceName ) );
        }
        else
        {
            return resource.toString();
        }
    }

    /**
     * Helper method to load configuration data.
     *
     * @param location the location of configuration data as a url
     * @return the Configuration
     * @throws DeploymentException if an error occurs
     */
    private Configuration getConfigurationFor( final String location )
        throws DeploymentException
    {
        try
        {
            return ConfigurationBuilder.build( location );
        }
        catch( final Exception e )
        {
            final String message = REZ.getString( "deploy.error.config.create", location );
            getLogger().error( message, e );
            throw new DeploymentException( message, e );
        }
    }

    /**
     * Setup Configuration for all the Blocks/BlockListeners in Sar.
     *
     * @param metaData the SarMetaData.
     * @param configurations the block configurations.
     * @throws DeploymentException if an error occurs
     */
    private void setupConfiguration( final SarMetaData metaData,
                                     final Configuration[] configurations )
        throws DeploymentException
    {
        final String application = metaData.getName();

        for( int i = 0; i < configurations.length; i++ )
        {
            final Configuration configuration = configurations[ i ];
            final String name = configuration.getName();
            final boolean listener = hasBlockListener( name, metaData.getListeners() );

            if( !hasBlock( name, metaData.getBlocks() ) && !listener )
            {
                final String message =
                    REZ.getString( "deploy.error.extra.config",
                                   name );
                throw new DeploymentException( message );
            }

            try
            {
                //No way to validate listener configuration--yet
                if( listener || m_validator.isFeasiblyValid( application, name, configuration ) )
                {
                    m_repository.storeConfiguration( application,
                                                     name,
                                                     configuration );
                }
                else
                {
                    final String message = REZ.getString( "deploy.error.config.invalid", name );

                    throw new DeploymentException( message );
                }
            }
            catch( final ConfigurationException ce )
            {
                throw new DeploymentException( ce.getMessage(), ce );
            }
        }
    }

    /**
     * Return true if specified array contains entry with specified name.
     *
     * @param name the blocks name
     * @param blocks the set of BlockMetaData objects to search
     * @return true if block present, false otherwise
     */
    private boolean hasBlock( final String name, final BlockMetaData[] blocks )
    {
        for( int i = 0; i < blocks.length; i++ )
        {
            final String other = blocks[ i ].getName();
            if( other.equals( name ) )
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Return true if specified array contains entry with specified name.
     *
     * @param name the blocks name
     * @param listeners the set of BlockListenerMetaData objects to search
     * @return true if block present, false otherwise
     */
    private boolean hasBlockListener( final String name,
                                      final BlockListenerMetaData[] listeners )
    {
        for( int i = 0; i < listeners.length; i++ )
        {
            if( listeners[ i ].getName().equals( name ) )
            {
                return true;
            }
        }

        return false;
    }

    /**
     * Make sure that the work directory is created and not a file.
     *
     * @throws Exception if work directory can not be created or is a file
     */
    private void initWorkDirectory()
        throws Exception
    {
        if( !m_baseWorkDirectory.exists() )
        {
            final String message =
                REZ.getString( "deploy.create-dir.notice",
                               m_baseWorkDirectory );
            getLogger().info( message );

            if( !m_baseWorkDirectory.mkdirs() )
            {
                final String error =
                    REZ.getString( "deploy.workdir-nocreate.error",
                                   m_baseWorkDirectory );
                throw new Exception( error );
            }
        }

        if( !m_baseWorkDirectory.isDirectory() )
        {
            final String message =
                REZ.getString( "deploy.workdir-notadir.error",
                               m_baseWorkDirectory );
            throw new Exception( message );
        }
    }
}
TOP

Related Classes of org.apache.avalon.phoenix.components.deployer.DefaultDeployer

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.