KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > common > GenericOID


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.common;
13
14 import com.versant.core.metadata.ClassMetaData;
15 import com.versant.core.metadata.FieldMetaData;
16 import com.versant.core.metadata.MDStatics;
17 import com.versant.core.metadata.ModelMetaData;
18 import com.versant.core.util.FastParser;
19 import com.versant.core.util.OIDObjectInput;
20 import com.versant.core.util.OIDObjectOutput;
21
22 import java.io.*;
23 import java.math.BigDecimal JavaDoc;
24 import java.math.BigInteger JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.Locale JavaDoc;
27
28 /**
29  * This is an OID implementation suitable for use with any PC class. It is
30  * intended for use during development when the OID class generating code is
31  * broken. The meta data OID factory method can just return these for all
32  * PC classes. Performance is not important for this class as it will not
33  * be used in a production release.
34  */

35 public abstract class GenericOID implements OID, Externalizable
36                         
37 {
38
39     protected ClassMetaData cmd;
40     protected boolean resolved;
41     protected Object JavaDoc[] pk;
42
43     public GenericOID() {
44     }
45
46     public GenericOID(ClassMetaData cmd, boolean resolved) {
47         if (cmd == null) {
48             throw BindingSupportImpl.getInstance().internal("The supplied cmd is null");
49         }
50         this.cmd = cmd;
51         this.resolved = resolved;
52         pk = new Object JavaDoc[cmd.pkFields == null ? 1 : cmd.pkFields.length];
53     }
54
55     /**
56      * This is for the GenericState implementation.
57      */

58     public Object JavaDoc[] getPk() {
59         return pk;
60     }
61
62     /**
63      * Do we know the actual class of the object we are referencing? An
64      * OID may be created from a reference to a base class. The actual
65      * class of the object referenced might only be detirmined when its
66      * State is fetched from the store.
67      *
68      * @see #resolve
69      */

70     public boolean isResolved() {
71         return resolved;
72     }
73
74     /**
75      * Resolve this OID from the state. This will update our class index
76      * to reflect the state. It is a NOP to call this on an already
77      * resolved OID.
78      *
79      * @see #isResolved
80      */

81     public void resolve(State state) {
82         if (!resolved) {
83             cmd = state.getClassMetaData();
84             resolved = true;
85         }
86     }
87
88     public int getClassIndex() {
89         return cmd.index;
90     }
91
92     public ClassMetaData getClassMetaData() {
93         if (!resolved) {
94             throw BindingSupportImpl.getInstance().internal(
95                     "Called 'getClassMetaData()' on unresolved oid");
96         }
97         return cmd;
98     }
99
100     public ClassMetaData getAvailableClassMetaData() {
101         return cmd;
102     }
103
104     public ClassMetaData getBaseClassMetaData() {
105         return cmd.top;
106     }
107
108     public int getIdentityType() {
109         return cmd.top.identityType;
110     }
111
112     public void copyKeyFields(Object JavaDoc[] data) {
113         for (int i = 0; i < pk.length; i++) pk[i] = data[i];
114     }
115
116     /**
117      * Return a copy of the oid.
118      */

119     public OID copy() {
120         GenericOID copy = newInstance();
121         copy.resolved = resolved;
122         copy.cmd = cmd;
123         copy.pk = pk;
124         return copy;
125     }
126
127     protected abstract GenericOID newInstance();
128
129     public void fillFromPK(Object JavaDoc pk) {
130         FieldMetaData[] pkFields = cmd.pkFields;
131         Object JavaDoc[] pkValues = new Object JavaDoc[pkFields.length];
132         for (int i = 0; i < pkFields.length; i++) {
133             try {
134                 pkValues[i] = pk.getClass().getField(pkFields[i].getPkFieldName()).get(pk);
135             } catch (Exception JavaDoc e) {
136                 throw BindingSupportImpl.getInstance().internal(e.getMessage(), e);
137             }
138         }
139         copyKeyFields(pkValues);
140     }
141
142     public OID fillFromIDObject(Object JavaDoc id) {
143         pk = new Object JavaDoc[cmd.pkFields.length];
144         if (cmd.objectIdClass == null) {
145             if (cmd.pkFields.length != 1) {
146                 throw BindingSupportImpl.getInstance().invalidOperation(
147                         "Classes with application can only have a single pk " +
148                         "field if a ApplicationId class is not specified");
149             }
150             pk[0] = id;
151         } else {
152             FieldMetaData[] pkFields = cmd.pkFields;
153             Object JavaDoc[] pkValues = pk;
154             for (int i = 0; i < pkFields.length; i++) {
155                 try {
156                     pkValues[i] = pk.getClass().getField(pkFields[i].getPkFieldName()).get(pk);
157                 } catch (Exception JavaDoc e) {
158                     throw BindingSupportImpl.getInstance().internal(e.getMessage(), e);
159                 }
160             }
161         }
162         return this;
163     }
164
165     /**
166      * Fill this OID from its toString. The classid will have already been
167      * parsed out with index indicating the first character after the
168      * separator.
169      */

170     public void fillFromIDString(String JavaDoc s, int i) {
171         try {
172             // There will always be only one column for datastore identity.
173
// Composite pk is only supported for application identity which
174
// will use the code in the objectid-class.
175
switch (cmd.datastoreIdentityTypeCode) {
176                 case MDStatics.INTW:
177                 case MDStatics.INT:
178                     pk[0] = new Integer JavaDoc(FastParser.parseInt(s, i));
179                     break;
180                 case MDStatics.SHORTW:
181                 case MDStatics.SHORT:
182                     pk[0] = new Short JavaDoc((short)FastParser.parseInt(s, i));
183                     break;
184                 case MDStatics.STRING:
185                     pk[0] = s.substring(i);
186                     break;
187                 case MDStatics.BOOLEANW:
188                 case MDStatics.BOOLEAN:
189                     pk[0] = new Boolean JavaDoc(s.substring(i));
190                     break;
191                 case MDStatics.BYTEW:
192                 case MDStatics.BYTE:
193                     pk[0] = new Byte JavaDoc((byte)FastParser.parseInt(s, i));
194                     break;
195                 case MDStatics.BIGDECIMAL:
196                     pk[0] = new BigDecimal JavaDoc(s.substring(i));
197                     break;
198                 case MDStatics.BIGINTEGER:
199                     pk[0] = new BigInteger JavaDoc(s.substring(i));
200                     break;
201                 case MDStatics.DOUBLEW:
202                 case MDStatics.DOUBLE:
203                     pk[0] = new Double JavaDoc(s.substring(i));
204                     break;
205                 case MDStatics.FLOATW:
206                 case MDStatics.FLOAT:
207                     pk[0] = new Float JavaDoc(s.substring(i));
208                     break;
209                 case MDStatics.LONGW:
210                 case MDStatics.LONG:
211                     pk[0] = new Long JavaDoc(FastParser.parseLong(s, i));
212                     break;
213                 default:
214                     throw BindingSupportImpl.getInstance().internal(
215                             "Unable to create id from the string '" + s +
216                             "' type code " + cmd.datastoreIdentityTypeCode);
217             }
218         } catch (Exception JavaDoc e) {
219             throw BindingSupportImpl.getInstance().invalidOperation("invalid OID String: '" + s + "'", e);
220         }
221     }
222
223     public int hashCode() {
224         if (pk == null) return super.hashCode();
225         int hc = pk[0].hashCode() + cmd.top.index;
226         for (int i = 1; i < pk.length; i++) hc = hc * 17 + pk[i].hashCode();
227         return hc;
228     }
229
230     public boolean equals(Object JavaDoc obj) {
231         if (obj == null) return false;
232         if (obj instanceof GenericOID) {
233             GenericOID o = (GenericOID)obj;
234             if (o.cmd.top != cmd.top) return false;
235             for (int i = pk.length - 1; i >= 0; i--) {
236                 if (pk[i] == null) {
237                     if (o.pk[i] != null) return false;
238                 } else if (!pk[i].equals(o.pk[i])) {
239                     return false;
240                 }
241             }
242             return true;
243         } else {
244             return obj.equals(this);
245         }
246     }
247
248     public String JavaDoc toString() {
249         if (!resolved) {
250             throw BindingSupportImpl.getInstance().internal(
251                     "This oid is not resolved to its actual type");
252         }
253         return toStringImp();
254     }
255
256     /**
257      * Get the toString of this OID even if it has not been resolved.
258      */

259     public String JavaDoc toStringImp() {
260         if (pk == null) return "null pk";
261         StringBuffer JavaDoc s = new StringBuffer JavaDoc();
262         s.append(cmd.classId);
263         s.append(MDStatics.OID_STRING_SEPERATOR);
264         int len = pk.length;
265         s.append(pk[0]);
266         for (int i = 1; i < len; i++) {
267             s.append(MDStatics.OID_STRING_SEPERATOR);
268             s.append(pk[i]);
269         }
270         return s.toString();
271     }
272
273     public abstract String JavaDoc toSString();
274
275     /**
276      * Encode the 'primary key' of this OID as a String. This is used for
277      * pretty printing OIDs in the workbench.
278      */

279     public String JavaDoc toPkString() {
280         if (pk == null) return "null pk";
281         StringBuffer JavaDoc s = new StringBuffer JavaDoc();
282         int len = pk.length;
283         s.append(pk[0]);
284         for (int i = 1; i < len; i++) {
285             s.append(',');
286             s.append(' ');
287             s.append(pk[i]);
288         }
289         return s.toString();
290     }
291
292     public int compareTo(Object JavaDoc o) {
293         OID oo = (OID)o;
294         int diff = cmd.top.index - oo.getBaseClassMetaData().index;
295         if (diff != 0) return diff;
296         if (oo.isNew()) {
297             return +1; // we are always after new OIDs
298
} else {
299             GenericOID oid = (GenericOID)oo;
300             for (int i = 0; i < pk.length; i++) {
301                 Object JavaDoc a = pk[i];
302                 Object JavaDoc b = oid.pk[i];
303                 if (a instanceof Comparable JavaDoc) {
304                     diff = ((Comparable JavaDoc)a).compareTo(b);
305                 } else {
306                     // yuck but I do not know any other way to do this
307
diff = a.toString().compareTo(b.toString());
308                 }
309                 if (diff != 0) return diff;
310             }
311             return 0;
312         }
313     }
314
315     /**
316      * Return the primary key stored in this OID as an long. This will only
317      * be called for datastore identity classes.
318      */

319     public long getLongPrimaryKey() {
320         return ((Number JavaDoc)pk[0]).longValue();
321     }
322
323     /**
324      * Set the primary key stored in this OID as an long. This will only be
325      * called for datastore identity classes.
326      */

327     public void setLongPrimaryKey(long pki) {
328         switch (cmd.datastoreIdentityTypeCode) {
329             case MDStatics.INTW:
330             case MDStatics.INT:
331                 pk[0] = new Integer JavaDoc((int)pki);
332                 break;
333             case MDStatics.SHORTW:
334             case MDStatics.SHORT:
335                 pk[0] = new Short JavaDoc((short)pki);
336                 break;
337             case MDStatics.BYTEW:
338             case MDStatics.BYTE:
339                 pk[0] = new Byte JavaDoc((byte)pki);
340                 break;
341             case MDStatics.LONGW:
342             case MDStatics.LONG:
343                 pk[0] = new Long JavaDoc(pki);
344                 break;
345             default:
346                 throw BindingSupportImpl.getInstance().internal(
347                         "Unhandled java type code " + cmd.datastoreIdentityTypeCode);
348         }
349     }
350
351     public void populateObjectIdClassInstance(Object JavaDoc o) {
352         ClassMetaData cmd = getAvailableClassMetaData();
353         if (cmd.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
354             throw BindingSupportImpl.getInstance().internal("not an app identity class: " +
355                     cmd.qname);
356         }
357         FieldMetaData[] a = cmd.pkFields;
358         for (int i = 0; i < a.length; i++) {
359             try {
360                 a[i].getObjectidClassField().set(o, pk[i]);
361             } catch (Exception JavaDoc e) {
362                 throw BindingSupportImpl.getInstance().internal(e.toString(), e);
363             }
364         }
365     }
366
367     public boolean isNew() {
368         return false;
369     }
370
371     public OID getMappedOID() {
372         return this;
373     }
374
375     public OID getRealOID() {
376         return this;
377     }
378
379     public OID getAvailableOID() {
380         return this;
381     }
382
383     public int getAvailableClassId() {
384         return getAvailableClassMetaData().classId;
385     }
386
387     public void setCmd(ClassMetaData cmd) {
388         this.cmd = cmd;
389     }
390
391     public void writeExternal(OIDObjectOutput os) throws IOException {
392         writeExternalImp(os);
393     }
394
395     public void writeExternal(ObjectOutput os) throws IOException {
396         os.writeShort(getClassIndex());
397         os.writeBoolean(resolved);
398         writeExternalImp(os);
399     }
400
401     private void writeExternalImp(ObjectOutput os) throws IOException {
402         if (cmd.pkFields == null) {
403             writeObjectByTypeCode(pk[0], cmd.datastoreIdentityTypeCode, os);
404         } else {
405             int n = cmd.pkFields.length;
406             for (int i = 0; i < n; i++) {
407                 writeObjectByTypeCode(pk[i], cmd.pkFields[i].typeCode, os);
408             }
409         }
410     }
411
412     public void readExternal(OIDObjectInput is) throws ClassNotFoundException JavaDoc,
413             IOException {
414         readExternalImp(is);
415     }
416
417     public void readExternal(ObjectInput is) throws ClassNotFoundException JavaDoc,
418             IOException {
419         cmd = ModelMetaData.getThreadMetaData().classes[is.readShort()];
420         resolved = is.readBoolean();
421         readExternalImp(is);
422     }
423
424     private void readExternalImp(ObjectInput is) throws IOException {
425         // cmd and resolved will have already been set by the constructor so
426
// no need to read them here
427
if (cmd.pkFields == null) {
428             pk = new Object JavaDoc[]{readObjectByTypeCode(cmd.datastoreIdentityTypeCode, is)};
429         } else {
430             int n = cmd.pkFields.length;
431             pk = new Object JavaDoc[n];
432             for (int i = 0; i < n; i++) {
433                 pk[i] = readObjectByTypeCode(cmd.pkFields[i].typeCode, is);
434             }
435         }
436     }
437
438     private void writeObjectByTypeCode(Object JavaDoc value, int typeCode, ObjectOutput os)
439             throws IOException {
440         if (value != null) {
441             //write a non-null indicator
442
os.writeBoolean(false);
443             switch (typeCode) {
444                 case MDStatics.INTW:
445                 case MDStatics.INT:
446                     os.writeInt(((Integer JavaDoc)value).intValue());
447                     break;
448                 case MDStatics.CHARW:
449                 case MDStatics.CHAR:
450                     os.writeInt(((Character JavaDoc)value).charValue());
451                     break;
452                 case MDStatics.SHORTW:
453                 case MDStatics.SHORT:
454                     os.writeShort(((Short JavaDoc)value).intValue());
455                     break;
456                 case MDStatics.STRING:
457                     os.writeUTF((String JavaDoc)value);
458                     break;
459                 case MDStatics.BOOLEANW:
460                 case MDStatics.BOOLEAN:
461                     os.writeBoolean(((Boolean JavaDoc)value).booleanValue());
462                     break;
463                 case MDStatics.BYTEW:
464                 case MDStatics.BYTE:
465                     os.writeByte(((Byte JavaDoc)value).byteValue());
466                     break;
467                 case MDStatics.DOUBLEW:
468                 case MDStatics.DOUBLE:
469                     os.writeDouble(((Double JavaDoc)value).doubleValue());
470                     break;
471                 case MDStatics.FLOATW:
472                 case MDStatics.FLOAT:
473                     os.writeFloat(((Float JavaDoc)value).floatValue());
474                     break;
475                 case MDStatics.LONGW:
476                 case MDStatics.LONG:
477                     os.writeLong(((Long JavaDoc)value).longValue());
478                     break;
479                 case MDStatics.LOCALE:
480                     final Locale JavaDoc l = (Locale JavaDoc)value;
481                     os.writeUTF(l.getLanguage());
482                     os.writeUTF(l.getCountry());
483                     os.writeUTF(l.getVariant());
484                     break;
485                 case MDStatics.BIGDECIMAL:
486                     os.writeUTF(value.toString());
487                     break;
488                 case MDStatics.BIGINTEGER:
489                     os.writeUTF(value.toString());
490                     break;
491                 case MDStatics.DATE:
492                     os.writeLong(((Date JavaDoc)value).getTime());
493                     break;
494                 default:
495                     throw BindingSupportImpl.getInstance().internal(
496                             "Unable to write type code " + typeCode);
497             }
498         } else {
499             //write a null indicator
500
os.writeBoolean(true);
501         }
502     }
503
504     private Object JavaDoc readObjectByTypeCode(int typeCode, ObjectInput is)
505             throws IOException {
506         if (is.readBoolean()) {
507             return null;
508         } else {
509             switch (typeCode) {
510                 case MDStatics.INTW:
511                 case MDStatics.INT:
512                     return new Integer JavaDoc(is.readInt());
513                 case MDStatics.CHARW:
514                 case MDStatics.CHAR:
515                     return new Character JavaDoc(is.readChar());
516                 case MDStatics.SHORTW:
517                 case MDStatics.SHORT:
518                     return new Short JavaDoc(is.readShort());
519                 case MDStatics.STRING:
520                     return is.readUTF();
521                 case MDStatics.BOOLEANW:
522                 case MDStatics.BOOLEAN:
523                     return new Boolean JavaDoc(is.readBoolean());
524                 case MDStatics.BYTEW:
525                 case MDStatics.BYTE:
526                     return new Byte JavaDoc(is.readByte());
527                 case MDStatics.DOUBLEW:
528                 case MDStatics.DOUBLE:
529                     return new Double JavaDoc(is.readDouble());
530                 case MDStatics.FLOATW:
531                 case MDStatics.FLOAT:
532                     return new Float JavaDoc(is.readFloat());
533                 case MDStatics.LONGW:
534                 case MDStatics.LONG:
535                     return new Long JavaDoc(is.readLong());
536                 case MDStatics.LOCALE:
537                     return new Locale JavaDoc(is.readUTF(), is.readUTF(),
538                             is.readUTF());
539                 case MDStatics.BIGDECIMAL:
540                     return new BigDecimal JavaDoc(is.readUTF());
541                 case MDStatics.BIGINTEGER:
542                     return new BigInteger JavaDoc(is.readUTF());
543                 case MDStatics.DATE:
544                     return new Date JavaDoc(is.readLong());
545                 default:
546                     throw BindingSupportImpl.getInstance().internal(
547                             "Unable to read java type code " + typeCode);
548             }
549         }
550     }
551
552 }
553
Popular Tags