001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.dna.impl;
006:
007: import com.tc.bytes.TCByteBuffer;
008: import com.tc.io.TCByteBufferInput;
009: import com.tc.io.TCByteBufferOutput;
010: import com.tc.io.TCSerializable;
011: import com.tc.object.ObjectID;
012: import com.tc.object.dna.api.DNA;
013: import com.tc.object.dna.api.DNACursor;
014: import com.tc.object.dna.api.DNAEncoding;
015: import com.tc.object.dna.api.DNAException;
016: import com.tc.object.dna.api.LiteralAction;
017: import com.tc.object.dna.api.LogicalAction;
018: import com.tc.object.dna.api.PhysicalAction;
019: import com.tc.util.Assert;
020:
021: import java.io.IOException;
022:
023: public class DNAImpl implements DNA, DNACursor, TCSerializable {
024: private static final DNAEncoding DNA_STORAGE_ENCODING = new DNAEncodingImpl(
025: DNAEncoding.STORAGE);
026:
027: private final ObjectStringSerializer serializer;
028: private final boolean createOutput;
029:
030: protected TCByteBufferInput input;
031: protected TCByteBuffer[] dataOut;
032:
033: private int actionCount = 0;
034: private int origActionCount;
035: private boolean isDelta;
036:
037: // Header info; parsed on deserializeFrom()
038: private ObjectID id;
039: private ObjectID parentID;
040: private String typeName;
041: private int arrayLength;
042: private String loaderDesc;
043:
044: // XXX: cleanup type of this field
045: private Object currentAction;
046:
047: private boolean wasDeserialized = false;
048:
049: public DNAImpl(ObjectStringSerializer serializer,
050: boolean createOutput) {
051: this .serializer = serializer;
052: this .createOutput = createOutput;
053: }
054:
055: public String getTypeName() {
056: return typeName;
057: }
058:
059: public ObjectID getObjectID() throws DNAException {
060: return id;
061: }
062:
063: public ObjectID getParentObjectID() throws DNAException {
064: return parentID;
065: }
066:
067: public DNACursor getCursor() {
068: return this ;
069: }
070:
071: public boolean next() throws IOException {
072: try {
073: return next(DNA_STORAGE_ENCODING);
074: } catch (ClassNotFoundException e) {
075: // This shouldn't happen when expand is "false"
076: throw Assert.failure("Internal error");
077: }
078: }
079:
080: public boolean next(DNAEncoding encoding) throws IOException,
081: ClassNotFoundException {
082: boolean hasNext = actionCount > 0;
083: if (hasNext) {
084: parseNext(encoding);
085: actionCount--;
086: } else {
087: if (input.available() > 0) {
088: throw new IOException(input.available()
089: + " bytes remaining (expect 0)");
090: }
091: }
092: return hasNext;
093: }
094:
095: private void parseNext(DNAEncoding encoding) throws IOException,
096: ClassNotFoundException {
097: byte recordType = input.readByte();
098:
099: switch (recordType) {
100: case DNAEncodingImpl.PHYSICAL_ACTION_TYPE:
101: parsePhysical(encoding, false);
102: return;
103: case DNAEncodingImpl.PHYSICAL_ACTION_TYPE_REF_OBJECT:
104: parsePhysical(encoding, true);
105: return;
106: case DNAEncodingImpl.LOGICAL_ACTION_TYPE:
107: parseLogical(encoding);
108: return;
109: case DNAEncodingImpl.ARRAY_ELEMENT_ACTION_TYPE:
110: parseArrayElement(encoding);
111: return;
112: case DNAEncodingImpl.ENTIRE_ARRAY_ACTION_TYPE:
113: parseEntireArray(encoding);
114: return;
115: case DNAEncodingImpl.LITERAL_VALUE_ACTION_TYPE:
116: parseLiteralValue(encoding);
117: return;
118: case DNAEncodingImpl.SUB_ARRAY_ACTION_TYPE:
119: parseSubArray(encoding);
120: return;
121: default:
122: throw new IOException("Invalid record type: " + recordType);
123: }
124:
125: // unreachable
126: }
127:
128: private void parseSubArray(DNAEncoding encoding)
129: throws IOException, ClassNotFoundException {
130: int startPos = input.readInt();
131: Object subArray = encoding.decode(input);
132: currentAction = new PhysicalAction(subArray, startPos);
133: }
134:
135: private void parseEntireArray(DNAEncoding encoding)
136: throws IOException, ClassNotFoundException {
137: Object array = encoding.decode(input);
138: currentAction = new PhysicalAction(array);
139: }
140:
141: private void parseLiteralValue(DNAEncoding encoding)
142: throws IOException, ClassNotFoundException {
143: Object value = encoding.decode(input);
144: currentAction = new LiteralAction(value);
145: }
146:
147: private void parseArrayElement(DNAEncoding encoding)
148: throws IOException, ClassNotFoundException {
149: int index = input.readInt();
150: Object value = encoding.decode(input);
151: currentAction = new PhysicalAction(index, value,
152: value instanceof ObjectID);
153: }
154:
155: private void parsePhysical(DNAEncoding encoding, boolean isReference)
156: throws IOException, ClassNotFoundException {
157: String fieldName = serializer.readFieldName(input);
158:
159: Object value = encoding.decode(input);
160: currentAction = new PhysicalAction(fieldName, value,
161: value instanceof ObjectID || isReference);
162: }
163:
164: private void parseLogical(DNAEncoding encoding) throws IOException,
165: ClassNotFoundException {
166: int method = input.readInt();
167: int paramCount = input.read();
168: if (paramCount < 0)
169: throw new AssertionError("Invalid param count:"
170: + paramCount);
171: Object[] params = new Object[paramCount];
172: for (int i = 0; i < params.length; i++) {
173: params[i] = encoding.decode(input);
174: }
175: currentAction = new LogicalAction(method, params);
176: }
177:
178: public LogicalAction getLogicalAction() {
179: return (LogicalAction) this .currentAction;
180: }
181:
182: public PhysicalAction getPhysicalAction() {
183: return (PhysicalAction) this .currentAction;
184: }
185:
186: public Object getAction() {
187: return this .currentAction;
188: }
189:
190: public String toString() {
191: try {
192: StringBuffer buf = new StringBuffer();
193: buf.append("DNAImpl\n");
194: buf.append("{\n");
195: buf.append(" type->" + getTypeName() + "\n");
196: buf.append(" id->" + getObjectID() + "\n");
197: buf.append(" version->" + getVersion() + "\n");
198: buf.append(" isDelta->" + isDelta() + "\n");
199: buf.append(" actionCount->" + actionCount + "\n");
200: buf.append(" actionCount (orig)->" + origActionCount
201: + "\n");
202: buf.append(" deserialized?->" + wasDeserialized + "\n");
203: buf.append("}\n");
204: return buf.toString();
205: } catch (Exception e) {
206: return e.getMessage();
207: }
208: }
209:
210: public int getArraySize() {
211: return arrayLength;
212: }
213:
214: public boolean hasLength() {
215: return getArraySize() >= 0;
216: }
217:
218: public long getVersion() {
219: return NULL_VERSION;
220: }
221:
222: /*
223: * This methods is synchronized coz both broadcast stage and L2 sync objects stage accesses it simultaneously
224: */
225: public synchronized void serializeTo(TCByteBufferOutput serialOutput) {
226: serialOutput.write(dataOut);
227: }
228:
229: public Object deserializeFrom(TCByteBufferInput serialInput)
230: throws IOException {
231: this .wasDeserialized = true;
232:
233: serialInput.mark();
234: int dnaLength = serialInput.readInt();
235: if (dnaLength <= 0)
236: throw new IOException("Invalid length:" + dnaLength);
237:
238: serialInput.tcReset();
239:
240: this .input = serialInput.duplicateAndLimit(dnaLength);
241: serialInput.skip(dnaLength);
242:
243: if (createOutput) {
244: // this is optional (it's only needed on the server side for txn broadcasts)
245: this .dataOut = input.toArray();
246: }
247:
248: // skip over the length
249: input.readInt();
250:
251: this .actionCount = input.readInt();
252: this .origActionCount = actionCount;
253:
254: if (actionCount < 0)
255: throw new IOException("Invalid action count:" + actionCount);
256:
257: this .isDelta = input.readBoolean();
258:
259: this .id = new ObjectID(input.readLong());
260: this .parentID = new ObjectID(input.readLong());
261: this .typeName = serializer.readString(input);
262: this .loaderDesc = serializer.readString(input);
263: this .arrayLength = input.readInt();
264:
265: return this ;
266: }
267:
268: public String getDefiningLoaderDescription() {
269: return this .loaderDesc;
270: }
271:
272: public int getActionCount() {
273: return this .actionCount;
274: }
275:
276: public boolean isDelta() {
277: return this .isDelta;
278: }
279:
280: public void reset() throws UnsupportedOperationException {
281: throw new UnsupportedOperationException(
282: "Reset is not supported by this class");
283: }
284:
285: }
|