1 package org.apache.torque.om;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.ArrayList;
58 import org.apache.commons.lang.ObjectUtils;
59
60 /***
61 * This class can be used as an ObjectKey to uniquely identify an
62 * object within an application where the key consists of multiple
63 * entities (such a String[] representing a multi-column primary key).
64 *
65 * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
66 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
67 * @author <a href="mailto:drfish@cox.net">J. Russell Smyth</a>
68 * @version $Id: ComboKey.java,v 1.14 2003/08/25 21:42:40 mpoeschl Exp $
69 */
70 public class ComboKey extends ObjectKey
71 {
72 // might want to shift these to TR.props
73
74 /*** The single character used to separate key values in a string. */
75 public static final char SEPARATOR = ':';
76
77 /*** The single character used to separate key values in a string. */
78 public static final String SEPARATOR_STRING = ":";
79
80 /*** The array of the keys */
81 private SimpleKey[] key;
82
83 /***
84 * Creates an ComboKey whose internal representation will be
85 * set later, through a set method
86 */
87 public ComboKey()
88 {
89 }
90
91 /***
92 * Creates a ComboKey whose internal representation is an
93 * array of SimpleKeys.
94 *
95 * @param keys the key values
96 */
97 public ComboKey(SimpleKey[] keys)
98 {
99 setValue(keys);
100 }
101
102 /***
103 * Sets the internal representation to a String array.
104 *
105 * @param keys the key values
106 * @see #toString()
107 */
108 public ComboKey(String keys)
109 {
110 setValue(keys);
111 }
112
113 /***
114 * Sets the internal representation using a SimpleKey array.
115 *
116 * @param keys the key values
117 */
118 public void setValue(SimpleKey[] keys)
119 {
120 this.key = keys;
121 }
122
123 /***
124 * Sets the internal representation using a String of the
125 * form produced by the toString method.
126 *
127 * @param keys the key values
128 */
129 public void setValue(String keys)
130 {
131 int startPtr = 0;
132 int indexOfSep = keys.indexOf(SEPARATOR);
133 ArrayList tmpKeys = new ArrayList();
134 while (indexOfSep != -1)
135 {
136 if (indexOfSep == startPtr)
137 {
138 tmpKeys.add(null);
139 }
140 else
141 {
142 char keyType = keys.charAt(startPtr);
143 String keyString = keys.substring(startPtr + 1, indexOfSep);
144
145 SimpleKey newKey = null;
146 switch(keyType)
147 {
148 case 'N':
149 newKey = new NumberKey(keyString);
150 break;
151 case 'S':
152 newKey = new StringKey(keyString);
153 break;
154 case 'D':
155 try
156 {
157 newKey = new DateKey(keyString);
158 }
159 catch (NumberFormatException nfe)
160 {
161 newKey = new DateKey();
162 }
163 break;
164 default:
165 // unextepcted key type
166 }
167 tmpKeys.add(newKey);
168 }
169 startPtr = indexOfSep + 1;
170 indexOfSep = keys.indexOf(SEPARATOR, startPtr);
171 }
172
173 this.key = new SimpleKey[tmpKeys.size()];
174 for (int i = 0; i < this.key.length; i++)
175 {
176 this.key[i] = (SimpleKey) tmpKeys.get(i);
177 }
178 }
179
180 /***
181 * Sets the internal representation using a ComboKey.
182 *
183 * @param keys the key values
184 */
185 public void setValue(ComboKey keys)
186 {
187 setValue((SimpleKey[]) keys.getValue());
188 }
189
190 /***
191 * Get the underlying object.
192 *
193 * @return the underlying object
194 */
195 public Object getValue()
196 {
197 return key;
198 }
199
200 /***
201 * This method will return true if the conditions for a looseEquals
202 * are met and in addition no parts of the keys are null.
203 *
204 * @param keyObj the comparison value
205 * @return whether the two objects are equal
206 */
207 public boolean equals(Object keyObj)
208 {
209 boolean isEqual = false;
210
211 if (key != null)
212 {
213 // check that all keys are not null
214 isEqual = true;
215 SimpleKey[] keys = key;
216 for (int i = 0; i < keys.length && isEqual; i++)
217 {
218 isEqual &= keys[i] != null && keys[i].getValue() != null;
219 }
220
221 isEqual &= looseEquals(keyObj);
222 }
223
224 return isEqual;
225 }
226
227 /***
228 * keyObj is equal to this ComboKey if keyObj is a ComboKey, String,
229 * ObjectKey[], or String[] that contains the same information this key
230 * contains.
231 * For example A String[] might be equal to this key, if this key was
232 * instantiated with a String[] and the arrays contain equal Strings.
233 * Another example, would be if keyObj is an ComboKey that was
234 * instantiated with a ObjectKey[] and this ComboKey was instantiated with
235 * a String[], but the ObjectKeys in the ObjectKey[] were instantiated
236 * with Strings that equal the Strings in this KeyObject's String[]
237 * This method is not as strict as the equals method which does not
238 * allow any null keys parts, while the internal key may not be null
239 * portions may be, and the two object will be considered equal if
240 * their null portions match.
241 *
242 * @param keyObj the comparison value
243 * @return whether the two objects are equal
244 */
245 public boolean looseEquals(Object keyObj)
246 {
247 boolean isEqual = false;
248
249 if (key != null)
250 {
251 // Checks a compound key (ObjectKey[] or String[]
252 // based) with the delimited String created by the
253 // toString() method. Slightly expensive, but should be less
254 // than parsing the String into its constituents.
255 if (keyObj instanceof String)
256 {
257 isEqual = toString().equals(keyObj);
258 }
259 // check against a ObjectKey. Two keys are equal, if their
260 // internal keys equivalent.
261 else if (keyObj instanceof ComboKey)
262 {
263 SimpleKey[] obj = (SimpleKey[])
264 ((ComboKey) keyObj).getValue();
265
266 SimpleKey[] keys1 = key;
267 SimpleKey[] keys2 = obj;
268 isEqual = keys1.length == keys2.length;
269 for (int i = 0; i < keys1.length && isEqual; i++)
270 {
271 isEqual &= ObjectUtils.equals(keys1[i], keys2[i]);
272 }
273 }
274 else if (keyObj instanceof SimpleKey[])
275 {
276 SimpleKey[] keys1 = key;
277 SimpleKey[] keys2 = (SimpleKey[]) keyObj;
278 isEqual = keys1.length == keys2.length;
279 for (int i = 0; i < keys1.length && isEqual; i++)
280 {
281 isEqual &= ObjectUtils.equals(keys1[i], keys2[i]);
282 }
283 }
284 }
285 return isEqual;
286 }
287
288 /***
289 *
290 * @param sb the StringBuffer to append
291 * @see #toString()
292 */
293 public void appendTo(StringBuffer sb)
294 {
295 if (key != null)
296 {
297 SimpleKey[] keys = key;
298 for (int i = 0; i < keys.length; i++)
299 {
300 if (keys[i] != null)
301 {
302 if (keys[i] instanceof StringKey)
303 {
304 sb.append("S");
305 }
306 else if (keys[i] instanceof NumberKey)
307 {
308 sb.append("N");
309 }
310 else if (keys[i] instanceof DateKey)
311 {
312 sb.append("D");
313 }
314 else
315 {
316 // unknown type
317 sb.append("U");
318 }
319 keys[i].appendTo(sb);
320 }
321 // MUST BE ADDED AFTER EACH KEY, IN CASE OF NULL KEY!
322 sb.append(SEPARATOR);
323 }
324 }
325 }
326
327 /***
328 * if the underlying key array is not null and the first element is
329 * not null this method returns the hashcode of the first element
330 * in the key. Otherwise calls ObjectKey.hashCode()
331 *
332 * @return an <code>int</code> value
333 */
334 public int hashCode()
335 {
336 if (key == null)
337 {
338 return super.hashCode();
339 }
340
341 SimpleKey sk = key[0];
342 if (sk == null)
343 {
344 return super.hashCode();
345 }
346
347 return sk.hashCode();
348 }
349
350 /***
351 * A String that may consist of one section or multiple sections
352 * separated by a colon. <br/>
353 * Each Key is represented by <code>[type N|S|D][value][:]</code>. <p/>
354 * Example: <br/>
355 * the ComboKey(StringKey("key1"), NumberKey(2)) is represented as
356 * <code><b>Skey1:N2:</b></code>
357 *
358 * @return a String representation
359 */
360 public String toString()
361 {
362 StringBuffer sbuf = new StringBuffer();
363 appendTo(sbuf);
364 return sbuf.toString();
365 }
366 }
This page was automatically generated by Maven