package com.openMap1.mapper.writer; import java.util.*; import com.openMap1.mapper.mapping.*; import com.openMap1.mapper.core.*; import com.openMap1.mapper.NodeDef; /** * represents the context when outputting XML - mainly the node of * the output document you are on, and what objects are uniquely defined (represented) * by that node and higher nodes. * * All paths have namespace prefixes as in the output XML structure definition, * not the MDL. */ public class outputContext { // definite path from the root to the node of the current procedure private Xpth rootPath; private NodeDef contextNode = null; public NodeDef contextNode() {return contextNode;} protected MDLBase MD; /* stack of classSets for anticipated or actual uniquely defined objects - those represented by outer nodes, or objects which can be got from them by following M:1 associations. Should match the classSets in the runtime subtreeContext at the same node. */ private Vector<ClassSet> uniqueCSets; /* whenValue objects for anticipated choices of values of when-condition nodes, above this node or in its unique subtree. Hashtable has key = root path string form, value = whenValue object Should match the whenValues in the runtime structureContext at the same node. */ private Hashtable<String, whenValue> whenValues; public Xpth rootPath() {return rootPath;} public Vector<ClassSet> uniqueCSets() {return uniqueCSets;} public Hashtable<String, whenValue> whenValues() {return whenValues;} public void addUniqueCSet(ClassSet cs) {uniqueCSets.addElement(cs);} outputContext(MDLBase md, Xpth rp) { rootPath = rp; MD = md; contextNode = MD.ms().getNodeDefByPath(rp.stringForm()); uniqueCSets = new Vector<ClassSet>(); whenValues = new Hashtable<String, whenValue>(); } // deep copy as starting point for changes to a new version public outputContext copyOC() throws MDLWriteException { int i; outputContext oc = new outputContext(MD,rootPath().copy()); for (i = 0; i < uniqueCSets.size(); i++) {oc.addUniqueCSet(uniqueCSets.elementAt(i));} for (Enumeration<whenValue> en = whenValues.elements(); en.hasMoreElements();) {oc.setWhenValue(en.nextElement());} return oc; } /* at some time I might make checks on paths and throw an exception - */ public void setWhenValue(whenValue wv) throws MDLWriteException { whenValues.put(wv.rootPath().stringForm(),wv); } public void setRootPath(Xpth rp) throws MDLWriteException { rootPath = rp; } /* true if this context contains a when-condition value which matches wv in both root path and value. */ public boolean matchesWhenValue(whenValue wv) { boolean res = false; for (Enumeration<whenValue> en = whenValues.elements(); en.hasMoreElements();) { whenValue ww = en.nextElement(); if (ww.equals(wv)) res = true; } return res; } // true if the object stack has one or more objects in this class and subset public boolean hasObject(ClassSet cSet) { boolean res = false; for (int i = 0; i < uniqueCSets.size(); i++) if (cSet.equals(uniqueCSet(i))) {res = true;} return res; } private ClassSet uniqueCSet(int i) {return uniqueCSets.elementAt(i);} /* filter a vector of association mappings, so the result contains only associations involving objects in the runtime context. */ public Vector<AssociationMapping> vetAssocs(Vector<AssociationMapping> allAssocs) throws MapperException { Vector<AssociationMapping> assocs = new Vector<AssociationMapping>(); for (int i = 0; i < allAssocs.size(); i++) { AssociationMapping am = (AssociationMapping)allAssocs.elementAt(i); if ((hasEndInContext(am.nodePath(),am.assocEnd(0)))| (hasEndInContext(am.nodePath(),am.assocEnd(1)))) {assocs.addElement(am);} } return assocs; } /* find the end ( = 1 or 2) of an association which connects to an object not in the runtime context. Return 0 if neither end connects. */ public int endNotInContext(AssociationMapping am) throws MapperException { int res = 0; if (!hasEndInContext(am.nodePath(),am.assocEnd(0))) {res = 1;} else if (!hasEndInContext(am.nodePath(),am.assocEnd(1))) {res = 2;} return res; } /* True if this end of the association connects to an object already in the runtime context. */ public boolean hasEndInContext(Xpth rootPath,associationEndMapping aem) throws MapperException { boolean res = false; NodeDef mappedNode = MD.ms().getNodeDefByPath(rootPath.stringForm()); if (hasObject(aem.cSet())) { /* the object may be of a ClassSet that is in context; but the actual object is only in context if the relative path from the association node to the object node leads to a unique node, i.e. if it was in the unique subtree of some higher context. */ res = mappedNode.uniquePath(aem.assocToObj()); } return res; } public String contextClasses() { String toWrite = "Classes in context: "; for (int i = 0; i < uniqueCSets.size(); i++) { ClassSet cs = uniqueCSets.elementAt(i); toWrite = toWrite + cs.stringForm()+ " "; } return toWrite; } }