gov.nih.nci.sdk.modelconverter.xmi2ecore.XMI2EcoreModelConverter.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.sdk.modelconverter.xmi2ecore.XMI2EcoreModelConverter.java

Source

/*L
 *  Copyright Ekagra Software Technologies Ltd.
 *  Copyright SAIC, SAIC-Frederick
 *
 *  Distributed under the OSI-approved BSD 3-Clause License.
 *  See http://ncip.github.com/cacore-sdk/LICENSE.txt for details.
 */

package gov.nih.nci.sdk.modelconverter.xmi2ecore;

import gov.nih.nci.sdk.modelconverter.ModelConverter;
import gov.nih.nci.sdk.modelconverter.util.ModelConverterUtil;
import gov.nih.nci.sdk.util.SDKUtil;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.eclipse.emf.codegen.util.CodeGenUtil;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
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.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.impl.EClassImpl;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.importer.ModelImporter;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.ecore.importer.UMLImporter;
import org.eclipse.uml2.uml.internal.resource.XMI2UMLResourceFactoryImpl;
import org.eclipse.uml2.uml.util.UMLUtil;

/**
 * XMI2EcoreModelConverter class converts UML model inside an XMI file to Ecore
 * model represented by <tt>EPackage</tt>.
 * 
 * TODO: This code does not load tag values of the Package level. Since this 
 * is not of the highest priority, I will add that feature later. --John
 * 
 * @author John Chen
 * 
 */
public class XMI2EcoreModelConverter extends UMLImporter implements ModelConverter {

    private Collection<EAnnotation> tags = new ArrayList<EAnnotation>();

    /**
     * Converts UML model inside the xmi file to Ecore model.
     * 
     * @param xmiFilePath
     *            full file path to the xmi file.
     * @return a root instance of EPackage inside the xmi file or <tt>null</tt>
     *         if there is none.
     * @throws Exception
     */
    public EPackage convert(String xmiFilePath) throws Exception {
        if (xmiFilePath == null)
            throw new IllegalArgumentException("xmiFilePath cannot be null.");

        File preparedFile = prepareFile(xmiFilePath);
        URI uri = URI.createFileURI(preparedFile.getCanonicalPath());
        String modelLocation = uri.toString();
        super.setModelLocation(modelLocation);

        Map<String, String> options = new HashMap<String, String>();
        List<URI> locationURIs = getModelLocationURIs();
        Collection<org.eclipse.uml2.uml.Package> packages = new ArrayList<org.eclipse.uml2.uml.Package>();

        ResourceSet umlResourceSet = createResourceSet();
        umlResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi",
                new XMI2UMLResourceFactoryImpl());

        for (URI locationURI : locationURIs) {
            packages.addAll(EcoreUtil.<org.eclipse.uml2.uml.Package>getObjectsByType(
                    umlResourceSet.getResource(locationURI, true).getContents(), UMLPackage.Literals.PACKAGE));
        }

        EcoreUtil.resolveAll(umlResourceSet);

        BasicDiagnostic diagnostics = null;

        Map<Object, Object> context = new HashMap<Object, Object>();
        context.put(org.eclipse.uml2.common.util.UML2Util.QualifiedTextProvider.class,
                UMLUtil.QualifiedTextProvider.DEFAULT);

        @SuppressWarnings("unchecked")
        Collection<EPackage> ePackages = (Collection<EPackage>) new UMLUtil.UML2EcoreConverter() {

            @Override
            protected void processEcoreTaggedValues(EPackage ePackage, Element element, Map<String, String> options,
                    DiagnosticChain diagnostics, Map<Object, Object> context) {

                super.processEcoreTaggedValues(ePackage, element, options, diagnostics, context);

                Stereotype ePackageStereotype = getAppliedEcoreStereotype(element, UMLUtil.STEREOTYPE__E_PACKAGE);

                if (null != ePackageStereotype) {
                    ModelImporter.EPackageImportInfo ePackageInfo = getEPackageImportInfo(ePackage);

                    if (element.hasValue(ePackageStereotype, UMLUtil.TAG_DEFINITION__BASE_PACKAGE)) {

                        StringBuffer basePackage = new StringBuffer();

                        for (StringTokenizer stringTokenizer = new StringTokenizer(
                                (String) element.getValue(ePackageStereotype, UMLUtil.TAG_DEFINITION__BASE_PACKAGE),
                                "."); stringTokenizer //$NON-NLS-1$
                                        .hasMoreTokens();) {

                            basePackage.append(CodeGenUtil.safeName(stringTokenizer.nextToken()));

                            if (stringTokenizer.hasMoreTokens()) {
                                basePackage.append('.');
                            }
                        }

                        ePackageInfo.setBasePackage(basePackage.toString());
                    }

                    if (element.hasValue(ePackageStereotype, UMLUtil.TAG_DEFINITION__PREFIX)) {

                        ePackageInfo.setPrefix(
                                (String) element.getValue(ePackageStereotype, UMLUtil.TAG_DEFINITION__PREFIX));
                    }
                }
            }
        }.convert(packages, options, diagnostics, context);

        EPackage rootEPackage = null;
        Iterator<EPackage> it = ePackages.iterator();
        if (it.hasNext()) {
            rootEPackage = it.next();
        }

        readTags(xmiFilePath, rootEPackage);

        fetchTags(preparedFile, rootEPackage);

        preparedFile.delete();

        SDKUtil.setSDKTags(tags);

        return rootEPackage;
    }

    private void readTags(String xmiFilePath, EPackage rootEPackage) {
        Iterator<EObject> pkgIter = rootEPackage.eContents().iterator();
        EObject eo = null;
        while (pkgIter.hasNext()) {
            eo = pkgIter.next();

            if (eo instanceof EClassImpl) {
                EClass eClass = (EClassImpl) eo;

                Map<String, String> ctags = ModelConverterUtil.getClassTags(xmiFilePath, eClass);
                addAnnotationToModelElement(eClass, ctags);

                EList<EAttribute> attrs = eClass.getEAttributes();
                if (attrs != null) {
                    Iterator<EAttribute> it = attrs.iterator();
                    while (it.hasNext()) {
                        EAttribute attr = it.next();
                        Map<String, String> tags = ModelConverterUtil.getAttributeTags(xmiFilePath, attr);
                        addAnnotationToModelElement(attr, tags);
                    }
                }

                EList<EOperation> opers = eClass.getEOperations();
                if (opers != null) {
                    Iterator<EOperation> it = opers.iterator();
                    while (it.hasNext()) {
                        EOperation oper = it.next();
                        Map<String, String> tags = ModelConverterUtil.getOperationTags(xmiFilePath, oper);
                        addAnnotationToModelElement(oper, tags);
                    }
                }

                EList<EReference> refs = eClass.getEReferences();
                if (refs != null) {
                    Iterator<EReference> it = refs.iterator();
                    while (it.hasNext()) {
                        EReference ref = it.next();
                        Map<String, String> tags = ModelConverterUtil.getReferenceTags(xmiFilePath, ref);
                        addAnnotationToModelElement(ref, tags);
                    }
                }

            } else if (eo instanceof EPackage) {
                EPackage pkg = (EPackage) eo;

                Map<String, String> tags = ModelConverterUtil.getPackageTags(xmiFilePath, pkg);
                addAnnotationToModelElement(pkg, tags);

                readTags(xmiFilePath, pkg);
            }
        }
    }

    File prepareFile(String filePath) throws IOException {
        File f = new File(filePath);
        if (!f.exists())
            throw new FileNotFoundException("File " + filePath + " does not exist.");

        List<String> lines = new ArrayList<String>();

        BufferedReader in = new BufferedReader(new FileReader(filePath));
        String line = null;
        while ((line = in.readLine()) != null) {

            // replace templateSignature
            if (line.indexOf(searchStringTemplateSignature) != -1) {
                line = StringUtils.replace(line, searchStringTemplateSignature, replacementTemplateSignature);
            }

            // replace thecustomprofile
            if (line.indexOf(searchStringCustomProfile) != -1) {
                line = StringUtils.replace(line, searchStringCustomProfile, replacementCustomProfile);
            }

            // add xmi:type
            if (line.indexOf(searchStringXMIType) != -1) {
                line = StringUtils.replace(line, searchStringXMIType, replacementXMITypeString);
            }

            lines.add(line);

            if (line.indexOf("</uml:Model>") != -1) {
                lines.add("</xmi:XMI>");
                break;
            }
        }
        in.close();

        String tmpDir = System.getProperty("user.dir", "");
        String tmpFileName = tmpDir + File.separator + "_sdk_" + f.getName();

        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(tmpFileName)));
        Iterator<String> it = lines.iterator();
        while (it.hasNext()) {
            String l = it.next();
            out.println(l);
        }
        out.flush();
        out.close();

        return new File(tmpFileName);
    }

    void fetchTags(File file, EPackage rootEPackage) throws IOException {
        if (file == null || rootEPackage == null)
            return;

        if (!file.exists())
            throw new FileNotFoundException("File " + file + " does not exist.");

        List<String> lines = new ArrayList<String>();
        List<TagLine> tagLines = new ArrayList<TagLine>();
        BufferedReader in = new BufferedReader(new FileReader(file));
        String line = null;
        TagLine tagLine = null;
        while ((line = in.readLine()) != null) {
            lines.add(line);

            if (line.indexOf("<thecustomprofile:") != -1 && line.indexOf(" base_") != -1) {
                tagLine = new TagLine(line);
                if (tagLine.isSDKTag()) {
                    tagLines.add(tagLine);
                }
            }
        }
        in.close();

        if (lines.size() == 0 || tagLines.size() == 0)
            return;

        fillInSourceForTags(lines, tagLines);
        linkTagsWithModel(rootEPackage, tagLines);
    }

    private void fillInSourceForTags(List<String> lines, List<TagLine> tagLines) {
        Iterator<TagLine> it = tagLines.iterator();
        while (it.hasNext()) {
            TagLine tag = it.next();
            fillInSourceForTag(lines, tag);
        }
    }

    private void fillInSourceForTag(List<String> lines, TagLine tag) {
        String searchToken = "xmi:id=\"" + tag.baseId + "\"";
        Iterator<String> it = lines.iterator();
        int count = 0;
        while (it.hasNext()) {
            String line = it.next();
            if (line.indexOf(searchToken) != -1) {
                String source = getValueForToken(line, "name");
                tag.source = source;
                if (tag.isClassTag()) {
                    tag.containerClass = source;
                } else if (tag.isPropTag() || tag.isOperTag()) {
                    detectClassName(lines, count, tag);
                } else if (tag.isRelGeneralizationTag()) {
                    detectClassName(lines, count, tag);
                    detectRelatedClassName(lines, line, tag);
                } else {
                    ;//TODO: need to handle Package and RelAggregation tags
                }
            }
            count++;
        }
    }

    String detectClassName(List<String> lines, int index, TagLine tag) {
        String s = null;
        for (int i = index; i > 0; i--) {
            String line = lines.get(i).trim();
            if (line.startsWith("<packagedElement xmi:type=\"uml:Class\"")) {
                s = getValueForToken(line, "name");
                tag.containerClass = s;
                break;
            }
        }
        return s;
    }

    void detectRelatedClassName(List<String> lines, String tagLine, TagLine tag) {
        String general = getValueForToken(tagLine, "general");
        String searchToken = "xmi:id=\"" + general + "\"";
        Iterator<String> it = lines.iterator();
        while (it.hasNext()) {
            String line = it.next();
            if (line.indexOf(searchToken) != -1) {
                String name = getValueForToken(line, "name");
                tag.relatedClass = name;
                break;
            }
        }
    }

    private void linkTagsWithModel(EPackage rootPkg, List<TagLine> tagLines) {
        Iterator<TagLine> it = tagLines.iterator();
        while (it.hasNext()) {
            TagLine tag = it.next();
            linkTagWithModel(rootPkg, tag);
        }
    }

    private void linkTagWithModel(EPackage rootPkg, TagLine tag) {
        if (tag == null || !tag.isSDKTag())
            return;

        if (tag.isClassTag()) {
            //linkClassTagWithModel(rootPkg, tag);
        } else if (tag.isPropTag()) {
            //linkPropTagWithModel(rootPkg, tag);
        } else if (tag.isOperTag()) {
            //linkOperTagWithModel(rootPkg, tag);
        } else if (tag.isRelGeneralizationTag()) {
            linkRelGeneralizationTagWithModel(rootPkg, tag);
        } else if (tag.isRelAggregationTag()) {
            //This is handled by readTags
        } else if (tag.isPackageTag()) {
            //This is handled by readTags
        }
    }

    static String getValueForToken(String line, String token) {
        if (line.endsWith("/>")) {
            line = line.substring(0, line.length() - 2);
        } else if (line.endsWith(">")) {
            line = line.substring(0, line.length() - 2);
        }
        int nameIndex = line.indexOf(token + '=');
        if (nameIndex == -1)
            return null;

        int startIndex = nameIndex + token.length() + 1;
        int endIndex = line.indexOf(' ', startIndex + 1);
        String s = (endIndex != -1) ? line.substring(startIndex, endIndex) : line.substring(startIndex);
        s = StringUtils.remove(s, '"');
        return s;
    }

    public void linkClassTagWithModel(EPackage rootEPackage, TagLine tag) {
        if (rootEPackage == null || tag == null)
            return;

        EModelElement modelElement = gov.nih.nci.sdk.util.EcoreUtil.getModelElementForName(rootEPackage,
                tag.containerClass);
        if (modelElement == null) {
            System.out.println("linkClassTagWithModel ERROR: This should not happen.");//TODO: log the error.
        }

        addAnnotationToModelElement(modelElement, tag);
    }

    public void linkPropTagWithModel(EPackage rootEPackage, TagLine tag) {
        if (rootEPackage == null || tag == null)
            return;

        EModelElement modelElement = gov.nih.nci.sdk.util.EcoreUtil.getModelElementForName(rootEPackage,
                tag.containerClass);
        if (modelElement == null) {
            System.out.println("linkPropTagWithModel ERROR: This should not happen.");//TODO: log the error.
        }

        EList<EStructuralFeature> attributes = ((EClass) modelElement).getEAllStructuralFeatures();
        Iterator<EStructuralFeature> itAttr = attributes.iterator();
        while (itAttr.hasNext()) {
            EStructuralFeature attr = itAttr.next();

            if (tag.source.equals(attr.getName())) {
                addAnnotationToModelElement(attr, tag);
            }
        }
    }

    public void linkOperTagWithModel(EPackage rootEPackage, TagLine tag) {
        if (rootEPackage == null || tag == null)
            return;

        EModelElement modelElement = gov.nih.nci.sdk.util.EcoreUtil.getModelElementForName(rootEPackage,
                tag.containerClass);
        if (modelElement == null) {
            System.out.println("linkOperTagWithModel ERROR: This should not happen.");//TODO: log the error.
        }

        EList<EOperation> operations = ((EClass) modelElement).getEAllOperations();
        Iterator<EOperation> itOper = operations.iterator();
        while (itOper.hasNext()) {
            EOperation oper = itOper.next();

            if (tag.source.equals(oper.getName())) {
                addAnnotationToModelElement(oper, tag);
            }
        }
    }

    public void linkRelGeneralizationTagWithModel(EPackage rootEPackage, TagLine tag) {
        if (rootEPackage == null || tag == null)
            return;

        EModelElement modelElement = gov.nih.nci.sdk.util.EcoreUtil.getModelElementForName(rootEPackage,
                tag.containerClass);
        if (modelElement == null) {
            System.out.println("linkRelGeneralizationTagWithModel ERROR: This should not happen.");//TODO: log the error.
        }

        addAnnotationToModelElement(modelElement, tag);
    }

    private void addAnnotationToModelElement(EModelElement modelElement, TagLine tag) {
        addAnnotationToModelElement(modelElement, tag.name, tag.value);
    }

    private void addAnnotationToModelElement(EModelElement modelElement, String tagName, String tagValue) {
        EAnnotation ann = EcoreFactory.eINSTANCE.createEAnnotation();
        ann.setSource(tagName);
        ann.setEModelElement(modelElement);
        ann.getDetails().put(tagName, tagValue);
        tags.add(ann);
    }

    private void addAnnotationToModelElement(ENamedElement element, Map<String, String> tags) {
        if (tags == null || tags.size() == 0)
            return;
        Set<Entry<String, String>> tagSet = tags.entrySet();
        for (Entry<String, String> entry : tagSet) {
            String name = entry.getKey();
            String value = entry.getValue();
            addAnnotationToModelElement(element, name, value);
        }
    }

    class TagLine {
        String baseId;
        String baseLevel;
        String name;
        String value;
        String source;
        String containerClass;
        String relatedClass;

        TagLine(String line) {
            init(line);
        }

        boolean isSDKTag() {
            return SDKUtil.isSDKTag(name);
        }

        boolean isPropTag() {
            return "Attribute".equals(baseLevel);
        }

        boolean isClassTag() {
            return "Class".equals(baseLevel);
        }

        boolean isOperTag() {
            return "Operation".equals(baseLevel);
        }

        boolean isRelAggregationTag() {
            return "Aggregation".equals(baseLevel);
        }

        boolean isRelGeneralizationTag() {
            return "Generalization".equals(baseLevel);
        }

        boolean isPackageTag() {
            throw new UnsupportedOperationException();//TODO
        }

        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("name=").append(name).append(",");
            sb.append("value=").append(value).append(",");
            sb.append("baseLevel=").append(baseLevel).append(",");
            sb.append("baseId=").append(baseId).append(",");
            sb.append("source=").append(source).append(",");
            sb.append("containerClass=").append(containerClass).append(",");
            sb.append("relatedClass=").append(relatedClass);
            return sb.toString();
        }

        private void init(String line) {
            if (line == null)
                return;
            try {
                //parse the line
                line = line.trim();
                name = line.substring("<thecustomprofile:".length(), line.indexOf(' '));
                name = StringUtils.remove(name, '"');

                int valueStartIndex = line.indexOf(name + '=');
                if (valueStartIndex != -1) {
                    value = line.substring(line.lastIndexOf('=') + 2, line.lastIndexOf('"'));

                    String ln = line.substring(line.indexOf("base_") + 5, valueStartIndex - 1);
                    ln = StringUtils.remove(ln, '"');
                    baseLevel = ln.substring(0, ln.indexOf('='));

                    baseId = ln.substring(ln.indexOf('=') + 1);
                }
            } catch (Exception ex) {
                throw new IllegalArgumentException("Failed to parse line \"" + line + "\".");
            }
        }
    }

    private static final String searchStringTemplateSignature = "uml:TemplateSignature";
    private static final String replacementTemplateSignature = "uml:RedefinableTemplateSignature";

    private static final String searchStringCustomProfile = "thecustomprofile:owner";
    private static final String replacementCustomProfile = "thecustomprofile:import";

    private static final String searchStringXMIType = "<defaultValue xmi:id";
    private static final String replacementXMITypeString = "<defaultValue xmi:type=\"uml:LiteralString\" xmi:id";
}