Package com.sun.enterprise.module.common_impl

Source Code of com.sun.enterprise.module.common_impl.AbstractModulesRegistryImpl

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007-2011 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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.module.common_impl;

import com.sun.enterprise.module.Module;
import com.sun.enterprise.module.ModuleDefinition;
import com.sun.enterprise.module.ModuleMetadata;
import com.sun.enterprise.module.ModulesRegistry;
import com.sun.enterprise.module.Repository;
import com.sun.enterprise.module.ResolveError;
import com.sun.enterprise.module.bootstrap.BootException;
import com.sun.enterprise.module.bootstrap.Populator;
import com.sun.hk2.component.InhabitantsParser;
import com.sun.hk2.component.ExistingSingletonInhabitant;
import org.jvnet.hk2.component.ComponentException;
import org.jvnet.hk2.component.Habitat;
import org.jvnet.hk2.component.InhabitantsParserFactory;
import org.jvnet.hk2.config.ConfigParser;

import java.io.IOException;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.*;

/**
* The Modules Registry maintains the registry of all available module.
*
* TODO: concurrency bug in the acess of the repositories field.
*
* @author Jerome Dochez
* @author Sanjeeb.Sahoo@Sun.COM
*/
public abstract class AbstractModulesRegistryImpl implements ModulesRegistry, InhabitantsParserFactory {
    /**
     * {@link ModulesRegistry} can form a tree structure by using this pointer.
     * It works in a way similar to the classloader tree. Modules defined in the parent
     * are visible to children.
     */
    protected final AbstractModulesRegistryImpl parent;
    protected final ConcurrentMap<ModuleId,Module> modules = new ConcurrentHashMap<ModuleId,Module>();

    protected final Map<Integer,Repository> repositories = new TreeMap<Integer,Repository>();

    private final ConcurrentMap<Class<?>, CopyOnWriteArrayList<?>> runningServices =
      new ConcurrentHashMap<Class<?>,CopyOnWriteArrayList<?>>();

    /**
     * Service provider class names and which modules they are in.
     *
     * <p>
     * This is used for the classloader punch-in hack &mdash; to work nicely
     * with classic service loader implementation, we need to be able to allow
     * any modules to see these classes.
     */
    protected final Map<String,Module> providers = new HashMap<String,Module>();
    private Map<String, Habitat> habitats = new Hashtable<String, Habitat>();

    protected AbstractModulesRegistryImpl(AbstractModulesRegistryImpl parent) {
        this.parent = parent;
    }

    /**
     * Creates an uninitialized {@link Habitat}
     *
     */
    public Habitat newHabitat() throws ComponentException {
        Habitat habitat = new Habitat();
        initializeHabitat(habitat);
        return habitat;
    }
   
    protected void initializeHabitat(Habitat h) throws ComponentException {
      h.addIndex(new ExistingSingletonInhabitant<Logger>(Logger.getAnonymousLogger()),
          Logger.class.getName(), null);
    }

    /**
     * Creates a {@link Habitat} from all the modules in this registry
     *
     * @param name
     *      Determines which inhabitants descriptors are loaded.
     *      (so that different parallel habitats can be
     *      created over the same modules registry.)
     */
    public Habitat createHabitat(String name) throws ComponentException {
        Habitat h = newHabitat();
        return createHabitat(name, h);
    }

    public Habitat createHabitat(String name, Habitat h) throws ComponentException {
        if (h==null) {
            h = newHabitat();
        }
       
        // TODO: should get the inhabitantsParser out of Main instead since
        // this could have been overridden
        return createHabitat(name, createInhabitantsParser(h));
    }

    public Habitat createHabitat(String name, InhabitantsParser parser) throws ComponentException {
        try {
            Habitat habitat = parser.habitat;

            for (final Module module : getModules())
                parseInhabitants(module, name,parser);

            populateConfig(habitat);

            // default modules registry is the one that created the habitat
            habitat.addIndex(new ExistingSingletonInhabitant<ModulesRegistry>(this),
                    ModulesRegistry.class.getName(), null);
            habitats.put(name, habitat);

            habitat.initialized();
           
            return habitat;
        } catch (Exception e) {
            throw new ComponentException("Failed to create a habitat",e);
        }
    }

    protected void populateConfig(Habitat habitat) throws BootException {
        ConfigParser configParser = new ConfigParser(habitat);
        for( Populator p : habitat.getAllByContract(Populator.class) )
            p.run(configParser);
    }

    public abstract void parseInhabitants(Module module,
                                  String name,
                                  InhabitantsParser inhabitantsParser)
            throws IOException;

    /**
     * Add a new <code>Repository</code> to this registry. From now on
     * the repository will be used to procure requested module not yet registered
     * in this registry instance. Repository can be searched in a particular
     * order (to accomodate performance requirements like looking at local
     * repositories first), a search order (1 to 100) can be specified when
     * adding a repository to the registry (1 is highest priority).
     * @param repository new repository to attach to this registry
     * @param weight int value from 1 to 100 to specify the search order
     */
    public synchronized void addRepository(Repository repository, int weight) {
        // check that we don't already have this repository
        for (Repository repo : repositories.values()) {
            if (repo.getLocation().equals(repository.getLocation())) {
                throw new RuntimeException("repository at " + repository.getLocation() + " already registered");
            }
        }
        while (repositories.containsKey(weight)) {
            weight++;
        }
        repositories.put(weight, repository);
    }
   
    /**
     * Add a new <code>Repository</code> to this registry. From now on
     * the repository will be used to procure requested nodule not
     * registered in this instance.
     * @param repository new repository to attach to this registry
     */
    public synchronized void addRepository(Repository repository) {
        repositories.put(100+repositories.size(), repository);
    }
   
    /**
     * Remove a repository from the list of attached repositories to
     * this instances. After this call, the <code>Repository</code>
     * name will not be used to procure missing modules any
     * longer
     * @param name name of the repository to remove
     */
    public synchronized void removeRepository(String name) {
        for (Integer weight : repositories.keySet()) {
            Repository repo = repositories.get(weight);
            if (repo.getName().equals(name)) {
                repositories.remove(weight);
                return;
            }
        }
    }

    /**
     * Get a repository from the list of attached repositories
     *
     * @param name name of the repository to return
     * @return the repository or null if not found
     */
    public synchronized Repository getRepository(String name) {
        for (Integer weight : repositories.keySet()) {
            Repository repo = repositories.get(weight);
            if (repo.getName().equals(name)) {
                return repo;
            }
        }
        return null;
    }

    /**
     * Returns the <code>Module</code> instance giving a name and version
     * constraints.
     *
     * @param name the module name
     * @param version the module version.
     * @return the module instance or null if none can be found
     * @throws ResolveError if the module dependencies cannot be resolved
     */
    public Module makeModuleFor(String name, String version) throws ResolveError {
        return makeModuleFor(name, version, true);
    }

    public Module makeModuleFor(String name, String version, boolean resolve) throws ResolveError {
        Module module;
        Logger.getAnonymousLogger().fine("this.makeModuleFor("+name+ ", " +
                version + ", " + resolve + ") called.");
        if(parent!=null) {
            module = parent.makeModuleFor(name,version, resolve);
            if(module!=null)        return module;
        }

        module = modules.get(AbstractFactory.getInstance().createModuleId(name, version));
        if (module==null) {
            module = loadFromRepository(name, version);
            if (module!=null) {
                add(module);
            }
        }
        if (module!=null && resolve) {
            try {
                module.resolve();
            } catch(Throwable e) {
                module.uninstall();
                throw new ResolveError(e);
            }
        }
        Logger.getAnonymousLogger().fine("this.makeModuleFor("+name+ ", " + version + ") returned " + module);
        return module;
    }

    /**
     * Find and return a loaded Module that has the package name in its list
     * of exported interfaces.
     *
     * @param packageName the requested implementation package name.
     * @return the <code>Module</code> instance implementing the package
     * name or null if not found.
     * @throws ResolveError if the module dependencies cannot be resolved
     */
    public Module makeModuleFor(String packageName) throws ResolveError {
        if(parent!=null) {
            Module m = parent.makeModuleFor(packageName);
            if(m!=null)     return m;
        }

        for (Module module : modules.values()) {
            String[] exportedPkgs = module.getModuleDefinition().getPublicInterfaces();
            for (String exportedPkg : exportedPkgs) {
                if (exportedPkg.equals(packageName)) {
                    module.resolve();
                    return module;
                }
            }
        }
        return null;
    }

