001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: import com.versant.core.common.OID;
014: import com.versant.core.common.NewObjectOID;
015: import com.versant.core.metadata.ModelMetaData;
016: import com.versant.core.metadata.MDStatics;
017: import com.versant.core.metadata.ClassMetaData;
018:
019: import java.io.Externalizable;
020: import java.io.IOException;
021: import java.io.ObjectInput;
022: import java.io.ObjectOutput;
023:
024: import com.versant.core.common.BindingSupportImpl;
025:
026: /**
027: * This is the JDO Genie specific class that represents datastore id
028: * instances for usage by users. Requests for the id instance of an
029: * datastore instance will return this and the same for getObjectIdClass.
030: */
031:
032: public final class VersantOid implements Externalizable {
033:
034: private transient PMCacheEntry ce;
035: public transient OID actualOID;
036:
037: public int classId;
038: public long pk;
039:
040: public VersantOid() {
041: }
042:
043: public VersantOid(OID actualOID, ModelMetaData jmd, boolean resolved) {
044: this .actualOID = actualOID;
045: if (resolved) {
046: classId = actualOID.getClassMetaData().classId;
047: } else {
048: classId = actualOID.getAvailableClassId();
049: }
050: pk = actualOID.getLongPrimaryKey();
051: }
052:
053: public VersantOid(PCStateMan sm, ModelMetaData jmd, boolean resolved) {
054: actualOID = sm.oid;
055: if (sm.oid.isNew() && ((NewObjectOID) sm.oid).realOID != null) {
056: //don't set the sm if the actual oid is available.
057: actualOID = ((NewObjectOID) sm.oid).realOID;
058: } else {
059: this .ce = sm.cacheEntry;
060: }
061:
062: classId = actualOID.getAvailableClassId();
063: pk = actualOID.getLongPrimaryKey();
064: }
065:
066: public VersantOid(String s) {
067: try {
068: char c = s.charAt(0);
069: int classId = c - '0';
070: checkClassIDDigit(classId, c, s);
071: int i = 1;
072: for (;;) {
073: c = s.charAt(i++);
074: if (c == MDStatics.OID_CHAR_SEPERATOR)
075: break;
076: int digit = c - '0';
077: checkClassIDDigit(digit, c, s);
078: classId = classId * 10 + digit;
079: }
080: this .classId = classId;
081: c = s.charAt(i++);
082: int n = s.length();
083: long pk = c - '0';
084: checkPkDigit(pk, c, s);
085: for (; i < n;) {
086: c = s.charAt(i++);
087: int digit = c - '0';
088: checkPkDigit(digit, c, s);
089: pk = pk * 10 + digit;
090: }
091: this .pk = pk;
092: } catch (Exception e) {
093: if (BindingSupportImpl.getInstance()
094: .isOwnInvalidObjectIdException(e)) {
095: throw (RuntimeException) e;
096: } else {
097: throw BindingSupportImpl.getInstance().invalidObjectId(
098: "Invalid OID String: '" + s + "': " + e, e);
099: }
100: }
101: }
102:
103: private void checkClassIDDigit(int digit, char c, String s) {
104: if (digit < 0 || digit > 9) {
105: throw BindingSupportImpl.getInstance().invalidObjectId(
106: "Invalid digit '" + c
107: + "' in classID for OID String: '" + s
108: + "'", null);
109: }
110: }
111:
112: private void checkPkDigit(long digit, char c, String s) {
113: if (digit < 0 || digit > 9) {
114: throw BindingSupportImpl.getInstance().invalidObjectId(
115: "Invalid digit '" + c
116: + "' in primary key for OID String: '" + s
117: + "'", null);
118: }
119: }
120:
121: public void writeExternal(ObjectOutput out) throws IOException {
122: convertToRealOID();
123: out.writeInt(classId);
124: out.writeLong(pk);
125: }
126:
127: public void readExternal(ObjectInput in) throws IOException {
128: classId = in.readInt();
129: pk = in.readLong();
130: }
131:
132: public String toString() {
133: convertToRealOID();
134: return classId + "-" + pk;
135: }
136:
137: private void convertToRealOID() {
138: if (actualOID == null)
139: return;
140: if (!actualOID.isNew())
141: return;
142: NewObjectOID newOid = (NewObjectOID) actualOID;
143: getActualOID(newOid);
144:
145: classId = newOid.getCmd().classId;
146: pk = actualOID.getLongPrimaryKey();
147: }
148:
149: /**
150: * Attempt to obtain the real oid for this newOid.
151: */
152: private void getActualOID(NewObjectOID newOid) {
153: if (newOid.realOID != null) {
154: actualOID = ((NewObjectOID) actualOID).realOID;
155: } else {
156: //try from sm
157: if (ce != null) {
158: PCStateMan sm = (PCStateMan) ce.get();
159: if (sm != null && !sm.getPmProxy().isClosed()) {
160: actualOID = sm.getRealOID();
161: } else {
162: throw BindingSupportImpl
163: .getInstance()
164: .exception(
165: "The transaction is which this "
166: + "JDO Object Id was used was never finished");
167: }
168: } else {
169: throw BindingSupportImpl
170: .getInstance()
171: .exception(
172: "The transaction is which this "
173: + "JDO Object Id was used was never finished");
174: }
175: }
176: }
177:
178: public boolean equals(Object object) {
179: convertToRealOID();
180: if (object instanceof VersantOid) {
181: VersantOid o = (VersantOid) object;
182: o.convertToRealOID();
183: return classId == o.classId && pk == o.pk;
184: }
185: return false;
186: }
187:
188: public int hashCode() {
189: convertToRealOID();
190: return classId + (int) pk * 29;
191: }
192:
193: }
|