com.abstratt.mdd.core.util.MDDUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.abstratt.mdd.core.util.MDDUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2008 Abstratt Technologies
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Rafael Chaves (Abstratt Technologies) - initial API and implementation
 *******************************************************************************/
package com.abstratt.mdd.core.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.io.IOUtils;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.query.conditions.eobjects.EObjectCondition;
import org.eclipse.emf.query.statements.FROM;
import org.eclipse.emf.query.statements.IQueryResult;
import org.eclipse.emf.query.statements.SELECT;
import org.eclipse.emf.query.statements.WHERE;
import org.eclipse.uml2.common.util.UML2Util.EObjectMatcher;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.Behavior;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralNull;
import org.eclipse.uml2.uml.LiteralSpecification;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.MultiplicityElement;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.StructuredActivityNode;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.TypedElement;
import org.eclipse.uml2.uml.UMLPackage.Literals;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import com.abstratt.mdd.core.IRepository;
import com.abstratt.mdd.core.MDDCore;
import com.abstratt.mdd.core.util.MDDUtil.IActivityNodeTreeVisitor.Outcome;
import com.abstratt.pluginutils.LogUtils;

/**
 * Another utility class
 */
public class MDDUtil {

    /**
     * Source for an annotation placed on every resource generated by this tool.
     */
    public static final String GENERATED = "com.abstratt/mdd/";
    public static final String UNIT = "com.abstratt/mdd/unit";

    public static class EClassMatcher implements EObjectMatcher {
        private EClass eClass;

        public EClassMatcher(EClass eClass) {
            super();
            this.eClass = eClass;
        }

        public boolean matches(EObject eObject) {
            return eClass.isInstance(eObject);
        }

    }

    public static interface IActivityNodeTreeVisitor {
        enum Outcome {
            CONTINUE, SKIP, STOP
        };
    }

    private static SAXParserFactory cachedParserFactory;

    /**
     * Enhances the given qualified name with the given segment.
     */
    public static String appendSegment(String qualifiedName, String segment) {
        Assert.isNotNull(qualifiedName);
        return qualifiedName + NamedElement.SEPARATOR + segment;
    }

    public static LiteralUnlimitedNatural createLiteralUnlimitedNatural(Package parent, Integer value) {
        LiteralUnlimitedNatural valueSpec = (LiteralUnlimitedNatural) parent.createPackagedElement(null,
                IRepository.PACKAGE.getLiteralUnlimitedNatural());
        valueSpec.setValue(value == null ? LiteralUnlimitedNatural.UNLIMITED : value.intValue());
        valueSpec.setType(BasicTypeUtils.findBuiltInType("Integer"));
        return valueSpec;
    }

    public static LiteralBoolean createLiteralBoolean(Package parent, Boolean value) {
        LiteralBoolean valueSpec = (LiteralBoolean) parent.createPackagedElement(null,
                IRepository.PACKAGE.getLiteralBoolean());
        valueSpec.setValue(value);
        valueSpec.setType(BasicTypeUtils.findBuiltInType("Boolean"));
        return valueSpec;
    }

    public static LiteralInteger createLiteralInteger(Package parent, Integer value) {
        LiteralInteger valueSpec = (LiteralInteger) parent.createPackagedElement(null,
                IRepository.PACKAGE.getLiteralInteger());
        valueSpec.setValue(value);
        valueSpec.setType(BasicTypeUtils.findBuiltInType("Integer"));
        return valueSpec;
    }

    public static LiteralString createLiteralString(Package parent, String value) {
        LiteralString valueSpec = (LiteralString) parent.createPackagedElement(null,
                IRepository.PACKAGE.getLiteralString());
        valueSpec.setValue(value);
        valueSpec.setType(BasicTypeUtils.findBuiltInType("String"));
        return valueSpec;
    }

    public static LiteralNull createLiteralNull(Package parent) {
        LiteralNull valueSpec = (LiteralNull) parent.createPackagedElement(null,
                IRepository.PACKAGE.getLiteralNull());
        return valueSpec;
    }

    public static LiteralSpecification createLiteralValue(Object value, EClass eClass, Package parentProduct) {
        if (Literals.LITERAL_BOOLEAN == eClass)
            return createLiteralBoolean(parentProduct, (Boolean) value);
        if (Literals.LITERAL_INTEGER == eClass)
            return createLiteralInteger(parentProduct, (Integer) value);
        if (Literals.LITERAL_STRING == eClass)
            return createLiteralString(parentProduct, (String) value);
        if (Literals.LITERAL_UNLIMITED_NATURAL == eClass)
            return createLiteralUnlimitedNatural(parentProduct, (Integer) value);
        if (Literals.LITERAL_NULL == eClass)
            return createLiteralNull(parentProduct);
        Assert.isLegal(false, "unsupported literal specification: " + eClass);
        // never gets here
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <T> List<T> filterByClass(List elements, EClass elementClass) {
        List<T> filtered = new ArrayList<T>(elements.size());
        for (Object object : elements)
            if (elementClass.isInstance(object))
                filtered.add((T) object);
        return filtered;
    }

    public static <T extends Element> T findSingleByClass(List<? extends Element> elements, EClass elementClass,
            boolean required) {
        List<T> found = filterByClass(elements, elementClass);
        if (found.size() > 2)
            throw new IllegalArgumentException("Found: " + found.size());
        if (found.isEmpty())
            if (required)
                throw new IllegalArgumentException("Found none");
            else
                return null;
        return found.get(0);
    }

    public static java.net.URI fromEMFToJava(URI emfURI) {
        return java.net.URI.create(emfURI.toString());
    }

    public static URI fromJavaToEMF(java.net.URI javaURI) {
        return URI.createURI(javaURI.toString());
    }

    public static String getArgumentListString(List<? extends TypedElement> argumentList) {
        StringBuffer name = new StringBuffer("(");
        for (TypedElement argument : argumentList) {
            name.append(getTypeName(argument.getType()));
            addMultiplicity(name, argument);
            name.append(", ");
        }
        if (!argumentList.isEmpty())
            name.delete(name.length() - ", ".length(), name.length());
        name.append(")");
        return name.toString();
    }

    protected static void addMultiplicity(StringBuffer name, TypedElement argument) {
        if (argument instanceof MultiplicityElement) {
            MultiplicityElement multiple = (MultiplicityElement) argument;
            if (multiple.isMultivalued()) {
                name.append("[" + multiple.getLower() + ", ");
                name.append(multiple.getUpper() == LiteralUnlimitedNatural.UNLIMITED ? "*" : multiple.getUpper());
                name.append("]");
            }
        }
    }

    /**
     * Returns the qualified name for the parent and simple name given.
     */
    public static String getChildQualifiedName(NamedElement parent, String childSimpleName) {
        return parent.getQualifiedName() + NamedElement.SEPARATOR + childSimpleName;
    }

    public static String getDisplayName(TypedElement typed) {
        final String baseTypeName = MDDUtil.getTypeName(typed.getType());
        if (!(typed instanceof MultiplicityElement))
            return baseTypeName;
        MultiplicityElement asMultiple = (MultiplicityElement) typed;
        if (!asMultiple.isMultivalued())
            return baseTypeName;
        return baseTypeName + '[' + ']';
    }

    /** Returns the first segment in the given QName. */
    public static String getFirstSegment(String qualifiedName) {
        int firstSeparator = qualifiedName.indexOf(NamedElement.SEPARATOR);
        return firstSeparator == -1 ? qualifiedName : qualifiedName.substring(0, firstSeparator);
    }

    /**
     * Returns the last segment in the given QName.
     */
    public static String getLastSegment(String qualifiedName) {
        int lastSeparator = qualifiedName.lastIndexOf(NamedElement.SEPARATOR);
        return lastSeparator == -1 ? qualifiedName
                : qualifiedName.substring(lastSeparator + NamedElement.SEPARATOR.length());
    }

    /**
     * Returns the nearest parent of the given class. Fails if cannot find one.
     * Returns the reference itself if is an instance of the given class.
     * 
     * @param reference
     *            the reference element
     * @param eClass
     *            the type
     * @return any enclosing element of the given class
     */
    public static <T extends Element> T getNearest(Element reference, EClass eClass) {
        if (eClass.isInstance(reference))
            return (T) reference;
        Assert.isTrue(reference.getOwner() != null, "No '" + eClass.getName() + "' around ");
        return getNearest(reference.getOwner(), eClass);
    }

    /**
     * Returns the outermost parent of the given class. Fails if cannot find one.
     * Returns the reference itself if is an instance of the given class and no parent can be found.
     * 
     * @param reference
     *            the reference element
     * @param eClass
     *            the type
     * @return the outermost enclosing element of the given class
     */
    public static <T extends Element> T getFarthest(Element reference, EClass eClass) {
        T parent = getFarthest(reference.getOwner(), eClass);
        if (eClass.isInstance(parent))
            return parent;
        return eClass.isInstance(reference) ? (T) reference : null;
    }

    public static String getTokenFromQName(String qualifiedName) {
        return qualifiedName.replaceAll(NamedElement.SEPARATOR, "_");
    }

    public static String getDescription(Element element) {
        return ElementUtils.getComments(element);
    }

    public static String getTypeName(Type type) {
        if (type == null)
            return "<any>";
        if (type.getName() != null)
            return type.getName();
        if (type instanceof Behavior)
            return computeSignatureName(type);
        if (MDDExtensionUtils.isSignature(type))
            return computeSignatureName(type);
        return "Unknown " + type.eClass().getName();
    }

    public static String computeSignatureName(List<Parameter> signature) {
        StringBuffer name = new StringBuffer("{(");
        final List<Parameter> inputParameters = FeatureUtils.filterParameters(signature,
                ParameterDirectionKind.IN_LITERAL);
        for (Parameter parameter : inputParameters) {
            if (parameter.getName() != null) {
                name.append(parameter.getName());
                name.append(" ");
            }
            name.append(": ");
            final Type parameterType = parameter.getType();
            final String parameterTypeName = parameterType == null ? "any" : parameterType.getQualifiedName();
            name.append(parameterTypeName);
            addMultiplicity(name, parameter);
            name.append(", ");
        }
        if (!inputParameters.isEmpty())
            name.delete(name.length() - ", ".length(), name.length());
        name.append(")");
        List<Parameter> returnParameter = FeatureUtils.filterParameters(signature,
                ParameterDirectionKind.RETURN_LITERAL);
        if (!returnParameter.isEmpty()) {
            name.append(" : ");
            final Type returnType = returnParameter.get(0).getType();
            final String returnTypeName = returnType == null ? "any" : returnType.getQualifiedName();
            name.append(returnTypeName);
        }
        name.append('}');
        return name.toString();
    }

    public static String computeSignatureName(Type type) {
        if (type instanceof Behavior)
            return computeSignatureName(((Behavior) type).getOwnedParameters());
        if (MDDExtensionUtils.isSignature(type))
            return computeSignatureName(MDDExtensionUtils.getSignatureParameters(type));
        return null;
    }

    /**
     * Returns whether the given name is qualified.
     */
    public static boolean isQualifiedName(String name) {
        return name.indexOf(NamedElement.SEPARATOR) >= 0;
    }

    public static String removeFirstSegment(String qualifiedName) {
        int firstSeparator = qualifiedName.indexOf(NamedElement.SEPARATOR);
        return firstSeparator == -1 || firstSeparator == qualifiedName.length() - NamedElement.SEPARATOR.length()
                ? null
                : qualifiedName.substring(firstSeparator + Namespace.SEPARATOR.length());
    }

    /**
     * Returns the given qualified name with the last segment removed.
     */
    public static String removeLastSegment(String qualifiedName) {
        int lastSeparator = qualifiedName.lastIndexOf(NamedElement.SEPARATOR);
        return lastSeparator == -1 ? null : qualifiedName.substring(0, lastSeparator);
    }

    public static String toShortString(Element element) {
        return element.eClass().getName() + "@" + System.identityHashCode(element);
    }

    /*
     * This method dynamically invokes a corresponding visitor method based on the type of the node 
     * being visited. If a type-specific method is not found (visitFoo(Foo), where Foo is the instance class of 
     * the element), a generic visitAny(ActivityNode) method is invoked.  
     */
    private static IActivityNodeTreeVisitor.Outcome visitNode(ActivityNode node, IActivityNodeTreeVisitor visitor) {
        String eClassName = node.eClass().getName();
        try {
            Method visitorMethod;
            try {
                visitorMethod = visitor.getClass().getDeclaredMethod("visit" + eClassName,
                        node.eClass().getInstanceClass());
            } catch (NoSuchMethodException e) {
                // fallback: call visitAny(ActitivityNode) instead
                visitorMethod = visitor.getClass().getDeclaredMethod("visitAny", ActivityNode.class);
            }
            visitorMethod.setAccessible(true);
            return (Outcome) visitorMethod.invoke(visitor, node);
        } catch (NoSuchMethodException e) {
            // keep going...
        } catch (IllegalAccessException e) {
            LogUtils.logWarning(MDDCore.PLUGIN_ID, "Unexpected error", e);
        } catch (InvocationTargetException e) {
            LogUtils.logWarning(MDDCore.PLUGIN_ID, "Unexpected error", e);
        }
        // no visitor method found, continue
        return IActivityNodeTreeVisitor.Outcome.CONTINUE;
    }

    public static boolean visitTree(ActivityNode root, IActivityNodeTreeVisitor visitor) {
        final Outcome outcome = visitNode(root, visitor);
        if (outcome == Outcome.STOP)
            return false;
        if (outcome == Outcome.SKIP || !(root instanceof StructuredActivityNode))
            return true;
        StructuredActivityNode parent = (StructuredActivityNode) root;
        for (ActivityNode current : parent.getNodes())
            if (!visitTree(current, visitor))
                return false;
        return true;
    }

    private MDDUtil() {
        // prevent instantiation
    }

    public static boolean isGenerated(java.net.URI uri) {
        if (cachedParserFactory == null) {
            cachedParserFactory = SAXParserFactory.newInstance();
        }
        SAXParser xmlParser;
        try {
            xmlParser = cachedParserFactory.newSAXParser();
        } catch (ParserConfigurationException e) {
            if (Platform.inDebugMode())
                LogUtils.logError(MDDCore.PLUGIN_ID, "Error creating XML parser", e);
            return false;
        } catch (SAXException e) {
            if (Platform.inDebugMode())
                LogUtils.logError(MDDCore.PLUGIN_ID, "Error creating XML parser", e);
            return false;
        }
        final boolean[] generated = { false };
        final boolean[] aborted = { false };
        InputStream stream = null;
        try {
            stream = new BufferedInputStream(uri.toURL().openStream());
            xmlParser.parse(stream, new DefaultHandler() {
                private boolean skipping = true;

                @Override
                public void startElement(String uri, String localName, String name, Attributes attributes)
                        throws SAXException {
                    if (name.equalsIgnoreCase("eAnnotations"))
                        if (GENERATED.equals(attributes.getValue("source"))) {
                            generated[0] = true;
                            aborted[0] = true;
                            throw new SAXParseException("", null);
                        } else
                            return;
                    if (!skipping) {
                        // should have seen the annotation by now
                        aborted[0] = true;
                        throw new SAXParseException("", null);
                    }
                    if (name.startsWith("uml"))
                        skipping = false;
                }
            });
        } catch (SAXException e) {
            if (!aborted[0] && Platform.inDebugMode())
                LogUtils.logError(MDDCore.PLUGIN_ID, "Error parsing " + uri, e);
        } catch (IOException e) {
            if (Platform.inDebugMode())
                LogUtils.logError(MDDCore.PLUGIN_ID, "Error parsing " + uri, e);
        } finally {
            if (stream != null)
                try {
                    stream.close();
                } catch (IOException e) {
                    // no biggie
                }
        }
        return generated[0];
    }

    public static boolean isGenerated(Package package_) {
        return getRootPackage(package_).getEAnnotation(GENERATED) != null;
    }

    public static Package getRootPackage(Package start) {
        final Package nestingPackage = start.getNestingPackage();
        return (nestingPackage != null) ? getRootPackage(nestingPackage) : start;
    }

    public static <T extends Element> List<T> findAllFrom(EObjectCondition condition,
            Collection<? extends Element> startingPoints) {
        List<T> result = new ArrayList<T>();
        IQueryResult partial = new SELECT(new FROM(startingPoints), new WHERE(condition)).execute();
        for (EObject object : partial)
            result.add((T) object);
        return result;
    }

    public static void markGenerated(Package package_) {
        if (MDDUtil.isGenerated(package_))
            return;
        final Package root = getRootPackage(package_);
        root.createEAnnotation(MDDUtil.GENERATED).getDetails().put("dateCreated",
                new SimpleDateFormat("yyyy/MM/dd hh:mm:ss SSS Z").format(new Date()));
    }

    public static String getGeneratedTimestamp(Package package_) {
        final Package root = getRootPackage(package_);
        EAnnotation eAnnotation = root.getEAnnotation(MDDUtil.GENERATED);
        if (eAnnotation == null)
            return null;
        return eAnnotation.getDetails().get("dateCreated");
    }

    public static void clearGenerated(Package package_) {
        Package root = getRootPackage(package_);
        EAnnotation annotation = root.getEAnnotation(GENERATED);
        if (annotation != null)
            root.getEAnnotations().remove(annotation);
    }

    public static void unloadResources(ResourceSet resourceSet) {
        unloadResources(resourceSet.getResources());
    }

    public static void unloadResources(EList<Resource> resources) {
        for (Resource resource : resources)
            unloadResource(resource);
    }

    public static void unloadResource(Resource current) {
        current.unload();
    }

    public static Properties loadRepositoryProperties(URI baseRepositoryURI) {
        URI propertiesURI = baseRepositoryURI.appendSegment(IRepository.MDD_PROPERTIES);
        URL asURL;
        try {
            asURL = new URL(propertiesURI.toString());
        } catch (MalformedURLException e) {
            // should never happen as it is produced by URI
            LogUtils.log(new Status(IStatus.ERROR, MDDCore.PLUGIN_ID, 0,
                    "Error loading properties at '" + propertiesURI + "'", e));
            return new Properties();
        }
        BufferedInputStream contents = null;
        try {
            contents = new BufferedInputStream(asURL.openStream());
            Properties properties = new Properties();
            properties.load(contents);
            return properties;
        } catch (FileNotFoundException e) {
            return new Properties();
        } catch (IOException e) {
            LogUtils.log(new Status(IStatus.ERROR, MDDCore.PLUGIN_ID, 0,
                    "Error loading properties at '" + propertiesURI + "'", e));
            return new Properties();
        } finally {
            IOUtils.closeQuietly(contents);
        }
    }

    public static boolean doesRepositoryExist(URI repositoryURI) {
        if (!repositoryURI.isFile())
            return false;
        File repositoryDir = new File(repositoryURI.toFileString());
        return repositoryDir.isDirectory() && new File(repositoryDir, IRepository.MDD_PROPERTIES).isFile();
    }
}