Package org.apache.hivemind.impl

Source Code of org.apache.hivemind.impl.RegistryInfrastructureConstructor

// Copyright 2004, 2005 The Apache Software Foundation
//
// Licensed 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.hivemind.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.hivemind.ErrorHandler;
import org.apache.hivemind.Location;
import org.apache.hivemind.Occurances;
import org.apache.hivemind.ShutdownCoordinator;
import org.apache.hivemind.conditional.EvaluationContextImpl;
import org.apache.hivemind.conditional.Node;
import org.apache.hivemind.conditional.Parser;
import org.apache.hivemind.internal.ConfigurationPoint;
import org.apache.hivemind.internal.Module;
import org.apache.hivemind.internal.RegistryInfrastructure;
import org.apache.hivemind.internal.ServicePoint;
import org.apache.hivemind.parse.ConfigurationPointDescriptor;
import org.apache.hivemind.parse.ContributionDescriptor;
import org.apache.hivemind.parse.DependencyDescriptor;
import org.apache.hivemind.parse.ImplementationDescriptor;
import org.apache.hivemind.parse.InstanceBuilder;
import org.apache.hivemind.parse.InterceptorDescriptor;
import org.apache.hivemind.parse.ModuleDescriptor;
import org.apache.hivemind.parse.ServicePointDescriptor;
import org.apache.hivemind.schema.Schema;
import org.apache.hivemind.schema.impl.SchemaImpl;
import org.apache.hivemind.util.IdUtils;

/**
* Fed a series of {@link org.apache.hivemind.parse.ModuleDescriptor}s, this class will assemble
* them into a final {@link org.apache.hivemind.internal.RegistryInfrastructure} as well as perform
* some validations.
* <p>
* This class was extracted from {@link org.apache.hivemind.impl.RegistryBuilder}.
*
* @author Howard M. Lewis Ship
* @since 1.1
*/
public class RegistryInfrastructureConstructor
{
    private ErrorHandler _errorHandler;

    private Log _log;

    private RegistryAssembly _assembly;

    /** @since 1.1 */

    private Parser _conditionalExpressionParser;

    public RegistryInfrastructureConstructor(ErrorHandler errorHandler, Log log,
            RegistryAssembly assembly)
    {
        _errorHandler = errorHandler;
        _log = log;
        _assembly = assembly;
    }

    /**
     * Map of {@link ModuleDescriptor} keyed on module id.
     */

    private Map _moduleDescriptors = new HashMap();

    /**
     * Map of {@link ModuleImpl} keyed on module id.
     */
    private Map _modules = new HashMap();

    /**
     * Map of {@link Schema} keyed on fully qualified module id.
     */
    private Map _schemas = new HashMap();

    /**
     * Map of {@link ServicePointImpl} keyed on fully qualified id.
     */

    private Map _servicePoints = new HashMap();

    /**
     * Map of {@link ConfigurationPointImpl} keyed on fully qualified id.
     */

    private Map _configurationPoints = new HashMap();

    /**
     * Shutdown coordinator shared by all objects.
     */

    private ShutdownCoordinator _shutdownCoordinator = new ShutdownCoordinatorImpl();

    /**
     * This class is used to check the dependencies of a ModuleDescriptor. As the checker is run it
     * will log errors to the ErrorHandler if dependencies don't resolve or the versions dont match.
     */
    private class ModuleDependencyChecker implements Runnable
    {
        private ModuleDescriptor _source;

        public ModuleDependencyChecker(ModuleDescriptor source)
        {
            _source = source;
        }

        public void run()
        {
            List dependencies = _source.getDependencies();
            int count = size(dependencies);

            for (int i = 0; i < count; i++)
            {
                DependencyDescriptor dependency = (DependencyDescriptor) dependencies.get(i);
                checkDependency(dependency);
            }
        }

        private void checkDependency(DependencyDescriptor dependency)
        {
            ModuleDescriptor requiredModule = (ModuleDescriptor) _moduleDescriptors.get(dependency
                    .getModuleId());

            if (requiredModule == null)
            {
                _errorHandler.error(
                        _log,
                        ImplMessages.dependencyOnUnknownModule(dependency),
                        dependency.getLocation(),
                        null);
                return;
            }

            if (dependency.getVersion() != null
                    && !dependency.getVersion().equals(requiredModule.getVersion()))
            {
                _errorHandler.error(
                        _log,
                        ImplMessages.dependencyVersionMismatch(dependency),
                        dependency.getLocation(),
                        null);
                return;
            }
        }
    }

    /**
     * Constructs the registry infrastructure, based on data collected during the prior calls to
     * {@link #addModuleDescriptor(ModuleDescriptor)}. Expects that all post-processing of the
     * {@link RegistryAssembly} has already occured.
     */
    public RegistryInfrastructure constructRegistryInfrastructure(Locale locale)
    {
        RegistryInfrastructureImpl result = new RegistryInfrastructureImpl(_errorHandler, locale);

        addServiceAndConfigurationPoints(result);

        addImplementationsAndContributions();

        checkForMissingServices();

        checkContributionCounts();

        result.setShutdownCoordinator(_shutdownCoordinator);

        addModulesToRegistry(result);

        // The caller is responsible for invoking startup().

        return result;
    }

    public void addModuleDescriptor(ModuleDescriptor md)
    {
        String id = md.getModuleId();

        if (_log.isDebugEnabled())
            _log.debug("Processing module " + id);

        if (_modules.containsKey(id))
        {
            Module existing = (Module) _modules.get(id);

            _errorHandler.error(_log, ImplMessages.duplicateModuleId(id, existing.getLocation(), md
                    .getLocation()), null, null);

            // Ignore the duplicate module descriptor.
            return;
        }

        ModuleImpl module = new ModuleImpl();

        module.setLocation(md.getLocation());
        module.setModuleId(id);
        module.setPackageName(md.getPackageName());
        module.setClassResolver(md.getClassResolver());

        if (size(md.getDependencies()) > 0)
            _assembly.addPostProcessor(new ModuleDependencyChecker(md));

        for (Iterator schemas = md.getSchemas().iterator(); schemas.hasNext();)
        {
            SchemaImpl schema = (SchemaImpl) schemas.next();

            schema.setModule(module);

            _schemas.put(IdUtils.qualify(id, schema.getId()), schema);
        }

        _modules.put(id, module);

        _moduleDescriptors.put(id, md);
    }

    private void addServiceAndConfigurationPoints(RegistryInfrastructureImpl infrastructure)
    {
        for (Iterator i = _moduleDescriptors.values().iterator(); i.hasNext();)
        {
            ModuleDescriptor md = (ModuleDescriptor) i.next();

            String id = md.getModuleId();

            ModuleImpl module = (ModuleImpl) _modules.get(id);

            addServicePoints(infrastructure, module, md);

            addConfigurationPoints(infrastructure, module, md);
        }
    }

    private void addServicePoints(RegistryInfrastructureImpl infrastructure, Module module,
            ModuleDescriptor md)
    {
        String moduleId = md.getModuleId();
        List services = md.getServicePoints();
        int count = size(services);

        for (int i = 0; i < count; i++)
        {
            ServicePointDescriptor sd = (ServicePointDescriptor) services.get(i);

            String pointId = moduleId + "." + sd.getId();

            ServicePoint existingPoint = (ServicePoint) _servicePoints.get(pointId);

            if (existingPoint != null)
            {
                _errorHandler.error(_log, ImplMessages.duplicateExtensionPointId(
                        pointId,
                        existingPoint), sd.getLocation(), null);
                continue;
            }

            if (_log.isDebugEnabled())
                _log.debug("Creating service point " + pointId);

            // Choose which class to instantiate based on
            // whether the service is create-on-first-reference
            // or create-on-first-use (deferred).

            ServicePointImpl point = new ServicePointImpl();

            point.setExtensionPointId(pointId);
            point.setLocation(sd.getLocation());
            point.setModule(module);

            point.setServiceInterfaceName(sd.getInterfaceClassName());

            point.setParametersSchema(findSchema(sd.getParametersSchema(), module, sd
                    .getParametersSchemaId(), point.getLocation()));

            point.setParametersCount(sd.getParametersCount());
            point.setVisibility(sd.getVisibility());

            point.setShutdownCoordinator(_shutdownCoordinator);

            infrastructure.addServicePoint(point);

            // Save this for the second phase, where contributions
            // from other modules are applied.

            _servicePoints.put(pointId, point);

            addInternalImplementations(module, pointId, sd);
        }
    }

    private void addConfigurationPoints(RegistryInfrastructureImpl registry, Module module,
            ModuleDescriptor md)
    {
        String moduleId = md.getModuleId();
        List points = md.getConfigurationPoints();
        int count = size(points);

        for (int i = 0; i < count; i++)
        {
            ConfigurationPointDescriptor cpd = (ConfigurationPointDescriptor) points.get(i);

            String pointId = moduleId + "." + cpd.getId();

            ConfigurationPoint existingPoint = (ConfigurationPoint) _configurationPoints
                    .get(pointId);

            if (existingPoint != null)
            {
                _errorHandler.error(_log, ImplMessages.duplicateExtensionPointId(
                        pointId,
                        existingPoint), cpd.getLocation(), null);
                continue;
            }

            if (_log.isDebugEnabled())
                _log.debug("Creating configuration point " + pointId);

            ConfigurationPointImpl point = new ConfigurationPointImpl();

            point.setExtensionPointId(pointId);
            point.setLocation(cpd.getLocation());
            point.setModule(module);
            point.setExpectedCount(cpd.getCount());

            point.setContributionsSchema(findSchema(cpd.getContributionsSchema(), module, cpd
                    .getContributionsSchemaId(), cpd.getLocation()));

            point.setVisibility(cpd.getVisibility());

            point.setShutdownCoordinator(_shutdownCoordinator);

            registry.addConfigurationPoint(point);

            // Needed later when we reconcile the rest
            // of the configuration contributions.

            _configurationPoints.put(pointId, point);
        }
    }

    private void addContributionElements(Module sourceModule, ConfigurationPointImpl point,
            List elements)
    {
        if (size(elements) == 0)
            return;

        if (_log.isDebugEnabled())
            _log
                    .debug("Adding contributions to configuration point "
                            + point.getExtensionPointId());

        ContributionImpl c = new ContributionImpl();
        c.setContributingModule(sourceModule);
        c.addElements(elements);

        point.addContribution(c);
    }

    private void addModulesToRegistry(RegistryInfrastructureImpl registry)
    {
        // Add each module to the registry.

        Iterator i = _modules.values().iterator();
        while (i.hasNext())
        {
            ModuleImpl module = (ModuleImpl) i.next();

            if (_log.isDebugEnabled())
                _log.debug("Adding module " + module.getModuleId() + " to registry");

            module.setRegistry(registry);
        }
    }

    private void addImplementationsAndContributions()
    {
        for (Iterator i = _moduleDescriptors.values().iterator(); i.hasNext();)
        {
            ModuleDescriptor md = (ModuleDescriptor) i.next();

            if (_log.isDebugEnabled())
                _log.debug("Adding contributions from module " + md.getModuleId());

            addImplementations(md);
            addContributions(md);
        }
    }

    private void addImplementations(ModuleDescriptor md)
    {
        String moduleId = md.getModuleId();
        Module sourceModule = (Module) _modules.get(moduleId);

        List implementations = md.getImplementations();
        int count = size(implementations);

        for (int i = 0; i < count; i++)
        {
            ImplementationDescriptor impl = (ImplementationDescriptor) implementations.get(i);

            if (!includeContribution(impl.getConditionalExpression(), sourceModule, impl
                    .getLocation()))
                continue;

            String pointId = impl.getServiceId();
            String qualifiedId = IdUtils.qualify(moduleId, pointId);

            addImplementations(sourceModule, qualifiedId, impl);
        }

    }

    private void addContributions(ModuleDescriptor md)
    {
        String moduleId = md.getModuleId();
        Module sourceModule = (Module) _modules.get(moduleId);

        List contributions = md.getContributions();
        int count = size(contributions);

        for (int i = 0; i < count; i++)
        {
            ContributionDescriptor cd = (ContributionDescriptor) contributions.get(i);

            if (!includeContribution(cd.getConditionalExpression(), sourceModule, cd.getLocation()))
                continue;

            String pointId = cd.getConfigurationId();
            String qualifiedId = IdUtils.qualify(moduleId, pointId);

            ConfigurationPointImpl point = (ConfigurationPointImpl) _configurationPoints
                    .get(qualifiedId);

            if (point == null)
            {
                _errorHandler.error(_log, ImplMessages.unknownConfigurationPoint(moduleId, cd), cd
                        .getLocation(), null);

                continue;
            }

            if (!point.visibleToModule(sourceModule))
            {
                _errorHandler.error(_log, ImplMessages.configurationPointNotVisible(
                        point,
                        sourceModule), cd.getLocation(), null);
                continue;
            }

            addContributionElements(sourceModule, point, cd.getElements());
        }
    }

    private Schema findSchema(SchemaImpl schema, Module module, String schemaId, Location location)
    {
        if (schema != null)
        {
            schema.setModule(module);
            return schema;
        }

        if (schemaId == null)
            return null;

        String moduleId = module.getModuleId();
        String qualifiedId = IdUtils.qualify(moduleId, schemaId);

        return getSchema(qualifiedId, moduleId, location);
    }

    private Schema getSchema(String schemaId, String referencingModule, Location reference)
    {
        Schema schema = (Schema) _schemas.get(schemaId);

        if (schema == null)
            _errorHandler
                    .error(_log, ImplMessages.unableToResolveSchema(schemaId), reference, null);
        else if (!schema.visibleToModule(referencingModule))
        {
            _errorHandler.error(
                    _log,
                    ImplMessages.schemaNotVisible(schemaId, referencingModule),
                    reference,
                    null);
            schema = null;
        }

        return schema;
    }

    /**
     * Adds internal service contributions; the contributions provided inplace with the service
     * definition.
     */
    private void addInternalImplementations(Module sourceModule, String pointId,
            ServicePointDescriptor spd)
    {
        InstanceBuilder builder = spd.getInstanceBuilder();
        List interceptors = spd.getInterceptors();

        if (builder == null && interceptors == null)
            return;

        if (builder != null)
            addServiceInstanceBuilder(sourceModule, pointId, builder, true);

        if (interceptors == null)
            return;

        int count = size(interceptors);

        for (int i = 0; i < count; i++)
        {
            InterceptorDescriptor id = (InterceptorDescriptor) interceptors.get(i);
            addInterceptor(sourceModule, pointId, id);
        }
    }

    /**
     * Adds ordinary service contributions.
     */

    private void addImplementations(Module sourceModule, String pointId, ImplementationDescriptor id)
    {
        InstanceBuilder builder = id.getInstanceBuilder();
        List interceptors = id.getInterceptors();

        if (builder != null)
            addServiceInstanceBuilder(sourceModule, pointId, builder, false);

        int count = size(interceptors);
        for (int i = 0; i < count; i++)
        {
            InterceptorDescriptor ind = (InterceptorDescriptor) interceptors.get(i);

            addInterceptor(sourceModule, pointId, ind);
        }
    }

    /**
     * Adds an {@link InstanceBuilder} to a service extension point.
     */
    private void addServiceInstanceBuilder(Module sourceModule, String pointId,
            InstanceBuilder builder, boolean isDefault)
    {
        if (_log.isDebugEnabled())
            _log.debug("Adding " + builder + " to service extension point " + pointId);

        ServicePointImpl point = (ServicePointImpl) _servicePoints.get(pointId);

        if (point == null)
        {
            _errorHandler.error(
                    _log,
                    ImplMessages.unknownServicePoint(sourceModule, pointId),
                    builder.getLocation(),
                    null);
            return;
        }

        if (!point.visibleToModule(sourceModule))
        {
            _errorHandler.error(
                    _log,
                    ImplMessages.servicePointNotVisible(point, sourceModule),
                    builder.getLocation(),
                    null);
            return;
        }

        if (point.getServiceConstructor(isDefault) != null)
        {
            _errorHandler.error(
                    _log,
                    ImplMessages.duplicateFactory(sourceModule, pointId, point),
                    builder.getLocation(),
                    null);

            return;
        }

        point.setServiceModel(builder.getServiceModel());
        point.setServiceConstructor(builder.createConstructor(point, sourceModule), isDefault);
    }

    private void addInterceptor(Module sourceModule, String pointId, InterceptorDescriptor id)
    {
        if (_log.isDebugEnabled())
            _log.debug("Adding " + id + " to service extension point " + pointId);

        ServicePointImpl point = (ServicePointImpl) _servicePoints.get(pointId);

        String sourceModuleId = sourceModule.getModuleId();

        if (point == null)
        {
            _errorHandler.error(_log, ImplMessages.unknownServicePoint(sourceModule, pointId), id
                    .getLocation(), null);

            return;
        }

        if (!point.visibleToModule(sourceModule))
        {
            _errorHandler.error(_log, ImplMessages.servicePointNotVisible(point, sourceModule), id
                    .getLocation(), null);
            return;
        }

        ServiceInterceptorContributionImpl sic = new ServiceInterceptorContributionImpl();

        // Allow the factory id to be unqualified, to refer to an interceptor factory
        // service from within the same module.

        sic.setFactoryServiceId(IdUtils.qualify(sourceModuleId, id.getFactoryServiceId()));
        sic.setLocation(id.getLocation());

        sic.setFollowingInterceptorIds(IdUtils.qualifyList(sourceModuleId, id.getBefore()));
        sic.setPrecedingInterceptorIds(IdUtils.qualifyList(sourceModuleId, id.getAfter()));
        sic.setName(id.getName() != null ? IdUtils.qualify(sourceModuleId, id.getName()) : null);
        sic.setContributingModule(sourceModule);
        sic.setParameters(id.getParameters());

        point.addInterceptorContribution(sic);
    }

    /**
     * Checks that each service has at service constructor.
     */
    private void checkForMissingServices()
    {
        Iterator i = _servicePoints.values().iterator();
        while (i.hasNext())
        {
            ServicePointImpl point = (ServicePointImpl) i.next();

            if (point.getServiceConstructor() != null)
                continue;

            _errorHandler.error(_log, ImplMessages.missingService(point), null, null);
        }
    }

    /**
     * Checks that each configuration extension point has the right number of contributions.
     */

    private void checkContributionCounts()
    {
        Iterator i = _configurationPoints.values().iterator();

        while (i.hasNext())
        {
            ConfigurationPointImpl point = (ConfigurationPointImpl) i.next();

            Occurances expected = point.getExpectedCount();

            int actual = point.getContributionCount();

            if (expected.inRange(actual))
                continue;

            _errorHandler.error(_log, ImplMessages.wrongNumberOfContributions(
                    point,
                    actual,
                    expected), point.getLocation(), null);
        }

    }

    /**
     * Filters a contribution based on an expression. Returns true if the expression is null, or
     * evaluates to true. Returns false if the expression if non-null and evaluates to false, or an
     * exception occurs evaluating the expression.
     *
     * @param expression
     *            to parse and evaluate
     * @param location
     *            of the expression (used if an error is reported)
     * @since 1.1
     */

    private boolean includeContribution(String expression, Module module, Location location)
    {
        if (expression == null)
            return true;

        if (_conditionalExpressionParser == null)
            _conditionalExpressionParser = new Parser();

        try
        {
            Node node = _conditionalExpressionParser.parse(expression);

            return node.evaluate(new EvaluationContextImpl(module.getClassResolver()));
        }
        catch (RuntimeException ex)
        {
            _errorHandler.error(_log, ex.getMessage(), location, ex);

            return false;
        }
    }

    private static int size(Collection c)
    {
        return c == null ? 0 : c.size();
    }
}
TOP

Related Classes of org.apache.hivemind.impl.RegistryInfrastructureConstructor

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.