package agg.xt_basis; import java.util.List; import java.util.Vector; import agg.attribute.AttrInstance; import agg.attribute.AttrEvent; import agg.attribute.impl.AttrTupleManager; import agg.attribute.impl.ValueTuple; import agg.attribute.impl.ValueMember; import agg.attribute.impl.VarTuple; import agg.attribute.impl.VarMember; import agg.attribute.impl.ContextView; import agg.util.XMLHelper; import agg.util.XMLObject; import agg.util.Change; import agg.util.Pair; /** * @version $Id: Arc.java,v 1.40 2010/11/06 18:34:59 olga Exp $ * @author $Author: olga $ */ @SuppressWarnings("serial") public class Arc extends GraphObject implements XMLObject { protected boolean inheritance = false; protected boolean directed = true; protected GraphObject itsSource; protected GraphObject itsTarget; protected String keyStr = null; protected Arc( final Type type, final GraphObject src, final GraphObject tar, final Graph context) { this.itsContext = context; this.itsType = type; this.itsSource = src; this.itsTarget = tar; addToSrcTar(this.itsSource, this.itsTarget); this.itsContextUsage = hashCode(); if (!this.itsType.isAttrTypeEmpty()) { this.itsAttr = AttrTupleManager.getDefaultManager().newInstance( this.itsType.getAttrType(), context.getAttrContext()); } if (this.itsAttr != null) this.itsAttr.addObserver(this); this.keyStr = this.itsSource.getType().convertToKey() .concat(this.itsType.convertToKey()) .concat(this.itsTarget.getType().convertToKey()); } /** * @param attr * An attribute instance of a new arc if it should have attributes. May be <code>null</code>. * @param type * An arc type of a new arc. * @param src * A source node of a new arc. * @param tar * A target node of a new arc. * @param context * A graph in which to consider a new arc with its source and target nodes. */ public Arc( final AttrInstance attr, final Type type, final GraphObject src, final GraphObject tar, final Graph context) { this.itsContext = context; this.itsType = type; this.itsSource = src; this.itsTarget = tar; addToSrcTar(this.itsSource, this.itsTarget); this.itsContextUsage = hashCode(); this.itsAttr = attr; if (this.itsAttr != null) this.itsAttr.addObserver(this); this.keyStr = this.itsSource.getType().convertToKey() .concat(this.itsType.convertToKey()) .concat(this.itsTarget.getType().convertToKey()); } protected Arc( final Arc orig, final GraphObject src, final GraphObject tar, final Graph context) { this(orig.getType(), src, tar, context); if (orig.getAttribute() != null) { if (this.itsAttr == null) this.createAttributeInstance(); ((ValueTuple) this.itsAttr).copyEntries(orig.getAttribute()); } // object name is not jet used in AGG GUI if (!"".equals(orig.getObjectName())) { this.setObjectName(orig.getObjectName()); } } /* * Add <code>this</code> to the outgoing arcs of the <code>src</code> * and to the incoming arcs of the <code>tar</code> . */ protected void addToSrcTar(final GraphObject src, final GraphObject tar) { if ((src != null) && (tar != null)) { ((Node)src).addOut(this); ((Node)tar).addIn(this); } } public void dispose() { // long t = System.nanoTime(); ((Node)this.itsTarget).removeIn(this); ((Node)this.itsSource).removeOut(this); if (this.itsAttr != null) { this.itsAttr.removeObserver(this); ((ValueTuple) this.itsAttr).dispose(); this.itsAttr = null; } this.itsType = null; this.itsContext = null; this.itsContextUsage = -1; this.itsTarget = null; this.itsSource = null; // System.out.println("Arc disposed in: "+(System.nanoTime()-t)+"nano"); } public void finalize() {} /** * If the specified parameter is <code>true</code> set this edge to be an inheritance edge of a type graph. * @param inherit */ protected void setInheritance(boolean inherit) { this.inheritance = inherit; } /** * Returns true if this edge is an inheritance edge of a type graph. */ public boolean isInheritance() { return this.inheritance; } public final boolean isArc() { return true; } public final boolean isNode() { return false; } public boolean isAbstract() { return false; } public final GraphObject getSource() { return this.itsSource; } public final GraphObject getTarget() { return this.itsTarget; } public void setSource(Node n) { ((Node)this.itsSource).removeOut(this); this.itsSource = n; n.addOut(this); this.keyStr = this.itsSource.getType().convertToKey() .concat(this.itsType.convertToKey()) .concat(this.itsTarget.getType().convertToKey()); } public void setTarget(Node n) { ((Node)this.itsTarget).removeIn(this); this.itsTarget = n; n.addIn(this); this.keyStr = this.itsSource.getType().convertToKey() .concat(this.itsType.convertToKey()) .concat(this.itsTarget.getType().convertToKey()); } public Type getSourceType() { return this.itsSource.getType(); } public Type getTargetType() { return this.itsTarget.getType(); } /** * Converts my type to the type key string that can be used for search * operations: * <code> ((Arc) this).getSource().getType().convertToKey() * + ((Arc) this).getType().convertToKey() * + ((Arc) this).getTarget().getType().convertToKey() * </code> */ public String convertToKey() { this.keyStr = this.itsSource.getType().convertToKey() .concat(this.itsType.convertToKey()) .concat(this.itsTarget.getType().convertToKey()); return this.keyStr; } public String resetTypeKey() { this.keyStr = this.itsSource.getType().resetKey() .concat(this.itsType.resetKey()) .concat(this.itsTarget.getType().resetKey()); return this.keyStr; } public List<String> convertToKeyParentExtended() { final List<String> list = new Vector<String>(); Vector<Type> mySrcParents = this.getSource().getType().getAllParents(); Vector<Type> myTarParents = this.getTarget().getType().getAllParents(); for (int i = 0; i < mySrcParents.size(); ++i) { for (int j = 0; j < myTarParents.size(); ++j) { String keystr = mySrcParents.get(i).convertToKey() + this.getType().convertToKey() + myTarParents.get(j).convertToKey(); list.add(keystr); } } return list; } /** * The edge type map key is the string: * getSource().getType().convertToKey()+getType().convertToKey()+getTarget().getType().convertToKey() * and is used to fill the type to objects map of a graph. * * @return String key */ public String getTypeMapKey() { return this.convertToKey(); } public void setDirected(boolean b) { this.directed = b; } public boolean isDirected() { return this.directed; } public boolean isLoop() { return (this.itsSource == this.itsTarget); } public boolean compareTo(GraphObject o) { if (o == null || !o.isArc()) { return false; } Arc a = (Arc) o; // if (!this.getObjectName().equals(a.getObjectName())) { // return false; // } if (!this.itsType.isParentOf(a.getType())) { return false; } if ((this.itsAttr == null && a.getAttribute() == null) || ((this.attrExists() && a.attrExists()) && this.itsAttr.compareTo(a.getAttribute()))) { ; } else { return false; } if (!this.compareSrcTarTo(a)) { return false; } if (!this.compareMultiplicityTo(a)) { return false; } return true; } protected boolean compareSrcTarTo(Arc a) { if (!((Node) getSource()).compareTo(a.getSource()) || !((Node) getTarget()).compareTo(a.getTarget()) ) { return false; } return true; } protected boolean compareMultiplicityTo(Arc a) { if (this.itsContext.isTypeGraph()) { Type srcType = getSource().getType(); Type tarType = getTarget().getType(); Type a_srcType = a.getSource().getType(); Type a_tarType = a.getTarget().getType(); int minmax = this.itsType.getSourceMin(srcType, tarType); int a_minmax = a.getType().getSourceMin(a_srcType, a_tarType); if (minmax != a_minmax) return false; else { minmax = this.itsType.getTargetMin(srcType, tarType); a_minmax = a.getType().getTargetMin(a_srcType, a_tarType); if (minmax != a_minmax) return false; else { minmax = this.itsType.getSourceMax(srcType, tarType); a_minmax = a.getType().getSourceMax(a_srcType, a_tarType); if (minmax != a_minmax) return false; else { minmax = this.itsType.getTargetMax(srcType, tarType); a_minmax = a.getType().getTargetMax(a_srcType, a_tarType); if (minmax != a_minmax) return false; } } } } return true; } public void XwriteObject(XMLHelper h) { h.openNewElem("Edge", this); if (!this.directed) h.addAttr("directed", "false"); if (!this.visible) h.addAttr("visible", "false"); if (!this.getObjectName().equals("")) h.addAttr("name", this.getObjectName()); h.addObject("type", this.itsType, false); h.addObject("source", getSource(), false); h.addObject("target", getTarget(), false); // save multiplicity, if part of type graph if (this.itsContext != null && this.itsContext.isTypeGraph()) { // System.out.println("Arc.Xwrite... is elem of type graph"); Type sourceType = getSource().getType(); Type targetType = getTarget().getType(); int minmax = this.itsType.getSourceMin(sourceType, targetType); if (minmax != Type.UNDEFINED) h.addAttr("sourcemin", Integer.toString(minmax)); minmax = this.itsType.getTargetMin(sourceType, targetType); // System.out.println("targetmin " +minmax); if (minmax != Type.UNDEFINED) h.addAttr("targetmin", Integer.toString(minmax)); minmax = this.itsType.getSourceMax(sourceType, targetType); if (minmax != Type.UNDEFINED) h.addAttr("sourcemax", Integer.toString(minmax)); minmax = this.itsType.getTargetMax(sourceType, targetType); // System.out.println("targetmax " +minmax); if (minmax != Type.UNDEFINED) h.addAttr("targetmax", Integer.toString(minmax)); } h.addObject("", this.itsAttr, true); h.close(); } public void XreadObject(XMLHelper h) { if (h.isTag("Edge", this)) { String str = h.readAttr("directed"); this.directed = str.equals("false")? false: true; str = h.readAttr("visible"); this.visible = str.equals("false")? false: true; str = h.readAttr("name"); this.setObjectName(str); if (this.itsType.getAttrType() != null || this.itsType.hasInheritedAttribute()) this.createAttributeInstance(); AttrInstance attri = this.itsAttr; if (attri != null) { // if(Debug.HASHCODE){ // agg.attribute.AttrType attrType = itsType.getAttrType(); // if(!((agg.attribute.impl.DeclTuple) // attrType).containsName("HASHCODE")) // attrType.addMember(agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),"String", // "HASHCODE" ); // // agg.attribute.impl.ValueMember mem = // ((agg.attribute.impl.ValueTuple) // attri).getValueMemberAt("HASHCODE"); // String hc = String.valueOf(hashCode()); // mem.setExprAsObject(hc); // mem.checkValidity(); // } h.enrichObject(attri); } h.close(); // if this node uses variable // in its attribute so the variable will be marked if (this.itsContext != null && this.itsContext.getAttrContext() != null && this.itsAttr != null) { ValueTuple value = (ValueTuple) this.itsAttr; for (int i = 0; i < value.getSize(); i++) { ValueMember val = value.getValueMemberAt(i); if (val.isSet() && val.getExpr().isVariable()) { ContextView viewContext = (ContextView) ((ValueTuple) val .getHoldingTuple()).getContext(); VarTuple variable = (VarTuple) viewContext .getVariables(); VarMember var = variable.getVarMemberAt(val .getExprAsText()); if (getContext().isNacGraph()) var.setMark(VarMember.NAC); else if (getContext().isPacGraph()) var.setMark(VarMember.PAC); else if (viewContext.doesAllowComplexExpressions()) var.setMark(VarMember.RHS); else var.setMark(VarMember.LHS); // System.out.println(this.itsContext.getName()+" "+var.getName()+" "+var.getMark()); } } } } } public String toString() { String result = ""; String t = this.itsType.getStringRepr(); if (t.equals("")) t = "[unnamed]"; String tSrc = getSource().getType().getStringRepr(); if (tSrc.equals("")) tSrc = "[unnamed]"; String tTrg = getTarget().getType().getStringRepr(); if (tTrg.equals("")) tTrg = "[unnamed]"; result = " (" + "[" + hashCode() + "] " + "Arc: " + tSrc + "---" + t + "--->" + tTrg + ") "; if (this.itsAttr != null) { result = result+this.itsAttr.toString(); } return result; } /** * Implements the AttrObserver. Propagates the change * <code>agg.util.Change.OBJECT_MODIFIED<code> * and object Pair (this, ev.getID()) * to its Graph if the attributes are changed. */ public void attributeChanged(AttrEvent ev) { if (this.itsContext != null) { Pair<Object, AttrEvent> p = new Pair<Object, AttrEvent>(this, ev); this.itsContext.propagateChange(new Change(Change.OBJECT_MODIFIED, p)); } } }