Source code: org/bdgp/apps/dagedit/datamodel/Term.java
1 package org.bdgp.apps.dagedit.datamodel;
2
3 import javax.swing.undo.StateEditable;
4 import java.util.*;
5 import javax.swing.tree.TreePath;
6 import org.bdgp.util.*;
7 import java.io.Serializable;
8
9 public class Term implements StateEditable, Cloneable,
10 org.bdgp.util.Comparable, Serializable {
11
12 private static int autoID = 0;
13
14 protected String term = "";
15 protected String definition = "";
16 protected String comment = "";
17 protected String id = "";
18 protected String idPrefix = "";
19 protected boolean root = false;
20
21 protected Vector children;
22 protected Vector parents;
23 protected Vector danglingParents;
24
25 protected Vector synonyms;
26 protected Vector references;
27 protected Vector defReferences;
28 protected Vector categories;
29
30 protected int depth;
31
32 protected int productCount;
33
34 private int intid;
35 private static int idgen = 0;
36 private boolean debug = false;
37
38 public Term(String term) {
39 this(term, null, false);
40 }
41
42 public Term(String term, String id) {
43 this(term, id, false);
44 }
45
46 public Term(String term, String id, boolean isRoot) {
47 children = new Vector ();
48 parents = new Vector ();
49 danglingParents = new Vector();
50 synonyms = new Vector ();
51 references = new Vector ();
52 defReferences = new Vector ();
53 categories = new Vector();
54 this.term = term;
55 intid = idgen++;
56 setID(id);
57 this.root = isRoot;
58 }
59
60 public void addCategory(TermCategory category) {
61 if (category == null)
62 throw new RuntimeException();
63 categories.addElement(category);
64 }
65
66 public void removeCategory(TermCategory category) {
67 categories.removeElement(category);
68 }
69
70 public boolean belongsToCategory(TermCategory category) {
71 return categories.contains(category);
72 }
73
74 public Vector getCategories() {
75 return categories;
76 }
77
78 public void setCategories(Vector categories) {
79 for(int i=0; i < categories.size(); i++) {
80 if (categories.elementAt(i) == null)
81 throw new RuntimeException();
82 }
83
84 this.categories = categories;
85 }
86
87 public void setRoot(boolean root) {
88 this.root = root;
89 }
90
91 public boolean isRoot() {
92 return root;
93 }
94
95 public String getComment() {
96 return comment;
97 }
98
99 public void setComment(String comment) {
100 this.comment = comment;
101 }
102
103 public static String formatID(String prefix, int id, int length) {
104 String idStr = id+"";
105 int digitCount = length - idStr.length();
106 if (digitCount < 0)
107 digitCount = 0;
108 idStr = prefix+":"+StringUtil.repeat('0', digitCount)+
109 idStr;
110 return idStr;
111 }
112
113 public static String formatID(String prefix, String idStr, int length) {
114 if (idStr.startsWith(prefix+":"))
115 idStr = idStr.substring(prefix.length()+1,idStr.length());
116 try {
117 return formatID(prefix, Integer.parseInt(idStr), length);
118 } catch (NumberFormatException e) {
119 return null;
120 }
121 }
122
123 public boolean isObsolete() {
124 return !root && (parents.size() == 0);
125 }
126
127 public boolean isNonTriviallyObsolete() {
128 return isNonTriviallyObsolete(new Hashtable());
129 }
130
131 private boolean isNonTriviallyObsolete(Hashtable lookedAt) {
132 if (lookedAt.containsKey(this))
133 return false;
134 lookedAt.put(this, this);
135
136 if (isObsolete())
137 return true;
138
139 if (parents.size() == 0) {
140 return false;
141 }
142 for(int i=0; i < parents.size(); i++) {
143 TermRelationship tr = (TermRelationship) parents.elementAt(i);
144 Term parent = tr.getParent();
145 if (!parent.isNonTriviallyObsolete(lookedAt)) {
146 return false;
147 }
148 }
149 return true;
150 }
151
152 public TreePath [] getPaths() {
153 Vector pathsVector = getPathsAsVector();
154 TreePath [] paths = new TreePath[pathsVector.size()];
155 for(int i=0; i < pathsVector.size(); i++)
156 paths[i] = (TreePath) pathsVector.elementAt(i);
157 return paths;
158 }
159
160 public Vector getPathsAsVector() {
161 Vector out = new Vector();
162 if (isRoot()) {
163 TreePath path = new TreePath(new TermRelationship(this,
164 null,
165 null));
166 out.addElement(path);
167 } else {
168 for(int i=0; i < parents.size(); i++) {
169 TermRelationship tr = (TermRelationship) parents.elementAt(i);
170 Vector paths = tr.getPathsAsVector();
171 for(int j=0; j < paths.size(); j++) {
172 TreePath path = (TreePath) paths.elementAt(j);
173 if (!out.contains(path))
174 out.addElement(path);
175 }
176 }
177 }
178 return out;
179 }
180
181 public Vector getRelationshipsToParent(Term in) {
182 Vector out = new Vector();
183 for(int i=0; i < parents.size(); i++) {
184 TermRelationship r = (TermRelationship) parents.elementAt(i);
185 if (r.getParent().equals(in))
186 out.addElement(r);
187 }
188 return out;
189 }
190
191
192
193 public Vector getRelationshipsForChild(Term in) {
194 Vector out = new Vector();
195 for(int i=0; i < children.size(); i++) {
196 TermRelationship r = (TermRelationship) children.elementAt(i);
197 if (r.getChild().equals(in))
198 out.addElement(r);
199 }
200 return out;
201 }
202
203 public String toString() {
204 if (debug)
205 return term +" {"+intid+"}";
206 else
207 return term;
208 }
209
210 public int getProductCount() {
211 return productCount;
212 }
213
214 public void setProductCount(int in) {
215 productCount = in;
216 }
217
218 public boolean equals(Term other) {
219 return this == other;
220 }
221
222 public int hashCode() {
223 if (getID() == null)
224 return super.hashCode();
225 else
226 return getID().hashCode();
227 }
228
229 public String getTerm() {
230 return term;
231 }
232
233 public void setTerm(String term) {
234 this.term = term;
235 }
236
237 public String getDefinition() {
238 return definition;
239 }
240
241 public void setDefinition( String definition ) {
242 this.definition = definition;
243 }
244
245 public String getIDPrefix() {
246 return idPrefix;
247 }
248
249 public void setIDPrefix(String idPrefix) {
250 this.idPrefix = idPrefix;
251 }
252
253 public String getID() {
254 return idPrefix+":"+id;
255 }
256
257 public void setID(String prefix, String id ) {
258 this.id = id;
259 this.idPrefix = prefix;
260 }
261
262 public void setID(String id) {
263 if (id != null) {
264 int colonIndex = id.indexOf(":");
265 String prefix = id.substring(0, colonIndex);
266 String idnum = id.substring(colonIndex+1);
267 setID(prefix, idnum);
268 } else {
269 setID(null, null);
270 }
271 }
272
273 public String getIDSuffix() {
274 return id;
275 }
276
277 public void setIDSuffix(String id) {
278 this.id = id;
279 }
280
281 public Vector getChildren() {
282 return children;
283 }
284
285 public void setChildren(Vector children) {
286 this.children = children;
287 }
288
289 public void setParents(Vector parents) {
290 this.parents = parents;
291 }
292
293 public void addChild(Term child, TermRelationshipType type) {
294 TermRelationship tr = new TermRelationship(child, this, type);
295 addChild(tr);
296 }
297
298 public void addChild(TermRelationship relation) {
299 int index = children.indexOf(relation);
300 if (index < 0) {
301 children.addElement (relation);
302 relation.getChild().addParent(relation);
303 }
304 }
305
306 public void removeChild(Term child) {
307 Vector v = getRelationshipsForChild(child);
308 for(int i=0; i < v.size(); i++) {
309 TermRelationship tr = (TermRelationship) v.elementAt(i);
310 removeChild(tr);
311 }
312 }
313
314 public void removeChild(TermRelationship relation) {
315 children.removeElement(relation);
316 relation.getChild().removeParent(relation);
317 }
318
319 public void removeParent(Term parent) {
320 Vector v = getRelationshipsToParent(parent);
321 for(int i=0; i < v.size(); i++) {
322 TermRelationship tr = (TermRelationship) v.elementAt(i);
323 removeParent(tr);
324 }
325 }
326
327 public void removeParent(TermRelationship relation) {
328 parents.removeElement(relation);
329 }
330
331 public void addParent(Term parent, TermRelationshipType type) {
332 addParent(new TermRelationship(this, parent, type));
333 }
334
335 public void addParent (TermRelationship relation) {
336 if (!parents.contains(relation)) {
337 parents.addElement (relation);
338 }
339 }
340
341 public Vector getParents () {
342 return parents;
343 }
344
345 public void removeAllParents() {
346 parents.removeAllElements();
347 }
348
349 public void addDanglingParent(DanglingRelationship relation) {
350 danglingParents.addElement(relation);
351 }
352
353 public void removeDanglingParent(DanglingRelationship relation) {
354 danglingParents.addElement(relation);
355 }
356
357 public Vector getDanglingParents() {
358 return danglingParents;
359 }
360
361 public void removeAllChildren() {
362 children.removeAllElements();
363 }
364
365 public Vector getSynonyms() {
366 return synonyms;
367 }
368
369 public void addSynonym (Synonym synonym) {
370 for(int i=0; i < synonyms.size(); i++) {
371 Synonym s = (Synonym) synonyms.elementAt(i);
372 if (s.equals(synonym)) {
373 for(int j=0; j < synonym.getDbxrefs().size(); j++) {
374 Dbxref ref = (Dbxref) synonym.getDbxrefs().elementAt(j);
375 s.addDbxref(ref);
376 }
377 return;
378 }
379 }
380 synonyms.addElement(synonym);
381 }
382
383 public void setSynonyms(Vector synonyms) {
384 this.synonyms = new Vector();
385 for(int i=0; i < synonyms.size(); i++)
386 addSynonym((Synonym) synonyms.elementAt(i));
387 }
388
389 public Vector getDbxrefs() {
390 return references;
391 }
392
393 public void addDbxref (Dbxref ref) {
394 if ( ! references.contains(ref) ) {
395 references.addElement (ref);
396 }
397 }
398
399 public void setDbxrefs(Vector refs) {
400 this.references = new Vector();
401 for(int i=0; i < refs.size(); i++)
402 addDbxref((Dbxref) refs.elementAt(i));
403 }
404
405 public Vector getDefDbxrefs() {
406 return defReferences;
407 }
408
409 public void addDefDbxref (Dbxref ref) {
410 if ( ! defReferences.contains(ref) ) {
411 defReferences.addElement (ref);
412 }
413 }
414
415 public void setDefDbxrefs(Vector refs) {
416 this.defReferences = new Vector();
417 for(int i=0; i < refs.size(); i++)
418 addDefDbxref((Dbxref) refs.elementAt(i));
419 }
420
421 public boolean hasAncestor(Term term) {
422 return hasAncestor(term, new HashSet());
423 }
424
425 private boolean hasAncestor(Term term, HashSet lookedAt) {
426 if (lookedAt.contains(this)) {
427 return false;
428 } else
429 lookedAt.add(this);
430 for(int i=0; i < parents.size(); i++) {
431 TermRelationship tr = (TermRelationship) parents.elementAt(i);
432
433 if (tr.getParent().getID().equals(term.getID()))
434 return true;
435 else if (tr.getParent().hasAncestor(term, lookedAt))
436 return true;
437 }
438 return false;
439 }
440
441 public void storeState(Hashtable in) {
442 Vector childRelationshipStates = new Vector();
443 for(int i=0; i < children.size(); i++) {
444 TermRelationship r = (TermRelationship) children.elementAt(i);
445 Hashtable rstate = new Hashtable();
446 r.storeState(rstate);
447 childRelationshipStates.addElement(rstate);
448 }
449
450 if (id != null)
451 in.put("datamodel.Term.id", id);
452 if (idPrefix != null)
453 in.put("datamodel.Term.idPrefix", idPrefix);
454 in.put("datamodel.Term.term", term);
455 if (definition != null)
456 in.put("datamodel.Term.definition", definition);
457 if (comment != null)
458 in.put("datamodel.Term.comment", comment);
459 in.put("datamodel.Term.synonyms", VectorUtil.trueClone(synonyms));
460 in.put("datamodel.Term.children", children.clone());
461 in.put("datamodel.Term.parents", parents.clone());
462 in.put("datamodel.Term.references", references.clone());
463 in.put("datamodel.Term.defReferences", defReferences.clone());
464 in.put("datamodel.Term.categories", categories.clone());
465 in.put("datamodel.Term.children.properties",
466 childRelationshipStates);
467 }
468
469 private void setIntID(int in) {
470 intid = in;
471 }
472
473 public Object clone() {
474 try {
475 Term out = (Term) super.clone();
476 out.setChildren((Vector) children.clone());
477 out.setParents((Vector) parents.clone());
478 out.setSynonyms(VectorUtil.trueClone(synonyms));
479 out.setDbxrefs(VectorUtil.trueClone(references));
480 out.setDefDbxrefs(VectorUtil.trueClone(defReferences));
481 out.setCategories(VectorUtil.trueClone(categories));
482 out.setIntID(idgen++);
483 return out;
484 } catch (Exception e) {
485 e.printStackTrace();
486 return null;
487 }
488 }
489
490 public void restoreState(Hashtable in) {
491 String stored_id = (String) in.get("datamodel.Term.id");
492 String stored_prefix = (String) in.get("datamodel.Term.prefix");
493 String stored_term = (String) in.get("datamodel.Term.term");
494 String stored_def = (String) in.get("datamodel.Term.definition");
495 String stored_comment = (String) in.get("datamodel.Term.comment");
496 Vector stored_syn = (Vector) in.get("datamodel.Term.synonyms");
497 Vector stored_ref = (Vector) in.get("datamodel.Term.references");
498 Vector stored_defRef = (Vector) in.get("datamodel.Term.defReferences");
499 Vector stored_children = (Vector) in.get("datamodel.Term.children");
500 Vector stored_parents = (Vector) in.get("datamodel.Term.parents");
501 Vector stored_cstates = (Vector)
502 in.get("datamodel.Term.children.properties");
503 Vector stored_cats = (Vector) in.get("datamodel.Term.categories");
504
505 if (stored_id != null)
506 id = stored_id;
507 if (stored_term != null)
508 term = stored_term;
509 if (stored_prefix != null)
510 idPrefix = stored_prefix;
511 if (stored_def != null)
512 definition = stored_def;
513 if (stored_comment != null)
514 comment = stored_comment;
515 if (stored_syn != null)
516 synonyms = stored_syn;
517 if (stored_ref != null)
518 references = stored_ref;
519 if (stored_defRef != null)
520 defReferences = stored_defRef;
521 if (stored_cats != null)
522 categories = stored_cats;
523 if (stored_children != null)
524 children = stored_children;
525 if (stored_parents != null)
526 parents = stored_parents;
527
528 if (stored_cstates != null) {
529 for(int i=0; i < stored_cstates.size(); i++) {
530 Hashtable state = (Hashtable) stored_cstates.elementAt(i);
531 TermRelationship tr = (TermRelationship)
532 children.elementAt(i);
533 tr.restoreState(state);
534 }
535 }
536 }
537
538 public Term getRoot() {
539 if (parents.size() == 0)
540 return this;
541 else
542 return ((TermRelationship) parents.elementAt(0)).
543 getParent().getRoot();
544 }
545
546 public Enumeration getAllDescendants() {
547 return getAllDescendants(false);
548 }
549
550 public Enumeration getAllDescendants(boolean includeSelf) {
551 Hashtable hash = new Hashtable();
552 getUniqueChildNodesHash(hash, this);
553 if (!includeSelf) {
554 if (getID() != null)
555 hash.remove(getID());
556 else
557 hash.remove(this);
558 }
559 return hash.elements();
560 }
561
562 private static void getUniqueChildNodesHash(Hashtable hash, Term term) {
563 if (term.getIDPrefix() != null && term.getIDSuffix() != null) {
564 if (hash.get(term.getID()) != null)
565 return;
566 else
567 hash.put(term.getID(), term);
568 } else {
569 if (hash.get(term) != null)
570 return;
571 else
572 hash.put(term, term);
573 }
574 Vector v = term.getChildren();
575 for(int i=0; i < v.size(); i++) {
576 TermRelationship tr = (TermRelationship) v.elementAt(i);
577 getUniqueChildNodesHash(hash, tr.getChild());
578 }
579 }
580
581 public Hashtable getAllDescendantsHash() {
582 return getAllDescendantsHash(false);
583 }
584
585 public Hashtable getAllDescendantsHash(boolean includeSelf) {
586 Hashtable hash = new Hashtable();
587 getUniqueChildNodesHash(hash, this);
588 if (!includeSelf) {
589 if (getID() != null)
590 hash.remove(getID());
591 else
592 hash.remove(this);
593 }
594 return hash;
595 }
596
597 public Enumeration getAllAncestors() {
598 return getAllAncestors(false);
599 }
600
601 public Enumeration getAllAncestors(boolean includeSelf) {
602 Hashtable hash = new Hashtable();
603 getUniqueParentNodesHash(hash, this);
604 if (!includeSelf) {
605 if (getID() != null)
606 hash.remove(getID());
607 else
608 hash.remove(this);
609 }
610 return hash.elements();
611 }
612
613 private static void getUniqueParentNodesHash(Hashtable hash, Term term) {
614 if (term.getID() != null) {
615 if (hash.get(term.getID()) != null)
616 return;
617 else
618 hash.put(term.getID(), term);
619 } else {
620 if (hash.get(term) != null)
621 return;
622 else
623 hash.put(term, term);
624 }
625 Vector v = term.getParents();
626 for(int i=0; i < v.size(); i++) {
627 TermRelationship tr = (TermRelationship) v.elementAt(i);
628 getUniqueParentNodesHash(hash, tr.getParent());
629 }
630 }
631
632 public Hashtable getAllAncestorsHash() {
633 return getAllAncestorsHash(false);
634 }
635
636 public Hashtable getAllAncestorsHash(boolean includeSelf) {
637 Hashtable hash = new Hashtable();
638 getUniqueParentNodesHash(hash, this);
639 if (!includeSelf) {
640 if (getID() != null)
641 hash.remove(getID());
642 else
643 hash.remove(this);
644 }
645 return hash;
646 }
647
648 /**
649 * Creates a clone of all the nodes down to term. The leaves of the
650 * cloned tree are term, NOT a clone of term. This means that
651 * even though the cloned parents of term refer to term, term does
652 * not contain a reference to those parents
653 */
654 public static Term cloneParentTree(Term term) {
655 Term newRoot = null;
656 Enumeration e = term.getAllAncestors(false);
657 Hashtable newTermHash = new Hashtable();
658 Hashtable oldTermHash = new Hashtable();
659 while(e.hasMoreElements()) {
660 Term originalTerm = (Term) e.nextElement();
661 Term newTerm = (Term) originalTerm.clone();
662 if (originalTerm.getID().equals(term.getID())) {
663 System.err.println("Not including "+originalTerm+" in list");
664 continue;
665 }
666 if (originalTerm.isRoot())
667 newRoot = newTerm;
668 newTermHash.put(newTerm, originalTerm);
669 oldTermHash.put(originalTerm, newTerm);
670 }
671 // This is NOT redundant. This has to be done in two passes to
672 // guarantee that the newTermHash is fully populated
673 e = newTermHash.keys();
674 while(e.hasMoreElements()) {
675 Term newTerm = (Term) e.nextElement();
676
677 Term originalTerm = (Term) newTermHash.get(newTerm);
678
679 newTerm.removeAllParents();
680 newTerm.removeAllChildren();
681
682 for(int i=0; i < originalTerm.children.size(); i++) {
683 TermRelationship tr = (TermRelationship) originalTerm.
684 children.elementAt(i);
685 Term newChild = (Term) oldTermHash.get(tr.getChild());
686 if (newChild != null) {
687 TermRelationship trNew =
688 new TermRelationship(newChild,
689 newTerm,
690 tr.getType());
691 newTerm.children.addElement(trNew);
692 } else if (tr.getChild() == term) {
693 TermRelationship trNew =
694 new TermRelationship(term,
695 newTerm,
696 tr.getType());
697 newTerm.children.addElement(trNew);
698 }
699 }
700 for(int i=0; i < originalTerm.parents.size(); i++) {
701 TermRelationship tr = (TermRelationship) originalTerm.
702 parents.elementAt(i);
703 Term newParent = (Term) oldTermHash.get(tr.getParent());
704 TermRelationship trNew =
705 new TermRelationship(newTerm,
706 newParent,
707 tr.getType());
708 newTerm.parents.addElement(trNew);
709 }
710 }
711
712 return newRoot;
713 }
714
715 public static Term cloneSubtree(Term in) {
716 Term newRoot = null;
717 Enumeration e = in.getAllDescendants(true);
718 Hashtable newTermHash = new Hashtable();
719 Hashtable oldTermHash = new Hashtable();
720 while(e.hasMoreElements()) {
721 Term originalTerm = (Term) e.nextElement();
722 Term newTerm = (Term) originalTerm.clone();
723 if (originalTerm == in)
724 newRoot = newTerm;
725 newTermHash.put(newTerm, originalTerm);
726 oldTermHash.put(originalTerm, newTerm);
727 }
728 // This is NOT redundant. This has to be done in two passes to
729 // guarantee that the newTermHash is fully populated
730 e = newTermHash.keys();
731 while(e.hasMoreElements()) {
732 Term newTerm = (Term) e.nextElement();
733 Term originalTerm = (Term) newTermHash.get(newTerm);
734
735 newTerm.removeAllParents();
736 newTerm.removeAllChildren();
737
738 for(int i=0; i < originalTerm.children.size(); i++) {
739 TermRelationship tr = (TermRelationship) originalTerm.
740 children.elementAt(i);
741 Term newChild = (Term) oldTermHash.get(tr.getChild());
742 TermRelationship trNew =
743 new TermRelationship(newChild,
744 newTerm,
745 tr.getType());
746 newTerm.children.addElement(trNew);
747 }
748 for(int i=0; i < originalTerm.parents.size(); i++) {
749 TermRelationship tr = (TermRelationship) originalTerm.
750 parents.elementAt(i);
751 Term newParent = (Term) oldTermHash.get(tr.getParent());
752 if (newParent != null) {
753 TermRelationship trNew =
754 new TermRelationship(newTerm,
755 newParent,
756 tr.getType());
757 newTerm.parents.addElement(trNew);
758 }
759 }
760 }
761 return newRoot;
762 }
763
764 public int compareTo(Object in) {
765 if (in instanceof Term) {
766 int cmp = getTerm().toUpperCase().compareTo(
767 ((Term) in).getTerm().toUpperCase());
768 if (cmp < 0)
769 return org.bdgp.util.Comparable.LESS_THAN;
770 else if (cmp > 0)
771 return org.bdgp.util.Comparable.GREATER_THAN;
772 else {
773 cmp = getID().toUpperCase().compareTo(
774 ((Term) in).getID().toUpperCase());
775 if (cmp < 0)
776 return org.bdgp.util.Comparable.LESS_THAN;
777 else if (cmp > 0)
778 return org.bdgp.util.Comparable.GREATER_THAN;
779 else
780 return org.bdgp.util.Comparable.EQUAL_TO;
781 }
782 } else {
783 return toString().compareTo(in.toString());
784 }
785 }
786 }