/** * */ package agg.xt_basis.agt; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.Vector; import agg.attribute.impl.ContextView; import agg.attribute.impl.TupleMapping; import agg.attribute.impl.ValueTuple; import agg.attribute.impl.VarMember; import agg.attribute.impl.VarTuple; import agg.util.Change; import agg.util.Pair; import agg.util.XMLHelper; import agg.xt_basis.Arc; import agg.xt_basis.BadMappingException; import agg.xt_basis.BaseFactory; import agg.xt_basis.Graph; import agg.xt_basis.GraphKind; import agg.xt_basis.GraphObject; import agg.xt_basis.Match; import agg.xt_basis.NestedApplCond; import agg.xt_basis.Node; import agg.xt_basis.OrdinaryMorphism; import agg.xt_basis.Rule; import agg.xt_basis.TypeException; import agg.xt_basis.TypeSet; /** * Multi rule is an extending rule of an interaction rule scheme. The kernel * rule of a rule scheme is embedded into multi rule. So the application of two * or more multi rules is synchronized by the kernel rule above this embedding. * * @author olga * */ public class MultiRule extends Rule implements Observer { private RuleScheme itsRuleScheme; /** embedded morphism left */ private OrdinaryMorphism embeddingLeft; /** embedded morphism right */ private OrdinaryMorphism embeddingRight; private final Hashtable<GraphObject, GraphObject> kernel2objects = new Hashtable<GraphObject, GraphObject>(); private final Hashtable<GraphObject, GraphObject> objects2kernel = new Hashtable<GraphObject, GraphObject>(); private List<OrdinaryMorphism> shiftedApplConds = new Vector<OrdinaryMorphism>(); // private boolean isChanged = false; /** * Creates a multi rule with empty left and right graphs based on the * specified type set. */ public MultiRule(TypeSet types) { super(types); this.itsName = "MultiRule"; } /** * Creates a multi rule based on the specified left and right embedding of * the kernel rule. Target graph of the left embedding is the LHS, target * graph of the right embedding is the RHS of the multi rule. The object * mapping of the kernel rule builds partial mapping of the multi rule. */ public MultiRule(final Rule kernelRule, final OrdinaryMorphism embeddingLeft, final OrdinaryMorphism embeddingRight) { super(embeddingLeft.getTarget(), embeddingRight.getTarget()); this.itsName = "MultiRule"; // this.itsOrig.setAttrContext(getAttrManager().newLeftContext( // getAttrContext())); // this.itsImag.setAttrContext(getAttrManager().newRightContext( // getAttrContext())); this.embeddingLeft = embeddingLeft; this.embeddingRight = embeddingRight; this.applyEmbeddedRuleMapping(kernelRule); this.itsOrig.setKind(GraphKind.LHS); this.itsImag.setKind(GraphKind.RHS); kernelRule.getLeft().setKind(GraphKind.LHS); kernelRule.getRight().setKind(GraphKind.RHS); mapKernel2MultiObject(); } /** * Returns its full name : schemeName.ruleName */ public String getQualifiedName() { if (this.itsRuleScheme != null) return this.itsRuleScheme.getName().concat(".").concat(this.itsName); return this.itsName; } public void addShiftedKernelApplCond(OrdinaryMorphism cond, boolean pac) { this.shiftedApplConds.add(cond); if (pac) { this.itsPACs.add(0, cond); } else { this.itsNACs.add(0, cond); } } public void addShiftedKernelNestedApplCond(NestedApplCond cond) { this.shiftedApplConds.add(cond); this.itsACs.add(0, cond); } public void removeShiftedKernelApplConds() { for (int i=0; i<this.shiftedApplConds.size(); i++) { OrdinaryMorphism cond = this.shiftedApplConds.get(i); if (this.itsACs.contains(cond)) { this.destroyNestedAC(cond); } else if (this.itsPACs.contains(cond)) { this.destroyPAC(cond); } else if (this.itsNACs.contains(cond)) { this.destroyNAC(cond); } } this.shiftedApplConds.clear(); } public void removeShiftedKernelApplCond(OrdinaryMorphism cond, boolean pac) { if (this.shiftedApplConds.remove(cond)) { if (pac) { this.destroyPAC(cond); } else { this.destroyNAC(cond); } } } /** * Returns a match which partially based on the match of the kernel rule. */ public Match getMatch(final Rule kernelRule) { if (this.itsMatch == null && kernelRule == this.itsRuleScheme.getKernelRule()) { if (this.itsRuleScheme.getKernelRule().getMatch() != null) { this.itsMatch = BaseFactory.theFactory().createMatch( this, this.itsRuleScheme.getKernelRule().getMatch() .getTarget()); } if (!setPartialMultiMatch(this.itsRuleScheme.getKernelRule() .getMatch())) { this.itsMatch.dispose(); this.itsMatch = null; } } return this.itsMatch; } /** Create partial match based of the specified multi rule. */ private boolean setPartialMultiMatch(final Match kernelMatch) { if (kernelMatch != null) { // set partial match taken from valid kernel match final Iterator<Node> e1 = kernelMatch.getSource().getNodesSet() .iterator(); while (e1.hasNext()) { final GraphObject objLkern = e1.next(); final GraphObject objLmulti = this.embeddingLeft .getImage(objLkern); final GraphObject imgKernMatch = kernelMatch.getImage(objLkern); if (objLmulti != null && imgKernMatch != null) { try { this.itsMatch.addMapping(objLmulti, imgKernMatch); } catch (BadMappingException ex) { return false; } } } final Iterator<Arc> e2 = kernelMatch.getSource().getArcsSet() .iterator(); while (e2.hasNext()) { final GraphObject objLkern = e2.next(); final GraphObject objLmulti = this.embeddingLeft .getImage(objLkern); final GraphObject imgKernMatch = kernelMatch.getImage(objLkern); if (objLmulti != null && imgKernMatch != null) { try { this.itsMatch.addMapping(objLmulti, imgKernMatch); } catch (BadMappingException ex) { return false; } } } this.itsMatch.adaptAttrContextValues(kernelMatch.getAttrContext()); setTempInputParameter(kernelMatch); if (this.itsMatch.getSize() > 0) { this.itsMatch.setPartialMorphismCompletion(true); } } return true; } private void setTempInputParameter(final Match kernelMatch) { // VarTuple ruleVars = (VarTuple) this.getAttrContext().getVariables(); VarTuple kernVars = (VarTuple) kernelMatch.getAttrContext() .getVariables(); VarTuple matchVars = (VarTuple) this.itsMatch.getAttrContext() .getVariables(); for (int i = 0; i < kernVars.getNumberOfEntries(); i++) { VarMember kernVar = kernVars.getVarMemberAt(i); VarMember var = matchVars.getVarMemberAt(kernVar.getName()); if (var != null && kernVar.getDeclaration().getTypeName().equals( var.getDeclaration().getTypeName())) { if (kernVar.isSet()) { var.setExprAsText(kernVar.getExprAsText()); if (!var.isInputParameter()) { var.setInputParameter(true); } } } } } /** * @return true if the left embedding of the LHS of the kernel rule holds, * otherwise false. */ public boolean isLeftEmbeddingValid() { Iterator<?> kernelElems = this.embeddingLeft.getSource().getNodesSet() .iterator(); while (kernelElems.hasNext()) { final GraphObject obj = (GraphObject) kernelElems.next(); if (this.embeddingLeft.getImage(obj) == null) { return false; } final GraphObject img = this.embeddingLeft.getImage(obj); adoptEntriesWhereEmpty(this.embeddingLeft, obj, img); } if (kernelElems.hasNext()) return false; kernelElems = this.embeddingLeft.getSource().getArcsSet().iterator(); while (kernelElems.hasNext()) { final GraphObject obj = (GraphObject) kernelElems.next(); if (this.embeddingLeft.getImage(obj) == null) { return false; } final GraphObject img = this.embeddingLeft.getImage(obj); adoptEntriesWhereEmpty(this.embeddingLeft, obj, img); } if (kernelElems.hasNext()) return false; return true; } /** * @return true if the right embedding of the RHS of the kernel rule holds, * otherwise false. */ public boolean isRightEmbeddingValid() { Iterator<?> kernelElems = this.itsRuleScheme.getKernelRule().getRight() .getNodesSet().iterator(); while (kernelElems.hasNext()) { final GraphObject obj = (GraphObject) kernelElems.next(); if (this.embeddingRight.getImage(obj) == null) { return false; } final GraphObject img = this.embeddingRight.getImage(obj); adoptEntriesWhereEmpty(this.embeddingRight, obj, img); } if (kernelElems.hasNext()) return false; kernelElems = this.itsRuleScheme.getKernelRule().getRight() .getArcsSet().iterator(); while (kernelElems.hasNext()) { final GraphObject obj = (GraphObject) kernelElems.next(); if (this.embeddingRight.getImage(obj) == null) { return false; } final GraphObject img = this.embeddingRight.getImage(obj); adoptEntriesWhereEmpty(this.embeddingRight, obj, img); } if (kernelElems.hasNext()) return false; return true; } /** * * @return true if the rule morphism embedding of the kernel rule holds, * otherwise false. */ public boolean isMorphismEmbeddingValid() { final Enumeration<GraphObject> kernelDom = this.itsRuleScheme .getKernelRule().getDomain(); while (kernelDom.hasMoreElements()) { final GraphObject goKern = kernelDom.nextElement(); final GraphObject imgKern = this.itsRuleScheme.getKernelRule() .getImage(goKern); final GraphObject go = this.embeddingLeft.getImage(goKern); if (go == null) { return false; } else if (imgKern != null && this.embeddingRight.getImage(imgKern) != this .getImage(go)) { return false; } else if (imgKern == null && this.getImage(go) != null) { return false; } } return true; } /** * Set partial rule morphism mapping based on the specified kernel rule. * * @param kernelRule * kernel rule of its rule scheme * @return true if rule mapping set successfully, otherwise false. */ public boolean applyEmbeddedRuleMapping(final Rule kernelRule) { final Enumeration<GraphObject> kernelDom = kernelRule.getDomain(); while (kernelDom.hasMoreElements()) { final GraphObject goKern = kernelDom.nextElement(); final GraphObject imgKern = kernelRule.getImage(goKern); if (imgKern != null && this.getImage(this.embeddingLeft.getImage(goKern)) != this.embeddingRight.getImage(imgKern)) { try { this.addPlainMapping(this.embeddingLeft.getImage(goKern), this.embeddingRight.getImage(imgKern)); } catch (BadMappingException ex) { return false; } } } return true; } private void mapKernel2MultiObject() { final Iterator<Node> nLeft = this.itsOrig.getNodesSet().iterator(); while (nLeft.hasNext()) { GraphObject obj = nLeft.next(); if (this.embeddingLeft.getInverseImage(obj).hasMoreElements()) { this.mapKernel2MultiObject(this.embeddingLeft.getInverseImage( obj).nextElement(), obj); } } final Iterator<Arc> aLeft = this.itsOrig.getArcsSet().iterator(); while (aLeft.hasNext()) { GraphObject obj = aLeft.next(); if (this.embeddingLeft.getInverseImage(obj).hasMoreElements()) { this.mapKernel2MultiObject(this.embeddingLeft.getInverseImage( obj).nextElement(), obj); } } final Iterator<Node> nRight = this.itsImag.getNodesSet().iterator(); while (nRight.hasNext()) { GraphObject obj = nRight.next(); if (this.embeddingRight.getInverseImage(obj).hasMoreElements()) { this.mapKernel2MultiObject(this.embeddingRight.getInverseImage( obj).nextElement(), obj); } } final Iterator<Arc> aRight = this.itsImag.getArcsSet().iterator(); while (aRight.hasNext()) { GraphObject obj = aRight.next(); if (this.embeddingRight.getInverseImage(obj).hasMoreElements()) { this.mapKernel2MultiObject(this.embeddingRight.getInverseImage( obj).nextElement(), obj); } } } /** * Checks left, right and rule morphism embedding of the kernel rule. */ public boolean isReadyToTransform() { if (this.isLeftEmbeddingValid() && this.isRightEmbeddingValid() && this.isMorphismEmbeddingValid() && super.isReadyToTransform()) { return true; } return false; } /** * Set the reference of its rule scheme. * * @param rs * its rule scheme */ public void setRuleScheme(final RuleScheme rs) { this.itsRuleScheme = rs; } /** * @return the reference of its rule scheme */ public RuleScheme getRuleScheme() { return this.itsRuleScheme; } /** * Set the left embedding morphism with the source graph is the left graph * of the kernel rule and the target graph is the left graph of this multi * rule. * * @param left * the left embedding morphism */ public void setEmbeddingLeft(final OrdinaryMorphism left) { this.embeddingLeft = left; } /** * Set the right embedding morphism with the source graph is the right graph * of the kernel rule and the target graph is the right graph of this multi * rule. * * @param right * the right embedding morphism */ public void setEmbeddingRight(final OrdinaryMorphism right) { this.embeddingRight = right; } /** * @return its left embedding morphism with the source graph is the left * graph of the kernel rule and the target graph is the left graph * of this multi rule. */ public OrdinaryMorphism getEmbeddingLeft() { return this.embeddingLeft; } /** * * @return its right embedding morphism with the source graph is the right * graph of the kernel rule and the target graph is the right graph * of this multi rule. */ public OrdinaryMorphism getEmbeddingRight() { return this.embeddingRight; } public void addEmbeddingLeft(final GraphObject kern, final GraphObject obj) { this.embeddingLeft.addMapping(kern, obj); this.kernel2objects.put(kern, obj); this.objects2kernel.put(obj,kern); } public void addEmbeddingRight(final GraphObject kern, final GraphObject obj) { this.embeddingRight.addMapping(kern, obj); this.kernel2objects.put(kern, obj); this.objects2kernel.put(obj,kern); } public void removeEmbeddingLeft(final GraphObject obj) { if (this.kernel2objects.get(obj) != null) { GraphObject obj2 = this.kernel2objects.get(obj); this.embeddingLeft.removeMappingFast(obj, true); this.kernel2objects.remove(obj); this.objects2kernel.remove(obj2); } else if (this.objects2kernel.get(obj) != null) { GraphObject obj2 = this.objects2kernel.get(obj); this.embeddingLeft.removeMappingFast(obj2, true); this.kernel2objects.remove(obj2); this.objects2kernel.remove(obj); } } public void removeEmbeddingRight(final GraphObject obj) { if (this.kernel2objects.get(obj) != null) { GraphObject obj2 = this.kernel2objects.get(obj); this.embeddingRight.removeMappingFast(obj, false); this.kernel2objects.remove(obj); this.objects2kernel.remove(obj2); } else if (this.objects2kernel.get(obj) != null) { GraphObject obj2 = this.objects2kernel.get(obj); this.embeddingRight.removeMappingFast(obj2, false); this.kernel2objects.remove(obj2); this.objects2kernel.remove(obj); } } public List<Node> getOwnNodesLeft() { Vector<Node> list = new Vector<Node>(); Iterator<Node> nodes = this.itsOrig.getNodesSet().iterator(); while (nodes.hasNext()) { Node n = nodes.next(); if (!this.embeddingLeft.getCodomainObjects().contains(n)) { list.add(n); } } return list; } public List<Node> getOwnNodesRight() { Vector<Node> list = new Vector<Node>(); Iterator<Node> nodes = this.itsImag.getNodesSet().iterator(); while (nodes.hasNext()) { Node n = nodes.next(); if (!this.embeddingRight.getCodomainObjects().contains(n)) { list.add(n); } } return list; } public List<Arc> getOwnArcsLeft() { Vector<Arc> list = new Vector<Arc>(); Iterator<Arc> arcs = this.itsOrig.getArcsSet().iterator(); while (arcs.hasNext()) { Arc a = arcs.next(); if (!this.embeddingLeft.getCodomainObjects().contains(a)) { list.add(a); } } return list; } public List<Arc> getOwnArcsRight() { Vector<Arc> list = new Vector<Arc>(); Iterator<Arc> arcs = this.itsImag.getArcsSet().iterator(); while (arcs.hasNext()) { Arc a = arcs.next(); if (!this.embeddingRight.getCodomainObjects().contains(a)) { list.add(a); } } return list; } public void removeOwnMappings() { List<Arc> arcs = getOwnArcsLeft(); for (int i=0; i<arcs.size(); i++) { this.removeMappingFast(arcs.get(i), true); } List<Node> nodes = getOwnNodesLeft(); for (int i=0; i<nodes.size(); i++) { this.removeMappingFast(nodes.get(i), true); } } public void removeOwnNodesLeft() { List<Node> nodes = getOwnNodesLeft(); for (int i=0; i<nodes.size(); i++) { try { this.itsOrig.destroyNode(nodes.get(i), false, true); } catch (TypeException ex) {} } } public void removeOwnNodesRight() { List<Node> nodes = getOwnNodesRight(); for (int i=0; i<nodes.size(); i++) { try { this.itsImag.destroyNode(nodes.get(i), false, true); } catch (TypeException ex) {} } } public void removeOwnArcsLeft() { List<Arc> arcs = getOwnArcsLeft(); for (int i=0; i<arcs.size(); i++) { try { this.itsOrig.destroyArc(arcs.get(i), false, true); } catch (TypeException ex) {} } } public void removeOwnArcsRight() { List<Arc> arcs = getOwnArcsRight(); for (int i=0; i<arcs.size(); i++) { try { this.itsImag.destroyArc(arcs.get(i), false, true); } catch (TypeException ex) {} } } /** * @param obj * an object of the LHS of the kernel rule * @return true if the specified graph object belongs to the LHS of the * kernel rule */ public boolean isSourceOfEmbeddingLeft(final GraphObject obj) { return this.embeddingLeft.getImage(obj) != null; } /** * @param obj * an object of the RHS of the kernel rule * @return true if the specified graph object belongs to the RHS of the * kernel rule */ public boolean isSourceOfEmbeddingRight(final GraphObject obj) { return this.embeddingRight.getImage(obj) != null; } /** * @param obj * an object of the LHS of this multi rule * @return true if the specified graph object belongs to the LHS of this * multi rule and its source object of the left embedding belongs to * the LHS of the kernel rule. */ public boolean isTargetOfEmbeddingLeft(final GraphObject obj) { return this.embeddingLeft.getInverseImage(obj).hasMoreElements(); } /** * @param obj * an object of the RHS of this multi rule * @return true if the specified graph object belongs to the RHS of this * multi rule and its source object of the right embedding belongs * to the RHS of the kernel rule. */ public boolean isTargetOfEmbeddingRight(final GraphObject obj) { return this.embeddingRight.getInverseImage(obj).hasMoreElements(); } /** Set the left graph of the multi rule. */ public final void setLeft(Graph left) { this.clear(); this.itsOrig = left; } /** Set the right graph of the multi rule. */ public final void setRight(Graph right) { this.clear(); this.itsImag = right; } public void mapKernel2MultiObject(final GraphObject kernelObj, final GraphObject obj) { this.kernel2objects.put(kernelObj, obj); this.objects2kernel.put(obj, kernelObj); } /* * (non-Javadoc) * * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ @SuppressWarnings("rawtypes") public void update(Observable o, Object arg) { // System.out.println("MultiRule.update: "+o+" "+arg); GraphObject go = null; Graph graph = null; if (arg instanceof Change) { Change change = (Change) arg; if (change.getItem() instanceof GraphObject) { go = (GraphObject) change.getItem(); } else if (change.getItem() instanceof Pair) { Pair<?, ?> p = (Pair) change.getItem(); if (p.first instanceof GraphObject) go = (GraphObject) p.first; } if (o instanceof Graph) { if (this.itsRuleScheme.getKernelRule().getLeft() == o) graph = this.itsOrig; else if (this.itsRuleScheme.getKernelRule().getRight() == o) graph = this.itsImag; } if (go != null && graph != null) { if (change.getEvent() == Change.OBJECT_MODIFIED) { GraphObject mgo = this.kernel2objects.get(go); if (mgo != null) { mgo.copyAttributes(go); // ((ValueTuple)mgo.getAttribute()).showValue(); } } } } } private void adoptEntriesWhereEmpty(final OrdinaryMorphism morph, final GraphObject from, final GraphObject to) { if (morph.getImage(from) != null && from.getAttribute() != null && to.getAttribute() != null) { final ContextView context = (ContextView) morph.getAttrContext(); Vector<TupleMapping> mappings = context .getMappingsToTarget((ValueTuple) to.getAttribute()); if (mappings != null) { mappings.elementAt(0).adoptEntriesWhereEmpty( (ValueTuple) from.getAttribute(), (ValueTuple) to.getAttribute()); } } } /** * Save the multi rule. * * @param h * AGG XML helper */ public void XwriteObject(XMLHelper h) { super.XwriteObject(h); } /** * Load the multi rule. * * @param h * AGG XML helper */ public void XreadObject(XMLHelper h) { super.XreadObject(h); } }