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

org.plasma.xml.uml.DefaultUMLModelAssembler Maven / Gradle / Ivy

/**
 * Copyright 2017 TerraMeta Software, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.plasma.xml.uml;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.bind.JAXBException;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventLocator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom2.Attribute;
import org.jdom2.CDATA;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.Text;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.plasma.common.bind.BindingValidationEventHandler;
import org.plasma.metamodel.Alias;
import org.plasma.metamodel.Behavior;
import org.plasma.metamodel.Class;
import org.plasma.metamodel.ClassRef;
import org.plasma.metamodel.DataTypeRef;
import org.plasma.metamodel.Documentation;
import org.plasma.metamodel.Enumeration;
import org.plasma.metamodel.EnumerationConstraint;
import org.plasma.metamodel.EnumerationLiteral;
import org.plasma.metamodel.EnumerationRef;
import org.plasma.metamodel.Model;
import org.plasma.metamodel.Package;
import org.plasma.metamodel.Property;
import org.plasma.metamodel.ValueConstraint;
import org.plasma.runtime.ConfigUtils;
//import org.plasma.provisioning.MetamodelAssembler;
//import org.plasma.provisioning.MetamodelDataBinding;
//import org.plasma.provisioning.xsd.SchemaMetamodelAssembler;
import org.plasma.sdo.profile.SDOAlias;
import org.plasma.sdo.profile.SDOEnumerationConstraint;
import org.plasma.sdo.profile.SDOKey;
import org.plasma.sdo.profile.SDONamespace;
import org.plasma.sdo.profile.SDOSort;
import org.plasma.sdo.profile.SDOUniqueConstraint;
import org.plasma.sdo.profile.SDOValueConstraint;
import org.plasma.sdo.profile.SDOXmlProperty;
import org.plasma.xml.schema.Schema;
import org.xml.sax.SAXException;

public abstract class DefaultUMLModelAssembler implements UMLModelAssembler {
  private static Log log = LogFactory.getLog(DefaultUMLModelAssembler.class);

  protected String xmiVersion;
  protected Namespace umlNs;
  protected Namespace xmiNs;
  protected Namespace plasmaNs;
  protected String dataTypeHRefPrefix;
  protected Namespace platformNs;
  protected Namespace xsiNs;
  protected String xsiSchemaLocation;

  private Model provisioningModel;
  private String destNamespaceURI;
  private String destNamespacePrefix;
  private boolean derivePackageNamesFromURIs = true;
  private Document document;
  private Map packageMap = new HashMap();
  private Map classMap = new HashMap();
  private Map classPackageMap = new HashMap();
  private Map enumMap = new HashMap();
  private Map enumPackageMap = new HashMap();

  private Element xmiElem;
  private Element modelElem;
  private Map elementMap = new HashMap();
  private Map associationElementMap = new HashMap();
  private Map enumElementMap = new HashMap();

  @SuppressWarnings("unused")
  private DefaultUMLModelAssembler() {
  }

  protected DefaultUMLModelAssembler(Model model, String destNamespaceURI,
      String destNamespacePrefix) {
    super();
    this.destNamespaceURI = destNamespaceURI;
    this.destNamespacePrefix = destNamespacePrefix;
    if (destNamespaceURI == null || destNamespaceURI.trim().length() == 0)
      throw new IllegalArgumentException("expected 'destNamespaceURI' argument");
    if (destNamespacePrefix == null || destNamespacePrefix.trim().length() == 0)
      throw new IllegalArgumentException("expected 'destNamespacePrefix' argument");
    this.provisioningModel = model;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getDestNamespaceURI()
   */
  @Override
  public String getDestNamespaceURI() {
    return destNamespaceURI;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * org.plasma.xml.uml.UMLModelAssembler#setDestNamespaceURI(java.lang.String)
   */
  @Override
  public void setDestNamespaceURI(String destNamespaceURI) {
    this.destNamespaceURI = destNamespaceURI;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getDestNamespacePrefix()
   */
  @Override
  public String getDestNamespacePrefix() {
    return destNamespacePrefix;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * org.plasma.xml.uml.UMLModelAssembler#setDestNamespacePrefix(java.lang.String
   * )
   */
  @Override
  public void setDestNamespacePrefix(String destNamespacePrefix) {
    this.destNamespacePrefix = destNamespacePrefix;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#isDerivePackageNamesFromURIs()
   */
  @Override
  public boolean isDerivePackageNamesFromURIs() {
    return derivePackageNamesFromURIs;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * org.plasma.xml.uml.UMLModelAssembler#setDerivePackageNamesFromURIs(boolean)
   */
  @Override
  public void setDerivePackageNamesFromURIs(boolean derivePackageNamesFromURIs) {
    this.derivePackageNamesFromURIs = derivePackageNamesFromURIs;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getDocument()
   */
  @Override
  public Document getDocument() {
    if (this.document == null)
      this.document = buildDocumentModel(this.provisioningModel, this.destNamespaceURI,
          this.destNamespacePrefix);
    return this.document;
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getContent()
   */
  @Override
  @SuppressWarnings("deprecation")
  public String getContent() {
    return getContent(new XMLOutputter());
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getContent(java.lang.String,
   * boolean)
   */
  @Override
  @SuppressWarnings("deprecation")
  public String getContent(java.lang.String indent, boolean newlines) {
    XMLOutputter outputter = new XMLOutputter();

    outputter.getFormat().setIndent(indent);

    return getContent(outputter);
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * org.plasma.xml.uml.UMLModelAssembler#getContent(org.jdom2.output.Format)
   */
  @Override
  public String getContent(Format format) {
    return getContent(new XMLOutputter(format));
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getContent(java.io.OutputStream)
   */
  @Override
  @SuppressWarnings("deprecation")
  public void getContent(OutputStream stream) {
    XMLOutputter outputter = new XMLOutputter();
    getContent(stream, outputter);
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getContent(java.io.OutputStream,
   * java.lang.String, boolean)
   */
  @Override
  @SuppressWarnings("deprecation")
  public void getContent(OutputStream stream, java.lang.String indent, boolean newlines) {
    XMLOutputter outputter = new XMLOutputter();
    outputter.getFormat().setIndent(indent);
    getContent(stream, outputter);
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.plasma.xml.uml.UMLModelAssembler#getContent(java.io.OutputStream,
   * org.jdom2.output.Format)
   */
  @Override
  public void getContent(OutputStream stream, Format format) {
    getContent(stream, new XMLOutputter(format));
  }

  private String getContent(XMLOutputter outputter) {
    String result = null;
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    try {
      if (this.document == null)
        this.document = buildDocumentModel(this.provisioningModel, this.destNamespaceURI,
            this.destNamespacePrefix);
      outputter.output(this.document, os);
      os.flush();
      result = new String(os.toByteArray());
    } catch (java.io.IOException e) {
    } finally {
      try {
        os.close();
      } catch (IOException e) {
      }
    }
    return result;
  }

  private void getContent(OutputStream stream, XMLOutputter outputter) {
    String result = null;
    try {
      if (this.document == null)
        this.document = buildDocumentModel(this.provisioningModel, this.destNamespaceURI,
            this.destNamespacePrefix);
      outputter.output(this.document, stream);
      stream.flush();
    } catch (java.io.IOException e) {
    } finally {
      try {
        stream.close();
      } catch (IOException e) {
      }
    }
  }

  // private Document buildDocumentModel(Schema schema, String destNamespaceURI,
  // String destNamespacePrefix) {
  // SchemaMetamodelAssembler stagingAssembler = new
  // SchemaMetamodelAssembler(schema,
  // destNamespaceURI, destNamespacePrefix);
  // Model model = stagingAssembler.getModel();
  // return buildDocumentModel(model, destNamespaceURI, destNamespacePrefix);
  // }

  private Document buildDocumentModel(Model model, String destNamespaceURI,
      String destNamespacePrefix) {
    this.xmiElem = new Element("XMI");
    this.xmiElem.setNamespace(xmiNs);
    Document document = new Document(this.xmiElem);
    this.xmiElem.setAttribute(new Attribute("version", this.xmiVersion, this.xmiNs));
    this.xmiElem.addNamespaceDeclaration(umlNs);
    this.xmiElem.addNamespaceDeclaration(xmiNs);
    this.xmiElem.addNamespaceDeclaration(plasmaNs);
    if (this.platformNs != null)
      this.xmiElem.addNamespaceDeclaration(platformNs);
    if (this.xsiNs != null) {
      this.xmiElem.addNamespaceDeclaration(xsiNs);
      this.xmiElem
          .setAttribute(new Attribute("schemaLocation", this.xsiSchemaLocation, this.xsiNs));
    }

    if (this.derivePackageNamesFromURIs)
      this.modelElem = this.buildModelFromURITokens(model);
    else
      this.modelElem = this.buildModelFromPackageNames(model);

    collectPackages(model);
    collectClasses(model);
    collectEnumerations(model);

    for (Class clss : this.classMap.values()) {
      Package pkg = this.classPackageMap.get(clss);
      Element clssElem = buildClass(clss);
      elementMap.put(clss.getId(), clssElem);
      // build properties w/o any associations
      for (Property property : clss.getProperties()) {

        Element ownedAttribute = buildProperty(pkg, clss, property, clssElem);
        elementMap.put(property.getId(), ownedAttribute);
      }
    }

    // create associations
    for (Class clss : this.classMap.values()) {
      for (Property prop : clss.getProperties()) {

        if (prop.getType() instanceof DataTypeRef)
          continue;

        if (associationElementMap.get(prop.getId()) != null)
          continue; // we created it

        String associationUUID = UUID.randomUUID().toString();

        // link assoc to both properties
        Element leftOwnedAttribute = elementMap.get(prop.getId());
        leftOwnedAttribute.setAttribute(new Attribute("association", associationUUID));

        Property targetProp = getOppositeProperty(clss, prop);
        if (targetProp != null) {
          Element rightOwnedAttribute = elementMap.get(targetProp.getId());
          rightOwnedAttribute.setAttribute(new Attribute("association", associationUUID));

          Element association = buildAssociation(prop, targetProp, this.modelElem, associationUUID);

          // map it to both props so we can know not to create it again
          associationElementMap.put(prop.getId(), association);
          associationElementMap.put(targetProp.getId(), association);
        } else {
          Class targetClass = getOppositeClass(clss, prop);
          Element association = buildAssociation(prop, targetClass, this.modelElem, associationUUID);

          // map it to both props so we can know not to create it again
          associationElementMap.put(prop.getId(), association);

        }
      }
    }

    // add profile applications
    Element profileApplicationElem = buildProfileApplication();
    if (profileApplicationElem != null)
      this.modelElem.addContent(profileApplicationElem);

    return document;
  }

  private void collectPackages(Package pkg) {
    if (pkg.getUri() != null) {
      packageMap.put(pkg.getUri() + "#" + pkg.getName(), pkg);
    }
    for (Package child : pkg.getPackages()) {
      collectPackages(child);
    }
  }

  private void collectClasses(Package pkg) {
    mapClasses(pkg);
    for (Package child : pkg.getPackages())
      collectClasses(child);
  }

  private void mapClasses(Package pkg) {
    for (Class clss : pkg.getClazzs()) {
      classMap.put(clss.getUri() + "#" + clss.getName(), clss);
      classPackageMap.put(clss, pkg);
    }
  }

  private void collectEnumerations(Package pkg) {
    mapEnumerations(pkg);
    for (Package child : pkg.getPackages())
      collectEnumerations(child);
  }

  private void mapEnumerations(Package pkg) {
    for (Enumeration enm : pkg.getEnumerations()) {
      enumMap.put(enm.getUri() + "#" + enm.getName(), enm);
      enumPackageMap.put(enm, pkg);
    }
  }

  private Element buildModelFromPackageNames(Model model) {
    Element modelElem = new Element("Model");
    modelElem.setNamespace(umlNs);
    this.xmiElem.addContent(modelElem);
    modelElem.setAttribute(new Attribute("id", model.getId(), xmiNs));
    modelElem.setAttribute(new Attribute("name", model.getName()));
    modelElem.setAttribute(new Attribute("visibility", "public"));
    elementMap.put(model.getId(), modelElem);
    if (model.getDocumentations() != null)
      for (Documentation doc : model.getDocumentations()) {
        addOwnedComment(modelElem, model.getId(), doc.getBody().getValue());
      }

    // Only a root (model) package
    // tag the model w/a SDO namespace stereotype, else tag the
    // last package descendant below
    if (model.getPackages().size() == 0) {
      Element modelStereotype = new Element(SDONamespace.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(modelStereotype);
      modelStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      modelStereotype.setAttribute(new Attribute(SDONamespace.BASE__PACKAGE, model.getId()));
      modelStereotype.setAttribute(new Attribute(SDONamespace.URI, model.getUri()));
      if (model.getAlias() != null)
        addAlias(model.getAlias(), model.getId());
    } else {
      for (Package child : model.getPackages())
        addPackages(child, modelElem);
    }

    return modelElem;
  }

  private void addPackages(Package pkg, Element parent) {
    Element pkgElem = new Element("packagedElement");
    parent.addContent(pkgElem); // add package child
    pkgElem.setAttribute(new Attribute("type", "uml:Package", xmiNs));
    pkgElem.setAttribute(new Attribute("id", pkg.getId(), xmiNs));
    pkgElem.setAttribute(new Attribute("name", pkg.getName()));
    pkgElem.setAttribute(new Attribute("visibility", "public"));
    elementMap.put(pkg.getId(), pkgElem);
    if (pkg.getAlias() != null)
      addAlias(pkg.getAlias(), pkg.getId());

    if (pkg.getUri() != null && pkg.getUri().length() > 0) {
      Element pkgStereotypeElem = new Element(SDONamespace.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(pkgStereotypeElem);
      pkgStereotypeElem.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      pkgStereotypeElem.setAttribute(new Attribute(SDONamespace.BASE__PACKAGE, pkg.getId()));
      pkgStereotypeElem.setAttribute(new Attribute(SDONamespace.URI, pkg.getUri()));
    }

    if (pkg.getDocumentations() != null)
      for (Documentation doc : pkg.getDocumentations()) {
        addOwnedComment(pkgElem, pkg.getId(), doc.getBody().getValue());
      }
    for (Package child : pkg.getPackages())
      addPackages(child, pkgElem);

  }

  private Element buildModelFromURITokens(Model model) {
    Element rootPackageElem = null;

    String[] packageNames = ConfigUtils.toPackageTokens(model.getUri());

    Element modelElem = new Element("Model");
    modelElem.setNamespace(umlNs);
    this.xmiElem.addContent(modelElem);
    modelElem.setAttribute(new Attribute("id", model.getId(), xmiNs));
    modelElem.setAttribute(new Attribute("name", packageNames[0]));
    modelElem.setAttribute(new Attribute("visibility", "public"));
    elementMap.put(model.getId(), modelElem);
    // FIXME: duplicating model level docs at package
    // descendant level
    if (model.getDocumentations() != null)
      for (Documentation doc : model.getDocumentations()) {
        addOwnedComment(modelElem, model.getId(), doc.getBody().getValue());
      }

    // tag the model w/a SDO namespace streotype, else tag the
    // last package descendant below
    if (packageNames.length == 1) {
      Element modelStereotype = new Element(SDONamespace.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(modelStereotype);
      modelStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      modelStereotype.setAttribute(new Attribute(SDONamespace.BASE__PACKAGE, model.getId()));
      modelStereotype.setAttribute(new Attribute(SDONamespace.URI, this.destNamespaceURI));
    }

    rootPackageElem = modelElem;

    for (int i = 1; i < packageNames.length; i++) {

      Element pkgElem = new Element("packagedElement");
      rootPackageElem.addContent(pkgElem);
      String id = UUID.randomUUID().toString();
      pkgElem.setAttribute(new Attribute("type", "uml:Package", xmiNs));
      pkgElem.setAttribute(new Attribute("id", id, xmiNs));
      pkgElem.setAttribute(new Attribute("name", packageNames[i]));
      pkgElem.setAttribute(new Attribute("visibility", "public"));
      elementMap.put(id, pkgElem);

      if (i == packageNames.length - 1) {
        Element pkgStereotypeElem = new Element(SDONamespace.class.getSimpleName(), plasmaNs);
        this.xmiElem.addContent(pkgStereotypeElem);
        pkgStereotypeElem.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
        pkgStereotypeElem.setAttribute(new Attribute(SDONamespace.BASE__PACKAGE, id));
        pkgStereotypeElem.setAttribute(new Attribute(SDONamespace.URI, this.destNamespaceURI));
        // FIXME: no packages or package-level docs in provisioning model
        // use model-level docs here
        if (model.getDocumentations() != null)
          for (Documentation doc : model.getDocumentations()) {
            addOwnedComment(pkgElem, id, doc.getBody().getValue());
          }
      }

      rootPackageElem = pkgElem;
    }

    return rootPackageElem;
  }

  /**
   * Creates and element which is a profile application for the model
   * 
   * @return the profile application or null if not applicable for concerned
   *         subclass
   */
  protected abstract Element buildProfileApplication();

  private Element buildClass(Class clss) {
    if (log.isDebugEnabled())
      log.debug("creating class " + clss.getName());
    // find parent element
    Package pkgParent = this.classPackageMap.get(clss);
    Element parent = this.elementMap.get(pkgParent.getId());

    Element clssElem = new Element("packagedElement");
    parent.addContent(clssElem);
    elementMap.put(clss.getId(), clssElem);
    clssElem.setAttribute(new Attribute("type", "uml:Class", xmiNs));
    clssElem.setAttribute(new Attribute("id", clss.getId(), xmiNs));
    clssElem.setAttribute(new Attribute("name", clss.getName()));
    if (clss.isAbstract())
      clssElem.setAttribute(new Attribute("isAbstract", "true"));
    clssElem.setAttribute(new Attribute("visibility", "public"));
    if (clss.getDocumentations() != null)
      for (Documentation doc : clss.getDocumentations()) {
        addOwnedComment(clssElem, clss.getId(), doc.getBody().getValue());
      }

    if (clss.getAlias() != null) {
      addAlias(clss.getAlias(), clss.getId());
    }

    for (ClassRef baseRef : clss.getSuperClasses()) {
      Element generalizationElem = new Element("generalization");
      generalizationElem.setAttribute(new Attribute("type", "uml:Generalization", xmiNs));
      generalizationElem.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      clssElem.addContent(generalizationElem);
      String ref = baseRef.getUri() + "#" + baseRef.getName();
      Class baseClass = classMap.get(ref);
      if (baseClass != null) {
        generalizationElem.setAttribute(new Attribute("general", baseClass.getId()));
      } else { // assume an external reference
        Element generalElem = new Element("general");
        generalizationElem.addContent(generalElem);
        generalElem.setAttribute(new Attribute("type", "uml:Class", xmiNs));
        generalElem.setAttribute(new Attribute("href", ref));
      }
    }
    /*
     * --e.g. XMI for an external reference  
     *  
     */
    if (clss.getBehaviors().size() > 0)
      addBehaviors(clss, clssElem, clss.getBehaviors());

    return clssElem;
  }

  /**
   * Adds a UML owned opaque behavior ala. below for each provisioning behavior.
   * 
   *  FOO BAR; SQL
   * 
   * 
   * @param clss
   *          the
   * @param clssElem
   *          the element
   * @param behaviors
   *          the bahaviors
   */
  private void addBehaviors(Class clss, Element clssElem, List behaviors) {

    for (Behavior behavior : behaviors) {
      Element ownedBehavior = new Element("ownedBehavior");
      clssElem.addContent(ownedBehavior);
      ownedBehavior.setAttribute(new Attribute("type", "uml:OpaqueBehavior", xmiNs));
      ownedBehavior.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      ownedBehavior.setAttribute(new Attribute("visibility", "public"));
      ownedBehavior.setAttribute(new Attribute("name", behavior.getType().name()));

      Element language = new Element("language");
      language.setText(behavior.getLanguage());
      ownedBehavior.addContent(language);

      Element body = new Element("body");
      Text text = new Text(behavior.getValue());
      body.addContent(text);
      ownedBehavior.addContent(body);

    }

  }

  private void addAlias(Alias alias, String namedElementId) {
    Element aliasStereotype = new Element(SDOAlias.class.getSimpleName(), plasmaNs);
    this.xmiElem.addContent(aliasStereotype);
    aliasStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
    aliasStereotype.setAttribute(new Attribute(SDOAlias.BASE__NAMED_ELEMENT, namedElementId));
    if (alias.getPhysicalName() != null)
      aliasStereotype.setAttribute(new Attribute(SDOAlias.PHYSICAL_NAME, alias.getPhysicalName()));
    if (alias.getLocalName() != null)
      aliasStereotype.setAttribute(new Attribute(SDOAlias.LOCAL_NAME, alias.getLocalName().trim()));
    if (alias.getBusinessName() != null)
      aliasStereotype.setAttribute(new Attribute(SDOAlias.BUSINESS_NAME, alias.getBusinessName()
          .trim()));
  }

  private Element buildProperty(Package pkg, Class clss, Property property, Element parentElem) {
    if (log.isDebugEnabled())
      log.debug("creating property " + property.getName());

    Element ownedAttribute = new Element("ownedAttribute");
    parentElem.addContent(ownedAttribute);
    ownedAttribute.setAttribute(new Attribute("type", "uml:Property", xmiNs));
    ownedAttribute.setAttribute(new Attribute("id", property.getId(), xmiNs));
    ownedAttribute.setAttribute(new Attribute("name", property.getName()));
    if (property.getVisibility() != null)
      ownedAttribute.setAttribute(new Attribute("visibility", property.getVisibility().value()));
    if (property.getDocumentations() != null)
      for (Documentation doc : property.getDocumentations()) {
        if (doc.getBody() != null)
          addOwnedComment(ownedAttribute, property.getId(), doc.getBody().getValue());
      }

    Element upperValue = new Element("upperValue");
    ownedAttribute.addContent(upperValue);
    upperValue.setAttribute(new Attribute("type", "uml:LiteralUnlimitedNatural", xmiNs));
    upperValue.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
    upperValue.setAttribute(new Attribute("visibility", "public"));
    if (property.isMany())
      upperValue.setAttribute(new Attribute("value", "*"));
    else
      upperValue.setAttribute(new Attribute("value", "1"));

    Element lowerValue = new Element("lowerValue");
    ownedAttribute.addContent(lowerValue);
    lowerValue.setAttribute(new Attribute("type", "uml:LiteralInteger", xmiNs));
    lowerValue.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
    lowerValue.setAttribute(new Attribute("visibility", "public"));
    if (property.isNullable())
      lowerValue.setAttribute(new Attribute("value", "0"));
    else
      lowerValue.setAttribute(new Attribute("value", "1"));

    if (property.getType() instanceof DataTypeRef) {
      Element type = new Element("type");
      ownedAttribute.addContent(type);
      type.setAttribute(new Attribute("type", "uml:DataType", xmiNs));
      // type.setAttribute(new Attribute("id", UUID.randomUUID().toString(),
      // xmiNs));
      type.setAttribute(new Attribute("href", this.dataTypeHRefPrefix
          + ((DataTypeRef) property.getType()).getName()));
    } else {
      // set reference specific attribs
      ClassRef targetClassRef = (ClassRef) property.getType();
      Class targetClass = classMap.get(targetClassRef.getUri() + "#" + targetClassRef.getName());
      ownedAttribute.setAttribute(new Attribute("type", targetClass.getId()));
    }

    // add stereotypes in order of "priority" in terms of how we
    // would like them to appear in UML tools
    if (property.getKey() != null) {
      Element keyStereotype = new Element(SDOKey.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(keyStereotype);
      keyStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      keyStereotype.setAttribute(new Attribute(SDOKey.BASE__PROPERTY, property.getId()));
      keyStereotype.setAttribute(new Attribute(SDOKey.TYPE, // provisioning
                                                            // key-type is JAXB
                                                            // generated and
                                                            // upper-case
          property.getKey().getType().name().toLowerCase()));
    }

    if (property.getUniqueConstraint() != null) {
      Element uniqueStereotype = new Element(SDOUniqueConstraint.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(uniqueStereotype);
      uniqueStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      uniqueStereotype.setAttribute(new Attribute(SDOUniqueConstraint.BASE__PROPERTY, property
          .getId()));
      uniqueStereotype.setAttribute(new Attribute(SDOUniqueConstraint.GROUP, property
          .getUniqueConstraint().getGroup()));
    }

    if (property.getAlias() != null) {
      addAlias(property.getAlias(), property.getId());
    }

    if (property.getSort() != null) {
      Element sequenceStereotype = new Element(SDOSort.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(sequenceStereotype);
      sequenceStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      sequenceStereotype.setAttribute(new Attribute(SDOSort.BASE__PROPERTY, property.getId()));
      sequenceStereotype.setAttribute(new Attribute(SDOSort.KEY, String.valueOf(property.getSort()
          .getKey())));
    }

    if (property.getXmlProperty() != null) {
      Element xmlPropertyStereotype = new Element(SDOXmlProperty.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(xmlPropertyStereotype);
      xmlPropertyStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      xmlPropertyStereotype.setAttribute(new Attribute(SDOXmlProperty.BASE__PROPERTY, property
          .getId()));
      xmlPropertyStereotype.setAttribute(new Attribute(SDOXmlProperty.NODE_TYPE, property
          .getXmlProperty().getNodeType().name().toLowerCase()));
    }

    if (property.getValueConstraint() != null) {
      Element valueContStereotype = new Element(SDOValueConstraint.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(valueContStereotype);
      valueContStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.BASE__PROPERTY, property
          .getId()));

      ValueConstraint vc = property.getValueConstraint();
      if (vc.getTotalDigits() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.TOTAL_DIGITS, String
            .valueOf(vc.getTotalDigits())));
      if (vc.getFractionDigits() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.FRACTION_DIGITS, String
            .valueOf(vc.getFractionDigits())));
      if (vc.getMaxInclusive() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MAX_INCLUSIVE, String
            .valueOf(vc.getMaxInclusive())));
      if (vc.getMaxExclusive() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MAX_EXCLUSIVE, String
            .valueOf(vc.getMaxExclusive())));
      if (vc.getMaxLength() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MAX_LENGTH, String
            .valueOf(vc.getMaxLength())));
      if (vc.getMinInclusive() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MIN_INCLUSIVE, String
            .valueOf(vc.getMinInclusive())));
      if (vc.getMinExclusive() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MIN_EXCLUSIVE, String
            .valueOf(vc.getMinExclusive())));
      if (vc.getMinLength() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.MIN_LENGTH, String
            .valueOf(vc.getMinLength())));
      if (vc.getPattern() != null)
        valueContStereotype.setAttribute(new Attribute(SDOValueConstraint.PATTERN, String
            .valueOf(vc.getPattern())));
    }

    if (property.getEnumerationConstraint() != null) {
      Element enumConstraintStereotype = new Element(
          SDOEnumerationConstraint.class.getSimpleName(), plasmaNs);
      this.xmiElem.addContent(enumConstraintStereotype);
      enumConstraintStereotype
          .setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
      enumConstraintStereotype.setAttribute(new Attribute(SDOUniqueConstraint.BASE__PROPERTY,
          property.getId()));

      EnumerationConstraint constraint = property.getEnumerationConstraint();
      EnumerationRef enumRef = constraint.getValue();
      String enumRefId = enumRef.getUri() + "#" + enumRef.getName();

      Element enumeration = this.enumElementMap.get(enumRefId);
      if (enumeration == null) {
        enumeration = this.buildEnumeration(constraint);
        Element pkgElement = this.elementMap.get(pkg.getId());
        pkgElement.addContent(enumeration);
        this.enumElementMap.put(enumRefId, enumeration);
      }
      Attribute enumId = enumeration.getAttribute("id", xmiNs);
      enumConstraintStereotype.setAttribute(new Attribute(SDOEnumerationConstraint.VALUE, enumId
          .getValue()));
    }

    return ownedAttribute;
  }

  private Element buildAssociation(Property property, Property targetProperty, Element parentElem,
      String uuid) {
    Element associationElem = new Element("packagedElement");
    parentElem.addContent(associationElem);
    associationElementMap.put(property.getId(), associationElem);
    associationElementMap.put(targetProperty.getId(), associationElem);
    associationElem.setAttribute(new Attribute("type", "uml:Association", xmiNs));
    associationElem.setAttribute(new Attribute("id", uuid, xmiNs));
    associationElem.setAttribute(new Attribute("visibility", "public"));

    Element leftMemberEnd = new Element("memberEnd");
    associationElem.addContent(leftMemberEnd);
    leftMemberEnd.setAttribute(new Attribute("idref", property.getId(), xmiNs));

    Element rightMemberEnd = new Element("memberEnd");
    associationElem.addContent(rightMemberEnd);
    rightMemberEnd.setAttribute(new Attribute("idref", targetProperty.getId(), xmiNs));

    return associationElem;
  }

  private Element buildAssociation(Property property, Class targetClass, Element parentElem,
      String uuid) {
    Element association = new Element("packagedElement");
    parentElem.addContent(association);
    association.setAttribute(new Attribute("type", "uml:Association", xmiNs));
    association.setAttribute(new Attribute("id", uuid, xmiNs));
    association.setAttribute(new Attribute("visibility", "public"));

    Element leftMemberEnd = new Element("memberEnd");
    association.addContent(leftMemberEnd);
    leftMemberEnd.setAttribute(new Attribute("idref", property.getId(), xmiNs));

    String rightPropId = UUID.randomUUID().toString();
    Element rightMemberEnd = new Element("memberEnd");
    association.addContent(rightMemberEnd);
    rightMemberEnd.setAttribute(new Attribute("idref", rightPropId, xmiNs));

    Element navigableOwnedEnd = new Element("navigableOwnedEnd");
    association.addContent(navigableOwnedEnd);
    navigableOwnedEnd.setAttribute(new Attribute("idref", rightPropId, xmiNs));

    Element ownedEnd = new Element("ownedEnd");
    association.addContent(ownedEnd);
    ownedEnd.setAttribute(new Attribute("type", "uml:Property", xmiNs));
    ownedEnd.setAttribute(new Attribute("id", rightPropId, xmiNs));
    ownedEnd.setAttribute(new Attribute("visibility", "private"));
    ownedEnd.setAttribute(new Attribute("type", targetClass.getId()));

    // if its external we'll need this goo
    /*
     * { targetClassId =
     * targetClassInfo.getSharedPackage().getExternalReferenceBase() + "#" +
     * targetClassInfo.getUuid(); Element type = new Element("type");
     * ownedEnd.addContent(type); type.setAttribute(new Attribute("type",
     * "uml:Class", xmiNs)); type.setAttribute(new Attribute("href",
     * targetClassId)); }
     */

    Element upperValue = new Element("upperValue");
    ownedEnd.addContent(upperValue);
    upperValue.setAttribute(new Attribute("type", "uml:LiteralUnlimitedNatural", xmiNs));
    upperValue.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
    upperValue.setAttribute(new Attribute("visibility", "public"));
    upperValue.setAttribute(new Attribute("value", "*"));

    Element lowerValue = new Element("lowerValue");
    ownedEnd.addContent(lowerValue);
    lowerValue.setAttribute(new Attribute("type", "uml:LiteralInteger", xmiNs));
    lowerValue.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
    lowerValue.setAttribute(new Attribute("visibility", "public"));

    return association;
  }

  private Element buildEnumeration(EnumerationConstraint constraint) {
    Enumeration enm = this.enumMap.get(constraint.getValue().getUri() + "#"
        + constraint.getValue().getName());

    Element enumerationElem = new Element("packagedElement");
    enumerationElem.setAttribute(new Attribute("type", "uml:Enumeration", xmiNs));
    String enumId = UUID.randomUUID().toString();
    enumerationElem.setAttribute(new Attribute("id", enumId, xmiNs));
    enumerationElem.setAttribute(new Attribute("name", enm.getName()));
    enumerationElem.setAttribute(new Attribute("visibility", "public"));

    if (enm.getDocumentations() != null)
      for (Documentation doc : enm.getDocumentations()) {
        addOwnedComment(enumerationElem, enumId, doc.getBody().getValue());
      }

    for (EnumerationLiteral lit : enm.getEnumerationLiterals()) {
      Element literal = new Element("ownedLiteral");
      enumerationElem.addContent(literal);
      literal.setAttribute(new Attribute("type", "uml:EnumerationLiteral", xmiNs));
      String literalId = UUID.randomUUID().toString();
      literal.setAttribute(new Attribute("id", literalId, xmiNs));
      literal.setAttribute(new Attribute("name", lit.getValue()));
      literal.setAttribute(new Attribute("visibility", "public"));
      if (lit.getDocumentations() != null)
        for (Documentation doc : lit.getDocumentations()) {
          addOwnedComment(literal, literalId, doc.getBody().getValue());
        }

      if (lit.getAlias() != null && lit.getAlias().getPhysicalName() != null) {
        Element aliasStereotype = new Element(SDOAlias.class.getSimpleName(), plasmaNs);
        this.xmiElem.addContent(aliasStereotype);
        aliasStereotype.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));
        aliasStereotype.setAttribute(new Attribute(SDOAlias.BASE__NAMED_ELEMENT, literalId));
        aliasStereotype.setAttribute(new Attribute(SDOAlias.PHYSICAL_NAME, lit.getAlias()
            .getPhysicalName()));
      }
    }
    return enumerationElem;

  }

  private void addOwnedComment(Element owner, String ownerId, String commentBody) {
    Element comment = new Element("ownedComment");
    owner.addContent(comment);
    comment.setAttribute(new Attribute("type", "uml:Comment", xmiNs));
    comment.setAttribute(new Attribute("id", UUID.randomUUID().toString(), xmiNs));

    Element body = new Element("body");
    comment.addContent(body);
    body.addContent(new CDATA(commentBody));

    Element annotatedElement = new Element("annotatedElement");
    comment.addContent(annotatedElement);
    annotatedElement.setAttribute(new Attribute("idref", ownerId, xmiNs));
  }

  private Class getOppositeClass(Class def, Property propertyDef) {
    Class targetDef = classMap.get(propertyDef.getType().getUri() + "#"
        + propertyDef.getType().getName());
    return targetDef;
  }

  private Property getOppositeProperty(Class def, Property propertyDef) {
    Class targetDef = classMap.get(propertyDef.getType().getUri() + "#"
        + propertyDef.getType().getName());
    for (Property p : targetDef.getProperties()) {
      if (p.getName().equals(propertyDef.getOpposite()))
        return p;
    }
    return null;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy