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.io.TCByteBufferOutputStream;
008: import com.tc.io.TCByteBufferOutputStream.Mark;
009: import com.tc.object.ObjectID;
010: import com.tc.object.dna.api.DNAWriter;
011: import com.tc.object.dna.api.DNAEncoding;
012: import com.tc.util.Conversion;
013:
014: public class DNAWriterImpl implements DNAWriter {
015:
016: private static final long NULL_ID = ObjectID.NULL_ID.toLong();
017:
018: private final TCByteBufferOutputStream output;
019: private final Mark headerMark;
020: private final Mark parentIdMark;
021: private final Mark arrayLengthMark;
022: private final ObjectStringSerializer serializer;
023: private final DNAEncoding encoding;
024: private int actionCount = 0;
025:
026: public DNAWriterImpl(TCByteBufferOutputStream output, ObjectID id,
027: String className, ObjectStringSerializer serializer,
028: DNAEncoding encoding, String loaderDesc) {
029: this .output = output;
030: this .encoding = encoding;
031:
032: this .headerMark = output.mark();
033: output.writeInt(-1); // reserve 4 bytes for total length of this DNA
034: output.writeInt(-1); // reserve 4 bytes for # of actions
035: output.writeBoolean(true);
036: output.writeLong(id.toLong());
037: this .parentIdMark = output.mark();
038: output.writeLong(NULL_ID); // reserve 8 bytes for the parent object ID
039: this .serializer = serializer;
040: serializer.writeString(output, className);
041: serializer.writeString(output, loaderDesc);
042: this .arrayLengthMark = output.mark();
043: output.writeInt(-1); // reserve 4 bytes for array length
044: }
045:
046: public void addLogicalAction(int method, Object[] parameters) {
047: actionCount++;
048: output.writeByte(DNAEncodingImpl.LOGICAL_ACTION_TYPE);
049: output.writeInt(method);
050: output.writeByte(parameters.length);
051:
052: for (int i = 0; i < parameters.length; i++) {
053: encoding.encode(parameters[i], output);
054: }
055: }
056:
057: public void addSubArrayAction(int start, Object array, int length) {
058: actionCount++;
059: output.writeByte(DNAEncodingImpl.SUB_ARRAY_ACTION_TYPE);
060: output.writeInt(start);
061: encoding.encodeArray(array, output, length);
062: }
063:
064: public void addClassLoaderAction(String classLoaderFieldName,
065: Object value) {
066: actionCount++;
067: output.writeByte(DNAEncodingImpl.PHYSICAL_ACTION_TYPE);
068: serializer.writeFieldName(output, classLoaderFieldName);
069: encoding.encodeClassLoader(value, output);
070: }
071:
072: /**
073: * XXX::This method is uses the value to decide if the field is actually a referencable fields (meaning it is a non
074: * literal type.) This implementation is slightly flawed as you can set an instance of Integer or String to Object.
075: * But since that can only happens in Physical applicator and it correctly calls the other interface, this is left
076: * intact for now.
077: */
078: public void addPhysicalAction(String fieldName, Object value) {
079: addPhysicalAction(fieldName, value, value instanceof ObjectID);
080: }
081:
082: /**
083: * NOTE::README:XXX: This method is called from instrumented code in the L2.
084: *
085: * @see PhysicalStateClassLoader.createBasicDehydrateMethod()
086: */
087: public void addPhysicalAction(String fieldName, Object value,
088: boolean canBeReferenced) {
089: if (value == null) {
090: // Normally null values are converted into Null ObjectID much earlier, but this is not true when there are
091: // multiple versions of a class in a cluster sharing data.
092: value = ObjectID.NULL_ID;
093: canBeReferenced = true;
094: }
095:
096: actionCount++;
097: if (canBeReferenced) {
098: // An Object reference can be set to a literal instance, like
099: // Object o = new Integer(10);
100: // XXX::Earlier we used to also check LiteralValues.isLiteralInstance(value) before entering this block, but I
101: // think that is unnecessary and wrong when we optimize later to store ObjectIDs as longs in most cases in the L2
102: output
103: .writeByte(DNAEncodingImpl.PHYSICAL_ACTION_TYPE_REF_OBJECT);
104: } else {
105: output.writeByte(DNAEncodingImpl.PHYSICAL_ACTION_TYPE);
106: }
107: serializer.writeFieldName(output, fieldName);
108: encoding.encode(value, output);
109: }
110:
111: public void addArrayElementAction(int index, Object value) {
112: actionCount++;
113: output.writeByte(DNAEncodingImpl.ARRAY_ELEMENT_ACTION_TYPE);
114: output.writeInt(index);
115: encoding.encode(value, output);
116: }
117:
118: public void addEntireArray(Object value) {
119: actionCount++;
120: output.writeByte(DNAEncodingImpl.ENTIRE_ARRAY_ACTION_TYPE);
121: encoding.encodeArray(value, output);
122: }
123:
124: public void addLiteralValue(Object value) {
125: actionCount++;
126: output.writeByte(DNAEncodingImpl.LITERAL_VALUE_ACTION_TYPE);
127: encoding.encode(value, output);
128: }
129:
130: public void finalizeDNA(boolean isDelta) {
131: int totalLength = this .output.getBytesWritten()
132: - this .headerMark.getPosition();
133: byte[] lengths = new byte[9];
134: Conversion.writeInt(totalLength, lengths, 0);
135: Conversion.writeInt(actionCount, lengths, 4);
136: lengths[8] = isDelta ? (byte) 1 : (byte) 0;
137: this .headerMark.write(lengths);
138: }
139:
140: public void setParentObjectID(ObjectID id) {
141: this .parentIdMark.write(Conversion.long2Bytes(id.toLong()));
142: }
143:
144: public void setArrayLength(int length) {
145: this.arrayLengthMark.write(Conversion.int2Bytes(length));
146: }
147: }
|