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

org.plasma.provisioning.MetamodelAssembler Maven / Gradle / Ivy

There is a newer version: 2.2.1
Show newest version
/**
 * 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.provisioning;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.plasma.common.exception.ProvisioningException;
import org.plasma.metamodel.Alias;
import org.plasma.metamodel.Body;
import org.plasma.metamodel.Class;
import org.plasma.metamodel.ClassRef;
import org.plasma.metamodel.ConcurentDataFlavor;
import org.plasma.metamodel.ConcurrencyType;
import org.plasma.metamodel.Concurrent;
import org.plasma.metamodel.DataTypeRef;
import org.plasma.metamodel.Derivation;
import org.plasma.metamodel.Documentation;
import org.plasma.metamodel.DocumentationType;
import org.plasma.metamodel.Enumeration;
import org.plasma.metamodel.EnumerationConstraint;
import org.plasma.metamodel.EnumerationLiteral;
import org.plasma.metamodel.EnumerationRef;
import org.plasma.metamodel.Increment;
import org.plasma.metamodel.Key;
import org.plasma.metamodel.KeyType;
import org.plasma.metamodel.Model;
import org.plasma.metamodel.Package;
import org.plasma.metamodel.PackageRef;
import org.plasma.metamodel.Property;
import org.plasma.metamodel.Sort;
import org.plasma.metamodel.TypeRef;
import org.plasma.metamodel.ValueConstraint;
import org.plasma.metamodel.VisibilityType;
import org.plasma.metamodel.XmlNodeType;
import org.plasma.metamodel.XmlProperty;
import org.plasma.query.Query;
import org.plasma.query.collector.PropertySelection;
import org.plasma.query.collector.PropertySelectionCollector;
import org.plasma.runtime.DataAccessProviderName;
import org.plasma.runtime.NonExistantNamespaceException;
import org.plasma.runtime.PlasmaRuntime;
import org.plasma.sdo.DataType;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.helper.PlasmaTypeHelper;
import org.plasma.sdo.repository.Comment;
import org.plasma.sdo.repository.Namespace;
import org.plasma.sdo.repository.PlasmaRepository;

import commonj.sdo.Type;

/**
 * Assembles a provisioning model based on the configured SDO environment
 * iterating through the configured SDO name-spaces or taking a specific
 * name-space list or various of the constructor arguments.
 */
public class MetamodelAssembler {
  private static final String DERIVED_ARTIFACT_URI_PREFIX = "http://derived-artifact/";
  private static Log log = LogFactory.getLog(MetamodelAssembler.class);
  private Model model;
  private List namespaces;
  private Map packageMap = new HashMap();
  private Map classMap = new HashMap();
  private Map enumerationMap = new HashMap();
  private String destNamespaceURI;
  private DataAccessProviderName serviceName;

  /**
   * Constructs a provisioning model based on all configured SDO namespaces.
   */
  public MetamodelAssembler() {
    this(PlasmaRepository.getInstance().getAllNamespaces());
  }

  /**
   * Constructs a provisioning model based on the given provider.
   * 
   * @param serviceName
   *          the service provider
   */
  public MetamodelAssembler(DataAccessProviderName serviceName) {
    this.serviceName = serviceName;
    construct(PlasmaRepository.getInstance().getAllNamespaces());
  }

  /**
   * Constructs a provisioning model based on the given list of SDO name spaces.
   * 
   * @param namespaces
   *          the SDO name spaces
   */
  public MetamodelAssembler(List namespaces) {
    construct(PlasmaRepository.getInstance().getAllNamespaces());
  }

  /**
   * Constructs a provisioning model based on the given query.
   * 
   * @param query
   *          the query
   * @param destNamespaceURI
   *          the destination namespace URI
   * @param destNamespacePrefix
   *          the destination namespace prefix
   */
  public MetamodelAssembler(Query query, String destNamespaceURI, String destNamespacePrefix) {
    super();
    construct(query, destNamespaceURI, destNamespacePrefix);
  }

