001: /*
002: * <copyright>
003: *
004: * Copyright 2000-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.tools.csmart.core.property.name;
028:
029: /**
030: * A CompositeName composed from a parent name and a SimpleName. This
031: * class is abstract; the method for getting the parent name is left
032: * open so that part of the name can be supplied from subclasses.
033: **/
034: public abstract class MultiName implements CompositeName {
035: static final long serialVersionUID = 2707819060093765374L;
036:
037: private SimpleName sname;
038:
039: protected MultiName(SimpleName name) {
040: setName(name);
041: }
042:
043: public void setName(SimpleName newName) {
044: sname = newName;
045: decache(); // just to be certain, decache the hashcode
046: }
047:
048: protected abstract CompositeName getParentName();
049:
050: private transient volatile int _size = 0;
051:
052: /**
053: * Get the number of elements of the name.
054: * @return the number elements of the name
055: **/
056: public int size() {
057: if (_size == 0) {
058: CompositeName parent = getPrefix();
059: if (parent == null) {
060: _size = sname.size();
061: } else {
062: _size = sname.size() + parent.size();
063: }
064: }
065: return _size;
066: }
067:
068: /**
069: * Get the n-th element of the name
070: * @param n the element index
071: * @return the Name of the selected element
072: **/
073: public CompositeName get(int n) {
074: int size = size();
075: if (n >= size)
076: throw new IllegalArgumentException("Index out of range: "
077: + n + ">=" + size);
078: if (n < 0)
079: throw new IllegalArgumentException("Negative index: " + n);
080: CompositeName this p = this ;
081: for (int i = (size - 1); i > n; i--) {
082: this p = this p.getPrefix();
083: }
084: return this p.last();
085: }
086:
087: public CompositeName getPrefix() {
088: return getParentName();
089: }
090:
091: public CompositeName getPrefix(int n) {
092: int size = size();
093: if (n >= size)
094: throw new IllegalArgumentException("Index out of range: "
095: + n + ">=" + size);
096: if (n < 0)
097: throw new IllegalArgumentException("Negative index: " + n);
098: CompositeName name = this ;
099: int end = (size - 1) - n;
100: for (int i = 0; i < end; i++)
101: name = name.getPrefix(); // fix typo
102: return name;
103: }
104:
105: public CompositeName last() {
106: return sname;
107: }
108:
109: /**
110: * Test if this name ends with the given name
111: * @param that the name to compare to
112: * @return true if the final elements of this name are equal to
113: * the elements of the given name
114: **/
115: public boolean endsWith(CompositeName that) {
116: int thatSize = that.size();
117: int this Size = size();
118: if (thatSize > this Size)
119: return false; // test name has too many components
120:
121: CompositeName this p = this ;
122: CompositeName thatp = that;
123: for (int i = thatSize; i > 0; i--) {
124: CompositeName this el = this p.last();
125: CompositeName thatel = this p.last();
126: if (!this el.equals(thatel)) {
127: return false;
128: }
129: this p = this p.getPrefix();
130: thatp = thatp.getPrefix();
131: }
132: return true;
133: }
134:
135: /**
136: * Test if this name starts with the given name
137: * @param that the name to compare to
138: * @return true if the initial elements of this name are equal to
139: * the elements of the given name
140: **/
141: public boolean startsWith(CompositeName that) {
142: int thatSize = that.size();
143: int this Size = size();
144: if (thatSize > this Size)
145: return false; // test name has too many components
146:
147: // backup thisp to the right spot.
148: CompositeName this p = this ;
149: for (int i = (this Size - thatSize); i > 0; i--) {
150: this p = this p.getPrefix();
151: }
152:
153: CompositeName thatp = that;
154: for (int i = thatSize; i > 0; i--) {
155: CompositeName this el = this p.last();
156: CompositeName thatel = this p.last();
157: if (!this el.equals(thatel)) {
158: return false;
159: }
160: this p = this p.getPrefix();
161: thatp = thatp.getPrefix();
162: }
163: return true;
164: }
165:
166: /**
167: * Test two names for equality. Names may be of different classes
168: * as long as they are equivalent
169: * @param o Object to be compared with. Must be a CompositeName.
170: **/
171: public boolean equals(Object o) {
172: if (o == this )
173: return true; // minor optimization
174: if (o instanceof CompositeName) {
175: int diff = compareTo(o);
176: return diff == 0;
177: }
178: return false;
179: }
180:
181: /**
182: * Compare two CompositeNames element by element.
183: **/
184: public int compareTo(Object o) {
185: CompositeName that = (CompositeName) o;
186: int thatSize = that.size();
187: int this Size = size();
188: int sz = Math.min(thatSize, this Size);
189: int diff = 0;
190: for (int i = 0; diff == 0 && i < sz; i++) {
191: Object tn = that.get(i);
192: if (tn == null) {
193: return 1;
194: }
195: diff = get(i).compareTo(tn);
196: }
197: if (diff == 0)
198: diff = this Size - thatSize;
199: return diff;
200: }
201:
202: /**
203: * For debugging, print this name as a series of dot separated strings.
204: **/
205: public String toString() {
206: if (_tostring == null) {
207: _tostring = toStringBuffer(new StringBuffer()).toString();
208: }
209: return _tostring;
210: }
211:
212: private transient volatile String _tostring = null;
213:
214: protected StringBuffer toStringBuffer(StringBuffer buf) {
215: CompositeName parentName = getParentName();
216: if (parentName instanceof MultiName) {
217: return ((MultiName) parentName).toStringBuffer(buf).append(
218: '.').append(sname);
219: }
220: if (parentName != null)
221: buf.append(parentName.toString()).append('.');
222: return buf.append(sname);
223: }
224:
225: /** cache the hashcode. Decached by decache() **/
226: private transient volatile int _hc = 0;
227:
228: public int hashCode() {
229: if (_hc == 0) {
230: int result = sname.hashCode();
231: CompositeName pname = getParentName();
232: if (pname != null)
233: result += pname.hashCode() * 7;
234: if (result == 0)
235: result = 1;
236: _hc = result;
237: }
238: return _hc;
239: }
240:
241: /** wipe the hashcode cache **/
242: public void decache() {
243: _hc = 0;
244: _tostring = null;
245: _size = 0;
246: }
247: }
|