package com.openMap1.mapper.mapping; import java.util.*; import com.openMap1.mapper.core.Xpth; import com.openMap1.mapper.util.messageChannel; import com.openMap1.mapper.util.ModelUtil; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.AssocEndMapping; import com.openMap1.mapper.PropMapping; import org.eclipse.emf.ecore.EPackage; /** * the mapping to one end of an association. * both associationEndMappings of an associationMapping are created * with the same nodePath - the path from the root to the association node. * * This class is a wrapper around the model class AssocEndMapping * * @author Robert Worden * @version 1.0 */ public class associationEndMapping extends MappingTwo { public AssocEndMapping aem() {return (AssocEndMapping)map();} private String minCardinality; // "0", "1", "M", or "undefined" private String maxCardinality; // "1", "M", or "undefined" /* minCardinality and maxCardinality as defined in the MDL. These are either undefined (value '') or '1' - i.e the MDL can only make the min and max cardinalities more constrained, than either the object model or the XML structure would imply. It cannot make them less constrained. */ private String minCardinalityFromMDL = ""; private String maxCardinalityFromMDL = ""; /** role name for the end (UML 'association name' */ public String roleName() {return aem().getMappedRole();} /** XPath from association node to object at this end */ public Xpth assocToObj()throws MapperException {return aem().getAssociationToObjectXPath();} /** XPath from object at this end to association */ public Xpth objToAssoc() throws MapperException {return aem().getObjectToAssociationXPath();} /** minCardinality and maxCardinality from the object model * - not defined in MDL, but are only set up * when validating MDL, from the class model in check 4; and used in check 9. * "0", "1", "M", or "undefined" */ public String minCardinality() {return minCardinality;} /** set minCardinality */ public void setMinCardinality(String s) {minCardinality = s;} /** maxCardinality and maxCardinality from the object model * - not defined in MDL, but are only set up * when validating MDL, from the class model in check 4; and used in check 9. * "1", "M", or "undefined" */ public String maxCardinality() {return maxCardinality;} /** set max cardinality */ public void setMaxCardinality(String s) {maxCardinality = s;} /** minCardinality as defined in the MDL. Either undefined (value '') or '1' - i.e the MDL can only make the min and max cardinalities more constrained, than either the object model or the XML structure would imply. It cannot make them less constrained. */ public String minCardinalityFromMDL() {return minCardinalityFromMDL;} /** maxCardinality as defined in the MDL. Either undefined (value '') or '1' - i.e the MDL can only make the min and max cardinalities more constrained, than either the object model or the XML structure would imply. It cannot make them less constrained. */ public String maxCardinalityFromMDL() {return maxCardinalityFromMDL;} /** if true, this association is an inclusion condition for the class/subset */ public boolean required() {return aem().isRequiredForObject();} public int end() {return aem().getEnd();} public associationEndMapping getOtherEndMapping() {return otherEndMapping;} public void setOtherEndMapping(associationEndMapping otherEndMapping) {this.otherEndMapping = otherEndMapping;} private associationEndMapping otherEndMapping = null; /** * mapping for one end of an association * * @param aem the AssocEndMapping * @param md messageChannel: for writing messages */ public associationEndMapping(AssocEndMapping aem, messageChannel md) throws MapperException { super(aem, md); mappingType = MappingTwo.ASSOCIATION; minCardinality = "undefined"; maxCardinality = "undefined"; // if (minFromMDL.equals("1")) minCardinalityFromMDL = "1"; // if (maxFromMDL.equals("1")) maxCardinalityFromMDL = "1"; } /** simple write of the end mapping */ public void write() { mChan().message("Association end mapping to class " + cSet().stringForm() + " at end " + end()); writeConditions(); } /** true if the path from the association node to the object is a pure ascent */ public boolean pureAscent() throws MapperException { return (assocToObj().pureAscent()); } /** true if the path from the association node to the object node is 'stay here' */ public boolean identity() throws MapperException { return (assocToObj().selfPath()); } /** XPaths for link conditions */ public Vector<Xpth> linkConditionPaths() { Vector<Xpth> res = new Vector<Xpth>(); for (int i = 0; i < linkConditions().size();i++) { linkCondition lc = linkConditions().elementAt(i); res.addElement(lc.rhsEndToRightValue()); } return res; } /** XPaths for equality link conditions */ public Vector<Xpth> equalityLinkConditionPaths() { Vector<Xpth> res = new Vector<Xpth>(); for (int i = 0; i < linkConditions().size();i++) { linkCondition lc = linkConditions().elementAt(i); if (lc.test.equals("=")) {res.addElement(lc.rhsEndToRightValue());} } return res; } /** true if the association node represents multiple instances of the association, to multiple objects of this end class. */ public int multiInstanceLinks() { int multis = 0; for (int i = 0; i < linkConditions().size();i++) { linkCondition lc = linkConditions().elementAt(i); if (lc.test.equals("containsAsWord")) multis++; } return multis; } /** true if the association node has any link conditions in a set of nodes defined by their root paths */ public boolean hasLinkValuesIn(Vector<Xpth> nodePaths) { boolean hasVals = false; for (int i = 0; i < linkConditions().size();i++) { linkCondition lc = linkConditions().elementAt(i); if (lc.rootToLeftValue().oneOf(nodePaths)) hasVals = true; } return hasVals; } /** simple description */ public String description() { return("mapping for association end at class '" + className() + "'"); } /** true if the link conditions of an association end mapping guarantee that the path from the association node to the object node will only give one object - i.e. if the link conditions pick out unique values for all properties in a unique identifier of the object, as defined by the MDL in MD. */ public boolean uniqueLinkConditions() throws MapperException { boolean res = false; EPackage classModelRoot = ModelUtil.getClassModelRoot(aem()); Vector<Vector<String>> uids = ModelUtil.uniqueIdentifiers(className(),classModelRoot); // can only be true if there are some link conditions and some unique identifiers if ((linkConditions().size() > 0) && (uids.size() > 0)) // try out all unique identifiers, to see if any are defined by the link conditions for (int i = 0; i < uids.size(); i++) { Vector<String> uid = uids.elementAt(i); boolean uidDefined = true; // loop over all properties in a unique identifier for (Iterator<String> it = uid.iterator();it.hasNext();) if (uidDefined) { String propName = it.next(); boolean propDefined = false; /* there may be several property mappings - choice or redundant; If any mappings are defined by the link conditions, assume the property is defined. */ Vector<PropMapping> propMappings = ModelUtil.getPropertyMappings(cSet(),propName,aem()); if (propMappings.size() == 0) {uidDefined = false;} else for (int k = 0; k < propMappings.size(); k++) { PropMapping pm = propMappings.elementAt(k); if (definedPropertyMapping(pm)) propDefined = true; } if (!propDefined) uidDefined = false; } if (uidDefined) res = true; } return res; } /** true if one of the link conditions in this association mapping is sufficient to define the value of the property in the property mapping.*/ private boolean definedPropertyMapping(PropMapping pm) throws MapperException { boolean res = false; for (int i = 0; i < linkConditions().size(); i++) { linkCondition lc = linkConditions().elementAt(i); // double condition too stringent?? if ((lc.rootToRightValue().equalPath(pm.getRootXPath())) && (lc.rhsEndToRightValue().equalPath(pm.getObjectToPropertyXPath()))) res = true; } return res; } }