  private void construct(List namespaces) {
    this.namespaces = namespaces;

    List namespacesToProcess = new ArrayList();
    for (Namespace namespace : this.namespaces) {
      if (this.serviceName != null) {
        try {
          PlasmaRuntime.getInstance().getProvisioningByNamespaceURI(this.serviceName,
              namespace.getUri());
        } catch (NonExistantNamespaceException e) {
          log.debug("ignoring non " + this.serviceName.name() + " namespace: " + namespace.getUri());
          continue;
        }
      }
      namespacesToProcess.add(namespace);
    }

    if (namespacesToProcess.size() == 0)
      throw new ProvisioningException("no namespaces to process");

    if (namespacesToProcess.size() > 1) {
      this.model = new Model();
      this.model.setId(UUID.randomUUID().toString());
      this.model.setName("derived model");
      this.model.setUri(DERIVED_ARTIFACT_URI_PREFIX + UUID.randomUUID().toString());
      Documentation documentation = new Documentation();
      documentation.setType(DocumentationType.DEFINITION);
      Body body = new Body();
      body.setValue("derived model");
      documentation.setBody(body);
      this.model.getDocumentations().add(documentation);
    }

    // create and map packages, classes
    for (Namespace namespace : namespacesToProcess) {
      if (log.isDebugEnabled())
        log.debug("processing namespace: " + namespace.getUri());

      List types = PlasmaTypeHelper.INSTANCE.getTypes(namespace.getUri());
      for (commonj.sdo.Type type : types) {
        PlasmaType plasmaType = (PlasmaType) type;

        Package pkg = this.packageMap.get(plasmaType.getURI());
        if (pkg == null) {
          if (namespacesToProcess.size() > 1) {
            pkg = createPackage(namespace, plasmaType, false);
            this.model.getPackages().add(pkg);
          } else {
            pkg = createPackage(namespace, plasmaType, true);
            this.model = (Model) pkg;
          }
          this.packageMap.put(plasmaType.getURI(), pkg);
        }
        String qualifiedName = plasmaType.getURI() + "#" + plasmaType.getName();
        Class clss = this.classMap.get(qualifiedName);
        if (clss == null) {
          if (log.isDebugEnabled())
            log.debug("processing type: " + qualifiedName);
          clss = createClass(pkg, plasmaType);
          assert (clss.getUri().equals(pkg.getUri()));
          this.classMap.put(qualifiedName, clss);

          createEnumerations(pkg, clss, plasmaType);
        }
      }
    }

    // create fields
    for (Class clss : classMap.values()) {
      PlasmaType sdoType = (PlasmaType) PlasmaTypeHelper.INSTANCE.getType(clss.getUri(),
          clss.getName());
      Package pkg = this.packageMap.get(sdoType.getURI());
      List properties = sdoType.getDeclaredProperties();
      if (log.isDebugEnabled())
        log.debug("adding " + properties.size() + " properties class: " + clss.getUri() + "#"
            + clss.getName());
      createFields(pkg, clss, properties);
    }
  }

  public Model getModel() {
    return this.model;
  }

  private void createFields(Package pkg, Class clss, List properties) {
    for (commonj.sdo.Property prop : properties) {
      PlasmaProperty plasmaProperty = (PlasmaProperty) prop;
      if (plasmaProperty.getPhysicalName() == null && !plasmaProperty.isMany()) {
        log.warn("no physical name found for singular property, "
            + plasmaProperty.getContainingType().getURI() + "#"
            + plasmaProperty.getContainingType().getName() + "." + plasmaProperty.getName());
      }
      Property field = null;
      if (plasmaProperty.getType().isDataType()) {
        field = createDataProperty(pkg, clss, plasmaProperty);
        if (log.isDebugEnabled())
          log.debug("adding data property " + clss.getUri() + "#" + clss.getName() + "."
              + field.getName());
      } else {
        PlasmaProperty oppositeProperty = (PlasmaProperty) plasmaProperty.getOpposite();
        field = createReferenceProperty(pkg, clss, plasmaProperty, oppositeProperty);
        if (log.isDebugEnabled())
          log.debug("adding reference property " + clss.getUri() + "#" + clss.getName() + "."
              + field.getName());
      }
      clss.getProperties().add(field);

    }
  }

  private void createEnumerations(Package pkg, Class clss, PlasmaType sdoType) {
    List properties = sdoType.getDeclaredProperties();
    for (commonj.sdo.Property prop : properties) {
      PlasmaProperty plasmaProperty = (PlasmaProperty) prop;
      if (plasmaProperty.getPhysicalName() == null) {
        if (!plasmaProperty.isMany())
          log.warn("no physical name found for singular property, "
              + plasmaProperty.getContainingType().getURI() + "#"
              + plasmaProperty.getContainingType().getName() + "." + plasmaProperty.getName());
        continue;
      }
      if (!plasmaProperty.getType().isDataType())
        continue;
      if (plasmaProperty.getRestriction() == null)
        continue;

      // FIXME - assumes class URI and enum URI are same
      org.plasma.sdo.repository.Enumeration sdoEnumeration = plasmaProperty.getRestriction();
      String enumKey = clss.getUri() + "#" + sdoEnumeration.getName();
      Enumeration enumeration = this.enumerationMap.get(enumKey);
      if (enumeration == null) {
        enumeration = createEnumeration(clss, sdoEnumeration);
        pkg.getEnumerations().add(enumeration);
        this.enumerationMap.put(enumKey, enumeration);
      }
    }
  }

  private Enumeration createEnumeration(Class clss, org.plasma.sdo.repository.Enumeration sdoEnum) {
    Enumeration enumeration = new Enumeration();
    enumeration.setName(sdoEnum.getName());
    enumeration.setUri(clss.getUri()); // FIXME - a bad assumption that these
                                       // are same URI
    enumeration.setId(UUID.randomUUID().toString());
    if (sdoEnum.findAlias() != null) {
      org.plasma.sdo.Alias sdoAlias = sdoEnum.findAlias();
      Alias alias = new Alias();
      enumeration.setAlias(alias);
      alias.setPhysicalName(sdoAlias.getPhysicalName());
      alias.setLocalName(sdoAlias.getLocalName());
      alias.setBusinessName(sdoAlias.getBusinessName());
    }

    for (org.plasma.sdo.repository.EnumerationLiteral lit : sdoEnum.getOwnedLiteral()) {
      EnumerationLiteral literal = new EnumerationLiteral();
      literal.setName(lit.getName());
      literal.setValue(lit.getName());
      if (lit.findAlias() != null) {
        org.plasma.sdo.Alias sdoAlias = lit.findAlias();
        Alias alias = new Alias();
        literal.setAlias(alias);

        alias.setPhysicalName(sdoAlias.getPhysicalName());
        alias.setLocalName(sdoAlias.getLocalName());
        alias.setBusinessName(sdoAlias.getBusinessName());
      }

      if (lit.getComments() != null && lit.getComments().size() > 0) {
        for (Comment comment : lit.getComments()) {
          Documentation documentation = new Documentation();
          documentation.setType(DocumentationType.DEFINITION);
          Body body = new Body();
          body.setValue(comment.getBody());
          documentation.setBody(body);
          literal.getDocumentations().add(documentation);
        }
      }

      enumeration.getEnumerationLiterals().add(literal);
    }

    return enumeration;
  }

  private Property createDataProperty(Package pkg, Class clss, PlasmaProperty sourceProperty) {
    Property property = createProperty(pkg, clss, sourceProperty);
    if (!sourceProperty.getType().isDataType())
      throw new IllegalArgumentException("given property is not a data property, " + clss.getUri()
          + "#" + clss.getName() + "." + sourceProperty.getName());

    DataType sdoType = DataType.valueOf(sourceProperty.getType().getName());
    TypeRef type = createDatatype(sdoType.name());
    property.setType(type);

    if (sourceProperty.getKey() != null) {
      org.plasma.sdo.Key sdoKey = sourceProperty.getKey();
      Key key = new Key();
      // target provisioning enum is JAXB generated so upper case
      key.setType(KeyType.valueOf(sdoKey.getType().name().toUpperCase()));
      property.setKey(key);
    }

    if (sourceProperty.getConcurrent() != null) {
      org.plasma.sdo.Concurrent sdoConcurrent = sourceProperty.getConcurrent();
      Concurrent conc = new Concurrent();
      // target provisioning enum is JAXB generated so upper case
      conc.setType(ConcurrencyType.valueOf(sdoConcurrent.getType().name().toUpperCase()));
      conc.setDataFlavor(ConcurentDataFlavor.valueOf(sdoConcurrent.getDataFlavor().name()
          .toUpperCase()));
      property.setConcurrent(conc);
    }

    if (sourceProperty.getXmlProperty() != null) {
      org.plasma.sdo.XmlProperty sdoXmlProperty = sourceProperty.getXmlProperty();
      XmlProperty xmlProp = new XmlProperty();
      // target provisioning enum is JAXB generated so upper case
      xmlProp.setNodeType(XmlNodeType.valueOf(sdoXmlProperty.getNodeType().name().toUpperCase()));
      property.setXmlProperty(xmlProp);
    }

    if (sourceProperty.getIncrement() != null) {
      Increment increment = new Increment();
      property.setIncrement(increment);
    }

    if (sourceProperty.getValueConstraint() != null) {
      org.plasma.sdo.ValueConstraint sdoValConst = sourceProperty.getValueConstraint();

      ValueConstraint valueConstraint = new ValueConstraint();
      if (sdoValConst.getFractionDigits() != null)
        valueConstraint.setFractionDigits(sdoValConst.getFractionDigits());
      if (sdoValConst.getMaxExclusive() != null)
        valueConstraint.setMaxExclusive(sdoValConst.getMaxExclusive());
      if (sdoValConst.getMaxInclusive() != null)
        valueConstraint.setMaxInclusive(sdoValConst.getMaxInclusive());
      if (sdoValConst.getMaxLength() != null)
        valueConstraint.setMaxLength(sdoValConst.getMaxLength());
      if (sdoValConst.getMinExclusive() != null)
        valueConstraint.setMinExclusive(sdoValConst.getMinExclusive());
      if (sdoValConst.getMinInclusive() != null)
        valueConstraint.setMinInclusive(sdoValConst.getMinInclusive());
      if (sdoValConst.getMinLength() != null)
        valueConstraint.setMinLength(sdoValConst.getMinLength());
      if (sdoValConst.getPattern() != null)
        valueConstraint.setPattern(sdoValConst.getPattern());

      property.setValueConstraint(valueConstraint);
    }

    org.plasma.sdo.repository.Enumeration sdoEnum = sourceProperty.getRestriction();
    if (sdoEnum != null) {
      // FIXME - really, same URI as class??
      String enumKey = clss.getUri() + "#" + sdoEnum.getName();
      Enumeration enumeration = this.enumerationMap.get(enumKey);
      if (enumeration == null) {
        enumeration = createEnumeration(clss, sdoEnum);
        pkg.getEnumerations().add(enumeration);
        this.enumerationMap.put(enumKey, enumeration);
      }

      EnumerationConstraint enumConstraint = new EnumerationConstraint();
      EnumerationRef enumRef = new EnumerationRef();
      enumRef.setName(enumeration.getName());
      enumRef.setUri(enumeration.getUri());
      enumConstraint.setValue(enumRef);
      property.setEnumerationConstraint(enumConstraint);
    }
    return property;
  }

  private Property createReferenceProperty(Package pkg, Class clss, PlasmaProperty sourceProperty,
      PlasmaProperty oppositeProperty) {
    Property property = createProperty(pkg, clss, sourceProperty);
    if (!sourceProperty.getType().isDataType()) {
      String qualifiedName = null;
      if (this.destNamespaceURI != null)
        qualifiedName = destNamespaceURI + "#" + sourceProperty.getType().getName();
      else
        qualifiedName = sourceProperty.getType().getURI() + "#"
            + sourceProperty.getType().getName();

      Class propertyClass = this.classMap.get(qualifiedName);
      if (propertyClass == null)
        throw new ProvisioningException("could not find class, " + qualifiedName);

      ClassRef ref = new ClassRef();
      ref.setName(propertyClass.getName());
      ref.setUri(propertyClass.getUri());
      property.setType(ref);
      if (oppositeProperty != null)
        property.setOpposite(oppositeProperty.getName());
    } else
      throw new IllegalArgumentException("given property is not a reference property, "
          + clss.getUri() + "#" + clss.getName() + "." + sourceProperty.getName());
    return property;
  }

  private Property createProperty(Package pkg, Class clss, PlasmaProperty sourceProperty) {
    Property property = new Property();
    property.setId(UUID.randomUUID().toString());
    property.setName(sourceProperty.getName());
    property.setNullable(sourceProperty.isNullable());
    property.setReadOnly(sourceProperty.isReadOnly());
    property.setMany(sourceProperty.isMany());
    property.setVisibility(VisibilityType.PUBLIC);

    if (sourceProperty.getAlias() != null) {
      org.plasma.sdo.Alias sdoAlias = sourceProperty.getAlias();
      Alias alias = new Alias();
      property.setAlias(alias);

      alias.setPhysicalName(sdoAlias.getPhysicalName());
      alias.setLocalName(sdoAlias.getLocalName());
      alias.setBusinessName(sdoAlias.getBusinessName());
    }

    if (sourceProperty.getSort() != null) {
      org.plasma.sdo.Sort sdoSort = sourceProperty.getSort();
      Sort sort = new Sort();
      sort.setKey(sdoSort.getKey());
      property.setSort(sort);
    }

    if (sourceProperty.getDescription() != null && sourceProperty.getDescription().size() > 0) {
      for (Comment comment : sourceProperty.getDescription()) {
        Documentation documentation = new Documentation();
        documentation.setType(DocumentationType.DEFINITION);
        Body body = new Body();
        body.setValue(comment.getBody());
        documentation.setBody(body);
        property.getDocumentations().add(documentation);
      }
    }

    return property;
  }

  private DataTypeRef createDatatype(String name) {
    DataTypeRef dataTypeRef = new DataTypeRef();
    dataTypeRef.setName(name);
    dataTypeRef.setUri(PlasmaRuntime.getInstance().getSDODataTypesNamespace().getUri());
    return dataTypeRef;
  }

  private Package createPackage(Namespace namespace, PlasmaType type, boolean modelPackage) {
    Package pkg = null;
    if (!modelPackage)
      pkg = new Package();
    else
      pkg = new Model();
    pkg.setName(namespace.getName());
    pkg.setId(UUID.randomUUID().toString());

    if (namespace.findAlias() != null) {
      org.plasma.sdo.Alias sdoAlias = namespace.findAlias();
      Alias alias = new Alias();
      pkg.setAlias(alias);

      alias.setPhysicalName(sdoAlias.getPhysicalName());
      alias.setLocalName(sdoAlias.getLocalName());
      alias.setBusinessName(sdoAlias.getBusinessName());
    }

    for (Comment cmt : namespace.getComments()) {
      Documentation doc = new Documentation();
      doc.setType(DocumentationType.DEFINITION);
      Body body = new Body();
      body.setValue(cmt.getBody());
      doc.setBody(body);
      pkg.getDocumentations().add(doc);
    }
    pkg.setUri(type.getURI());
    return pkg;
  }

  private Class createClass(Package pkg, PlasmaType plasmaType) {
    Class clss = new Class();
    pkg.getClazzs().add(clss);
    clss.setId(UUID.randomUUID().toString());
    clss.setName(plasmaType.getName());
    clss.setUri(plasmaType.getURI());
    clss.setAbstract(plasmaType.isAbstract());
    if (plasmaType.getPhysicalName() != null) {
      Alias alias = new Alias();
      clss.setAlias(alias);
      alias.setPhysicalName(plasmaType.getPhysicalName());
    }
    if (plasmaType.getAlias() != null) {
      org.plasma.sdo.Alias sdoAlias = plasmaType.getAlias();
      Alias alias = new Alias();
      clss.setAlias(alias);
      alias.setPhysicalName(sdoAlias.getPhysicalName());
      alias.setLocalName(sdoAlias.getLocalName());
      alias.setBusinessName(sdoAlias.getBusinessName());
    }

    for (commonj.sdo.Type baseType : plasmaType.getBaseTypes()) {
      ClassRef ref = new ClassRef();
      ref.setName(baseType.getName());
      ref.setUri(baseType.getURI());
      clss.getSuperClasses().add(ref);
    }
    if (plasmaType.getDescription() != null && plasmaType.getDescription().size() > 0) {
      for (Comment comment : plasmaType.getDescription()) {
        Documentation documentation = new Documentation();
        documentation.setType(DocumentationType.DEFINITION);
        Body body = new Body();
        body.setValue(comment.getBody());
        documentation.setBody(body);
        clss.getDocumentations().add(documentation);
      }
    }

    return clss;
  }

  /**
   * Constructs a provisioning model based on the given PlasmaQuery#8482; query.
   * Property ordering or sequence is imposed on all properties based on the
   * query ordering.
   * 
   * @param query
   *          the PlasmaQuery#8482; query
   * @param destNamespaceURI
   * @param destNamespacePrefix
   */
  private void construct(Query query, String destNamespaceURI, String destNamespacePrefix) {
    if (destNamespaceURI == null || destNamespaceURI.trim().length() == 0)
      throw new IllegalArgumentException("expected argument 'destNamespaceURI'");
    this.destNamespaceURI = destNamespaceURI;

    this.model = new Model();
    this.model.setId(UUID.randomUUID().toString());
    this.model.setUri(destNamespaceURI);
    this.model.setName(query.getName());
    Derivation derivation = new Derivation();
    PackageRef packageRef = new PackageRef();
    packageRef.setName(query.getName());
    packageRef.setUri(query.getFromClause().getUri());
    derivation.setPackageSupplier(packageRef);
    this.model.setDerivation(derivation);
    Documentation documentation = new Documentation();
    documentation.setType(DocumentationType.DEFINITION);
    Body body = new Body();
    body.setValue("derived model");
    documentation.setBody(body);
    this.model.getDocumentations().add(documentation);

    // collect types/properties from the Select within the
    // given query, then iterate over collected types
    PlasmaType rootType = (PlasmaType) PlasmaTypeHelper.INSTANCE.getType(query.getFromClause()
        .getUri(), query.getFromClause().getName());
    ClassRef rootClass = new ClassRef();
    rootClass.setName(rootType.getName());
    rootClass.setUri(rootType.getURI());
    this.model.setRootClass(rootClass);

    PropertySelectionCollector collector = new PropertySelectionCollector(
        (org.plasma.query.model.Select) query.getSelectClause(), rootType);
    Map> queryPropertyMap = collector.getResult();

    // create entities first pass
    Iterator iter = queryPropertyMap.keySet().iterator();
    while (iter.hasNext()) {
      PlasmaType sdoType = (PlasmaType) iter.next();
      Class clss = createClass(model, sdoType);
      classMap.put(destNamespaceURI + "#" + clss.getName(), clss);
    }

    // create "hollow" base types if needed
    iter = queryPropertyMap.keySet().iterator();
    while (iter.hasNext()) {
      PlasmaType sdoType = (PlasmaType) iter.next();
      constructBaseTypes(query, sdoType, collector, queryPropertyMap);
    }

    // add properties
    Iterator iter2 = queryPropertyMap.keySet().iterator();
    while (iter2.hasNext()) {
      PlasmaType sdoType = (PlasmaType) iter2.next();
      List list = queryPropertyMap.get(sdoType);
      Class clss = classMap.get(destNamespaceURI + "#" + sdoType.getName());

      // add datatype properties in query list
      for (commonj.sdo.Property p : sdoType.getDeclaredProperties()) {
        PlasmaProperty plasmaProperty = (PlasmaProperty) p;
        if (!plasmaProperty.getType().isDataType())
          continue;
        if (list.contains(plasmaProperty.getName())) {

          Property field = createDataProperty(this.model, clss, plasmaProperty);
          Sort sort = new Sort();
          sort.setKey(String.valueOf(list.indexOf(plasmaProperty.getName())));
          field.setSort(sort);

          clss.getProperties().add(field);
        }
      }

      // add reference properties in query list
      for (commonj.sdo.Property p2 : sdoType.getDeclaredProperties()) {
        PlasmaProperty plasmaProperty = (PlasmaProperty) p2;
        if (plasmaProperty.getType().isDataType())
          continue; // only reference props
        if (!list.contains(plasmaProperty.getName()))
          continue;
        PlasmaProperty oppositeProperty = (PlasmaProperty) plasmaProperty.getOpposite();
        Property field = null;
        if (oppositeProperty != null) {
          PlasmaType oppositeType = (PlasmaType) plasmaProperty.getType();
          // Is the opposite is found in the query??
          if (collector.hasProperty(oppositeType, oppositeProperty)) {
            field = createReferenceProperty(this.model, clss, plasmaProperty, oppositeProperty);
          } else {
            if (plasmaProperty.isMany())
              field = createReferenceProperty(this.model, clss, plasmaProperty, oppositeProperty);
            else
              field = createReferenceProperty(this.model, clss, plasmaProperty, null);
          }
        } else {
          field = createReferenceProperty(this.model, clss, plasmaProperty, null);
        }

        Sort sequence = new Sort();
        sequence.setKey(String.valueOf(list.indexOf(plasmaProperty.getName())));
        field.setSort(sequence);

        clss.getProperties().add(field);
      }

      constructImplicitDatatypeProperties(query, sdoType, clss, list);

      // Note: must have singular opposite properties for RDBMS service
      // note these are visibility 'private'.
      constructImplicitReferenceProperties(query, sdoType, clss, collector, list);

    } // type
  }

  // For every type included in the query, include all base types
  // and their properties
  private void constructBaseTypes(Query query, Type sdoType, PropertySelection collector,
      Map> queryPropertyMap) {
    for (Type base : sdoType.getBaseTypes()) {
      PlasmaType sdoBaseType = (PlasmaType) PlasmaTypeHelper.INSTANCE.getType(base.getURI(),
          base.getName());
      Class existing = classMap.get(destNamespaceURI + "#" + base.getName());
      if (existing == null) {
        Class baseClss = createClass(model, (PlasmaType) base);
        classMap.put(destNamespaceURI + "#" + baseClss.getName(), baseClss);
        List baseList = queryPropertyMap.get(base.getURI() + "#" + base.getName());
        constructImplicitDatatypeProperties(query, sdoBaseType, baseClss, baseList);
        constructImplicitReferenceProperties(query, sdoBaseType, baseClss, collector, baseList);
        // List baseProperties =
        // base.getDeclaredProperties();
        // createFields(model, baseClss, baseProperties);
      }
      constructBaseTypes(query, sdoBaseType, collector, queryPropertyMap); // recurse
    }
  }

  /*
   * Add datatype properties not in query list but required to facilitate
   * completeness of down stream models. E.g. an XML Schema which we want to use
   * to 'define' a dynamic SDO namespace/model must know about primary key
   * fields. And other mandatory data fields??
   */
  private void constructImplicitDatatypeProperties(Query query, PlasmaType sdoType, Class clss,
      List list) {
    for (commonj.sdo.Property p : sdoType.getDeclaredProperties()) {
      PlasmaProperty plasmaProperty = (PlasmaProperty) p;
      if (!plasmaProperty.getType().isDataType())
        continue;
      if (list == null || !list.contains(plasmaProperty.getName())) {
        // Automatically add all key and concurency fields even though not
        // specified in query
        // , but make private and NOT required.
        // FIXME: If we knew more at a profile level about the key,
        // then more intelligent options might be possible
        if (plasmaProperty.getKey() != null || plasmaProperty.getConcurrent() != null) {
          Property field = createDataProperty(this.model, clss, plasmaProperty);
          field.setVisibility(VisibilityType.PRIVATE);
          field.setNullable(true);

          Sort sequence = new Sort();
          sequence.setKey(String.valueOf(clss.getProperties().size()));
          field.setSort(sequence);

          clss.getProperties().add(field);
        }
      }
    }
  }

  private void constructImplicitReferenceProperties(Query query, PlasmaType sdoType, Class clss,
      PropertySelection collector, List list) {
    for (commonj.sdo.Property p2 : sdoType.getDeclaredProperties()) {
      PlasmaProperty plasmaProperty = (PlasmaProperty) p2;
      if (plasmaProperty.getType().isDataType())
        continue; // only reference props
      if (list != null && list.contains(plasmaProperty.getName()))
        continue;
      PlasmaProperty oppositeProperty = (PlasmaProperty) plasmaProperty.getOpposite();

      /*
       * // FIXME: what a bout mandatory ref props ???? if (oppositeProperty !=
       * null && !plasmaProperty.isNullable()) { Property property =
       * createReferenceProperty(this.model, clss, plasmaProperty,
       * oppositeProperty); property.setVisibility(VisibilityType.PRIVATE);
       * 
       * Sort sequence = new Sort();
       * sequence.setKey(String.valueOf(clss.getProperty().size()));
       * property.setSort(sequence);
       * 
       * clss.getProperty().add(property); }
       */

      // Property is NOT directly referenced in the query
      // and it has an opposite and the opposite IS referenced
      // and this property is singular, create a private reference
      // property linked to the opposite. Such a singular property
      // will be required for RDBMS service meta data definitions
      // as a collection property must "map to" a singular property
      // linked to an RDBMS column.
      if (oppositeProperty != null && !plasmaProperty.isMany()) {
        PlasmaType oppositeType = (PlasmaType) plasmaProperty.getType();
        if (collector.hasProperty(oppositeType, oppositeProperty)) {
          String oppositeQualName = this.destNamespaceURI + "#" + oppositeType.getName();
          Class oppositeClass = classMap.get(oppositeQualName);
          if (oppositeClass == null)
            throw new IllegalStateException("could not find class, " + oppositeQualName);
          Property property = createReferenceProperty(this.model, clss, plasmaProperty,
              oppositeProperty);
          property.setVisibility(VisibilityType.PRIVATE);

          Sort sequence = new Sort();
          sequence.setKey(String.valueOf(clss.getProperties().size()));
          property.setSort(sequence);

          clss.getProperties().add(property);
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy