All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.eugene.models.object.xml.ObjectModelImpl Maven / Gradle / Ivy

There is a newer version: 3.0
Show newest version
/*
 * #%L
 * EUGene :: EUGene
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * This program 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 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.eugene.models.object.xml;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.eugene.ModelHelper;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelClassifier;
import org.nuiton.eugene.models.object.ObjectModelEnumeration;
import org.nuiton.eugene.models.object.ObjectModelInterface;
import org.nuiton.eugene.models.object.ObjectModelPackage;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Implementation class for the root node abstraction of object model trees.
 * This an entry point for browsing a model tree. This object offers as well
 * several facilities for a direct access to some of the object model elements.
 * In this concrete class, the tree is build by parsing an object model xml
 * description using lutinxml XMLObjectParser.
 *
 * Created: 14 janv. 2004
 *
 * @author Cédric Pineau - [email protected]
 * @plexus.component role="org.nuiton.eugene.models.Model" role-hint="objectmodel"
 */
public class ObjectModelImpl implements ObjectModel {

    /** logger */
    private static final Log log = LogFactory.getLog(ObjectModelImpl.class);

    protected String name;

    protected String version;

    protected Map classes = new HashMap<>();

    protected Map packages = new HashMap<>();

    protected Map interfaces = new HashMap<>();

    protected Map classifiers = new HashMap<>();

    protected Map enumerations = new HashMap<>();

    protected List comments = new ArrayList<>();

    protected Map tagValues = new HashMap<>();

    protected Set stereotypes = new HashSet<>();

    /**
     * Used to add others specific object to the model
     * The key defined must be unique to get the significative extension associated to
     */
    private Map extensions = new HashMap<>();

    @Override
    public String getModelType() {
        return ModelHelper.ModelType.OBJECT.getAlias();
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    @Override
    public String getVersion() {
        return version;
    }

    public void addPackage(ObjectModelPackageImpl aPackage) {
        aPackage.postInit();
        aPackage.setObjectModelImpl(this);

        if (!aPackage.isExtern()) {
            ObjectModelPackageImpl initialElement = (ObjectModelPackageImpl)
                    packages.get(aPackage.getName());
            if (initialElement == null) {
                packages.put(aPackage.getName(), aPackage);
            } else {

                // La package existe déjà. On va prendre tout ce que contient la
                // nouvelle package et l'ajouter à la précédente si nécessaire.

                mergePackages(initialElement, aPackage);
            }
        }
    }

    public void addClass(ObjectModelClassImpl clazz) {
        //if (clazz == null)
        //    return new ObjectModelClassImpl(this, null);
        clazz.postInit();
        clazz.setObjectModelImpl(this);

        if (!clazz.isExtern()) {
            ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
                    classes.get(clazz.getQualifiedName());
            if (initialElement == null) {
                classes.put(clazz.getQualifiedName(), clazz);
                classifiers.put(clazz.getQualifiedName(), clazz);
            } else {
                if (!(initialElement instanceof ObjectModelClassImpl)) {
                    throw new IllegalArgumentException(
                            "\"" + clazz + "\" is incompatible with already " +
                            "defined element \"" + initialElement + "\"");
                }
                ObjectModelClassImpl initialClazz =
                        (ObjectModelClassImpl) initialElement;

                // La classe existe déjà. On va prendre tout ce que contient la
                // nouvelle classe et l'ajouter à la précédente si nécessaire.

                mergeClasses(initialClazz, clazz);
//                clazz = initialClazz;
            }
        }
        //return clazz;
    }

    public void addAssociationClass(ObjectModelAssociationClassImpl clazz) {
        //if (clazz == null)
        //    return new ObjectModelAssociationClassImpl(this, null);
        clazz.postInit();
        clazz.setObjectModelImpl(this);

        if (!clazz.isExtern()) {
            ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
                    classes.get(clazz.getQualifiedName());
            if (initialElement == null) {
                classes.put(clazz.getQualifiedName(), clazz);
                classifiers.put(clazz.getQualifiedName(), clazz);
            } else {
                if (!(initialElement instanceof ObjectModelAssociationClassImpl)) {
                    throw new IllegalArgumentException(
                            "\"" + clazz + "\" is incompatible with " +
                            "already defined element \"" + initialElement +
                            "\""
                    );
                }
                ObjectModelAssociationClassImpl initialClazz =
                        (ObjectModelAssociationClassImpl) initialElement;

                mergeAssociationClasses(initialClazz, clazz);
//                clazz = initialClazz;
            }
        }
        //return clazz;
    }

    public void addComment(String comment) {
        comments.add(comment);
    }

    /**
     * Returns the name of this model.
     *
     * @return the name of this model.
     */
    @Override
    public String getName() {
        return name;
    }


    @Override
    public Collection getPackages() {
        return packages.values();
    }

    @Override
    public ObjectModelPackage getPackage(String packageName) {
        return packages.get(packageName);
    }

    @Override
    public ObjectModelPackage getPackage(ObjectModelClassifier classifier) {
        return getPackage(classifier.getPackageName());
    }

    @Override
    public boolean hasPackage(String packageName) {
        return packages.containsKey(packageName);
    }

    /**
     * Returns all classifiers defined in this model.
     *
     * @return a Collection containing all ObjectModelClassifier for this model.
     * @see ObjectModelClassifier
     */
    @Override
    public Collection getClassifiers() {
        return classifiers.values();
    }

    /**
     * Returns the classifier corresponding to the given qualified name, or null
     * if the model contains no classifier for this qualified name.
     *
     * @param qualifiedClassifierName -
     *                                the qualified name of the classifier to retrieve.
     * @return the ObjectModelClassifier of the found classifier, or null if the
     * model contains no classifier for this qualified name.
     */
    @Override
    public ObjectModelClassifier getClassifier(String qualifiedClassifierName) {
        return qualifiedClassifierName == null ? null
                                               : classifiers.get(qualifiedClassifierName);
    }

    /**
     * Returns all classes defined in this model.
     *
     * @return a Collection containing all ObjectModelClass for this model.
     * @see ObjectModelClass
     */
    @Override
    public Collection getClasses() {
        return classes.values();
    }

    /**
     * Returns the class corresponding to the given qualified name, or null if
     * the model contains no class for this qualified name.
     *
     * @param qualifiedClassName -
     *                           the qualified name of the class to retrieve.
     * @return the ObjectModelClass of the found class, or null if the model
     * contains no class for this qualified name.
     */
    @Override
    public ObjectModelClass getClass(String qualifiedClassName) {
        if (qualifiedClassName == null) {
            return null;
        }
        if (!hasClass(qualifiedClassName)) {
            if (log.isDebugEnabled()) {
                log.debug("Class " + qualifiedClassName + " not found in model");
            }
            return null;
        }
        return classes.get(qualifiedClassName);
    }

    @Override
    public boolean hasClass(String qualifiedClassName) {
        boolean hasClass = classes.containsKey(qualifiedClassName);
        return hasClass;
    }

    public void addInterface(ObjectModelInterfaceImpl interfacez) {
        //if (interfacez == null)
        //    return new ObjectModelInterfaceImpl(this, null);
        interfacez.postInit();
        interfacez.setObjectModelImpl(this);

        if (!interfacez.isExtern()) {
            ObjectModelElementImpl initialElement = (ObjectModelElementImpl)
                    interfaces.get(interfacez.getQualifiedName());
            if (initialElement == null) {
                interfaces.put(interfacez.getQualifiedName(), interfacez);
                classifiers.put(interfacez.getQualifiedName(), interfacez);
            } else {
                if (!(initialElement instanceof ObjectModelInterfaceImpl)) {
                    throw new IllegalArgumentException(
                            "\"" + interfacez + "\" is incompatible with " +
                            "already defined element \"" + initialElement +
                            "\"");
                }
                ObjectModelInterfaceImpl initialInterfacez =
                        (ObjectModelInterfaceImpl) initialElement;

                mergeClassifiers(initialInterfacez, interfacez);
//                interfacez = initialInterfacez;
            }
        }
        //return interfacez;
    }

    /**
     * Returns the interface corresponding to the given qualified name, or null
     * if the model contains no interface for this qualified name.
     *
     * @param qualifiedInterfaceName -
     *                               the qualified name of the interface to retrieve.
     * @return the ObjectModelInterface of the found interface, or null if the
     * model contains no interface for this qualified name.
     */
    @Override
    public ObjectModelInterface getInterface(String qualifiedInterfaceName) {
        ObjectModelInterface result = interfaces.get(qualifiedInterfaceName);
        if (result == null) {
            if (log.isDebugEnabled()) {
                log.debug("Interface " + qualifiedInterfaceName +
                          " not found in model");
            }
        }
        return result;
    }

    /**
     * Returns all interfaces defined in this model.
     *
     * @return a Collection containing all ObjectModelInterface for this model.
     * @see ObjectModelInterface
     */
    @Override
    public Collection getInterfaces() {
        return interfaces.values();
    }

    public void addEnumeration(ObjectModelEnumerationImpl enumeration) {
        enumeration.postInit();
        enumeration.setObjectModelImpl(this);
        classifiers.put(enumeration.getQualifiedName(), enumeration);
        enumerations.put(enumeration.getQualifiedName(), enumeration);
    }

    @Override
    public Collection getEnumerations() {
        return enumerations.values();
    }

    @Override
    public ObjectModelEnumeration getEnumeration(String qualifiedEnumerationName) {
        ObjectModelEnumeration result =
                enumerations.get(qualifiedEnumerationName);
        if (result == null) {
            if (log.isDebugEnabled()) {
                log.debug("Enumeration " + qualifiedEnumerationName +
                          " not found in model");
            }
        }
        return result;
    }

    /**
     * Returns all comments not lied to a particular model element
     *
     * @return a List containing all comments for this model as Strings.
     */
    @Override
    public List getComments() {
        return comments;
    }

    @Override
    public Set getStereotypes() {
        return stereotypes;
    }

    @Override
    public boolean hasStereotype(String stereotypeName) {
        return stereotypes.contains(stereotypeName);
    }

    @Override
    public void addStereotype(String stereotype) {
        stereotypes.add(stereotype);
    }

    protected void mergePackages(
            ObjectModelPackageImpl initialPackage,
            ObjectModelPackageImpl additionalPackage) {
        Iterator it;

        String description = "";
        String sourceDoc = "";
        if (initialPackage.documentation != null) {
            description += initialPackage.getDescription();
            if (initialPackage.documentation.contains("--")) {
                sourceDoc += initialPackage.getSourceDocumentation();
            }
        }
        if (additionalPackage.documentation != null) {
            if (!description.equals("")) {
                description += " - ";
            }
            description += additionalPackage.getDescription();
            if (additionalPackage.documentation.contains("--")) {
                if (!sourceDoc.equals("")) {
                    sourceDoc += " - ";
                }
                sourceDoc += additionalPackage.getSourceDocumentation();
            }
        }
        if (!description.equals("") || !sourceDoc.equals("")) {
            initialPackage.documentation = description + "--" + sourceDoc;
        }

        for (it = additionalPackage.getComments().iterator(); it.hasNext(); ) {
            String comment = (String) it.next();
            if (!initialPackage.comments.contains(comment)) {
                initialPackage.comments.add(comment);
            }
        }
        for (it = additionalPackage.getStereotypes().iterator(); it.hasNext(); ) {
            String stereotype = (String) it.next();
            if (!initialPackage.getStereotypes().contains(stereotype)) {
                initialPackage.stereotypes.add(stereotype);
            }
        }

        for (it = additionalPackage.getTagValues().keySet().iterator(); it.hasNext(); ) {
            String tagName = (String) it.next();
            if (!initialPackage.getTagValues().containsKey(tagName)) {
                initialPackage.tagValues.put(
                        tagName,
                        additionalPackage.getTagValue(tagName)
                );
            }
        }
    }

    protected void mergeClassifiers(
            ObjectModelClassifierImpl initialClazzifier,
            ObjectModelClassifierImpl additionalClazzifier) {
        Iterator it;

        // On n'utilise pas les parsetXXX puisque les post-init sont censés être
        // déjà faits...

        // System.out.println("Doc initial : " +
        // initialClazzifier.documentation);
        // System.out.println("Doc additional : " +
        // additionalClazzifier.documentation);
        String description = "";
        String sourceDoc = "";
        if (initialClazzifier.documentation != null) {
            description += initialClazzifier.getDescription();
            if (initialClazzifier.documentation.contains("--")) {
                sourceDoc += initialClazzifier.getSourceDocumentation();
            }
        }
        if (additionalClazzifier.documentation != null) {
            if (!description.equals("")) {
                description += " - ";
            }
            description += additionalClazzifier.getDescription();
            if (additionalClazzifier.documentation.contains("--")) {
                if (!sourceDoc.equals("")) {
                    sourceDoc += " - ";
                }
                sourceDoc += additionalClazzifier.getSourceDocumentation();
            }
        }
        if (!description.equals("") || !sourceDoc.equals("")) {
            initialClazzifier.documentation = description + "--" + sourceDoc;
        }
        // System.out.println("Doc after : " + initialClazzifier.documentation);

        for (it = additionalClazzifier.interfacesRefs.iterator(); it.hasNext(); ) {
            ObjectModelImplRef interfaceRef = (ObjectModelImplRef) it.next();
            if (!contains(initialClazzifier.interfacesRefs, interfaceRef)) {
                initialClazzifier.interfacesRefs.add(interfaceRef);
            }
            initialClazzifier.interfaces = null; // On force ainsi à
            // regénérer l'objet
        }
        for (it = additionalClazzifier.getOperations().iterator(); it.hasNext(); ) {
            ObjectModelOperationImpl operation = (ObjectModelOperationImpl) it.next();
            if (!contains(initialClazzifier.getOperations(), operation)) {
                initialClazzifier.operations.add(operation);
            }
        }
        for (it = additionalClazzifier.getDependencies().iterator(); it.hasNext(); ) {
            ObjectModelDependencyImpl dependency = (ObjectModelDependencyImpl) it.next();
            if (!contains(initialClazzifier.getDependencies(), dependency)) {
                initialClazzifier.dependencies.add(dependency);
            }
        }
        for (it = additionalClazzifier.getComments().iterator(); it.hasNext(); ) {
            String comment = (String) it.next();
            if (!initialClazzifier.comments.contains(comment)) {
                initialClazzifier.comments.add(comment);
            }
        }
        for (it = additionalClazzifier.getStereotypes().iterator(); it.hasNext(); ) {
            String stereotype = (String) it.next();
            if (!initialClazzifier.getStereotypes().contains(stereotype)) {
                initialClazzifier.stereotypes.add(stereotype);
            }
        }

        for (it = additionalClazzifier.getTagValues().keySet().iterator(); it.hasNext(); ) {
            String tagName = (String) it.next();
            if (!initialClazzifier.getTagValues().containsKey(tagName)) {
                initialClazzifier.tagValues.put(
                        tagName,
                        additionalClazzifier.getTagValue(tagName)
                );
            }
        }
    }

    /**
     * This method takes two ObjectModelClassImpl and merges both of them in the
     * first one
     *
     * @param initialClazz    the instance of ObjectModelClassImpl to be modified
     * @param additionalClazz the instance of ObjectModelClassImpl tu be used for merging
     */
    private void mergeClasses(ObjectModelClassImpl initialClazz,
                              ObjectModelClassImpl additionalClazz) {
        Iterator it;
        mergeClassifiers(initialClazz, additionalClazz);

        for (it = additionalClazz.getAttributes().iterator(); it.hasNext(); ) {
            ObjectModelAttributeImpl attribute =
                    (ObjectModelAttributeImpl) it.next();
            if (!contains(initialClazz.getAttributes(), attribute)) {
                initialClazz.attributes.put(attribute.getName(), attribute);
                initialClazz.orderedAttributes.add(attribute);
            }
        }
        for (it = additionalClazz.superclassesRefs.iterator(); it.hasNext(); ) {
            ObjectModelImplRef superclassRef = (ObjectModelImplRef) it.next();
            if (!contains(initialClazz.superclassesRefs, superclassRef)) {
                initialClazz.superclassesRefs.add(superclassRef);
            }
            initialClazz.superclasses = null; // On force ainsi à regénérer
            // l'objet
        }
    }

    private void mergeAssociationClasses(
            ObjectModelAssociationClassImpl initialAssocClazz,
            ObjectModelAssociationClassImpl additionalAssocClazz) {
        mergeClasses(initialAssocClazz, additionalAssocClazz);
        Iterator it;
        for (it = additionalAssocClazz.participantsRefs.iterator(); it.hasNext(); ) {
            ObjectModeImplAssociationClassParticipant participant =
                    (ObjectModeImplAssociationClassParticipant) it.next();
            if (!contains(initialAssocClazz.participantsRefs, participant)) {
                initialAssocClazz.participantsRefs.add(participant);
            }
            initialAssocClazz.participantsAttributes = null; // On force
            // ainsi à
            // regénérer
            // l'objet
            initialAssocClazz.participantsClassifiers = null; // On force
            // ainsi à
            // regénérer
            // l'objet
        }
    }

    private boolean contains(Collection coll,
                             ObjectModelAttributeImpl toFind) {
        for (ObjectModelAttribute attribute : coll) {
            if (attribute.getName().equals(toFind.getName())) { // Seul le nom
                // de l'attribut
                // compte
                return true;
            }
        }
        return false;
    }

    private boolean contains(Collection coll, ObjectModelOperationImpl toFind) {
        return coll.contains(toFind); // Le equals(...) de
        // ObjectModelOperationImpl convient
    }

    private boolean contains(Collection coll, ObjectModelImplRef toFind) {
        return coll.contains(toFind); // Le equals(...) de ObjectModelImplRef
        // convient
    }

    public ObjectModelImplTagValue addTagValue(ObjectModelImplTagValue tagValue) {
        if (tagValue == null) {
            return new ObjectModelImplTagValue();
        }
        tagValues.put(tagValue.getName(), tagValue.getValue());
        return tagValue;
    }

    @Override
    public Map getTagValues() {
        return tagValues;
    }

    @Override
    public String getTagValue(String tagValue) {
        return tagValue == null ? null : tagValues.get(tagValue);
    }

    @Override
    public void addTagValue(String tagValue, String value) {
        String oldValue = getTagValue(tagValue);
        if (StringUtils.isNotEmpty(oldValue) && !oldValue.equals(value)) {
            if (log.isWarnEnabled()) {
                log.warn("Replace tagValue '" + tagValue + "' (old:" +
                         oldValue + ", new: " + value + ")");
            }
        }
        tagValues.put(tagValue, value);
    }

    @Override
    public boolean hasTagValue(String tagValue) {
        return tagValues.containsKey(tagValue);
    }

    /**
     * Get the extension associated to the reference (unique). Create it if not exist.
     *
     * @param             object type returned
     * @param reference      unique corresponding to the extension to get
     * @param extensionClass class of the extension
     * @return the object value for the extension
     * @throws ClassCastException when extensionClass is not valid
     * @throws RuntimeException   when instantiation problem to create new extension
     */
    @Override
    @SuppressWarnings("unchecked")
    public  O getExtension(String reference, Class extensionClass) throws RuntimeException {
        if (reference == null) {
            throw new NullPointerException("reference parameter can not be null in method ObjectModelImpl#getExtension");
        }
        if (extensionClass == null) {
            throw new NullPointerException("extensionClass parameter can not be null in method ObjectModelImpl#getExtension.");
        }
        Object object = extensions.get(reference);
        O result;
        if (object != null && !extensionClass.isAssignableFrom(object.getClass())) {
            throw new ClassCastException("Invalid cast for " + extensionClass.getName());
        }
        if (object == null) {
            try {
                result = extensionClass.newInstance();
            } catch (Exception eee) { // IllegalAccessException and InstantiationException
                throw new RuntimeException("Unable to create new extension '" + extensionClass.getName() +
                                           "' for '" + reference + "'", eee);
            }
            extensions.put(reference, result);
        } else {
            result = (O) object;
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy