2 * Portions Copyright 2001-2003 Sun Microsystems, Inc.
3 * Portions Copyright 1999-2001 Language Technologies Institute,
4 * Carnegie Mellon University.
5 * All Rights Reserved. Use is subject to license terms.
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
11 package com.sun.speech.freetts;
13 import java.io.PrintWriter;
14 import java.util.StringTokenizer;
17 * Represents a node in a Relation. Items can have shared contents but
18 * each item has its own set of Daughters. The shared contents of an
19 * item (represented by ItemContents) includes the feature set for the
20 * item and the set of all relations that this item is contained in.
21 * An item can be contained in a number of relations and as daughters
22 * to other items. This class is used to keep track of all of these
23 * relationships. There may be many instances of item that reference
24 * the same shared ItemContents.
26 public class Item implements Dumpable {
27 private Relation ownerRelation;
28 private ItemContents contents;
30 private Item daughter;
36 * Creates an item. The item is coupled to a particular
37 * Relation. If shared contents is null a new sharedContents is
40 * @param relation the relation that owns this item
41 * @param sharedContents the contents that is shared with others.
42 * If null, a new sharedContents is created.
44 public Item(Relation relation, ItemContents sharedContents) {
45 ownerRelation = relation;
46 if (sharedContents != null) {
47 contents = sharedContents;
49 contents = new ItemContents();
57 getSharedContents().addItemRelation(relation.getName(), this);
61 * Finds the item in the given relation that has the same shared
64 * @param relationName the relation of interest
66 * @return the item as found in the given relation or null if not
69 public Item getItemAs(String relationName) {
70 return getSharedContents().getItemRelation(relationName);
75 * Retrieves the owning Relation.
77 * @return the relation that owns this item
79 public Relation getOwnerRelation() {
84 * Retrieves the shared contents for this item.
86 * @return the shared item contents
88 public ItemContents getSharedContents() {
93 * Determines if this item has daughters.
95 * @return true if this item has daughters
97 public boolean hasDaughters() {
98 return daughter != null;
102 * Retrieves the first daughter of this item.
104 * @return the first daughter or null if none
106 public Item getDaughter() {
111 * Retrieves the Nth daughter of this item.
113 * @param which the index of the daughter to return
115 * @return the Nth daughter or null if none at the given index
117 public Item getNthDaughter(int which) {
120 while (count++ != which && d != null) {
127 * Retrieves the last daughter of this item.
129 * @return the last daughter or null if none at the given index
131 public Item getLastDaughter() {
136 while (d.next != null) {
143 * Adds the given item as a daughter to this item.
145 * @param item the new daughter
147 public Item addDaughter(Item item) {
149 ItemContents contents;
151 Item p = getLastDaughter();
154 newItem = p.appendItem(item);
157 contents = new ItemContents();
159 contents = item.getSharedContents();
161 newItem = new Item(getOwnerRelation(), contents);
162 newItem.parent = this;
169 * Creates a new Item, adds it as a daughter to this item
170 * and returns the new item.
172 * @return the newly created item that was added as a daughter
174 public Item createDaughter() {
175 return addDaughter(null);
180 * Returns the parent of this item.
182 * @return the parent of this item
184 public Item getParent() {
186 for (n = this; n.prev != null; n = n.prev) {
196 * Sets the parent of this item.
198 * @param parent the parent of this item
201 private void setParent(Item parent) {
202 this.parent = parent;
207 * Returns the utterance associated with this item.
209 * @return the utterance that contains this item
211 public Utterance getUtterance() {
212 return getOwnerRelation().getUtterance();
216 * Returns the feature set of this item.
218 * @return the feature set of this item
220 public FeatureSet getFeatures() {
221 return getSharedContents().getFeatures();
225 * Dumps out this item to the given output stream.
227 * @param out where to send the output
228 * @param pad the leading whitspace
230 public void dump(PrintWriter out, int pad, String title) {
231 String itemName = title + ":" + toString();
232 getFeatures().dump(out, pad, itemName);
233 if (hasDaughters()) {
234 Item daughter = getDaughter();
235 while (daughter != null) {
236 daughter.dump(out, pad + 8, "d");
237 daughter = daughter.next;
243 * Finds the feature by following the given path.
244 * Path is a string of
245 * ":" or "." separated strings with the following interpretations:
248 * <li> p - previous item
249 * <li> parent - the parent
250 * <li> daughter - the daughter
251 * <li> daughter1 - same as daughter
252 * <li> daughtern - the last daughter
253 * <li> R:relname - the item as found in the given relation 'relname'
255 * The last element of the path will be interpreted as a
256 * voice/language specific feature function (if present) or an
257 * item feature name. If the feature function exists it will be
258 * called with the item specified by the path, otherwise, a
259 * feature will be retrieved with the given name. If neither exist
260 * than a String "0" is returned.
262 * @param pathAndFeature the path to follow
264 public Object findFeature(String pathAndFeature) {
271 Voice voice = getOwnerRelation().getUtterance().getVoice();
272 Object results = null;
275 lastDot = pathAndFeature.lastIndexOf(".");
276 // string can be of the form "p.feature" or just "feature"
279 feature = pathAndFeature;
282 feature = pathAndFeature.substring(lastDot + 1);
283 path = pathAndFeature.substring(0, lastDot);
287 item = findItem(path);
289 fp = voice.getFeatureProcessor(feature);
293 results = fp.process(item);
294 } catch (ProcessException pe) {
295 System.err.println("Trouble while processing " +
299 results = item.getFeatures().getObject(feature);
302 results = (results == null)
306 // System.out.println("FI " + pathAndFeature + " are " + results);
312 * Finds the item specified by the given path.
314 * Path is a string of ":" or
315 * "." separated strings with the following interpretations:
318 * <li> p - previous item
319 * <li> parent - the parent
320 * <li> daughter - the daughter
321 * <li> daughter1 - same as daughter
322 * <li> daughtern - the last daughter
323 * <li> R:relname - the item as found in the given relation 'relname'
325 * If the given path takes us outside of the bounds of the item
326 * graph, then list access exceptions will be thrown.
328 * @param path the path to follow
330 * @return the item at the given path
332 public Item findItem(String path) {
340 tok = new StringTokenizer(path, ":.");
342 while (pitem != null && tok.hasMoreTokens()) {
343 String token = tok.nextToken();
344 if (token.equals("n")) {
345 pitem = pitem.getNext();
346 } else if (token.equals("p")) {
347 pitem = pitem.getPrevious();
348 } else if (token.equals("nn")) {
349 pitem = pitem.getNext();
351 pitem = pitem.getNext();
353 } else if (token.equals("pp")) {
354 pitem = pitem.getPrevious();
356 pitem = pitem.getPrevious();
358 } else if (token.equals("parent")) {
359 pitem = pitem.getParent();
360 } else if (token.equals("daughter") || token.equals("daughter1")) {
361 pitem = pitem.getDaughter();
362 } else if (token.equals("daughtern")) {
363 pitem = pitem.getLastDaughter();
364 } else if (token.equals("R")) {
365 String relationName = tok.nextToken();
366 pitem = pitem.getSharedContents().getItemRelation(relationName);
368 System.out.println("findItem: bad feature " + token +
377 * Gets the next item in this list.
379 * @return the next item or null
381 public Item getNext() {
387 * Gets the previous item in this list.
389 * @return the previous item or null
391 public Item getPrevious() {
397 * Appends an item in this list after this item.
399 * @param originalItem new item has shared contents with this
402 * @return the newly appended item
404 public Item appendItem(Item originalItem) {
405 ItemContents contents;
408 if (originalItem == null) {
411 contents = originalItem.getSharedContents();
414 newItem = new Item(getOwnerRelation(), contents);
415 newItem.next = this.next;
416 if (this.next != null) {
417 this.next.prev = newItem;
422 if (this.ownerRelation.getTail() == this) {
423 this.ownerRelation.setTail(newItem);
429 * Attaches/appends an item to this one.
431 * @param item the item to append
433 void attach(Item item) {
439 * Prepends an item in this list before this item.
441 * @param originalItem new item has shared contents with this
444 * @return the newly appended item
446 public Item prependItem(Item originalItem) {
447 ItemContents contents;
450 if (originalItem == null) {
453 contents = originalItem.getSharedContents();
456 newItem = new Item(getOwnerRelation(), contents);
457 newItem.prev = this.prev;
458 if (this.prev != null) {
459 this.prev.next = newItem;
463 if (this.parent != null) {
464 this.parent.daughter = newItem;
465 newItem.parent = this.parent;
468 if (this.ownerRelation.getHead() == this) {
469 this.ownerRelation.setHead(newItem);
476 // Inherited from object
477 public String toString() {
478 // if we have a feature called 'name' use that
479 // otherwise fall back on the default.
480 String name = getFeatures().getString("name");
488 * Determines if the shared contents of the two items are the same.
490 * @param otherItem the item to compare
492 * @return true if the shared contents are the same
494 public boolean equalsShared(Item otherItem) {
495 if (otherItem == null) {
498 return getSharedContents().equals(otherItem.getSharedContents());