Package org.jboss.dna.repository

Source Code of org.jboss.dna.repository.DnaEngine$ConfigurationScanner

/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.dna.repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import net.jcip.annotations.Immutable;
import org.jboss.dna.common.collection.Problem;
import org.jboss.dna.common.collection.Problems;
import org.jboss.dna.common.collection.SimpleProblems;
import org.jboss.dna.common.util.CheckArg;
import org.jboss.dna.common.util.Logger;
import org.jboss.dna.graph.ExecutionContext;
import org.jboss.dna.graph.Graph;
import org.jboss.dna.graph.JcrLexicon;
import org.jboss.dna.graph.JcrMixLexicon;
import org.jboss.dna.graph.JcrNtLexicon;
import org.jboss.dna.graph.Location;
import org.jboss.dna.graph.Node;
import org.jboss.dna.graph.Subgraph;
import org.jboss.dna.graph.connector.RepositoryConnection;
import org.jboss.dna.graph.connector.RepositoryConnectionFactory;
import org.jboss.dna.graph.connector.RepositoryContext;
import org.jboss.dna.graph.connector.RepositorySource;
import org.jboss.dna.graph.connector.RepositorySourceException;
import org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector;
import org.jboss.dna.graph.mimetype.MimeTypeDetector;
import org.jboss.dna.graph.mimetype.MimeTypeDetectorConfig;
import org.jboss.dna.graph.mimetype.MimeTypeDetectors;
import org.jboss.dna.graph.observe.ObservationBus;
import org.jboss.dna.graph.property.Name;
import org.jboss.dna.graph.property.Path;
import org.jboss.dna.graph.property.PathExpression;
import org.jboss.dna.graph.property.PathNotFoundException;
import org.jboss.dna.graph.property.Property;
import org.jboss.dna.repository.sequencer.SequencerConfig;
import org.jboss.dna.repository.sequencer.SequencingService;

/**
* A single instance of the DNA services, which is obtained after setting up the {@link DnaConfiguration#build() configuration}.
*
* @see DnaConfiguration
*/
@Immutable
public class DnaEngine {

    public static final String CONFIGURATION_REPOSITORY_NAME = "dna:configuration";

    protected final DnaConfiguration.ConfigurationDefinition configuration;
    private final ConfigurationScanner scanner;
    private final Problems problems;
    protected final ExecutionContext context;

    private final RepositoryService repositoryService;
    private final SequencingService sequencingService;
    private final ExecutorService executorService;
    private final MimeTypeDetectors detectors;

    private final RepositoryConnectionFactory connectionFactory;

    protected DnaEngine( ExecutionContext context,
                         DnaConfiguration.ConfigurationDefinition configuration ) {
        this.problems = new SimpleProblems();

        // Use the configuration's context ...
        this.detectors = new MimeTypeDetectors();
        this.context = context.with(detectors);

        // And set up the scanner ...
        this.configuration = configuration;
        this.scanner = new ConfigurationScanner(this.problems, this.context, this.configuration);

        // Add the mime type detectors in the configuration ...
        for (MimeTypeDetectorConfig config : scanner.getMimeTypeDetectors()) {
            detectors.addDetector(config);
        }
        // Add an extension-based detector by default ...
        detectors.addDetector(new MimeTypeDetectorConfig("ExtensionDetector", "Extension-based MIME type detector",
                                                         ExtensionBasedMimeTypeDetector.class));

        // Create the RepositoryContext that the configuration repository source should use ...
        ObservationBus configurationChangeBus = new ObservationBus();
        RepositoryContext configContext = new SimpleRepositoryContext(context, configurationChangeBus, null);
        final RepositorySource configSource = this.configuration.getRepositorySource();
        configSource.initialize(configContext);

        // Create the RepositoryService, pointing it to the configuration repository ...
        Path pathToConfigurationRoot = this.configuration.getPath();
        String configWorkspaceName = this.configuration.getWorkspace();
        repositoryService = new RepositoryService(configSource, configWorkspaceName, pathToConfigurationRoot, context, problems);

        // Now register the repository service to be notified of changes to the configuration ...
        configurationChangeBus.register(repositoryService);

        // Create the sequencing service ...
        executorService = new ScheduledThreadPoolExecutor(10); // Use a magic number for now
        sequencingService = new SequencingService();
        sequencingService.setExecutionContext(context);
        sequencingService.setExecutorService(executorService);
        sequencingService.setRepositoryLibrary(repositoryService.getRepositoryLibrary());
        for (SequencerConfig sequencerConfig : scanner.getSequencingConfigurations()) {
            sequencingService.addSequencer(sequencerConfig);
        }

        // Set up the connection factory for this engine ...
        connectionFactory = new RepositoryConnectionFactory() {
            public RepositoryConnection createConnection( String sourceName ) throws RepositorySourceException {
                RepositorySource source = DnaEngine.this.getRepositorySource(sourceName);
                if (source == null) {
                    throw new RepositorySourceException(sourceName);
                }

                return source.getConnection();
            }
        };
    }

