%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.torque.om.ComboKey |
|
|
1 | package org.apache.torque.om; |
|
2 | ||
3 | /* |
|
4 | * Copyright 2001-2005 The Apache Software Foundation. |
|
5 | * |
|
6 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
7 | * you may not use this file except in compliance with the License. |
|
8 | * You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | ||
19 | import java.util.ArrayList; |
|
20 | import org.apache.commons.lang.ObjectUtils; |
|
21 | ||
22 | /** |
|
23 | * This class can be used as an ObjectKey to uniquely identify an |
|
24 | * object within an application where the key consists of multiple |
|
25 | * entities (such a String[] representing a multi-column primary key). |
|
26 | * |
|
27 | * @author <a href="mailto:jmcnally@collab.net">John McNally</a> |
|
28 | * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> |
|
29 | * @author <a href="mailto:drfish@cox.net">J. Russell Smyth</a> |
|
30 | * @version $Id: ComboKey.java 239630 2005-08-24 12:25:32Z henning $ |
|
31 | */ |
|
32 | public class ComboKey extends ObjectKey |
|
33 | { |
|
34 | // might want to shift these to TR.props |
|
35 | ||
36 | /** The single character used to separate key values in a string. */ |
|
37 | public static final char SEPARATOR = ':'; |
|
38 | ||
39 | /** The single character used to separate key values in a string. */ |
|
40 | public static final String SEPARATOR_STRING = ":"; |
|
41 | ||
42 | /** The array of the keys */ |
|
43 | private SimpleKey[] key; |
|
44 | ||
45 | /** |
|
46 | * Creates an ComboKey whose internal representation will be |
|
47 | * set later, through a set method |
|
48 | */ |
|
49 | public ComboKey() |
|
50 | 0 | { |
51 | 0 | } |
52 | ||
53 | /** |
|
54 | * Creates a ComboKey whose internal representation is an |
|
55 | * array of SimpleKeys. |
|
56 | * |
|
57 | * @param keys the key values |
|
58 | */ |
|
59 | public ComboKey(SimpleKey[] keys) |
|
60 | 48 | { |
61 | 48 | setValue(keys); |
62 | 48 | } |
63 | ||
64 | /** |
|
65 | * Sets the internal representation to a String array. |
|
66 | * |
|
67 | * @param keys the key values |
|
68 | * @see #toString() |
|
69 | */ |
|
70 | public ComboKey(String keys) |
|
71 | 3 | { |
72 | 3 | setValue(keys); |
73 | 3 | } |
74 | ||
75 | /** |
|
76 | * Sets the internal representation using a SimpleKey array. |
|
77 | * |
|
78 | * @param keys the key values |
|
79 | */ |
|
80 | public void setValue(SimpleKey[] keys) |
|
81 | { |
|
82 | 48 | this.key = keys; |
83 | 48 | } |
84 | ||
85 | /** |
|
86 | * Sets the internal representation using a String of the |
|
87 | * form produced by the toString method. |
|
88 | * |
|
89 | * @param keys the key values |
|
90 | */ |
|
91 | public void setValue(String keys) |
|
92 | { |
|
93 | 3 | int startPtr = 0; |
94 | 3 | int indexOfSep = keys.indexOf(SEPARATOR); |
95 | 3 | ArrayList tmpKeys = new ArrayList(); |
96 | 10 | while (indexOfSep != -1) |
97 | { |
|
98 | 7 | if (indexOfSep == startPtr) |
99 | { |
|
100 | 1 | tmpKeys.add(null); |
101 | } |
|
102 | else |
|
103 | { |
|
104 | 6 | char keyType = keys.class="keyword">charAt(startPtr); |
105 | 6 | String keyString = keys.substring(startPtr + 1, indexOfSep); |
106 | ||
107 | 6 | SimpleKey newKey = null; |
108 | 6 | switch(keyType) |
109 | { |
|
110 | case 'N': |
|
111 | 1 | newKey = new NumberKey(keyString); |
112 | 1 | break; |
113 | case 'S': |
|
114 | 4 | newKey = new StringKey(keyString); |
115 | 4 | break; |
116 | case 'D': |
|
117 | try |
|
118 | { |
|
119 | 1 | newKey = new DateKey(keyString); |
120 | } |
|
121 | 0 | catch (NumberFormatException nfe) |
122 | { |
|
123 | 0 | newKey = new DateKey(); |
124 | 1 | } |
125 | 0 | break; |
126 | default: |
|
127 | // unextepcted key type |
|
128 | } |
|
129 | 6 | tmpKeys.add(newKey); |
130 | } |
|
131 | 7 | startPtr = indexOfSep + 1; |
132 | 7 | indexOfSep = keys.indexOf(SEPARATOR, startPtr); |
133 | } |
|
134 | ||
135 | 3 | this.key = new SimpleKey[tmpKeys.size()]; |
136 | 10 | for (int i = 0; i < this.key.length; i++) |
137 | { |
|
138 | 7 | this.key[i] = (SimpleKey) tmpKeys.get(i); |
139 | } |
|
140 | 3 | } |
141 | ||
142 | /** |
|
143 | * Sets the internal representation using a ComboKey. |
|
144 | * |
|
145 | * @param keys the key values |
|
146 | */ |
|
147 | public void setValue(ComboKey keys) |
|
148 | { |
|
149 | 0 | setValue((SimpleKey[]) keys.getValue()); |
150 | 0 | } |
151 | ||
152 | /** |
|
153 | * Get the underlying object. |
|
154 | * |
|
155 | * @return the underlying object |
|
156 | */ |
|
157 | public Object getValue() |
|
158 | { |
|
159 | 8 | return key; |
160 | } |
|
161 | ||
162 | /** |
|
163 | * This method will return true if the conditions for a looseEquals |
|
164 | * are met and in addition no parts of the keys are null. |
|
165 | * |
|
166 | * @param keyObj the comparison value |
|
167 | * @return whether the two objects are equal |
|
168 | */ |
|
169 | public boolean equals(Object keyObj) |
|
170 | { |
|
171 | 7 | boolean isEqual = false; |
172 | ||
173 | 7 | if (key != null) |
174 | { |
|
175 | // check that all keys are not null |
|
176 | 7 | isEqual = true; |
177 | 7 | SimpleKey[] keys = key; |
178 | 22 | for (int i = 0; i < keys.length && isEqual; i++) |
179 | { |
|
180 | 15 | isEqual &= keys[i] != null && keys[i].getValue() != class="keyword">null; |
181 | } |
|
182 | ||
183 | 7 | isEqual &= looseEquals(keyObj); |
184 | } |
|
185 | ||
186 | 7 | return isEqual; |
187 | } |
|
188 | ||
189 | /** |
|
190 | * keyObj is equal to this ComboKey if keyObj is a ComboKey, String, |
|
191 | * ObjectKey[], or String[] that contains the same information this key |
|
192 | * contains. |
|
193 | * For example A String[] might be equal to this key, if this key was |
|
194 | * instantiated with a String[] and the arrays contain equal Strings. |
|
195 | * Another example, would be if keyObj is an ComboKey that was |
|
196 | * instantiated with a ObjectKey[] and this ComboKey was instantiated with |
|
197 | * a String[], but the ObjectKeys in the ObjectKey[] were instantiated |
|
198 | * with Strings that equal the Strings in this KeyObject's String[] |
|
199 | * This method is not as strict as the equals method which does not |
|
200 | * allow any null keys parts, while the internal key may not be null |
|
201 | * portions may be, and the two object will be considered equal if |
|
202 | * their null portions match. |
|
203 | * |
|
204 | * @param keyObj the comparison value |
|
205 | * @return whether the two objects are equal |
|
206 | */ |
|
207 | public boolean looseEquals(Object keyObj) |
|
208 | { |
|
209 | 9 | boolean isEqual = false; |
210 | ||
211 | 9 | if (key != null) |
212 | { |
|
213 | // Checks a compound key (ObjectKey[] or String[] |
|
214 | // based) with the delimited String created by the |
|
215 | // toString() method. Slightly expensive, but should be less |
|
216 | // than parsing the String into its constituents. |
|
217 | 9 | if (keyObj instanceof String) |
218 | { |
|
219 | 0 | isEqual = toString().equals(keyObj); |
220 | } |
|
221 | // check against a ObjectKey. Two keys are equal, if their |
|
222 | // internal keys equivalent. |
|
223 | 9 | else if (keyObj instanceof ComboKey) |
224 | { |
|
225 | 8 | SimpleKey[] obj = (SimpleKey[]) |
226 | ((ComboKey) keyObj).getValue(); |
|
227 | ||
228 | 8 | SimpleKey[] keys1 = key; |
229 | 8 | SimpleKey[] keys2 = obj; |
230 | 8 | isEqual = keys1.length == keys2.length; |
231 | 25 | for (int i = 0; i < keys1.length && isEqual; i++) |
232 | { |
|
233 | 17 | isEqual &= ObjectUtils.equals(keys1[i], keys2[i]); |
234 | } |
|
235 | } |
|
236 | 1 | else if (keyObj instanceof SimpleKey[]) |
237 | { |
|
238 | 0 | SimpleKey[] keys1 = key; |
239 | 0 | SimpleKey[] keys2 = (SimpleKey[]) keyObj; |
240 | 0 | isEqual = keys1.length == keys2.length; |
241 | 0 | for (int i = 0; i < keys1.length && isEqual; i++) |
242 | { |
|
243 | 0 | isEqual &= ObjectUtils.equals(keys1[i], keys2[i]); |
244 | } |
|
245 | } |
|
246 | } |
|
247 | 9 | return isEqual; |
248 | } |
|
249 | ||
250 | /** |
|
251 | * |
|
252 | * @param sb the StringBuffer to append |
|
253 | * @see #toString() |
|
254 | */ |
|
255 | public void appendTo(StringBuffer sb) |
|
256 | { |
|
257 | 5 | if (key != null) |
258 | { |
|
259 | 5 | SimpleKey[] keys = key; |
260 | 17 | for (int i = 0; i < keys.length; i++) |
261 | { |
|
262 | 12 | if (keys[i] != null) |
263 | { |
|
264 | 10 | if (keys[i] instanceof StringKey) |
265 | { |
|
266 | 7 | sb.append("S"); |
267 | } |
|
268 | 3 | else if (keys[i] instanceof NumberKey) |
269 | { |
|
270 | 2 | sb.append("N"); |
271 | } |
|
272 | 1 | else if (keys[i] instanceof DateKey) |
273 | { |
|
274 | 1 | sb.append("D"); |
275 | } |
|
276 | else |
|
277 | { |
|
278 | // unknown type |
|
279 | 0 | sb.append("U"); |
280 | } |
|
281 | 10 | keys[i].appendTo(sb); |
282 | } |
|
283 | // MUST BE ADDED AFTER EACH KEY, IN CASE OF NULL KEY! |
|
284 | 12 | sb.append(SEPARATOR); |
285 | } |
|
286 | } |
|
287 | 5 | } |
288 | ||
289 | /** |
|
290 | * if the underlying key array is not null and the first element is |
|
291 | * not null this method returns the hashcode of the first element |
|
292 | * in the key. Otherwise calls ObjectKey.hashCode() |
|
293 | * |
|
294 | * @return an <code>int</code> value |
|
295 | */ |
|
296 | public int hashCode() |
|
297 | { |
|
298 | 0 | if (key == null) |
299 | { |
|
300 | 0 | return super.hashCode(); |
301 | } |
|
302 | ||
303 | 0 | SimpleKey sk = key[0]; |
304 | 0 | if (sk == null) |
305 | { |
|
306 | 0 | return super.hashCode(); |
307 | } |
|
308 | ||
309 | 0 | return sk.hashCode(); |
310 | } |
|
311 | ||
312 | /** |
|
313 | * A String that may consist of one section or multiple sections |
|
314 | * separated by a colon. <br/> |
|
315 | * Each Key is represented by <code>[type N|S|D][value][:]</code>. <p/> |
|
316 | * Example: <br/> |
|
317 | * the ComboKey(StringKey("key1"), NumberKey(2)) is represented as |
|
318 | * <code><b>Skey1:N2:</b></code> |
|
319 | * |
|
320 | * @return a String representation |
|
321 | */ |
|
322 | public String toString() |
|
323 | { |
|
324 | 4 | StringBuffer sbuf = new StringBuffer(); |
325 | 4 | appendTo(sbuf); |
326 | 4 | return sbuf.toString(); |
327 | } |
|
328 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |