Package org.apache.avalon.phoenix.components.configuration

Source Code of org.apache.avalon.phoenix.components.configuration.FileSystemPersistentConfigurationRepository

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

import java.io.File;
import java.io.IOException;

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.excalibur.property.PropertyException;
import org.apache.avalon.excalibur.property.PropertyUtil;
import org.apache.avalon.framework.CascadingRuntimeException;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.avalon.framework.configuration.DefaultConfigurationSerializer;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.phoenix.interfaces.ConfigurationRepository;
import org.apache.avalon.phoenix.interfaces.ConfigurationRepositoryMBean;
import org.apache.excalibur.configuration.ConfigurationUtil;
import org.apache.excalibur.configuration.merged.ConfigurationMerger;
import org.apache.excalibur.configuration.merged.ConfigurationSplitter;

import org.xml.sax.SAXException;

/**
* <p>
* A ConfigurationRepository that will store partial configurations on disk.
* </p><p>
* When a Configuration is retrieved from the repository, the configuration from disk is
* <i>merged</i> with the configuration from the SAR. This merge is accompilished via
* <code>ConfigurationMerger.merge</code>.
* </p><p>
* When a Configuration is stored in the repository, if there is no <i>transient</i>, that is,
* configuration from the SAR, Configuration information, the first store is that. Subsequent
* calls to storeConfiguration will persist the difference between the <i>transient</i>
* Configuration and the passed configuration to disk. The differences are computed via
* <code>ConfigurationSplitter.split</code>
* </p>
*
* @author <a href="mailto:proyal@apache.org">Peter Royal</a>
* @see org.apache.excalibur.configuration.merged.ConfigurationMerger
* @see org.apache.excalibur.configuration.merged.ConfigurationSplitter
*/
public class FileSystemPersistentConfigurationRepository extends AbstractLogEnabled
    implements ConfigurationRepository, Contextualizable, Configurable, Initializable,
    ConfigurationRepositoryMBean
{
    private static final Resources REZ =
        ResourceManager.getPackageResources( FileSystemPersistentConfigurationRepository.class );

    private final DefaultConfigurationRepository m_persistedConfigurations =
        new DefaultConfigurationRepository();
    private final DefaultConfigurationRepository
        m_transientConfigurations = new DefaultConfigurationRepository();
    private final DefaultConfigurationRepository
        m_mergedConfigurations = new DefaultConfigurationRepository();

    private Context m_context;

    private File m_storageDirectory;

    public void contextualize( Context context )
        throws ContextException
    {
        m_context = context;
    }

    public void configure( final Configuration configuration ) throws ConfigurationException
    {
        this.m_storageDirectory = new File( constructStoragePath( configuration ) );

        try
        {
            FileUtil.forceMkdir( this.m_storageDirectory );
        }
        catch( IOException e )
        {
            final String message = REZ.getString( "config.error.dir.invalid",
                                                  this.m_storageDirectory );

            throw new ConfigurationException( message, e );

        }
    }

    private String constructStoragePath( final Configuration configuration )
        throws ConfigurationException
    {
        final String path =
            configuration.getChild( "storage-directory" ).getValue( "${phoenix.home}/conf/apps" );

        try
        {
            final Object opath = PropertyUtil.resolveProperty( path, m_context, false );

            if( opath instanceof String )
            {
                return FileUtil.normalize( ( String ) opath );
            }
            else
            {
                final String message = REZ.getString( "config.error.nonstring",
                                                      opath.getClass().getName() );

                throw new ConfigurationException( message );
            }
        }
        catch( PropertyException e )
        {
            final String message = REZ.getString( "config.error.missingproperty",
                                                  configuration.getLocation() );

            throw new ConfigurationException( message, e );
        }
    }

    public void initialize()
        throws Exception
    {
        loadConfigurations();
    }

    private void loadConfigurations()
        throws IOException, SAXException, ConfigurationException
    {
        final File[] apps = m_storageDirectory.listFiles( new ConfigurationDirectoryFilter() );

        for( int i = 0; i < apps.length; i++ )
        {
            loadConfigurations( apps[i] );
        }
    }

    private void loadConfigurations( File appPath )
        throws IOException, SAXException, ConfigurationException
    {
        final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
        final String app = appPath.getName();
        final File[] blocks = appPath.listFiles( new ConfigurationFileFilter() );

        for( int i = 0; i < blocks.length; i++ )
        {
            final String block =
                blocks[i].getName().substring( 0, blocks[i].getName().indexOf( ".xml" ) );

            m_persistedConfigurations.storeConfiguration( app,
                                                          block,
                                                          builder.buildFromFile( blocks[i] ) );

            if( getLogger().isDebugEnabled() )
                getLogger().debug( "Loaded persistent configuration [app: " + app
                                   + ", block: " + block + "]" );
        }
    }

    private void persistConfiguration( final String application,
                                       final String block,
                                       final Configuration configuration )
        throws SAXException, IOException, ConfigurationException
    {
        final DefaultConfigurationSerializer serializer = new DefaultConfigurationSerializer();
        final File directory = new File( this.m_storageDirectory, application );

        FileUtil.forceMkdir( directory );

        if( getLogger().isDebugEnabled() )
            getLogger().debug( "Serializing configuration to disk [app: " + application
                               + ", block: " + block + "]" );

        serializer.setIndent( true );
        serializer.serializeToFile( new File( directory, block + ".xml" ), configuration );
    }

    public void removeConfiguration( String application, String block )
        throws ConfigurationException
    {
        m_transientConfigurations.removeConfiguration( application, block );
        m_mergedConfigurations.removeConfiguration( application, block );
    }

    public synchronized void storeConfiguration( final String application,
                                                 final String block,
                                                 final Configuration configuration )
        throws ConfigurationException
    {

        if( m_transientConfigurations.hasConfiguration( application, block ) )
        {
            if( !ConfigurationUtil.equals( configuration, getConfiguration( application, block ) ) )
            {
                final Configuration layer =
                    ConfigurationSplitter.split( configuration,
                                                 getConfiguration( application,
                                                                   block,
                                                                   m_transientConfigurations ) );

                m_persistedConfigurations.storeConfiguration( application, block, layer );
                m_mergedConfigurations.removeConfiguration( application, block );

                try
                {
                    persistConfiguration( application, block, layer );
                }
                catch( SAXException e )
                {
                    final String message =
                        REZ.getString( "config.error.persist", application, block );

                    throw new ConfigurationException( message, e );
                }
                catch( IOException e )
                {
                    final String message =
                        REZ.getString( "config.error.persist", application, block );

                    throw new ConfigurationException( message, e );
                }
            }
        }
        else
        {
            m_transientConfigurations.storeConfiguration( application, block, configuration );
        }
    }

    public synchronized Configuration getConfiguration( final String application,
                                                        final String block )
        throws ConfigurationException
    {
        if( m_mergedConfigurations.hasConfiguration( application, block ) )
        {
            return m_mergedConfigurations.getConfiguration( application, block );
        }
        else
        {
            final Configuration configuration = createMergedConfiguration( application, block );

            m_mergedConfigurations.storeConfiguration( application, block, configuration );

            return configuration;
        }
    }

    private Configuration createMergedConfiguration( final String application,
                                                     final String block )
        throws ConfigurationException
    {
        final Configuration t = getConfiguration( application, block, m_transientConfigurations );
        final Configuration p = getConfiguration( application, block, m_persistedConfigurations );

        if( null == t && p == null )
        {
            final String message = REZ.getString( "config.error.noconfig", block, application );

            throw new ConfigurationException( message );
        }
        else if( null == t )
        {
            return p;
        }
        else if( null == p )
        {
            return t;
        }
        else
        {
            return ConfigurationMerger.merge( p, t );
        }
    }

    private Configuration getConfiguration( final String application,
                                            final String block,
                                            final DefaultConfigurationRepository repository )
    {
        if( repository.hasConfiguration( application, block ) )
        {
            try
            {
                return repository.getConfiguration( application, block );
            }
            catch( ConfigurationException e )
            {
                final String message = REZ.getString( "config.error.noconfig", block, application );

                throw new CascadingRuntimeException( message, e );
            }
        }
        else
        {
            return null;
        }
    }

    public boolean hasConfiguration( String application, String block )
    {
        return m_mergedConfigurations.hasConfiguration( application, block )
            || m_transientConfigurations.hasConfiguration( application, block )
            || m_persistedConfigurations.hasConfiguration( application, block );
    }
}
TOP

Related Classes of org.apache.avalon.phoenix.components.configuration.FileSystemPersistentConfigurationRepository

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.