001: /*
002: * $Header: /export/home/cvsroot/MyPersonalizerRepository/MyPersonalizer/Subsystems/Kernel/Sources/es/udc/mypersonalizer/kernel/model/properties/CompoundProperty.java,v 1.1.1.1 2004/03/25 12:08:37 fbellas Exp $
003: * $Revision: 1.1.1.1 $
004: * $Date: 2004/03/25 12:08:37 $
005: *
006: * =============================================================================
007: *
008: * Copyright (c) 2003, The MyPersonalizer Development Group
009: * (http://www.tic.udc.es/~fbellas/mypersonalizer/index.html) at
010: * University Of A Coruna
011: * All rights reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions are met:
015: *
016: * - Redistributions of source code must retain the above copyright notice,
017: * this list of conditions and the following disclaimer.
018: *
019: * - Redistributions in binary form must reproduce the above copyright notice,
020: * this list of conditions and the following disclaimer in the documentation
021: * and/or other materials provided with the distribution.
022: *
023: * - Neither the name of the University Of A Coruna nor the names of its
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: */
040:
041: package es.udc.mypersonalizer.kernel.model.properties;
042:
043: import java.util.Map;
044: import java.util.Iterator;
045:
046: /**
047: * A standard composite implementation of the <code>Property</code> interface.
048: *
049: * @author Fernando Bellas
050: * @since 1.0
051: */
052:
053: public class CompoundProperty extends AbstractProperty implements
054: Property {
055:
056: /**
057: * For interoperability with possible futures changes.
058: */
059: private static final long serialVersionUID = 6651147378170131963L;
060:
061: /**
062: * A structure of properties.
063: *
064: * @serial
065: */
066: private PropertyStructure[] values;
067:
068: /**
069: * Creates an instance of a <code>CompoundProperty</code> from its simple
070: * name and initial values (an array of <code>PropertyStructure</code>s).
071: * It is possible to pass an array of 0 elements
072: * (<code>new PropertyStructure[0]</code>) for the initial values. The
073: * properties of the structure must be the same for all of the values
074: * (no check is done).
075: *
076: * @param simpleName the simple name
077: * @param values the object values
078: */
079: public CompoundProperty(String simpleName,
080: PropertyStructure[] values) {
081: super (simpleName);
082: setValuesAsObject(values);
083: }
084:
085: /**
086: * Not supported.
087: */
088: public String[] getValuesAsString() {
089: throw new UnsupportedOperationException(
090: "Operation not supported");
091: }
092:
093: /**
094: * Not supported.
095: */
096: public void setValuesAsString(String[] valuesAsString) {
097: throw new UnsupportedOperationException(
098: "Operation not supported");
099: }
100:
101: /**
102: * Supported.
103: */
104: public Object[] getValuesAsObject() {
105: return values;
106: }
107:
108: /**
109: * Supported. The properties of the structure must be the same for all of
110: * the values (no check is done). It is possible to pass an array of 0
111: * elements (<code>setValuesAsObject(new PropertyStructure[0])</code>).
112: */
113: public void setValuesAsObject(Object[] values) {
114:
115: this .values = (PropertyStructure[]) values;
116:
117: }
118:
119: /**
120: * Supported.
121: */
122: public Property findProperty(String relativeName)
123: throws PropertyNotFoundException {
124:
125: /* Treat special case. */
126: if (relativeName.equals("")) {
127: return this ;
128: }
129:
130: /* Treat normal case. */
131: int firstDotPosition;
132: int secondDotPosition;
133: String indexAsString;
134: int indexAsInt;
135: String firstSimpleName;
136: int startingIndex = 0;
137: Property theProperty = this ;
138:
139: do {
140:
141: /* Obtain the index ("1" in the example). */
142: firstDotPosition = relativeName.indexOf('.', startingIndex);
143: if (firstDotPosition == -1) {
144: throw new PropertyNotFoundException(relativeName);
145: }
146: indexAsString = relativeName.substring(startingIndex,
147: firstDotPosition);
148: try {
149: indexAsInt = new Integer(indexAsString).intValue();
150: } catch (NumberFormatException e) {
151: throw new PropertyNotFoundException(relativeName);
152: }
153: if ((indexAsInt < 0)
154: || (indexAsInt >= theProperty.getValuesAsObject().length)) {
155: throw new PropertyNotFoundException(relativeName);
156: }
157:
158: /*
159: * Obtain the first simple name after the index ("keywords" in the
160: * example), and update "startingIndex".
161: */
162: secondDotPosition = relativeName.indexOf('.',
163: firstDotPosition + 1);
164: if (secondDotPosition == -1) {
165: firstSimpleName = relativeName
166: .substring(firstDotPosition + 1);
167: startingIndex = -1;
168: } else {
169: firstSimpleName = relativeName.substring(
170: firstDotPosition + 1, secondDotPosition);
171: startingIndex = secondDotPosition + 1;
172: }
173:
174: /*
175: * Locate the property refered by "indexAsInt" and
176: * "firstSimpleName".
177: */
178: try {
179: PropertyStructure propertyStructure = (PropertyStructure) theProperty
180: .getValuesAsObject()[indexAsInt];
181: theProperty = propertyStructure.get(firstSimpleName);
182: } catch (PropertyNotFoundException e) {
183: throw new PropertyNotFoundException(relativeName);
184: }
185:
186: } while (startingIndex != -1);
187:
188: return theProperty;
189:
190: }
191:
192: /**
193: * Returns the hash code of an instance of this class. The resulting
194: * hash code is the sum of the property values hash codes in the
195: * PropertyStructure[].
196: *
197: * @return the hash code
198: */
199: public int hashCode() {
200: int hashCode = 0;
201: for (int i = 0; i < values.length; i++) {
202: Map valueMap = values[i].getAsMap();
203: Iterator valueMapKeysIterator = valueMap.keySet()
204: .iterator();
205:
206: while (valueMapKeysIterator.hasNext()) {
207: Object valueMapKey = valueMapKeysIterator.next();
208: Object valueMapKeyValue = valueMap.get(valueMapKey);
209: hashCode += valueMapKeyValue.hashCode();
210: }
211: }
212: return hashCode;
213: }
214:
215: /**
216: * Returns if an instance of this class is equals to the one passed as a
217: * parameter. This method returns true if the property values an the
218: * structure for both properties are equal. Returns false otherwise.
219: *
220: * @param object the instance to be compared to.
221: * @return true if this instance and the one passed as a parameter are
222: * equal, false otherwise.
223: */
224: public boolean equals(Object object) {
225:
226: if (object == null) {
227: return false;
228: }
229:
230: CompoundProperty compoundProperty = null;
231: try {
232: compoundProperty = (CompoundProperty) object;
233:
234: } catch (ClassCastException e) {
235: return false;
236: }
237:
238: if (!getSimpleName().equals(compoundProperty.getSimpleName())) {
239: return false;
240: }
241:
242: /*
243: * Two compound properties are equal if the above conditions are
244: * satisfied and the PropertyStructure[]-s that they contain are
245: * equal. This code compares all the elements in the
246: * PropertyStructure[]-s.
247: */
248: PropertyStructure[] valuesToCompare = (PropertyStructure[]) compoundProperty
249: .getValuesAsObject();
250:
251: if (values.length != valuesToCompare.length) {
252: return false;
253: }
254:
255: boolean equals = true;
256: for (int i = 0; i < values.length && equals; i++) {
257:
258: Map valueMap = values[i].getAsMap();
259: Map valueToCompareMap = valuesToCompare[i].getAsMap();
260:
261: /*
262: * Two PropertyStructure are equal if properties that they
263: * contain are equal. In this case the order of the properties in
264: * the PropertyStructure does not matter.
265: */
266: Iterator valueMapKeysIterator = valueMap.keySet()
267: .iterator();
268:
269: while (valueMapKeysIterator.hasNext()) {
270:
271: Object valueMapKey = valueMapKeysIterator.next();
272: Object valueMapKeyValue = valueMap.get(valueMapKey);
273: Object valueToCompareMapKeyValue = valueToCompareMap
274: .get(valueMapKey);
275:
276: if (!valueMapKeyValue.equals(valueToCompareMapKeyValue)) {
277: equals = false;
278: }
279: }
280: }
281:
282: return equals;
283: }
284: }
|