package com.openMap1.mapper.mapping; import com.openMap1.mapper.core.Xpth; import com.openMap1.mapper.core.namespace; import com.openMap1.mapper.core.NamespaceSet; import com.openMap1.mapper.core.ClassSet; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.core.XpthException; import com.openMap1.mapper.util.GenUtil; import com.openMap1.mapper.util.ModelUtil; import com.openMap1.mapper.util.messageChannel; import com.openMap1.mapper.writer.XSLGenerator; import com.openMap1.mapper.writer.whenValue; import com.openMap1.mapper.writer.outputContext; import com.openMap1.mapper.AssocEndMapping; import com.openMap1.mapper.AttributeDef; import com.openMap1.mapper.CrossCondition; import com.openMap1.mapper.MappedStructure; import com.openMap1.mapper.Mapping; import com.openMap1.mapper.MappingCondition; import com.openMap1.mapper.NodeDef; import com.openMap1.mapper.PropMapping; import com.openMap1.mapper.ValueCondition; import java.util.Enumeration; import java.util.Vector; import java.util.Iterator; /** superclass for all mappings between the XML and the class model * - mappings representing objects, properties and associations. * Now a wrapper class for the Mapper model class Mapping */ public class MappingTwo { public static int OBJECT = 0; public static int PROPERTY = 1; public static int ASSOCIATION = 2; public String mappingTypeString() {return mappingTypeString[mappingType];} private String[] mappingTypeString = {"object","property","assoc"}; public int mappingType() {return mappingType;} protected int mappingType; private Mapping map; /** the model mapping object which this is a wrapper for */ public Mapping map() {return map;} private messageChannel mChan; public messageChannel mChan() {return mChan;} /** XPath from the root to the node representing something */ public Xpth nodePath() { Xpth np = null; try{np = map.getRootXPath();} catch (MapperException ex){GenUtil.surprise(ex,"mapper.nodePath");} return np; } public NodeDef mappedNode() { MappedStructure ms = ModelUtil.getMappedStructure(map); return ms.getNodeDefByPath(nodePath().stringForm()); } /** qualified class name of the object mapped, or object owning the property mapped */ public String className() {return map.getQualifiedClassName();} /** subset of the object mapped, or object owning the property mapped. * default ""; otherwise denotes that this node is one of several nodes representing objects, * properties or associationEnds of this class. */ public String subset() {return map.getSubset();} /** * @return true if the mapping has a subset other than null or "" */ public boolean hasSubset() { if (subset() == null) return false; if (subset().equals("")) return false; return true; } /** class and subset of the object mapped, or object owning the property mapped */ public ClassSet cSet() {return map.getClassSet();} /** * @return level in the stack of XOReaders from which this mapping came, * for XSLT generation */ public int stackLevel() {return stackLevel;} private int stackLevel = 0; /** * set the level in the stack of XOReaders from which this mapping came, * for XSLT generation * @param level */ public void setStackLevel(int level) {stackLevel = level;} /** * class and subset of the object mapped, or object owning the property mapped. * The subset has a prefix which defines the XOReader stack level, for XSLT generation * */ public ClassSet XSLCSet() { ClassSet cSet = null; try { String XSLSubset = "m" + stackLevel + "_" + subset(); cSet = new ClassSet(className(), XSLSubset); } catch (Exception ex) { System.out.println("Exception making XSL ClassSet "); System.out.println(className() + " " + subset()); } return cSet; } /* the mapping only represents what it represents when all these conditions are true. */ private Vector<whenCondition> whenConditions = new Vector<whenCondition>(); private Vector<linkCondition> linkConditions = new Vector<linkCondition>(); // vector of link conditions /** Vector of when-conditions which must hold for the mapping to apply */ public Vector<whenCondition> whenConditions() {return whenConditions;} /** Vector of link conditions which must hold for the mapping to apply */ public Vector<linkCondition> linkConditions() {return linkConditions;} /** Vector of all link and when-conditions which must hold for the mapping to apply */ public Vector<Condition> allConditions() { Vector<Condition> allConditions = new Vector<Condition>(); for (Iterator<linkCondition> il = linkConditions.iterator();il.hasNext();) allConditions.add(il.next()); for (Iterator<whenCondition> iw = whenConditions.iterator();iw.hasNext();) allConditions.add(iw.next()); return allConditions; } /** multiway describes choice or redundant mappings */ public String multiWay() {return map.getMultiWay().getLiteral();} /** One of the when-conditions which must hold for the mapping to apply */ public whenCondition whenCondition(int i) {return whenConditions.elementAt(i);} /** * One of the link conditions which must hold for the mapping to apply * * @param i int index of the condition * @return linkCondition the link condition */ public linkCondition linkCondition(int i) {return linkConditions.elementAt(i);} /** Add a when-condition which must hold for the mapping to apply */ public void addWhenCondition(whenCondition wc) {whenConditions.addElement(wc);} /** Add a link condition which must hold for the mapping to apply */ public void addLinkCondition(linkCondition lc) {linkConditions.addElement(lc);} /** true if this is a mapping to an XML attribute (not an element) */ public boolean isXMLAttributeMapping() {return (map.mappedNode() instanceof AttributeDef);} //--------------------------------------------------------------------------------------------------------- // constructor //--------------------------------------------------------------------------------------------------------- /** * * @param map */ public MappingTwo(Mapping map, messageChannel mChan) throws MapperException { this.map = map; this.mChan = mChan; for (Iterator<MappingCondition> it = map.getMappingConditions().iterator();it.hasNext();) { MappingCondition mc = it.next(); if (mc instanceof ValueCondition) { addWhenCondition(new whenCondition((ValueCondition)mc)); } else if (mc instanceof CrossCondition) try { int end = 0; if (map instanceof AssocEndMapping) {end = ((AssocEndMapping)map).getEnd();} else if (map instanceof PropMapping) {end = 0;} // allowed case; no change else throw new MapperException("Cross condition on a mapping which is not " + " a property mapping or an association end mapping"); addLinkCondition(new linkCondition((CrossCondition)mc, end)); } /* sometimes an object mapping required in a link condition is missing, * and I do not want this to throw the whole MDLBase initialisation.*/ catch (MapperException ex) {System.out.println(ex.getMessage());} } } //--------------------------------------------------------------------------------------------------------- // namespaces //--------------------------------------------------------------------------------------------------------- private namespace MDLNamespace = GenUtil.defaultMDLNamespace(); public namespace MDLNamespace() {return MDLNamespace;} String MDLPrefix() {return MDLNamespace().prefix();} String MDLURI() {return MDLNamespace().URI();} /** * reset the URI of the MDL namespace * @param newURI String the new URI (should identify the class model being mapped onto) */ public void setMDLURI(String newURI) {MDLNamespace = new namespace(GenUtil.defaultMDLNamespace().prefix(),newURI);} /** full namespace set, including the MDL namespace and the namespaces of the mapped XML */ public NamespaceSet NSSet() { NamespaceSet mappedSpaces = null; try { mappedSpaces = ModelUtil.getGlobalNamespaceSet(map); mappedSpaces.addNamespace(MDLNamespace); } catch (MapperException ex) {GenUtil.surprise(ex, "mapper.NSSet");} return mappedSpaces; } //--------------------------------------------------------------------------------------------------------- // other stuff //--------------------------------------------------------------------------------------------------------- /** should always be overridden, but just in case... */ public void write(messageChannel mChan) { mChan.message(""); mChan.message("Mapping to node " + nodePath().stringForm()); writeConditions(); } /** class and subset of the mapping */ public ClassSet getClassSet() {return cSet();} /** name of the representing node ( = prefixed element name or attribute name) */ String nodeName() {return map.mappedNode().getName();} /** XPaths to nodes required to evaluate 'when' conditions for this representation */ public Vector<Xpth> whenConditionPaths() { int i; Vector<Xpth> res = new Vector<Xpth>(); for (i = 0; i < whenConditions.size(); i++) { whenCondition wc = whenConditions.elementAt(i); // do not include when conditions that apply a function to the LHS if (wc.getLeftFunction().equals("")) res.addElement(wc.rootToLeftValue()); } return res; } /** XPaths to nodes required to evaluate 'when' and link conditions for this representation */ public Vector<Xpth> allConditionPaths() { Vector<Xpth> allC = new Vector<Xpth>(); for (Iterator<Xpth> it = whenConditionPaths().iterator();it.hasNext();) {allC.add(it.next());} for (Iterator<Xpth> it = linkConditionPaths().iterator();it.hasNext();) {allC.add(it.next());} return allC; } /** true if the 'when' conditions of this mapping are mutually exclusive with the 'when' * conditions of some other mapping - i.e if the two mappings cannot apply to * the same node instance.*/ public boolean exclusiveWhenConditions(MappingTwo m) throws XpthException { int i,j; whenCondition w1,w2; boolean res = false; if (nodePath().equalPath(m.nodePath())) for (i = 0; i < whenConditions.size(); i++) { w1 = whenConditions.elementAt(i); for (j = 0; j < m.whenConditions.size(); j++) { w2 = m.whenConditions.elementAt(j); if (w1.mutualExclusive(w2)) res = true; } } return res; } /** to be overridden */ public String description() { return("generic mapping"); } /** XPath form of when-conditions */ public String XPathWhenTests(XSLGenerator XX) throws MapperException { String res = ""; if (whenConditions.size() > 0) { res = "["; for (int i = 0; i < whenConditions.size(); i++) { if (i > 0) res = res + " and "; whenCondition wc = whenConditions.elementAt(i); res = res + wc.XPathForm(XX); } res = res + "]"; } return res; } /** XPath form of link conditions */ public String XPathLinkTests(XSLGenerator XX,boolean fromObject,String startVar) throws XpthException { String res = ""; if (linkConditions.size() > 0) { res = "["; for (int i = 0; i < linkConditions.size(); i++) { if (i > 0) res = res + " and "; linkCondition lc = linkConditions.elementAt(i); res = res + lc.XPathTest(XX,fromObject,startVar); } res = res + "]"; } return res; } /** XPaths to nodes required to evaluate link conditions for this representation * FIXME - this is obviously wrong. */ public Vector<Xpth> linkConditionPaths() {return new Vector<Xpth>();} /** write out text form of when-conditions and link conditions */ public void writeConditions() { for (int i = 0; i < whenConditions.size(); i++) { whenCondition wc = whenCondition(i); mChan.message("When: {" + wc.lhsEndToLeftValue().stringForm() + "} " + wc.test() + " '" + wc.rightValue() + "'"); } for (int i = 0; i < linkConditions.size(); i++) { linkCondition lc = linkCondition(i); mChan.message("Link: {" + lc.lhsEndToLeftValue().stringForm() + "} " + lc.test() + " {" + lc.rhsEndToRightValue().stringForm() + "}"); } } /** maximum absolute path length to this mapping, or to any of its when-condition or link * condition values */ public int mappingDepth() throws MapperException { int depth = 0; if (nodePath().definite()) { depth = nodePath().size(); for (int i = 0; i < whenConditionPaths().size(); i++) { Xpth wp = (Xpth)whenConditionPaths().elementAt(i); if (wp.size() > depth) depth = wp.size(); } for (int i = 0; i < linkConditions().size(); i++) { linkCondition lc = linkConditions().elementAt(i); if (lc.rootToLeftValue.size() > depth) depth = lc.rootToLeftValue.size(); if (lc.rootToRightValue().size() > depth) depth = lc.rootToRightValue().size(); } } return depth; } /** maximum inner path length inside the '//' step to this mapping, * or to any of its when-condition or link condition values */ public int innerDepth() throws XpthException { int depth = 0; if (!nodePath().definite()) { depth = nodePath().innerSize(); for (int i = 0; i < whenConditionPaths().size(); i++) { Xpth wp = (Xpth)whenConditionPaths().elementAt(i); if (wp.innerSize() > depth) depth = wp.innerSize(); } for (int i = 0; i < linkConditions().size(); i++) { linkCondition lc = linkConditions().elementAt(i); if (lc.rootToLeftValue.innerSize() > depth) depth = lc.rootToLeftValue.innerSize(); if (lc.rootToRightValue().innerSize() > depth) depth = lc.rootToRightValue().innerSize(); } } return depth; } /** true if this mapping is applicable in a given subtree context. * The context defines a set of when-condition values, and the nodes that represent them. * If any values conflict with the value of a when-condition defined on the same node in this mapping, * this mapping is not applicable. * Assumes that the only tests applied in when-conditions are '='. */ public boolean applicable(outputContext oc) throws XpthException { int i; boolean applicable = true; whenValue wv; whenCondition wc; for (i = 0; i < whenConditions.size(); i++) { wc = whenConditions.elementAt(i); for (Enumeration<whenValue> en = oc.whenValues().elements(); en.hasMoreElements();) { wv = en.nextElement(); if ((wc.rootToLeftValue().compatible(wv.rootPath())) && (!(wv.value().equals(wc.rightValue())))) applicable = false; } } return applicable; } public static Vector<MappingTwo> vCopy(Vector<MappingTwo> v) { Vector<MappingTwo> res = new Vector<MappingTwo>(); for (Iterator<MappingTwo> it = v.iterator();it.hasNext();) res.add(it.next()); return res; } }