View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  /*
19   * ObjectIdentity.java
20   *
21   */
22   
23  package javax.jdo.identity;
24  
25  import java.io.IOException;
26  import java.io.ObjectInput;
27  import java.io.ObjectOutput;
28  
29  import java.security.AccessController;
30  import java.security.PrivilegedAction;
31  
32  import javax.jdo.JDOUserException;
33  
34  import javax.jdo.spi.JDOImplHelper;
35  
36  /** This class is for identity with a single Object type field.
37   * @version 2.0
38   */
39  public class ObjectIdentity extends SingleFieldIdentity {
40      
41      /** The key is stored in the superclass field keyAsObject.
42       */
43      
44      /** The JDOImplHelper instance used for parsing the String to an Object.
45       */
46      private static JDOImplHelper helper = (JDOImplHelper)
47          AccessController.doPrivileged(
48              new PrivilegedAction<JDOImplHelper> () {
49                  public JDOImplHelper run () {
50                      return JDOImplHelper.getInstance();
51                  }
52              }
53          );
54      
55      /** The delimiter for String constructor.
56       */
57      private static final String STRING_DELIMITER = ":"; //NOI18N
58      
59      /** Constructor with class and key.
60       * @param pcClass the class
61       * @param param the key
62       */
63      @SuppressWarnings("static-access")
64      public ObjectIdentity (Class pcClass, Object param) {
65          super (pcClass);
66          assertKeyNotNull(param);
67          String paramString = null;
68          String keyString = null;
69          String className = null;
70          if (param instanceof String) {
71              /* The paramString is of the form "<className>:<keyString>" */
72              paramString = (String)param;
73              if (paramString.length() < 3) {
74                  throw new JDOUserException(
75                      msg.msg("EXC_ObjectIdentityStringConstructionTooShort") + //NOI18N
76                      msg.msg("EXC_ObjectIdentityStringConstructionUsage", //NOI18N
77                          paramString));
78              }
79              int indexOfDelimiter = paramString.indexOf(STRING_DELIMITER);
80              if (indexOfDelimiter < 0) {
81                  throw new JDOUserException(
82                      msg.msg("EXC_ObjectIdentityStringConstructionNoDelimiter") + //NOI18N
83                      msg.msg("EXC_ObjectIdentityStringConstructionUsage", //NOI18N
84                          paramString));
85              }
86              keyString = paramString.substring(indexOfDelimiter+1);
87              className = paramString.substring(0, indexOfDelimiter);
88              keyAsObject = helper.construct(className, keyString);
89          } else {
90              keyAsObject = param;
91          }
92          hashCode = hashClassName() ^ keyAsObject.hashCode();
93      }
94  
95      /** Constructor only for Externalizable.
96       */
97      public ObjectIdentity () {
98      }
99  
100     /** Return the key.
101      * @return the key
102      */
103     public Object getKey () {
104         return keyAsObject;
105     }
106 
107     /** Return the String form of the object id. The class of the
108      * object id is written as the first part of the result so that
109      * the class can be reconstructed later. Then the toString
110      * of the key instance is appended. During construction, 
111      * this process is reversed. The class is extracted from 
112      * the first part of the String, and the String constructor
113      * of the key is used to construct the key itself.
114      * @return the String form of the key
115      */
116     @Override
117     public String toString () {
118         return keyAsObject.getClass().getName()
119                 + STRING_DELIMITER
120                 + keyAsObject.toString();
121     }
122 
123     /** Determine if the other object represents the same object id.
124      * @param obj the other object
125      * @return true if both objects represent the same object id
126      */
127     @Override
128     public boolean equals (Object obj) {
129         if (this == obj) {
130             return true;
131         } else if (!super.equals (obj)) {
132             return false;
133         } else {
134             ObjectIdentity other = (ObjectIdentity) obj;
135             return keyAsObject.equals(other.keyAsObject);
136         }
137     }
138 
139     /** Provide the hash code for this instance. The hash code is the
140      * hash code of the contained key.
141      * @return the hash code
142      */
143     @Override
144     public int hashCode() {
145         return keyAsObject.hashCode();
146     }
147 
148     /** Determine the ordering of identity objects.
149      * @param o Other identity
150      * @return The relative ordering between the objects
151      * @since 2.2
152      */
153     public int compareTo(Object o) {
154         if (o instanceof ObjectIdentity) {
155         	ObjectIdentity other = (ObjectIdentity)o;
156             int result = super.compare(other);
157             if (result == 0) {
158                 if (other.keyAsObject instanceof Comparable && 
159                         keyAsObject instanceof Comparable) {
160                     return ((Comparable)keyAsObject).compareTo(
161                             (Comparable)other.keyAsObject);
162                 }
163                 else
164                 {
165                     throw new ClassCastException("The key class (" + 
166                             keyAsObject.getClass().getName() + 
167                             ") does not implement Comparable");
168                 }
169             } else {
170                 return result;
171             }
172         }
173         else if (o == null) {
174             throw new ClassCastException("object is null");
175         }
176         throw new ClassCastException(this.getClass().getName() + 
177                 " != " + o.getClass().getName());
178     }
179 
180     /** Write this object. Write the superclass first.
181      * @param out the output
182      */
183     @Override
184     public void writeExternal(ObjectOutput out) throws IOException {
185         super.writeExternal (out);
186         out.writeObject(keyAsObject);
187     }
188 
189     /** Read this object. Read the superclass first.
190      * @param in the input
191      */
192     @Override
193     public void readExternal(ObjectInput in)
194 		throws IOException, ClassNotFoundException {
195         super.readExternal (in);
196         keyAsObject = in.readObject();
197     }
198     
199 }