    protected Module loadFromRepository(String name, String version) {
        Set<Integer> keys = repositories.keySet();
        TreeSet<Integer> sortedKeys = new TreeSet<Integer>();
        sortedKeys.addAll(keys);
        for (Integer key : sortedKeys) {
            Repository repo = repositories.get(key);
            ModuleDefinition moduleDef = repo.find(name, version);
            if (moduleDef!=null) {
                return newModule(moduleDef);
            }
        }
        return null;
    }

    /**
     * Factory method for creating new instances of Module.
     * @param moduleDef module definition of the new module to be created
     * @return a new Module instance
     */
    protected abstract Module newModule(ModuleDefinition moduleDef);

    /**
     * Add a new module to this registry. Once added, the module will be
     * available through one of the getServiceImplementor methods.
     * @param newModule the new module
     */
    protected void add(Module newModule) {
        //if (Utils.isLoggable(Level.INFO)) {
        //    Utils.getDefaultLogger().info("New module " + newModule);
        //}
        assert newModule.getRegistry()==this;
        // see if this module is already added. This can happen
        // in case of OSGiModulesRegistryImpl which uses SynchronousBundleListener.
        ModuleId id = AbstractFactory.getInstance().createModuleId(
                newModule.getModuleDefinition());
        if (modules.get(id) != null) return;
        modules.put(id, newModule);

        // pick up providers from this module
        for( ModuleMetadata.Entry spi : newModule.getMetadata().getEntries() ) {
            for( String name : spi.providerNames )
                providers.put(name,newModule);
        }
        for (Map.Entry<String, Habitat> entry : habitats.entrySet()) {
            String name = entry.getKey();
            Habitat h = entry.getValue();
            try
            {
                // TODO: should get the inhabitantsParser out of Main instead since
                // this could have been overridden
                parseInhabitants(newModule, name, createInhabitantsParser(h));
            }
            catch (IOException e)
            {
                throw new RuntimeException("Not able to parse inhabitants information");
            }
        }
    }
   
    @Override
    public InhabitantsParser createInhabitantsParser(Habitat h) {
      return new InhabitantsParser(h);
    }
   
    /**
     * Removes a module from the registry. The module will not be accessible
     * from this registry after this method returns.
     */
    public void remove(Module module) {
        //if (Utils.isLoggable(Level.INFO)) {
        //    Utils.getDefaultLogger().info("Removed module " + module);
        //}
        assert module.getRegistry()==this;
        modules.remove(AbstractFactory.getInstance().createModuleId(module.getModuleDefinition()));

        // TODO: modules comes right back when getModules() is called.
        // the modeling is incorrect
    }
   
    /**
     * Returns the list of shared Modules registered in this instance.
     *
     * <p>
     * The returned list will not include the modules defined in the ancestor
     * {@link AbstractModulesRegistryImpl}s.
     *
     * @return an umodifiable list of loaded modules
     */
    public Collection<Module> getModules() {

        // make a copy to avoid synchronizing since this API can be called while
        // modules are added or removed by other threads.
        Map<Integer,Repository> repos = new TreeMap<Integer,Repository>();
        repos.putAll(repositories);

        // force repository extraction
        Set<Integer> keys = repos.keySet();
        TreeSet<Integer> sortedKeys = new TreeSet<Integer>();
        sortedKeys.addAll(keys);
        for (Integer key : sortedKeys) {
            Repository repo = repos.get(key);
            for (ModuleDefinition moduleDef : repo.findAll()) {
                if (modules.get(AbstractFactory.getInstance().createModuleId(moduleDef))==null) {
                    Module newModule = newModule(moduleDef);
                    if (newModule!=null) {
                        // When some module can't get installed,
                        // don't halt proceeding, instead continue
                        add(newModule);
                        // don't resolve such modules, we just want to know about them
                    }
                }
            }
        }
        return modules.values();
    }

    public Collection<Module> getModules(String moduleName)
    {
        List<Module> result = new ArrayList<Module>();
        for (Module m : getModules()) {
            if (m.getName().equals(moduleName)) result.add(m);
        }
        return result;
    }

    /**
     * Modules can notify their registry that they have changed (classes,
     * resources,etc...). Registries are requested to take appropriate action
     * to make the new module available.
     */
    public void changed(Module service) {
       
        System.out.println("I have received changed event from " + service);       
        // house keeping...
        remove(service);
        ModuleDefinition info = service.getModuleDefinition();
       
        Module newService = newModule(info);
       
        // store it
        add(newService);
    }  
   
    /**
     * Registers a new DefaultModuleDefinition in this registry. Using this module
     * definition, the registry will be capable of created shared and private
     * <code>Module</code> instances.
     */
    public synchronized Module add(ModuleDefinition info) throws ResolveError {
        return add(info, true);
    }

    public Module add(ModuleDefinition info, boolean resolve) throws ResolveError {
        // it may have already been created
        Module service = makeModuleFor(info.getName(), info.getVersion(), resolve);
        if (service!=null) {
        //    Utils.getDefaultLogger().info("Service " + info.getName()
        //       + " already registered");
        } else {
            // create the service instance
            service = newModule(info);
            if (service != null){
                add(service);
            }
        }
        return service;
    }

    /**
     * Print a Registry dump to the logger
     * @param logger the logger to dump on
     */
    public void print(Logger logger) {
        logger.info("Modules Registry information : " + modules.size() + " modules");
        for (Module module : modules.values()) {
            logger.info(module.getModuleDefinition().getName());
        }
    }

    public <T> Iterable<Class<? extends T>> getProvidersClass(final Class<T> serviceClass) {
        // oh boy, it really hurts not to have type inference.
        return new Iterable<Class<? extends T>>() {
            public Iterator<Class<? extends T>> iterator() {
                return new FlattenIterator<Class<? extends T>>(new AdapterIterator<Iterator<Class<? extends T>>,Module>(getModules().iterator()) {
                    protected Iterator<Class<? extends T>> adapt(Module module) {
                        return module.getProvidersClass(serviceClass).iterator();
                    }
                });
            }
        };
    }

    /**
     * Returns a collection of Module containing at least one implementation
     * of the passed service interface class.
     *
     * @param serviceClass the service interface class
     * @return a collection of module
     */
    public Iterable<Module> getModulesProvider(final Class serviceClass) {
        return new Iterable<Module>() {
            public Iterator<Module> iterator() {
                return new AdapterIterator<Module,Module>(getModules().iterator()) {
                    protected Module adapt(Module m) {
                        if(m.hasProvider(serviceClass))
                            return m;
                        else
                            return null;    // skip
                    }
                };
            }
        };
    }

    /**
     * Registers a running service, this is useful when other components need
     * to have access to a provider of a service without having to create
     * a new instance and initialize it.
     * @param serviceClass the service interface
     * @param provider the provider of that service.
     */
    public <T> void registerRunningService(Class<T> serviceClass, T provider) {
        CopyOnWriteArrayList rs = runningServices.get(serviceClass);
        if (rs==null) {
            rs = new CopyOnWriteArrayList<T>();
            CopyOnWriteArrayList existing = runningServices.putIfAbsent(serviceClass, rs);
            if(existing!=null)
                rs = existing;
        }
        rs.add(provider);
    }

    /**
     * Removes a running service, this is useful when a service instance is no longer
     * available as a provider of a service.
     */
    public <T> boolean unregisterRunningService(Class<T> serviceClass, T provider) {
        CopyOnWriteArrayList rs = runningServices.get(serviceClass);
        if (rs==null) {
            return false;
        }
        return rs.remove(provider);
    }

    /**
     * Returns all running services implementation of the passed service
     * interface
     * @param serviceClass the service interface
     * @return the list of providers of that service.
     */
    public <T> List<T> getRunningServices(Class<T> serviceClass) {
        List r = runningServices.get(serviceClass);
        if(r!=null)     return r;
        return Collections.emptyList();
    }

    /**
     * Gets the {@link Module} that provides the provider of the given name.
     */
    public Module getProvidingModule(String providerClassName) {
        return providers.get(providerClassName);
    }

    public void dumpState(PrintStream writer) {
       
        writer.println("Registry Info");
        for (Repository repo : repositories.values()) {
            writer.println("Attached repository : " + repo.getName());
            writer.println(repo.toString());
        }
        for (Module module : getModules()) {
           
            writer.println("Registered Module " + module.getModuleDefinition().getName());
            module.dumpState(writer);
        }
    }


}
TOP

Related Classes of com.sun.enterprise.module.common_impl.AbstractModulesRegistryImpl

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.