KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > util > MultiKey


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.util;
16
17 import java.io.Externalizable JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.ObjectInput JavaDoc;
20 import java.io.ObjectOutput JavaDoc;
21
22 import org.apache.tapestry.Tapestry;
23
24 /**
25  * A complex key that may be used as an alternative to nested
26  * {@link java.util.Map}s.
27  *
28  * @author Howard Lewis Ship
29  *
30  **/

31
32 public class MultiKey implements Externalizable JavaDoc
33 {
34     /**
35      * @since 2.0.4
36      *
37      **/

38     
39     private static final long serialVersionUID = 4465448607415788806L;
40     
41     private static final int HASH_CODE_UNSET = -1;
42
43     private transient int hashCode = HASH_CODE_UNSET;
44
45     private Object JavaDoc[] keys;
46
47     /**
48      * Public no-arguments constructor needed to be compatible with
49      * {@link Externalizable}; this leaves the new MultiKey in a
50      * non-usable state and shouldn't be used by user code.
51      *
52      **/

53
54     public MultiKey()
55     {
56     }
57
58     /**
59      * Builds a <code>MultiKey</code> from an array of keys. If the array is not
60      * copied, then it must not be modified.
61      *
62      * @param keys The components of the key.
63      * @param makeCopy If true, a copy of the keys is created. If false,
64      * the keys are simple retained by the <code>MultiKey</code>.
65      *
66      * @throws IllegalArgumentException if keys is null, of if the
67      * first element of keys is null.
68      *
69      **/

70
71     public MultiKey(Object JavaDoc[] keys, boolean makeCopy)
72     {
73         super();
74
75         if (keys == null || keys.length == 0)
76             throw new IllegalArgumentException JavaDoc(Tapestry.getMessage("MultiKey.null-keys"));
77
78         if (keys[0] == null)
79             throw new IllegalArgumentException JavaDoc(Tapestry.getMessage("MultiKey.first-element-may-not-be-null"));
80
81         if (makeCopy)
82         {
83             this.keys = new Object JavaDoc[keys.length];
84             System.arraycopy(keys, 0, this.keys, 0, keys.length);
85         }
86         else
87             this.keys = keys;
88     }
89
90     /**
91      * Returns true if:
92      * <ul>
93      * <li>The other object is a <code>MultiKey</code>
94      * <li>They have the same number of key elements
95      * <li>Every element is an exact match or is equal
96      * </ul>
97      *
98      **/

99
100     public boolean equals(Object JavaDoc other)
101     {
102         int i;
103
104         if (other == null)
105             return false;
106
107         if (keys == null)
108             throw new IllegalStateException JavaDoc(Tapestry.getMessage("MultiKey.no-keys"));
109
110         // Would a hashCode check be worthwhile here?
111

112         try
113         {
114             MultiKey otherMulti = (MultiKey) other;
115
116             if (keys.length != otherMulti.keys.length)
117                 return false;
118
119             for (i = 0; i < keys.length; i++)
120             {
121                 // On an exact match, continue. This means that null matches
122
// null.
123

124                 if (keys[i] == otherMulti.keys[i])
125                     continue;
126
127                 // If either is null, but not both, then
128
// not a match.
129

130                 if (keys[i] == null || otherMulti.keys[i] == null)
131                     return false;
132
133                 if (!keys[i].equals(otherMulti.keys[i]))
134                     return false;
135
136             }
137
138             // Every key equal. A match.
139

140             return true;
141         }
142         catch (ClassCastException JavaDoc e)
143         {
144         }
145
146         return false;
147     }
148
149     /**
150      * Returns the hash code of the receiver, which is computed from all the
151      * non-null key elements. This value is computed once and
152      * then cached, so elements should not change their hash codes
153      * once created (note that this
154      * is the same constraint that would be used if the individual
155      * key elements were
156      * themselves {@link java.util.Map} keys.
157      *
158      *
159      **/

160
161     public int hashCode()
162     {
163         if (hashCode == HASH_CODE_UNSET)
164         {
165             hashCode = keys[0].hashCode();
166
167             for (int i = 1; i < keys.length; i++)
168             {
169                 if (keys[i] != null)
170                     hashCode ^= keys[i].hashCode();
171             }
172         }
173
174         return hashCode;
175     }
176
177     /**
178     * Identifies all the keys stored by this <code>MultiKey</code>.
179     *
180     **/

181
182     public String JavaDoc toString()
183     {
184         StringBuffer JavaDoc buffer;
185         int i;
186
187         buffer = new StringBuffer JavaDoc("MultiKey[");
188
189         for (i = 0; i < keys.length; i++)
190         {
191             if (i > 0)
192                 buffer.append(", ");
193
194             if (keys[i] == null)
195                 buffer.append("<null>");
196             else
197                 buffer.append(keys[i]);
198         }
199
200         buffer.append(']');
201
202         return buffer.toString();
203     }
204
205     /**
206      * Writes a count of the keys, then writes each individual key.
207      *
208      **/

209
210     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc
211     {
212         out.writeInt(keys.length);
213
214         for (int i = 0; i < keys.length; i++)
215             out.writeObject(keys[i]);
216     }
217
218     /**
219      * Reads the state previously written by {@link #writeExternal(ObjectOutput)}.
220      *
221      **/

222
223     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc
224     {
225         int count;
226
227         count = in.readInt();
228         keys = new Object JavaDoc[count];
229
230         for (int i = 0; i < count; i++)
231             keys[i] = in.readObject();
232     }
233 }
Popular Tags