1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package javax.jdo.identity;
24
25 import java.io.Externalizable;
26 import java.io.IOException;
27 import java.io.ObjectInput;
28 import java.io.ObjectOutput;
29
30 import javax.jdo.JDOFatalInternalException;
31 import javax.jdo.JDONullIdentityException;
32
33 import javax.jdo.spi.I18NHelper;
34
35 /** This class is the abstract base class for all single field identity
36 * classes. A common case of application identity uses exactly one
37 * persistent field in the class to represent identity. In this case,
38 * the application can use a standard JDO class instead of creating
39 * a new user-defined class for the purpose.
40 * @version 2.0
41 */
42 public abstract class SingleFieldIdentity
43 implements Externalizable, Comparable {
44
45 /** The Internationalization message helper.
46 */
47 protected static I18NHelper msg = I18NHelper.getInstance ("javax.jdo.Bundle");
48
49 /** The class of the target object.
50 */
51 transient private Class targetClass;
52
53 /** The name of the class of the target object.
54 */
55 private String targetClassName;
56
57 /** The hashCode.
58 */
59 protected int hashCode;
60
61 /** The key as an Object.
62 */
63 protected Object keyAsObject;
64
65 /** Constructor with target class.
66 * @param pcClass the class of the target
67 * @since 2.0
68 */
69 protected SingleFieldIdentity(Class pcClass) {
70 if (pcClass == null)
71 throw new NullPointerException();
72 targetClass = pcClass;
73 targetClassName = pcClass.getName();
74 }
75
76 /** Constructor only for Externalizable.
77 * @since 2.0
78 */
79 public SingleFieldIdentity () {
80 }
81
82 /** Set the given key as the key for this instance.
83 * Compute the hash code for the instance.
84 * @since 2.0
85 */
86 protected void setKeyAsObject(Object key) {
87 assertKeyNotNull(key);
88 keyAsObject = key;
89 }
90
91 /** Assert that the key is not null. Throw a JDONullIdentityException
92 * if the given key is null.
93 * @since 2.0
94 */
95 protected void assertKeyNotNull(Object key) {
96 if (key == null) {
97 throw new JDONullIdentityException(
98 msg.msg("EXC_SingleFieldIdentityNullParameter"));
99 }
100 }
101
102 /** Return the target class.
103 * @return the target class.
104 * @since 2.0
105 */
106 public Class getTargetClass() {
107 return targetClass;
108 }
109
110 /** Return the target class name.
111 * @return the target class name.
112 * @since 2.0
113 */
114 public String getTargetClassName() {
115 return targetClassName;
116 }
117
118 /** Return the key as an Object. The method is synchronized to avoid
119 * race conditions in multi-threaded environments.
120 * @return the key as an Object.
121 * @since 2.0
122 */
123 public synchronized Object getKeyAsObject() {
124 if (keyAsObject == null) {
125 keyAsObject = createKeyAsObject();
126 }
127 return keyAsObject;
128 }
129
130 /** Create the key as an Object.
131 * @return the key as an Object;
132 * @since 2.0
133 */
134 protected Object createKeyAsObject() {
135 throw new JDOFatalInternalException
136 (msg.msg("EXC_CreateKeyAsObjectMustNotBeCalled"));
137 }
138
139 /** Check the class and class name and object type. If restored
140 * from serialization, class will be null so compare class name.
141 * @param obj the other object
142 * @return true if the class or class name is the same
143 */
144 public boolean equals(Object obj) {
145 if (this == obj) {
146 return true;
147 } else if (obj == null || this.getClass() != obj.getClass()) {
148 return false;
149 } else {
150 SingleFieldIdentity other = (SingleFieldIdentity) obj;
151 if (targetClass != null && targetClass == other.targetClass)
152 return true;
153 return targetClassName.equals (other.targetClassName);
154 }
155 }
156
157 /** Return the hash code of the class name.
158 * @return the hash code of the class name
159 * @since 2.0
160 */
161 protected int hashClassName() {
162 return targetClassName.hashCode();
163 }
164
165 /** Return the cached hash code.
166 * @return the cached hash code.
167 */
168 public int hashCode() {
169 return hashCode;
170 }
171
172 /** Write to the output stream.
173 * @param out the stream
174 */
175 public void writeExternal(ObjectOutput out) throws IOException {
176 out.writeObject(targetClassName);
177 out.writeInt(hashCode);
178 }
179
180 /** Read from the input stream.
181 * Creates a new instance with the target class name set
182 */
183 public void readExternal(ObjectInput in)
184 throws IOException, ClassNotFoundException {
185 targetClass = null;
186 targetClassName = (String)in.readObject();
187 hashCode = in.readInt();
188 }
189
190 /** Determine the ordering of identity objects. Only the class name
191 * is compared. This method is only used by subclasses.
192 * @param o Other identity
193 * @return The relative ordering between the objects
194 * @since 2.2
195 */
196 protected int compare(SingleFieldIdentity o) {
197 return targetClassName.compareTo(o.targetClassName);
198 }
199
200 }