org.openflexo.foundation.sg.implmodel.TechnologyModuleDefinition.java Source code

Java tutorial

Introduction

Here is the source code for org.openflexo.foundation.sg.implmodel.TechnologyModuleDefinition.java

Source

/*
 * (c) Copyright 2010-2011 AgileBirds
 *
 * This file is part of OpenFlexo.
 *
 * OpenFlexo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * OpenFlexo 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package org.openflexo.foundation.sg.implmodel;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.IOUtils;
import org.openflexo.foundation.sg.implmodel.enums.TechnologyLayer;
import org.openflexo.foundation.sg.implmodel.exception.TechnologyModuleCompatibilityCheckException;
import org.openflexo.foundation.sg.implmodel.exception.TechnologyModuleInitializationException;
import org.openflexo.toolbox.FileResource;
import org.openflexo.toolbox.JavaResourceUtil;
import org.openflexo.xmlcode.XMLDecoder;
import org.openflexo.xmlcode.XMLMapping;

/**
 * Contains the content of the module.xml at the {@link TechnologyModuleImplementation} creation
 * 
 * @author ndaniels
 */
public abstract class TechnologyModuleDefinition {

    private static final Logger logger = Logger.getLogger(TechnologyModuleDefinition.class.getPackage().getName());

    public static File MODULES_DIR = new FileResource("Generator/TechnologyModules");
    private static XMLMapping MODULE_MODEL;

    private static Map<String, TechnologyModuleDefinition> technologyModuleDefinitionMap = null;

    private TechnologyLayer technologyLayer;
    private String name;
    private String version;
    private String description;
    private LinkedHashSet<String> requiredModuleNames;
    private LinkedHashSet<String> compatibleModuleNames;
    private LinkedHashSet<String> incompatibleModuleNames;
    private Map<String, Class<? extends GenerationService>> requiredServices;

    public TechnologyModuleDefinition() throws TechnologyModuleInitializationException {
        loadModule();
    }

    /**
     * Return the path to the resources needed by this module. <br>
     * Can be a path to a java resource folder (ie. in a jar) or a path relative to MODULES_DIR in Flexo files. <br>
     * The returned path must NOT ends with a '/'. <br>
     * The denoted folder must contains a module.xml file. <br>
     * By default, this method will return the first folder containing a module.xml file. <br>
     * Pay attention that this method will be called BEFORE the module initialization (thus before having its name/version/... set)
     * 
     * @return the path to the resources needed by this module.
     * @throws TechnologyModuleInitializationException
     *             if resource path cannot be found
     */
    public String getResourcePath() {
        for (String resourceName : JavaResourceUtil.getMatchingResources(this.getClass(), "module.xml")) {
            if (resourceName.endsWith("/module.xml")) {
                return resourceName.substring(0, resourceName.length() - "/module.xml".length());
            }
        }

        throw new TechnologyModuleInitializationException(
                "module.xml not found for module '" + this.getClass() + "' !");
    }

    /**
     * Create a new instance of the appropriate {@link TechnologyModuleImplementation}.
     * 
     * @param implementationModel
     * @return the created {@link TechnologyModuleImplementation}
     * @throws TechnologyModuleCompatibilityCheckException
     *             if there is incompatibility with existing module.
     */
    public abstract TechnologyModuleImplementation createNewImplementation(ImplementationModel implementationModel)
            throws TechnologyModuleCompatibilityCheckException;

    /**
     * Load and parse the module.xml file associated to this {@link TechnologyModuleDefinition}. <br>
     * The variable of this TechnologyModuleDefinition must be fully initialized after this method call. <br>
     * This method is called at SG module loading, it can be used to perform any initialization needed. <br>
     * For example it will record all inspectors available in this jar. <br>
     * Override the method to load the needed GUI elements in the module using SGModule.recordTechnologyModuleGUIFactory.
     * 
     * @throws TechnologyModuleInitializationException
     *             if the module.xml file is not found, if it has parsing error or if any other exception occurred during initialization
     */
    protected void loadModule() throws TechnologyModuleInitializationException {

        InputStream inputStream = null;
        try {
            // Try to load from java resources
            inputStream = this.getClass().getResourceAsStream(getResourcePath() + "/module.xml");

            if (inputStream == null) {
                File xmlFile = new File(new File(MODULES_DIR, getResourcePath()), "module.xml");
                if (xmlFile.exists()) {
                    inputStream = new FileInputStream(xmlFile);
                }
            }

            if (inputStream == null) {
                logger.severe("Cannot find module.xml using path '" + getResourcePath() + "' !");
                throw new TechnologyModuleInitializationException(
                        "Cannot find module.xml using path '" + getResourcePath() + "' !");
            }

            TechnologyModuleDefinitionDTO returned = (TechnologyModuleDefinitionDTO) XMLDecoder
                    .decodeObjectWithMapping(inputStream, getModuleModel());
            fillFromDTO(returned);

            // Load inspectors
            SGJarInspectorGroup.INSTANCE.recordAllInspectors(getClass());
            logger.info("TechnologyModule " + name + " loaded");

        } catch (Exception e) {
            logger.log(Level.SEVERE, "Cannot load module '" + getClass() + "' !", e);

            if (e instanceof TechnologyModuleInitializationException) {
                throw (TechnologyModuleInitializationException) e;
            }

            throw new TechnologyModuleInitializationException(e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    private void fillFromDTO(TechnologyModuleDefinitionDTO dto) {
        this.technologyLayer = dto.technologyLayer;
        this.name = dto.name;
        this.description = dto.description;
        this.version = dto.version;
        this.requiredModuleNames = new LinkedHashSet<String>();
        this.compatibleModuleNames = new LinkedHashSet<String>();
        this.incompatibleModuleNames = new LinkedHashSet<String>();
        this.requiredServices = new HashMap<String, Class<? extends GenerationService>>();

        for (TechnologyModuleDefinitionDTO.CompatibilityModule module : dto.requiredModuleList) {
            this.requiredModuleNames.add(module.name);
        }
        for (TechnologyModuleDefinitionDTO.CompatibilityModule module : dto.compatibleModuleList) {
            if (!this.requiredModuleNames.contains(module.name)) {
                this.compatibleModuleNames.add(module.name);
            }
        }
        for (TechnologyModuleDefinitionDTO.CompatibilityModule module : dto.incompatibleModuleList) {
            if (!this.requiredModuleNames.contains(module.name)
                    && !this.compatibleModuleNames.contains(module.name)) {
                this.incompatibleModuleNames.add(module.name);
            }
        }
        for (TechnologyModuleDefinitionDTO.RequiredService requiredService : dto.requiredServiceList) {
            try {
                this.requiredServices.put(requiredService.serviceAlias,
                        (Class<? extends GenerationService>) Class.forName(requiredService.serviceInterface));
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("The interface " + requiredService.serviceInterface
                        + " is required by technology module : " + name + "But this interface can not be found !",
                        e);
            }
        }
    }

    /**
     * Recursively retrieve all modules required by this module, including itself. <br>
     * Return a map containing for each recursion level the list of required module. <br>
     * Order is preserved in each level.
     * 
     * @return the retrieved required modules.
     */
    public Map<Integer, LinkedHashSet<TechnologyModuleDefinition>> getAllRequiredModulesByLevel() {

        Map<Integer, LinkedHashSet<TechnologyModuleDefinition>> requiredModules = new HashMap<Integer, LinkedHashSet<TechnologyModuleDefinition>>();
        fillRequiredModules(requiredModules, 0);

        return requiredModules;
    }

    /**
     * Recursively retrieve all modules required by this module, including itself.
     * 
     * @return the retrieved required modules.
     */
    public Set<TechnologyModuleDefinition> getAllRequiredModules() {

        Map<Integer, LinkedHashSet<TechnologyModuleDefinition>> requiredModules = getAllRequiredModulesByLevel();

        LinkedHashSet<TechnologyModuleDefinition> result = new LinkedHashSet<TechnologyModuleDefinition>();
        for (LinkedHashSet<TechnologyModuleDefinition> set : requiredModules.values()) {
            result.addAll(set);
        }

        return result;
    }

    private void fillRequiredModules(Map<Integer, LinkedHashSet<TechnologyModuleDefinition>> requiredModules,
            int level) {

        // Avoid infinite loop (module1 requires module2 and module2 requires module1)
        for (LinkedHashSet<TechnologyModuleDefinition> set : requiredModules.values()) {
            if (set.contains(this)) {
                return;
            }
        }

        LinkedHashSet<TechnologyModuleDefinition> set = requiredModules.get(level);
        if (set == null) {
            set = new LinkedHashSet<TechnologyModuleDefinition>();
            requiredModules.put(level, set);
        }
        set.add(this);

        for (TechnologyModuleDefinition moduleDefinition : getRequiredModules()) {
            moduleDefinition.fillRequiredModules(requiredModules, level + 1);
        }
    }

    protected static XMLMapping getModuleModel() {
        if (MODULE_MODEL == null) {
            File moduleModelFile = new FileResource("Models/TechnologyModules/ModuleModel.xml");
            try {
                MODULE_MODEL = new XMLMapping(moduleModelFile);
            } catch (Exception e) {
                // Warns about the exception
                if (logger.isLoggable(Level.WARNING)) {
                    logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
                }
                e.printStackTrace();
            }
        }
        return MODULE_MODEL;
    }

    /**
     * Retrieve all {@link TechnologyModuleDefinition} available from classpath. <br>
     * Map contains the TechnologyModuleDefinition name as key and the TechnologyModuleDefinition itself as value.
     * 
     * @return the retrieved TechnologyModuleDefinition map.
     */
    private static Map<String, TechnologyModuleDefinition> getTechnologyModuleDefinitionMap() {
        if (technologyModuleDefinitionMap == null) {
            technologyModuleDefinitionMap = new Hashtable<String, TechnologyModuleDefinition>();

            ServiceLoader<TechnologyModuleDefinition> loader = ServiceLoader.load(TechnologyModuleDefinition.class);
            Iterator<TechnologyModuleDefinition> iterator = loader.iterator();
            while (iterator.hasNext()) {
                TechnologyModuleDefinition technologyModuleDefinition = iterator.next();

                if (technologyModuleDefinitionMap.containsKey(technologyModuleDefinition.getName())) {
                    logger.severe("Cannot include TechnologyModuleDefinition with name '"
                            + technologyModuleDefinition.getName()
                            + "' because it already exists !!!! A Technology module name MUST be unique !");
                } else {
                    technologyModuleDefinitionMap.put(technologyModuleDefinition.getName(),
                            technologyModuleDefinition);
                }
            }
        }

        return technologyModuleDefinitionMap;
    }

    /**
     * Return all available TechnologyModuleDefinition.
     * 
     * @return all available TechnologyModuleDefinition.
     */
    public static Collection<TechnologyModuleDefinition> getAllTechnologyModuleDefinitions() {
        return getTechnologyModuleDefinitionMap().values();
    }

    /**
     * Retrieve and return the TechnologyModuleDefinition with the specified name, null if it doesn't exist.
     * 
     * @param technologyModuleName
     * @return the TechnologyModuleDefinition with the specified name.
     */
    public static TechnologyModuleDefinition getTechnologyModuleDefinition(String technologyModuleName) {
        return getTechnologyModuleDefinitionMap().get(technologyModuleName);
    }

    /* ===================== */
    /* == Getter / Setter == */
    /* ===================== */

    public TechnologyLayer getTechnologyLayer() {
        return technologyLayer;
    }

    public String getName() {
        return name;
    }

    public String getVersion() {
        return version;
    }

    public String getDescription() {
        return description;
    }

    public Set<String> getRequiredModuleNames() {
        return requiredModuleNames;
    }

    public Set<String> getCompatibleModuleNames() {
        return compatibleModuleNames;
    }

    public Set<String> getIncompatibleModuleNames() {
        return incompatibleModuleNames;
    }

    public LinkedHashSet<TechnologyModuleDefinition> getRequiredModules() {
        LinkedHashSet<TechnologyModuleDefinition> result = new LinkedHashSet<TechnologyModuleDefinition>();
        for (String name : requiredModuleNames) {
            TechnologyModuleDefinition technologyModuleDefinition = getTechnologyModuleDefinition(name);
            if (technologyModuleDefinition != null) {
                result.add(technologyModuleDefinition);
            }
        }

        return result;
    }

    public LinkedHashSet<TechnologyModuleDefinition> getCompatibleModules() {
        LinkedHashSet<TechnologyModuleDefinition> result = new LinkedHashSet<TechnologyModuleDefinition>();
        for (String name : compatibleModuleNames) {
            TechnologyModuleDefinition technologyModuleDefinition = getTechnologyModuleDefinition(name);
            if (technologyModuleDefinition != null) {
                result.add(technologyModuleDefinition);
            }
        }

        return result;
    }

    public LinkedHashSet<TechnologyModuleDefinition> getIncompatibleModules() {
        LinkedHashSet<TechnologyModuleDefinition> result = new LinkedHashSet<TechnologyModuleDefinition>();
        for (String name : incompatibleModuleNames) {
            TechnologyModuleDefinition technologyModuleDefinition = getTechnologyModuleDefinition(name);
            if (technologyModuleDefinition != null) {
                result.add(technologyModuleDefinition);
            }
        }

        return result;
    }

    public Map<String, Class<? extends GenerationService>> getRequiredServices() {
        return requiredServices;
    }
}