001 /*
002 * jDTAUS - DTAUS fileformat.
003 * Copyright (c) 2005 Christian Schulte <cs@schulte.it>
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either
008 * version 2.1 of the License, or any later version.
009 *
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013 * Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public
016 * License along with this library; if not, write to the Free Software
017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
018 *
019 */
020 package org.jdtaus.core.container;
021
022 import java.io.Serializable;
023 import java.util.Arrays;
024 import java.util.Collection;
025 import java.util.HashMap;
026 import java.util.Map;
027
028 /**
029 * Collection of properties.
030 *
031 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
032 * @version $Id: Properties.java 2230 2007-03-26 01:37:48Z schulte2005 $
033 */
034 public class Properties implements Cloneable, Serializable
035 {
036
037 //--Properties--------------------------------------------------------------
038
039 /**
040 * The properties held by the instance.
041 * @serial
042 */
043 private Property[] properties;
044
045 /**
046 * Maps property names to properties.
047 * @serial
048 */
049 private final Map names = new HashMap();
050
051 /**
052 * Hash code.
053 * @serial
054 */
055 private int hashCode;
056
057 /**
058 * Gets the properties of the collection.
059 *
060 * @return the properties of the collection.
061 */
062 public Property[] getProperties()
063 {
064 if(this.properties == null)
065 {
066 this.properties = new Property[0];
067 this.hashCode = 0;
068 }
069
070 return this.properties;
071 }
072
073 /**
074 * Setter for property {@code properties}.
075 *
076 * @param value the new collection of properties.
077 *
078 * @throws DuplicatePropertyException if {@code value} contains duplicate
079 * properties.
080 */
081 public void setProperties(final Property[] value)
082 {
083 this.names.clear();
084 this.hashCode = 0;
085 this.properties = value;
086
087 if(value != null)
088 {
089 for(int i = value.length - 1; i >= 0; i--)
090 {
091 this.hashCode += value[i].hashCode();
092 if(this.names.put(value[i].getName(), value[i]) != null)
093 {
094 throw new DuplicatePropertyException(value[i].getName());
095 }
096 }
097 }
098 }
099
100 /**
101 * Gets a property for a name.
102 *
103 * @param name the name of the property to return.
104 *
105 * @return a reference to the property named {@code name}.
106 *
107 * @throws NullPointerException if {@code name} is {@code null}.
108 * @throws MissingPropertyException if no property matching {@code name}
109 * exists in the collection.
110 */
111 public Property getProperty(final String name)
112 {
113 if(name == null)
114 {
115 throw new NullPointerException("name");
116 }
117
118 final Property ret = (Property) this.names.get(name);
119
120 if(ret == null)
121 {
122 throw new MissingPropertyException(name);
123 }
124
125 return ret;
126 }
127
128 /**
129 * Gets a property for an index.
130 *
131 * @param index the index of the property to return.
132 *
133 * @return a reference to the property at {@code index}.
134 *
135 * @throws IndexOutOfBoundsException if {@code index} is negativ,
136 * greater than or equal to {@code size()}.
137 */
138 public final Property getProperty(final int index)
139 {
140 if(index < 0 || index >= this.size())
141 {
142 throw new ArrayIndexOutOfBoundsException(index);
143 }
144
145 return this.getProperties()[index];
146 }
147
148 /**
149 * Setter for a named property from property {@code properties}.
150 *
151 * @param property the property to update or to add to property
152 * {@code properties}.
153 *
154 * @return previous value of the property named {@code property.getName()}
155 * or {@code null} if no property with name {@code property.getName()}
156 * existed before.
157 *
158 * @throws NullPointerException if {@code property} is {@code null}.
159 * @throws IllegalArgumentException if a property with the same name but
160 * different type exists.
161 */
162 public Property setProperty(final Property property)
163 {
164 if(property == null)
165 {
166 throw new NullPointerException("property");
167 }
168
169 Property ret = null;
170
171 try
172 {
173
174 final Property p = this.getProperty(property.getName());
175 if(!p.getType().equals(property.getType()))
176 {
177 throw new IllegalArgumentException(p.getType().getName());
178 }
179 else
180 {
181 ret = (Property) p.clone();
182 this.hashCode -= p.hashCode();
183 p.setValue(property.getValue());
184 this.hashCode += p.hashCode();
185 }
186
187 }
188 catch(MissingPropertyException e)
189 {
190 final Collection props = Arrays.asList(this.getProperties());
191 props.add(property);
192 this.setProperties((Property[]) props.
193 toArray(new Property[props.size()]));
194
195 }
196
197 return ret;
198 }
199
200 /**
201 * Gets the number of properties held by the instance.
202 *
203 * @return the number of properties held by the instance.
204 */
205 public final int size()
206 {
207 return this.getProperties().length;
208 }
209
210 /**
211 * Creates a string representing the properties of the instance.
212 *
213 * @return a string representing the properties of the instance.
214 */
215 private String internalString()
216 {
217 final StringBuffer buf = new StringBuffer(200);
218 final Property[] properties = this.getProperties();
219 for(int i = properties.length - 1; i >= 0; i--)
220 {
221 buf.append("\n\tproperty[").append(i).append("]=").
222 append(properties[i]);
223
224 }
225
226 return buf.toString();
227 }
228
229 //--------------------------------------------------------------Properties--
230 //--Object------------------------------------------------------------------
231
232 /**
233 * Indicates whether some other object is equal to this one by comparing
234 * the values of all properties.
235 *
236 * @param o the reference object with which to compare.
237 *
238 * @return {@code true} if this object is the same as {@code o};
239 * {@code false} otherwise.
240 */
241 public boolean equals(final Object o)
242 {
243 boolean equal = this == o;
244
245 if(!equal && o instanceof Properties)
246 {
247 final Properties that = (Properties) o;
248 final Collection these = Arrays.asList(this.getProperties());
249 final Collection those = Arrays.asList(that.getProperties());
250
251 equal = these.size() == that.size() && these.containsAll(those);
252 }
253
254 return equal;
255 }
256
257 /**
258 * Returns a hash code value for this object.
259 *
260 * @return a hash code value for this object.
261 */
262 public int hashCode()
263 {
264 return this.hashCode;
265 }
266
267 /**
268 * Returns a string representation of the object.
269 *
270 * @return a string representation of the object.
271 */
272 public String toString()
273 {
274 return super.toString() + this.internalString();
275 }
276
277 /**
278 * Creates and returns a deep copy of this object.
279 *
280 * @return a clone of this instance.
281 */
282 public Object clone()
283 {
284 try
285 {
286 final Properties ret = (Properties) super.clone();
287 final Property[] props = this.getProperties();
288 ret.properties = new Property[props.length];
289
290 for(int i = props.length - 1; i >= 0; i--)
291 {
292 ret.properties[i] = (Property) props[i].clone();
293 }
294
295 return ret;
296 }
297 catch(CloneNotSupportedException e)
298 {
299 throw new AssertionError(e);
300 }
301 }
302
303 //------------------------------------------------------------------Object--
304 }