package agg.xt_basis;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import agg.attribute.AttrType;
import agg.attribute.impl.DeclMember;
import agg.attribute.impl.DeclTuple;
import agg.util.XMLHelper;
/**
* Implements the type of a node graph object.
*
* @author $Author: olga $
* @version $Id: NodeTypeImpl.java,v 1.19 2010/11/06 18:34:59 olga Exp $
*/
public class NodeTypeImpl implements Type {
String comment = "";
boolean isAbstract = false;
/**
* the name of the type
*/
String itsStringRepr;
/*
* the parent of the type
*/
// Type itsParent;
/**
* the parents of the type
*/
final Vector<Type> itsParents = new Vector<Type>(1);
final Vector<Type> itsChildren = new Vector<Type>(1);
/**
* the attributes of the type
*/
AttrType itsAttrType;
/**
* an additional String for special informations. It will be saved together
* with {@link #itsStringRepr} as the name and can contain any information
* as string. It is used for example for the layout information of
* {@link agg.editor.EdType}.
*/
String additionalRepr;
String imageFileName = "";
/**
* this value will be true,
* if a graph object inside of a type graph was defined.
*/
boolean typeGraphObjectDefined;
/** holds additional info about a type graph node */
TypeGraphNode typeGraphNode;
String keyStr = null;
protected NodeTypeImpl() {
this.itsAttrType = null;
this.itsStringRepr = "";
this.additionalRepr = ":RECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:";
this.resetKey();
}
/**
* Creates a new type with the given name. There is still not attributed type.
*
* @param name
* the name of the type
*/
protected NodeTypeImpl(String name) {
this.itsAttrType = null;
this.itsStringRepr = name;
this.additionalRepr = ":RECT:java.awt.Color[r=0,g=0,b=0]::[NODE]:";
this.resetKey();
}
/**
* Creates a new type with the given attributes and the given name.
*
* @param at
* the declaration of the attributes
* @param name
* the name of the type
*/
protected NodeTypeImpl(AttrType at, String name) {
this(name);
this.itsAttrType = at;
}
/**
* creates a new type with the given attributes and an empty name.
*
* @param at
* the declaration of the attributes
*/
protected NodeTypeImpl(AttrType at) {
this();
this.itsAttrType = at;
}
public void dispose() {
this.itsAttrType = null;
this.itsChildren.clear();
this.itsParents.clear();
// this.itsParent = null;
if (this.typeGraphNode != null) {
this.typeGraphNode.dispose();
this.typeGraphNode = null;
}
this.typeGraphObjectDefined = false;
}
public void finalize() {
}
public void createAttributeType() {
this.itsAttrType = agg.attribute.impl.AttrTupleManager.getDefaultManager()
.newType();
for (int i = 0; i < this.getParents().size(); i++) {
NodeTypeImpl t = (NodeTypeImpl) this.getParents().get(i);
if (t.getAttrType() == null)
t.createAttributeType();
((DeclTuple) this.itsAttrType).addParent((DeclTuple) t.getAttrType());
}
}
public void setAttributeType(final AttrType at) {
this.itsAttrType = at;
if (this.itsAttrType != null) {
for (int i = 0; i < this.getParents().size(); i++) {
NodeTypeImpl t = (NodeTypeImpl) this.getParents().get(i);
if (t.getAttrType() == null)
t.createAttributeType();
((DeclTuple) this.itsAttrType)
.addParent((DeclTuple) t.getAttrType());
}
}
}
public void removeAttributeType() {
if (this.itsAttrType != null) {
((DeclTuple)this.itsAttrType).dispose();
this.itsAttrType = null;
}
}
/**
* Returns true if its attribute type is <null>, otherwise - false.
* @see agg.xt_basis.Type#isAttrTypeEmpty()
*/
public boolean isAttrTypeEmpty() {
return (this.getAttrType() == null
// || this.getAttrType().getNumberOfEntries() == 0
);
}
/**
* Returns true if all parents of <this> have attribute type <null>, otherwise - false.
* @see agg.xt_basis.Type#isAttrTypeEmpty()
*/
public boolean isParentAttrTypeEmpty() {
List<Type> list = this.getAllParents();
for (int i = 1; i < list.size(); i++) {
NodeTypeImpl t = (NodeTypeImpl) list.get(i);
if (t.getAttrType() != null
// && t.getAttrType().getNumberOfEntries() != 0
) {
return false;
}
}
return true;
}
public boolean hasAnyAttrMember() {
List<Type> list = this.getAllParents();
for (int i = 0; i < list.size(); i++) {
NodeTypeImpl t = (NodeTypeImpl) list.get(i);
if (t.getAttrType() != null
&& t.getAttrType().getNumberOfEntries() != 0
) {
return true;
}
}
return false;
}
public boolean isNodeType() {
return true;
}
public boolean isArcType() {
return false;
}
/**
* Returns result string of <code>this.getStringRepr()+this.getAdditionalRepr()</code>
*
* @see <code>getStringRepr()</code> and <code>getAdditionalRepr()</code>
*/
public String convertToKey() {
if (this.keyStr == null) {
this.keyStr = this.itsStringRepr.concat("%").concat(this.additionalRepr);
// this.keyStr = String.valueOf(this.hashCode());
}
return this.keyStr;
}
public String resetKey() {
this.keyStr = this.itsStringRepr.concat("%").concat(this.additionalRepr);
// this.keyStr = String.valueOf(this.hashCode());
return this.keyStr;
}
/**
* Adds those attribute members of the specified Type type which are not
* found in this type. A conflict can arise when a new member and an
* existing member have equal names but different types. In this case the
* name of the existing attribute member will be extended by "?" and then
* the new attribute member will be added.
*/
public void adaptTypeAttribute(final Type type) {
if (type.getAttrType() == null)
return;
if (this.itsAttrType == null)
this.itsAttrType = agg.attribute.impl.AttrTupleManager
.getDefaultManager().newType();
DeclTuple declTuple = (DeclTuple) this.itsAttrType;
DeclTuple otherTuple = (DeclTuple) type.getAttrType();
for (int i = 0; i < otherTuple.getSize(); i++) {
DeclMember otherMem = (DeclMember) otherTuple.getMemberAt(i);
if (otherMem.getHoldingTuple() != otherTuple)
continue;
String otherName = otherMem.getName();
String otherType = otherMem.getTypeName();
boolean nameFound = false;
boolean conflict = false;
DeclMember mem = null;
for (int j = 0; j < declTuple.getSize(); j++) {
mem = (DeclMember) declTuple.getMemberAt(j);
if (mem.getHoldingTuple() != declTuple)
continue;
if (mem.getName().equals(otherName)) {
nameFound = true;
if (!mem.getTypeName().equals(otherType)) {
conflict = true;
} else
mem = null;
break;
}
mem = null;
}
if (nameFound && conflict && mem != null
&& (mem.getHoldingTuple() == declTuple)) {
mem.setName(mem.getName() + "?");
declTuple.addMember(
agg.attribute.facade.impl.DefaultInformationFacade
.self().getJavaHandler(), otherType, otherName);
} else if (!nameFound) {
declTuple.addMember(
agg.attribute.facade.impl.DefaultInformationFacade
.self().getJavaHandler(), otherType, otherName);
}
}
return;
}
public void checkDoubleAttributeType() {
if (this.itsAttrType == null)
return;
DeclTuple declTuple = (DeclTuple) this.itsAttrType;
for (int i = 0; i < declTuple.getSize(); i++) {
DeclMember memi = (DeclMember) declTuple.getMemberAt(i);
String n = memi.getName();
// String t = memi.getTypeName();
boolean nameFound = false;
boolean conflict = false;
DeclMember memj = null;
for (int j = i + 1; j < declTuple.getSize(); j++) {
memj = (DeclMember) declTuple.getMemberAt(j);
if (memj.getName().equals(n)) {
nameFound = true;
conflict = true;
}
if (nameFound && conflict) {
memj.setName(memj.getName() + "?");
}
nameFound = false;
conflict = false;
}
}
}
/**
* Returns TRUE if this type is equal to the type t.
*/
public boolean compareTo(final Type t) {
if (!getStringRepr().equals(t.getStringRepr())) {
return false;
}
if (!getAdditionalRepr().equals(t.getAdditionalRepr())) {
return false;
}
if (this.itsAttrType != null) {
if (t.getAttrType() == null
|| ((DeclTuple) this.itsAttrType).getSize()
!= ((DeclTuple) t.getAttrType()).getSize()
|| !((DeclTuple) this.itsAttrType).weakcompareTo(t.getAttrType())) {
return false;
}
return true;
}
if (t.getAttrType() != null) {
return false;
}
return true;
}
/**
* Returns TRUE if this type is different to the type t. The Vector
* difference will contain all found differences between the types,
* otherwise it is empty. This method should be used sooner for information
* about differences of types.
*/
public boolean differentTo(final Type t, final Vector<String> difference) {
String diff = "";
if (!getStringRepr().equals(t.getStringRepr())) {
diff = "Type name# " + getStringRepr() + " != " + t.getStringRepr();
difference.add(diff);
}
if (!getAdditionalRepr().equals(t.getAdditionalRepr())) {
diff = "Type graphical repr# " + getAdditionalRepr() + " != "
+ t.getAdditionalRepr();
difference.add(diff);
}
if (this.itsAttrType != null) {
if (t.getAttrType() == null) {
diff = "Attribute Type# " + "defined (is not null)" + " != "
+ "not defined (is null)";
difference.add(diff);
} else if (((DeclTuple) this.itsAttrType).getSize() != ((DeclTuple) t
.getAttrType()).getSize()) {
diff = "Attr member count# "
+ ((DeclTuple) this.itsAttrType).getSize() + " != "
+ ((DeclTuple) t.getAttrType()).getSize();
difference.add(diff);
} else if (!this.itsAttrType.compareTo(t.getAttrType())) {
DeclTuple dt1 = (DeclTuple) this.itsAttrType;
DeclTuple dt2 = (DeclTuple) t.getAttrType();
for (int i = 0; i < dt1.getSize(); i++) {
DeclMember dm1 = (DeclMember) dt1.getMemberAt(i);
DeclMember dm2 = (DeclMember) dt2.getMemberAt(i);
if (!dm1.compareTo(dm2)) {
diff = i + ". " + "Member decl(type:name)# "
+ dm1.getTypeName() + ":" + dm1.getName()
+ " != " + dm2.getTypeName() + ":"
+ dm2.getName();
difference.add(diff);
}
}
}
} else if (t.getAttrType() != null) {
diff = "Attribute Type# " + "not defined (is null)" + " != "
+ "defined (is not null)";
difference.add(diff);
}
if (difference.isEmpty())
return false;
return true;
}
public void setAbstract(final boolean b) {
this.isAbstract = b;
}
public boolean isAbstract() {
return this.isAbstract;
}
/**
* compares the specified type with parents of this object
*
* @return true, if the specified type has the same
* name, attributes and additional string representation
* like a parent of this object
*/
public boolean isChildOf(final Type t) {
Vector<Type> allParents = this.getAllParents();
for (int i = 1; i < allParents.size(); i++) {
if (allParents.get(i).compareTo(t))
return true;
}
return false;
}
/**
* compares the given type and its ancestors with this object
*
* @return true, if this type has the same name, attributes and additional
* representation as the specified type t or one of its ancestors.
*/
public boolean isParentOf(final Type t) {
// multiple inheritance
if (this.compareTo(t))
return true;
for (int i = 0; i < t.getParents().size(); i++) {
Type tAncestor = t.getParents().get(i);
if (this.isParentOf(tAncestor))
return true;
}
return false;
}
/**
* Checks whether there is any relation between this type and the given one or not.
* Two types are related if they have at least one common ancestor.
*/
public boolean isRelatedTo(final Type t) {
// multiple inheritance
if (compareTo(t) || this.isParentOf(t)) {
return true;
}
Vector<Type> allparents = getAllParents();
// allparents.get(0) (this) is already checked above
for (int i = 1; i < allparents.size(); i++) {
Type oldestAncestor = allparents.get(i);
if (oldestAncestor.isParentOf(t)) {
return true;
}
}
return false;
}
public List<Type> getClan() {
return getAllChildren();
}
/**
* Returns true when this node type is in inheritance clan of the defined
* node type t. The type t can be the parent or a child of its clan.
*/
public boolean isInClanOf(final Type t) {
if (t.hasCommonParentWith(this)
|| this.isChildOf(t))
return true;
return false;
}
public boolean hasCommonParentWith(final Type t) {
return !getCommonParentWith(t).isEmpty();
}
public List<Type> getCommonParentWith(final Type t) {
List<Type> list = new Vector<Type> ();
Vector<Type> allparents = getAllParents();
for (int i = 0; i < allparents.size(); i++) {
Type anAncestor = allparents.get(i);
if (anAncestor.isParentOf(t)) {
list.add(anAncestor);
}
}
return list;
}
/**
* returns a list with all the parents of the current type and itself as the
* first element
*
* @return list of all parents
*/
public Vector<Type> getAllParents() {
// multiple inheritance allowed
Vector<Type> myAllParents = new Vector<Type>();
myAllParents.add(this);
for (int i = 0; i < this.itsParents.size(); i++) {
Type currentAncestor = this.itsParents.get(i);
Vector<Type> moreParents = currentAncestor.getAllParents();
for (int j = 0; j < moreParents.size(); j++) {
Type p = moreParents.get(j);
if (!myAllParents.contains(p))
myAllParents.add(p);
}
}
return myAllParents;
}
/**
* returns a list with all the children of the current type and itself as
* the first element
*
* @return list of all children
*/
public Vector<Type> getAllChildren() {
Vector<Type> myAllChildren = new Vector<Type>();
myAllChildren.add(this);
for (int i = 0; i < this.itsChildren.size(); i++) {
Type ch = this.itsChildren.get(i);
Vector<Type> moreChildren = ch.getAllChildren();
for (int j = 0; j < moreChildren.size(); j++) {
Type p = moreChildren.get(j);
if (!myAllChildren.contains(p))
myAllChildren.add(p);
}
}
return myAllChildren;
}
public int getMaxMultiplicityOfAllChildren() {
if (this.typeGraphNode == null)
return -1;
// System.out.println("Parent: "+this.itsStringRepr);
int count = -1;
for (int i = 0; i < this.getChildren().size(); i++) {
Type chi = this.getChildren().get(i);
// System.out.println("Child_i: "+chi.getName());
if (chi.getSourceMax() != Type.UNDEFINED)
count+= chi.getSourceMax();
Vector<Type> moreChildren = chi.getAllChildren();
for (int j = 1; j < moreChildren.size(); j++) {
Type chj = moreChildren.get(j);
// System.out.println("Child_j: "+chj.getName());
if (chj.getSourceMax() != Type.UNDEFINED)
count+= chj.getSourceMax();
}
}
if (count > -1)
count++;
return count;
}
public int getMinMultiplicityOfAllChildren() {
if (this.typeGraphNode == null)
return -1;
int count = -1;
for (int i = 0; i < this.getChildren().size(); i++) {
Type chi = this.getChildren().get(i);
if (chi.getSourceMin() != Type.UNDEFINED)
count+= chi.getSourceMin();
Vector<Type> moreChildren = chi.getAllChildren();
for (int j = 1; j < moreChildren.size(); j++) {
Type chj = moreChildren.get(j);
if (chj.getSourceMin() != Type.UNDEFINED)
count+= chj.getSourceMin();
}
}
if (count > -1)
count++;
return count;
}
public void showRelatives() {
System.out.println("Type Relatives of \"" + this.getName()
+ "\" size: " + this.itsParents.size());
for (int i = 0; i < this.itsParents.size(); i++) {
Type p = this.itsParents.get(i);
System.out.print("\"" + p.getName() + "\", ");
}
System.out.println("\n***************************");
}
public void showAllRelatives() {
Vector<Type> v = getAllParents();
System.out.println("Type Relatives of \"" + getName() + "\" size: "
+ v.size());
for (int i = 0; i < v.size(); i++) {
Type p = v.get(i);
System.out.print("\"" + p.getName() + "\", ");
}
System.out.println("\n***************************");
}
/**
* Returns the string representation. Mostly used as the name of a type.
*/
public final String getStringRepr() {
return this.itsStringRepr;
}
/**
* Sets the string representation. Mostly used as the name of the type
*/
public final void setStringRepr(final String n) {
this.itsStringRepr = n;
this.resetKey();
}
/** Set textual comments for this type. */
public void setTextualComment(final String text) {
this.comment = text;
}
/** Return textual comments of this type. */
public String getTextualComment() {
return this.comment;
}
/**
* Returns my last direct parent.
*/
public Type getParent() {
return this.itsParents.isEmpty()? null: this.itsParents.lastElement();
}
/**
* Returns my all direct parents.
*/
public Vector<Type> getParents() {
return this.itsParents;
}
/**
* Remove my direct parent and set it to a new parent t. Due to this method
* I can have only one direct parent.
*/
public void setParent(final Type t) {
if (t == null && !this.itsParents.isEmpty()) {
removeParent(this.itsParents.lastElement());
return;
}
addParent(t);
}
/**
* Adds a new parent to my parent list.
*/
public void addParent(final Type t) {
if (t != null && !this.itsParents.contains(t)) {
if (t.getAttrType() != null && this.itsAttrType == null) {
this.createAttributeType();
} else if (t.getAttrType() == null && this.itsAttrType != null) {
((NodeTypeImpl) t).createAttributeType();
}
if (this.itsAttrType != null) {
DeclTuple myDeclTuple = (DeclTuple) this.itsAttrType;
myDeclTuple.addParent((DeclTuple) t.getAttrType());
}
this.itsParents.add(t);
// this.itsParent = t;
((NodeTypeImpl) t).addChild(this);
// showRelatives();
}
}
public void addChild(final Type t) {
if (!this.itsChildren.contains(t))
this.itsChildren.add(t);
}
/**
* Returns its direct children only.
*/
public Vector<Type> getChildren() {
return this.itsChildren;
}
public Vector<String> checkDoubleAttributeName(final Type otherType) {
Vector<String> v = new Vector<String>(5, 5);
if (this.itsAttrType == null || otherType.getAttrType() == null)
return v;
DeclTuple myDecl = (DeclTuple) this.itsAttrType;
DeclTuple otherDecl = (DeclTuple) otherType.getAttrType();
for (int i = 0; i < otherDecl.getNumberOfEntries(); i++) {
DeclMember mem = (DeclMember) otherDecl.getMemberAt(i);
if (myDecl.isLegalName(mem.getName()) > 0) {
if (mem.getHoldingTuple() != myDecl.getMemberAt(mem.getName()).getHoldingTuple()) {
v.add(otherDecl.getNameAsString(i));
}
}
}
return v;
}
/**
* Removes this parent from my parent list.
*/
public void removeParent(final Type t) {
if (t != null && this.itsParents.contains(t)) {
this.itsParents.remove(t);
((NodeTypeImpl) t).removeChild(this);
// showRelatives();
if (this.itsAttrType != null) {
DeclTuple myDeclTuple = (DeclTuple) this.itsAttrType;
myDeclTuple.removeParent((DeclTuple) t.getAttrType());
}
}
// if (!itsParents.isEmpty())
// itsParent = itsParents.lastElement();
// else
// itsParent = null;
}
public void removeChild(final Type t) {
this.itsChildren.remove(t);
}
public boolean hasInheritedAttribute() {
for (int i = 0; i < this.getParents().size(); i++) {
Type pi = this.getParents().get(i);
if (pi.getAttrType() != null)
return true;
Vector<Type> moreParents = pi.getAllParents();
for (int j = 0; j < moreParents.size(); j++) {
Type pj = moreParents.get(j);
if (pj.getAttrType() != null)
return true;
}
}
return false;
}
/**
* Returns the associated attribute type.
*/
public final AttrType getAttrType() {
return this.itsAttrType;
}
/**
* Returns the additional representation string
*
* @see #setAdditionalRepr
*/
public String getAdditionalRepr() {
return this.additionalRepr;
}
public String getImageFilename() {
return this.imageFileName;
}
public void setImageFilename(String imageFilename) {
this.imageFileName = imageFilename;
}
/**
* Set its additional graphical representation,
* which is always saved together with its name.
* Predefined minimal additional representation string
* of a Node - ":RECT:java.awt.Color[r=0,g=0,b=0]:[NODE]:".
*/
public void setAdditionalRepr(final String repr) {
if (repr.equals("NODE") || repr.equals("[NODE]"))
this.additionalRepr = ":RECT:java.awt.Color[r=0,g=0,b=0]:[NODE]:";
else
this.additionalRepr = repr;
this.resetKey();
}
public void XwriteObject(XMLHelper h) {
String n = getStringRepr();
// System.out.println("TypeImpl.XwriteObject: AdditionalRepr: " +this.additionalRepr);
if ((this.additionalRepr != null) && (!this.additionalRepr.equals(""))) {
n += ("%" + this.additionalRepr);
}
int idx = n.indexOf("[NODE]");
if (idx >= 0) {
// all parents write first
h.addEnumeration("", this.itsParents.elements(), true);
if (this.imageFileName.length() > 0) {
// insert the image filename into string n to save the additional type representation
n = n.substring(0, idx).concat(this.imageFileName).concat(":").concat("[NODE]:");
}
h.openNewElem("NodeType", this);
} else {
h.openNewElem("Type", this);
}
h.addAttr("name", n);
if (!this.comment.equals("")) {
h.addAttr("comment", this.comment);
}
h.addAttr("abstract", String.valueOf(this.isAbstract));
// multiple inheritance -olga
if (n.indexOf("[NODE]") >= 0) {
for (int i = 0; i < this.itsParents.size(); i++) {
h.openSubTag("Parent");
h.addObject("pID", this.itsParents.get(i), false);
h.close();
}
}
if (this.itsAttrType != null && this.itsAttrType.getNumberOfEntries() > 0) {
h.addObject("", this.itsAttrType, true);
}
// multiplicity will be written in the Arc / Node
// object in the type graph
h.close();
}
public void XreadObject(XMLHelper h) {
if (h.isTag("NodeType", this)
|| h.isTag("Type", this)) {
String n = h.readAttr("name");
// n = XMLHelper.checkNameDueToSpecialCharacters(n);
// System.out.println("TypeImpl.XreadObject: " +n);
String str = h.readAttr("comment");
if (!str.equals(""))
this.comment = str.toString();
this.isAbstract = false;
String abs = h.readAttr("abstract");
if (!"".equals(abs)) {
this.isAbstract = Boolean.valueOf(abs).booleanValue();
}
// System.out.println("TypeImpl.XreadObject: isAbstract: " +isAbstract);
int i = n.indexOf('%');
// set type name
if (i != -1) {
String test = n.substring(0, i);
test = XMLHelper.checkNameDueToSpecialCharacters(test);
this.itsStringRepr = test;
}
else {
String test = XMLHelper.checkNameDueToSpecialCharacters(n);
this.itsStringRepr = test;
}
AttrType tmpAttr = agg.attribute.impl.AttrTupleManager
.getDefaultManager().newType();
h.enrichObject(tmpAttr);
if (tmpAttr.getNumberOfEntries() != 0)
this.itsAttrType = tmpAttr;
else
this.itsAttrType = null;
if (i != -1) {
String a = n.substring(i + 1);
a = a.replaceAll("::", ":");
if (n.indexOf("[NODE]") != -1) {
// multiple inheritance - olga
Type p = (Type) h.getObjectRef("parent", null);
if (p != null) {
addParent(p);
int pi = 1;
while (true) {
p = (Type) h.getObjectRef("parent" + pi, null);
if (p != null) {
addParent(p);
pi++;
} else
break;
}
} else {
while (h.readSubTag("Parent")) {
Type pi = (Type) h.getObjectRef("pID", null);
if (pi != null) {
addParent(pi);
}
h.close();
}
}
a = extractImageFileName(a);
}
n = n.substring(0, i);
setAdditionalRepr(a);
}
// NOTE:: multiplicity will be read in the TypeGraph
// add parents of attributes
if (this.itsAttrType != null && this.itsAttrType.getNumberOfEntries() != 0) {
DeclTuple myDeclTuple = (DeclTuple) this.itsAttrType;
for (int p = 0; p < this.itsParents.size(); p++) {
Type t = this.itsParents.get(p);
myDeclTuple.addParent((DeclTuple) t.getAttrType());
}
}
h.close();
}
}
/*
* If an image file name (.jpg|.gif|.xpm) found, set local parameter this.imageFileName
* and returns a string without the image file name.
* Otherwise returns the same input string.
*/
private String extractImageFileName(String str) {
String[] test = str.split(":");
int indx = -1;
for (int i=0; i<test.length; i++) {
String s = test[i];
if (s.indexOf(".jpg") >= 0
|| s.indexOf(".gif")>= 0
|| s.indexOf(".xpm")>= 0) {
this.imageFileName = s;
indx = i;
break;
}
}
String out = ":";
if (indx != -1) {
for (int i=0; i<test.length; i++) {
if (i != indx && !"".equals(test[i])) {
String s = test[i];
out = out.concat(s);
out = out.concat(":");
}
}
} else {
out = str;
}
return out;
}
/**
* Returns the name of a type or "unnamed" if the name is empty string.
*/
public String getName() {
String stringRepr = this.getStringRepr();
if ("".equals(stringRepr)) {
return "unnamed";
}
return stringRepr;
}
/**
* returns if the given GraphObject is valid typed as defined in the type
* graph. Before this can be checked, all edges and nodes of the type graph
* must be added to theire types. The given object will not tested if this
* is its type.
*
* @return null, if the graphobject is valid typed otherwise a
* {@link TypeError} if there was a mismatch
*
*/
public TypeError check(final GraphObject node, final int level) {
if (level == TypeSet.DISABLED)
return null;
if (node instanceof Node) {
return check((Node) node, level);
}
throw new IllegalArgumentException(
"parameter must be of Node type.");
}
/**
* returns if the given Node is valid typed as defined in the type graph.
* Before this can be checked, all edges and nodes of the type graph must be
* added to their types.
*
* @return null, if the given Node is valid typed otherwise a
* {@link TypeError} if there was a mismatch
*/
public TypeError check(final Node node, final int level) {
if (this.typeGraphNode != null) {
if (level >= TypeSet.ENABLED) {
List<Node> list = node.getContext().getNodes(node.getType());
int count = list != null? list.size(): 0;
//???
if(!node.getContext().isNode(node)) {
count++; // a node is created and should be added to nodes of a graph
}
// if the level is set, check for max / min constraints
if (level == TypeSet.ENABLED_MAX
|| level == TypeSet.ENABLED_MAX_MIN) {
int sourceMax = this.typeGraphNode.getSourceMax();
if (sourceMax != UNDEFINED) {
if ((count > sourceMax)) {
return new TypeError(TypeError.TO_MUCH_NODES,
"- Too many ("+count+") nodes of type \""
+ getName()
+ "\".\nThere are only "
+ sourceMax + " allowed ( graph \""
+ node.getContext().getName()
+ "\" ).", node, this);
}
}
}
// check Min
if (level == TypeSet.ENABLED_MAX_MIN) {
int sourceMin = this.typeGraphNode.getSourceMin();
if (sourceMin > 0) {
if (count < sourceMin) {
return new TypeError(TypeError.TO_LESS_NODES,
"- Not enough ("+count+") nodes of type \""
+ getName()
+ "\".\nThere are at least "
+ sourceMin + " needed ( graph \""
+ node.getContext().getName()
+ "\" ).", node, this);
}
}
} // if ENABLED_MAX_MIN
return null;
}
return null;
} else if (level > TypeSet.ENABLED_INHERITANCE) {
return new TypeError(TypeError.NO_SUCH_TYPE,
"The type graph does not contain a node type with name \""
+ getName() + "\".", node, this);
} else {
return null;
}
}
/**
* Add the given GraphObject of a type graph to this type.
* The GraphObject nodeOrArc must be of this type:
* it is a Node if this is a node type,
* it is an Arc if this is an edge type.
* In case of it is a node type and a node object inside of a type graph
* is already exist, it should to be removed first.
*/
public boolean addTypeGraphObject(final GraphObject node) {
if (!node.getContext().isTypeGraph()) {
return false;
}
if (node instanceof Node) {
if (this.typeGraphNode == null)
this.typeGraphNode = new TypeGraphNode();
// set type graph object of node type
this.typeGraphNode.addTypeGraphObject((Node) node);
this.typeGraphObjectDefined = true;
return true;
}
return false;
}
/**
* Remove the given GraphObject from the type graph and from this type.
* Returns true if remove is done, otherwise false. To remove an GraphObject
* is not possible when the type graph check is activated.
*/
public boolean removeTypeGraphObject(final GraphObject node,
final boolean forceToRemove) {
if (node == null
|| !node.isNode()
|| node.getContext() == null
|| !node.getContext().isTypeGraph())
return true;
boolean allowedToRemove = false;
if (node.getContext().getTypeSet().getLevelOfTypeGraphCheck()
<= TypeSet.ENABLED_INHERITANCE
|| forceToRemove) {
allowedToRemove = true;
}
else {
allowedToRemove = false;
}
if (allowedToRemove) {
if (this.typeGraphNode == null) {
return true;
}
if (forceToRemove) {
this.typeGraphNode.forceRemoveTypeGraphObject();
} else if (!this.typeGraphNode.removeTypeGraphObject()) {
return false;
}
this.typeGraphObjectDefined = false;
return true;
}
return false;
}
/**
* Remove the given GraphObject from the type graph and from this type.
* Returns true if remove is done, otherwise false. To remove an GraphObject
* is not possible when the type graph check is activated.
*/
public boolean removeTypeGraphObject(final GraphObject node) {
return removeTypeGraphObject(node, false);
}
/**
* Disable type graph object of this type.
*/
public void disableTypeGraphObject() {
if (this.typeGraphNode != null) {
this.typeGraphNode.forceRemoveTypeGraphObject();
this.typeGraphObjectDefined = false;
}
}
/**
* Set the min of the multiplicity of a node type.
*/
public void setSourceMin(final int value) {
if (this.typeGraphNode != null)
this.typeGraphNode.setSourceMin(value);
}
/**
* Set the max of the multiplicity of a node type to the value. The node
* type is defined through the sourceType .
*/
public void setSourceMax(final int value) {
if (this.typeGraphNode != null)
this.typeGraphNode.setSourceMax(value);
}
/**
* Return the min of the multiplicity of a node type. The node type is
* defined through the sourceType.
*/
public int getSourceMin() {
if (this.typeGraphNode != null)
return this.typeGraphNode.getSourceMin();
return -1;
}
/**
* Return the max of the multiplicity of a node type.
*/
public int getSourceMax() {
if (this.typeGraphNode != null)
return this.typeGraphNode.getSourceMax();
return -1;
}
public void setVisibilityOfObjectsOfTypeGraphNode(boolean vis) {
if (this.typeGraphNode != null) {
this.typeGraphNode.setVisible(vis);
}
}
public boolean isObjectOfTypeGraphNodeVisible() {
return (this.typeGraphNode == null) || this.typeGraphNode.isVisible();
}
/**
* Returns the type graph node for this node type.
*/
public TypeGraphNode getTypeGraphNode() {
if (this.typeGraphNode == null)
this.typeGraphNode = new TypeGraphNode();
return this.typeGraphNode;
}
/**
* returns true,
* if there is an object in the type graph for this type.
*/
public boolean hasTypeGraphNode() {
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null)
return true;
return false;
}
/**
* returns the type graph node, if it is defined.
*/
public Node getTypeGraphNodeObject() {
return (this.typeGraphNode == null)? null: this.typeGraphNode.getNode();
}
/**
* Returns my own outgoing arc types on condition that a type graph is
* defined, otherwise returns an empty vector.
*/
public Vector<Type> getOwnOutgoingArcTypes() {
Vector<Type> result = new Vector<Type>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null){
final Iterator<Arc> outs = this.typeGraphNode.getNode().getOutgoingArcs();
while ( outs.hasNext()) {
result.add(outs.next().getType());
}
}
return result;
}
/**
* Returns all outgoing arc types (of my own and of my parents) on condition
* that a type graph is defined, otherwise returns an empty vector.
*/
public Vector<Type> getOutgoingArcTypes() {
Vector<Type> result = new Vector<Type>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
result.addAll(this.getOwnOutgoingArcTypes());
Vector<Type> myparents = this.getAllParents();
for (int i = 0; i < myparents.size(); i++) {
result.addAll(((NodeTypeImpl) myparents.get(i))
.getOwnOutgoingArcTypes());
}
}
return result;
}
/**
* Returns my own outgoing arcs on condition that a type graph is defined,
* otherwise returns an empty vector.
*/
public List<Arc> getOwnOutgoingArcs() {
Vector<Arc> result = new Vector<Arc>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
result.addAll(this.typeGraphNode.getNode().getOutgoingArcsSet());
}
return result;
}
/**
* Returns all outgoing arcs (of my own and of my parents) on condition that
* a type graph is defined, otherwise returns an empty vector.
*/
public Vector<Arc> getOutgoingArcs() {
Vector<Arc> result = new Vector<Arc>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
result.addAll(this.typeGraphNode.getNode().getOutgoingArcsSet());
Vector<Type> myparents = this.getAllParents();
for (int i = 0; i < myparents.size(); i++) {
result.addAll(((NodeTypeImpl) myparents.get(i))
.getOwnOutgoingArcs());
}
}
return result;
}
/**
* Returns my own incoming arc types on condition that a type graph is
* defined, otherwise returns an empty vector.
*/
public Vector<Type> getOwnIncomingArcTypes() {
final Vector<Type> result = new Vector<Type>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
final Iterator<Arc> arcs = this.typeGraphNode.getNode().getIncomingArcs();
while (arcs.hasNext()) {
result.add(arcs.next().getType());
}
}
return result;
}
/**
* Returns all incoming arc types (of my own and of my parents) on condition
* that a type graph is defined, otherwise returns an empty vector.
*/
public Vector<Type> getIncomingArcTypes() {
Vector<Type> result = new Vector<Type>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
result.addAll(this.getOwnIncomingArcTypes());
Vector<Type> myparents = this.getAllParents();
for (int i = 0; i < myparents.size(); i++) {
result.addAll(((NodeTypeImpl) myparents.get(i))
.getOwnIncomingArcTypes());
}
}
return result;
}
/**
* Returns my own incoming arcs on condition that a type graph is defined,
* otherwise returns an empty vector.
*/
public List<Arc> getOwnIncomingArcs() {
Vector<Arc> result = new Vector<Arc>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null)
result.addAll(this.typeGraphNode.getNode().getIncomingArcsSet());
return result;
}
/**
* Returns all incoming arcs (of my own and of my parents) on condition that
* a type graph is defined, otherwise returns an empty vector.
*/
public Vector<Arc> getIncomingArcs() {
Vector<Arc> result = new Vector<Arc>();
if (this.typeGraphNode != null
&& this.typeGraphNode.getNode() != null) {
result.addAll(this.typeGraphNode.getNode().getIncomingArcsSet());
Vector<Type> myparents = this.getAllParents();
for (int i = 0; i < myparents.size(); i++) {
result.addAll(((NodeTypeImpl) myparents.get(i))
.getOwnIncomingArcs());
}
}
return result;
}
/**
* returns true, if there is at least one object in the type graph for this
* type.
*/
public boolean isTypeGraphObjectDefined() {
return this.typeGraphObjectDefined;
}
/**
* The specified node must be an instance of my.
*/
public TypeError checkIfRemovable(final Node node, final int level) {
if (node.getType() != this
|| level != TypeSet.ENABLED_MAX_MIN
|| node.getContext() instanceof TypeGraph)
return null;
return checkMinMultiplicityOfNodeType(node);
}
/**
* The specified node must be an instance of my.
*/
private TypeError checkMinMultiplicityOfNodeType(final Node node) {
if (this.typeGraphNode == null) {
return null;
}
int minValue = this.typeGraphNode.getSourceMin();
if (minValue != UNDEFINED) {
List<Node> list = node.getContext().getNodes(this);
int count = list != null? list.size(): 0;
if (count - 1 < minValue) {
return new TypeError(TypeError.TO_LESS_NODES,
"Not enough nodes of type \"" + getName()
+ "\"" + " .\nThere are at least " + minValue
+ " needed ( graph \""
+ node.getContext().getName() + "\" ).", node,
this);
}
}
return null;
}
/**
* The specified Graph is not a type graph.
* Check the max multiplicity of this type because a new node should be created.
* Returns an error if this check failed, otherwise - null.
*/
public TypeError checkIfNodeCreatable(final Graph g, final int level) {
if (level != TypeSet.ENABLED_MAX_MIN
|| g instanceof TypeGraph)
return null;
return checkMaxMultiplicityOfNodeType(g);
}
/**
* The specified Graph is not a type graph.
* Check the max multiplicity of this type because a new node should be created.
* Returns an error if this check failed, otherwise - null.
*/
private TypeError checkMaxMultiplicityOfNodeType(final Graph g) {
if (this.typeGraphNode == null) {
return null;
}
int maxValue = this.typeGraphNode.getSourceMax();
if (maxValue != UNDEFINED) {
List<Node> list = g.getNodes(this);
int count = list != null? list.size(): 0;
if (count + 1 > maxValue) {
return new TypeError(TypeError.TO_MUCH_NODES,
"Too many nodes of type \"" + getName()
+ "\"" + " .\nThere are at most " + maxValue
+ " allowed ( graph \""
+ g.getName() + "\" ).",
this);
}
}
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfRemovableFromSource(agg.xt_basis.GraphObject, agg.xt_basis.Arc, int)
*/
public TypeError checkIfRemovableFromSource(
final GraphObject node, Arc arc,
int level) {
if (arc.getContext().isCompleteGraph()
&& level == TypeSet.ENABLED_MAX_MIN)
return checkSourceMin(node, arc, false, false);
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfRemovableFromSource(agg.xt_basis.GraphObject, agg.xt_basis.Arc, boolean, boolean, int)
*/
public TypeError checkIfRemovableFromSource(final GraphObject node, final Arc arc,
boolean deleteSrc, boolean deleteTar, int level) {
if (arc.getContext().isCompleteGraph()
&& level == TypeSet.ENABLED_MAX_MIN)
return checkSourceMin(node, arc, deleteSrc, deleteTar);
return null;
}
/*
* Source Max Multiplicity means how many ( at least ) nodes of the source node type
* are incoming into the target node.
*/
private TypeError checkSourceMin(final GraphObject srcnode, final Arc arc,
boolean deleteSrc, boolean deleteTar) {
// System.out.println("NodeTypeImpl.checkSourceMin(final GraphObject srcnode, final Arc arc)");
int sourceMin = arc.getType().getSourceMin(this, arc.getTarget().getType());
if (sourceMin != UNDEFINED) {
int count = ((Node)arc.getTarget()).getNumberOfIncomingArcs(arc.getType(), srcnode.getType());
if (count - 1 < sourceMin
&& !deleteTar) {
return new TypeError(TypeError.TO_LESS_ARCS,
"Too few edges of type \"" + arc.getType().getName()
+ "\"" + " (would) start at the source node " + "\""
+ arc.getSource().getType().getName()
+ "\"." + "\nThere are at least " + sourceMin
+ " needed ( graph \""
+ srcnode.getContext().getName() + "\" ).",
arc,
this);
}
}
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfRemovableFromTarget(agg.xt_basis.GraphObject, agg.xt_basis.Arc, int)
*/
public TypeError checkIfRemovableFromTarget(
final GraphObject node,
final Arc arc,
int level) {
if (arc.getContext().isCompleteGraph()
&& level == TypeSet.ENABLED_MAX_MIN)
return checkTargetMin(node, arc, false, false);
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfRemovableFromTarget(agg.xt_basis.GraphObject, agg.xt_basis.Arc, boolean, boolean, int)
*/
public TypeError checkIfRemovableFromTarget(
final GraphObject node,
final Arc arc,
boolean deleteSrc,
boolean deleteTar,
int level) {
if (arc.getContext().isCompleteGraph()
&& level == TypeSet.ENABLED_MAX_MIN)
return checkTargetMin(node, arc, deleteSrc, deleteTar);
return null;
}
/*
* Target Min Multiplicity means how many (at least ) nodes of the target node type
* are outgoing from the source node.
*/
private TypeError checkTargetMin(final GraphObject tarnode, final Arc arc,
boolean deleteSrc, boolean deleteTar) {
// System.out.println("NodeTypeImpl.checkTargetMin(final GraphObject tarnode, final Arc arc)");
int targetMin = arc.getType().getTargetMin(arc.getSource().getType(), this);
if (targetMin != UNDEFINED) {
int count = ((Node)arc.getSource()).getNumberOfOutgoingArcs(arc.getType(), tarnode.getType());
if (count - 1 < targetMin
&& !deleteSrc) {
return new TypeError(TypeError.TO_LESS_ARCS,
"Too few edges of type \"" + arc.getType().getName()
+ "\"" + " (would) end at the target node " + "\""
+ arc.getTarget().getType().getName()
+ "\"." + "\nThere are at least " + targetMin
+ " needed ( graph \""
+ tarnode.getContext().getName() + "\" ).",
arc,
this);
}
}
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getSourceMax(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public int getSourceMax(Type sourceType, Type targetType) {
return 0;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getSourceMin(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public int getSourceMin(Type sourceType, Type targetType) {
return 0;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getTargetMax(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public int getTargetMax(Type sourceType, Type targetType) {
return 0;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getTargetMin(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public int getTargetMin(Type sourceType, Type targetType) {
return 0;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getTypeGraphArcObject(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public Arc getTypeGraphArcObject(Type sourceType, Type targetType) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasTypeGraphArc()
*/
public boolean hasTypeGraphArc() {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#isObjectOfTypeGraphArcVisible(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public boolean isObjectOfTypeGraphArcVisible(Type sourceType,
Type targetType) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#setSourceMax(agg.xt_basis.Type, agg.xt_basis.Type, int)
*/
public void setSourceMax(Type sourceType, Type targetType, int value) {
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#setSourceMin(agg.xt_basis.Type, agg.xt_basis.Type, int)
*/
public void setSourceMin(Type sourceType, Type targetType, int value) {
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#setTargetMax(agg.xt_basis.Type, agg.xt_basis.Type, int)
*/
public void setTargetMax(Type sourceType, Type targetType, int value) {
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#setTargetMin(agg.xt_basis.Type, agg.xt_basis.Type, int)
*/
public void setTargetMin(Type sourceType, Type targetType, int value) {
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#setVisibityOfObjectsOfTypeGraphArc(agg.xt_basis.Type, agg.xt_basis.Type, boolean)
*/
public void setVisibityOfObjectsOfTypeGraphArc(Type sourceType,
Type targetType, boolean vis) {
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasTypeGraphArc(agg.xt_basis.GraphObject, agg.xt_basis.GraphObject)
*/
public boolean hasTypeGraphArc(GraphObject sourceType,
GraphObject targetType) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasTypeGraphArc(agg.xt_basis.Type)
*/
public boolean hasTypeGraphArc(Type sourceType) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasTypeGraphArc(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public boolean hasTypeGraphArc(Type sourceType, Type targetType) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#isEdgeCreatable(agg.xt_basis.Type, agg.xt_basis.Type, int)
*/
public boolean isEdgeCreatable(Type sourceType, Type targetType, int level) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getTargetsOfArc(agg.xt_basis.Type)
*/
public Vector<Type> getTargetsOfArc(Type sourceType) {
return new Vector<Type>(0);
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#isTypeGraphArcUsed(agg.xt_basis.Arc)
*/
public boolean isTypeGraphArcUsed(Arc arc) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getArcTypeGraphObjects()
*/
public HashMap<Type, HashMap<Type, TypeGraphArc>> getArcTypeGraphObjects() {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getSimilarTypeGraphArc(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public TypeGraphArc getSimilarTypeGraphArc(Type sourceType, Type targetType) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#getTypeGraphArc(agg.xt_basis.Type, agg.xt_basis.Type)
*/
public TypeGraphArc getTypeGraphArc(Type sourceType, Type targetType) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfEdgeCreatable(agg.xt_basis.Node, agg.xt_basis.Node, int)
*/
public TypeError checkIfEdgeCreatable(Node src, Node tar, int level) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkIfEdgeCreatable(agg.xt_basis.Graph, agg.xt_basis.Node, agg.xt_basis.Node, int)
*/
public TypeError checkIfEdgeCreatable(Graph g, Node src, Node tar, int level) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkSourceMax(agg.xt_basis.Graph, agg.xt_basis.Node, agg.xt_basis.Node)
*/
public TypeError checkSourceMax(Graph g, Node src, Node tar) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#checkTargetMax(agg.xt_basis.Graph, agg.xt_basis.Node, agg.xt_basis.Node)
*/
public TypeError checkTargetMax(Graph g, Node src, Node tar) {
return null;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#compareTypeGraphArcs(agg.xt_basis.Type)
*/
public boolean compareTypeGraphArcs(Type t) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#compareTypeGraphArcsMultiplicity(agg.xt_basis.Type)
*/
public boolean compareTypeGraphArcsMultiplicity(Type t) {
return false;
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasChild()
*/
public boolean hasChild() {
return !this.itsChildren.isEmpty();
}
/* (non-Javadoc)
* @see agg.xt_basis.Type#hasParent()
*/
public boolean hasParent() {
return !this.itsParents.isEmpty();
}
}