    /**
     * Get the problems that were encountered when setting up this engine from the configuration.
     *
     * @return the problems, which may be empty but will never be null
     */
    public Problems getProblems() {
        return problems;
    }

    /**
     * Get the context in which this engine is executing.
     *
     * @return the execution context; never null
     */
    public final ExecutionContext getExecutionContext() {
        return context;
    }

    /**
     * Get the {@link RepositorySource} instance used by this engine.
     *
     * @param repositoryName the name of the repository source
     * @return the source, or null if no source with the given name exists
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final RepositorySource getRepositorySource( String repositoryName ) {
        checkRunning();
        return repositoryService.getRepositoryLibrary().getSource(repositoryName);
    }

    /**
     * Get a factory of connections, backed by the RepositorySor
     *
     * @return the connection factory; never null
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final RepositoryConnectionFactory getRepositoryConnectionFactory() {
        checkRunning();
        return connectionFactory;
    }

    /**
     * Get the repository service.
     *
     * @return the repository service owned by this engine; never null
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final RepositoryService getRepositoryService() {
        checkRunning();
        return repositoryService;
    }

    /**
     * Get a graph to the underlying source.
     *
     * @param sourceName the name of the source
     * @return the graph
     * @throws IllegalArgumentException if the source name is null
     * @throws RepositorySourceException if a source with the supplied name does not exist
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final Graph getGraph( String sourceName ) {
        CheckArg.isNotNull(sourceName, "sourceName");
        return getGraph(getExecutionContext(), sourceName);
    }

    /**
     * Get a graph to the underlying source, using the supplied context. Note that the supplied context should be a derivative of
     * the engine's {@link #getExecutionContext() context}.
     *
     * @param context the context of execution for this graph; may not be null
     * @param sourceName the name of the source
     * @return the graph
     * @throws IllegalArgumentException if the context or source name are null
     * @throws RepositorySourceException if a source with the supplied name does not exist
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final Graph getGraph( ExecutionContext context,
                                 String sourceName ) {
        CheckArg.isNotNull(context, "context");
        CheckArg.isNotNull(sourceName, "sourceName");
        checkRunning();
        Graph graph = Graph.create(sourceName, getRepositoryService().getRepositoryLibrary(), context);
        if (configuration.getRepositorySource().getName().equals(sourceName) && configuration.getWorkspace() != null) {
            // set the workspace ...
            graph.useWorkspace(configuration.getWorkspace());
        }
        return graph;
    }

    /**
     * Get the sequencing service.
     *
     * @return the sequencing service owned by this engine; never null
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    public final SequencingService getSequencingService() {
        checkRunning();
        return sequencingService;
    }

    /**
     * Return the component that is able to detect MIME types given the name of a stream and a stream.
     *
     * @return the MIME type detector used by this engine; never null
     * @throws IllegalStateException if this engine was not {@link #start() started}
     */
    protected final MimeTypeDetector getMimeTypeDetector() {
        checkRunning();
        return detectors;
    }

    protected final boolean checkRunning() {
        if (repositoryService.getAdministrator().isStarted() && sequencingService.getAdministrator().isStarted()) {
            return true;
        }
        throw new IllegalStateException(RepositoryI18n.engineIsNotRunning.text());
    }

    /*
     * Lifecycle methods
     */
    /**
     * Start this engine to make it available for use.
     *
     * @throws IllegalStateException if this method is called when already shut down.
     * @see #shutdown()
     */
    public void start() {
        if (getProblems().hasErrors()) {
            // First log the messages ...
            Logger log = Logger.getLogger(getClass());
            log.error(RepositoryI18n.errorsPreventStarting);
            for (Problem problem : getProblems()) {
                log.error(problem.getMessage(), problem.getParameters());
            }
            // Then throw an exception ...
            throw new IllegalStateException(RepositoryI18n.errorsPreventStarting.text());
        }
        repositoryService.getAdministrator().start();
        sequencingService.getAdministrator().start();
    }

    /**
     * Shutdown this engine to close all connections, terminate any ongoing background operations (such as sequencing), and
     * reclaim any resources that were acquired by this engine. This method may be called multiple times, but only the first time
     * has an effect.
     *
     * @see #start()
     */
    public void shutdown() {
        // First, shutdown the sequencing service, which will prevent any additional jobs from going through ...
        sequencingService.getAdministrator().shutdown();

        // Then terminate the executor service, which may be running background jobs that are not yet completed ...
        try {
            executorService.awaitTermination(10 * 60, TimeUnit.SECONDS); // No TimeUnit.MINUTES in JDK 5
        } catch (InterruptedException ie) {
            // Reset the thread's status and continue this method ...
            Thread.interrupted();
        }
        executorService.shutdown();

        // Finally shut down the repository source, which closes all connections ...
        repositoryService.getAdministrator().shutdown();
    }

    /**
     * Blocks until the shutdown has completed, or the timeout occurs, or the current thread is interrupted, whichever happens
     * first.
     *
     * @param timeout the maximum time to wait for each component in this engine
     * @param unit the time unit of the timeout argument
     * @return <tt>true</tt> if this service complete shut down and <tt>false</tt> if the timeout elapsed before it was shut down
     *         completely
     * @throws InterruptedException if interrupted while waiting
     */
    public boolean awaitTermination( long timeout,
                                     TimeUnit unit ) throws InterruptedException {
        if (!sequencingService.getAdministrator().awaitTermination(timeout, unit)) return false;
        if (!executorService.awaitTermination(timeout, unit)) return false;
        if (!repositoryService.getAdministrator().awaitTermination(timeout, unit)) return false;
        return true;
    }

    /**
     * Get a graph to the configuration content.
     *
     * @return a graph to the configuration content
     */
    protected Graph getConfigurationGraph() {
        Graph result = Graph.create(configuration.getRepositorySource(), context);
        if (configuration.getWorkspace() != null) {
            result.useWorkspace(configuration.getWorkspace());
        }
        return result;
    }

    /**
     * The component responsible for reading the configuration repository and (eventually) for propagating changes in the
     * configuration repository into the services.
     */
    protected class ConfigurationScanner {
        private final Problems problems;
        private final ExecutionContext context;
        private final DnaConfiguration.ConfigurationDefinition configurationRepository;

        protected ConfigurationScanner( Problems problems,
                                        ExecutionContext context,
                                        DnaConfiguration.ConfigurationDefinition configurationRepository ) {
            this.problems = problems;
            this.context = context;
            this.configurationRepository = configurationRepository;
        }

        public List<MimeTypeDetectorConfig> getMimeTypeDetectors() {
            List<MimeTypeDetectorConfig> detectors = new ArrayList<MimeTypeDetectorConfig>();
            Graph graph = Graph.create(configurationRepository.getRepositorySource(), context);
            Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(configurationRepository.getPath(),
                                                                                            DnaLexicon.MIME_TYPE_DETECTORS);
            try {
                Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);

                Set<Name> skipProperties = new HashSet<Name>();
                skipProperties.add(DnaLexicon.READABLE_NAME);
                skipProperties.add(DnaLexicon.DESCRIPTION);
                skipProperties.add(DnaLexicon.CLASSNAME);
                skipProperties.add(DnaLexicon.CLASSPATH);
                skipProperties.add(DnaLexicon.PATH_EXPRESSION);
                Set<String> skipNamespaces = new HashSet<String>();
                skipNamespaces.add(JcrLexicon.Namespace.URI);
                skipNamespaces.add(JcrNtLexicon.Namespace.URI);
                skipNamespaces.add(JcrMixLexicon.Namespace.URI);

                for (Location detectorLocation : subgraph.getRoot().getChildren()) {
                    Node node = subgraph.getNode(detectorLocation);
                    String name = stringValueOf(node, DnaLexicon.READABLE_NAME);
                    if (name == null) name = stringValueOf(node);
                    String desc = stringValueOf(node, DnaLexicon.DESCRIPTION);
                    String classname = stringValueOf(node, DnaLexicon.CLASSNAME);
                    String[] classpath = stringValuesOf(node, DnaLexicon.CLASSPATH);
                    Map<String, Object> properties = new HashMap<String, Object>();
                    for (Property property : node.getProperties()) {
                        Name propertyName = property.getName();
                        if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
                        if (skipProperties.contains(propertyName)) continue;
                        if (property.isSingle()) {
                            properties.put(propertyName.getLocalName(), property.getFirstValue());
                        } else {
                            properties.put(propertyName.getLocalName(), property.getValuesAsArray());
                        }
                    }
                    MimeTypeDetectorConfig config = new MimeTypeDetectorConfig(name, desc, properties, classname, classpath);
                    detectors.add(config);
                }
            } catch (PathNotFoundException e) {
                // no detectors registered ...
            }
            return detectors;
        }

