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;
006:
007: import com.tc.exception.TCClassNotFoundException;
008: import com.tc.object.bytecode.TransparentAccess;
009: import com.tc.object.field.TCField;
010: import com.tc.util.Assert;
011: import com.tc.util.ClassUtils;
012:
013: import gnu.trove.THashMap;
014:
015: import java.lang.ref.ReferenceQueue;
016: import java.util.HashMap;
017: import java.util.Map;
018:
019: public class TCObjectPhysical extends TCObjectImpl {
020: private Map references = null;
021:
022: public TCObjectPhysical(ReferenceQueue queue, ObjectID id,
023: Object peer, TCClass tcc) {
024: super (queue, id, peer, tcc);
025: }
026:
027: private Map getReferences() {
028: synchronized (getResolveLock()) {
029: if (references == null) {
030: references = new THashMap(0);
031: }
032: return references;
033: }
034: }
035:
036: private boolean hasReferences() {
037: return references != null && !references.isEmpty();
038: }
039:
040: private ObjectID removeReference(String fieldName) {
041: synchronized (getResolveLock()) {
042: ObjectID rv = (ObjectID) references.remove(fieldName);
043: if (references.isEmpty()) {
044: references = null;
045: }
046: return rv;
047: }
048: }
049:
050: public void resolveAllReferences() {
051: TCClass tcc = getTCClass();
052:
053: while (tcc != null) {
054: TCField[] fields = tcc.getPortableFields();
055: for (int i = 0; i < fields.length; i++) {
056: if (fields[i].canBeReference())
057: resolveReference(fields[i].getName());
058: }
059: tcc = tcc.getSuperclass();
060: }
061: }
062:
063: public ArrayIndexOutOfBoundsException checkArrayIndex(int index) {
064: Object[] po = (Object[]) getPeerObject();
065: if (index >= po.length || index < 0) {
066: //
067: return new ArrayIndexOutOfBoundsException(index);
068: }
069: return null;
070: }
071:
072: public final void resolveArrayReference(int index) {
073: this .markAccessed();
074:
075: Object[] po = (Object[]) getPeerObject();
076: if (!hasReferences())
077: return;
078:
079: ObjectID id = removeReference(Integer.toString(index));
080:
081: if (id == null)
082: return;
083: if (id.isNull()) {
084: po[index] = null;
085: } else {
086: Object o;
087: try {
088: o = getObjectManager().lookupObject(id);
089: } catch (ClassNotFoundException e) {
090: throw new TCClassNotFoundException(e);
091: }
092: po[index] = o;
093: }
094: }
095:
096: public ObjectID setReference(String fieldName, ObjectID id) {
097: synchronized (getResolveLock()) {
098: return (ObjectID) getReferences().put(fieldName, id);
099: }
100: }
101:
102: public void setArrayReference(int index, ObjectID id) {
103: synchronized (getResolveLock()) {
104: Object[] po = (Object[]) getPeerObject();
105: if (po == null)
106: return;
107: po[index] = null;
108: setReference(String.valueOf(index), id);
109: }
110: }
111:
112: public void clearReference(String fieldName) {
113: synchronized (getResolveLock()) {
114: if (hasReferences()) {
115: removeReference(fieldName);
116: }
117: }
118: }
119:
120: public final void resolveReference(String fieldName) {
121: synchronized (getResolveLock()) {
122: this .markAccessed();
123: if (!hasReferences())
124: return;
125:
126: Object po = getPeerObject();
127: TCClass tcClass = getTCClass();
128: Assert.eval(tcClass != null);
129: TCField field = tcClass.getField(fieldName);
130: if (!field.canBeReference()) {
131: return;
132: }
133:
134: ObjectID id = (ObjectID) getReferences().get(fieldName);
135: // Already resolved
136: if (id == null) {
137: return;
138: }
139:
140: Object setObject = null;
141: if (id != null && !id.isNull()) {
142: try {
143: setObject = getObjectManager().lookupObject(id);
144: } catch (ClassNotFoundException e) {
145: throw new TCClassNotFoundException(e);
146: }
147: }
148: removeReference(fieldName);
149: ((TransparentAccess) po).__tc_setfield(field.getName(),
150: setObject);
151: }
152: }
153:
154: public void logicalInvoke(int method, String methodSignature,
155: Object[] params) {
156: throw new UnsupportedOperationException();
157: }
158:
159: public void literalValueChanged(Object newValue, Object oldValue) {
160: getObjectManager().getTransactionManager().literalValueChanged(
161: this , newValue, oldValue);
162: setPeerObject(new WeakObjectReference(getObjectID(), newValue,
163: getObjectManager().getReferenceQueue()));
164: }
165:
166: /**
167: * Unlike literalValueChange, this method is not synchronized on getResolveLock() because this method is called by the
168: * applicator thread which has been synchronized on getResolveLock() in TCObjectImpl.hydrate().
169: */
170: public void setLiteralValue(Object newValue) {
171: setPeerObject(new WeakObjectReference(getObjectID(), newValue,
172: getObjectManager().getReferenceQueue()));
173: }
174:
175: protected boolean isEvictable() {
176: return true;
177: }
178:
179: protected int clearReferences(Object pojo, int toClear) {
180: if (tcClazz.isIndexed()) {
181: if (ClassUtils.isPrimitiveArray(pojo))
182: return 0;
183: return clearArrayReferences((Object[]) pojo);
184: } else if (pojo instanceof TransparentAccess) {
185: return clearObjectReferences((TransparentAccess) pojo);
186: } else {
187: return 0;
188: }
189: }
190:
191: private int clearArrayReferences(Object[] array) {
192: int cleared = 0;
193: int l = array.length;
194: for (int i = 0; i < l; i++) {
195: Object o = array[i];
196: if (o == null)
197: continue;
198: if (getObjectManager().isManaged(o)) {
199: ObjectID lid = getObjectManager()
200: .lookupExistingObjectID(o);
201: ObjectID old = setReference(Integer.toString(i), lid);
202: if (old != null && !lid.equals(old)) {
203: // Formatting
204: throw new AssertionError(
205: "clearArrayReferences : mapped ["
206: + i
207: + "] to "
208: + lid
209: + " while there was an exisiting mapping in references : "
210: + old + " : TCObject = "
211: + getObjectID() + " : " + this
212: + " version = " + this .getVersion());
213: }
214: array[i] = null;
215: cleared++;
216: }
217: }
218: return cleared;
219: }
220:
221: private int clearObjectReferences(TransparentAccess ta) {
222: TCField[] fields = tcClazz.getPortableFields();
223: if (fields.length == 0) {
224: return 0;
225: }
226: Map fieldValues = null;
227: int cleared = 0;
228: for (int i = 0; i < fields.length; i++) {
229: TCField field = fields[i];
230: if (field.isFinal() || !field.canBeReference())
231: continue;
232: if (fieldValues == null) {
233: // lazy instantiation. TODO:: Add a new method in TransparentAccess __tc_getFieldNoResolve()
234: fieldValues = new HashMap();
235: ta.__tc_getallfields(fieldValues);
236: }
237: Object obj = fieldValues.get(field.getName());
238: if (obj == null)
239: continue;
240: TCObject tobj = getObjectManager()
241: .lookupExistingOrNull(obj);
242: if (tobj != null) {
243: ObjectID lid = tobj.getObjectID();
244: setValue(field.getName(), lid);
245: cleared++;
246: }
247: }
248: return cleared;
249: }
250: }
|