        public List<SequencerConfig> getSequencingConfigurations() {
            List<SequencerConfig> configs = new ArrayList<SequencerConfig>();
            Graph graph = Graph.create(configurationRepository.getRepositorySource(), context);
            Path pathToSequencersNode = context.getValueFactories().getPathFactory().create(configurationRepository.getPath(),
                                                                                            DnaLexicon.SEQUENCERS);
            try {
                Subgraph subgraph = graph.getSubgraphOfDepth(2).at(pathToSequencersNode);

                Set<Name> skipProperties = new HashSet<Name>();
                skipProperties.add(DnaLexicon.READABLE_NAME);
                skipProperties.add(DnaLexicon.DESCRIPTION);
                skipProperties.add(DnaLexicon.CLASSNAME);
                skipProperties.add(DnaLexicon.CLASSPATH);
                skipProperties.add(DnaLexicon.PATH_EXPRESSION);
                Set<String> skipNamespaces = new HashSet<String>();
                skipNamespaces.add(JcrLexicon.Namespace.URI);
                skipNamespaces.add(JcrNtLexicon.Namespace.URI);
                skipNamespaces.add(JcrMixLexicon.Namespace.URI);

                for (Location sequencerLocation : subgraph.getRoot().getChildren()) {
                    Node sequencerNode = subgraph.getNode(sequencerLocation);
                    String name = stringValueOf(sequencerNode, DnaLexicon.READABLE_NAME);
                    if (name == null) name = stringValueOf(sequencerNode);
                    String desc = stringValueOf(sequencerNode, DnaLexicon.DESCRIPTION);
                    String classname = stringValueOf(sequencerNode, DnaLexicon.CLASSNAME);
                    String[] classpath = stringValuesOf(sequencerNode, DnaLexicon.CLASSPATH);
                    String[] expressionStrings = stringValuesOf(sequencerNode, DnaLexicon.PATH_EXPRESSION);
                    List<PathExpression> pathExpressions = new ArrayList<PathExpression>();
                    if (expressionStrings != null) {
                        for (String expressionString : expressionStrings) {
                            try {
                                pathExpressions.add(PathExpression.compile(expressionString));
                            } catch (Throwable t) {
                                problems.addError(t,
                                                  RepositoryI18n.pathExpressionIsInvalidOnSequencer,
                                                  expressionString,
                                                  name,
                                                  t.getLocalizedMessage());
                            }
                        }
                    }
                    String[] goodExpressionStrings = new String[pathExpressions.size()];
                    for (int i = 0; i != pathExpressions.size(); ++i) {
                        PathExpression expression = pathExpressions.get(i);
                        goodExpressionStrings[i] = expression.getExpression();
                    }
                    Map<String, Object> properties = new HashMap<String, Object>();
                    for (Property property : sequencerNode.getProperties()) {
                        Name propertyName = property.getName();
                        if (skipNamespaces.contains(propertyName.getNamespaceUri())) continue;
                        if (skipProperties.contains(propertyName)) continue;
                        if (property.isSingle()) {
                            properties.put(propertyName.getLocalName(), property.getFirstValue());
                        } else {
                            properties.put(propertyName.getLocalName(), property.getValuesAsArray());
                        }
                    }
                    SequencerConfig config = new SequencerConfig(name, desc, properties, classname, classpath,
                                                                 goodExpressionStrings);
                    configs.add(config);
                }
            } catch (PathNotFoundException e) {
                // no detectors registered ...
            }
            return configs;
        }

        private String stringValueOf( Node node ) {
            return node.getLocation().getPath().getLastSegment().getString(context.getNamespaceRegistry());
        }

        private String stringValueOf( Node node,
                                      Name propertyName ) {
            Property property = node.getProperty(propertyName);
            if (property == null) return null;
            if (property.isEmpty()) return null;
            return context.getValueFactories().getStringFactory().create(property.getFirstValue());
        }

        private String[] stringValuesOf( Node node,
                                         Name propertyName ) {
            Property property = node.getProperty(propertyName);
            if (property == null) return null;
            return context.getValueFactories().getStringFactory().create(property.getValuesAsArray());
        }

    }
}
TOP

Related Classes of org.jboss.dna.repository.DnaEngine$ConfigurationScanner

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.