001: /*
002: Copyright (C) 2007 Mobixess Inc. http://www.java-objects-database.com
003:
004: This file is part of the JODB (Java Objects Database) open source project.
005:
006: JODB is free software; you can redistribute it and/or modify it under
007: the terms of version 2 of the GNU General Public License as published
008: by the Free Software Foundation.
009:
010: JODB is distributed in the hope that it will be useful, but WITHOUT ANY
011: WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
013: for more details.
014:
015: You should have received a copy of the GNU General Public License along
016: with this program; if not, write to the Free Software Foundation, Inc.,
017: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package com.mobixess.jodb.core.transaction;
020:
021: import java.io.IOException;
022: import java.lang.reflect.Array;
023: import java.lang.reflect.Field;
024: import java.util.BitSet;
025:
026: import com.mobixess.jodb.core.IllegalClassTypeException;
027: import com.mobixess.jodb.core.JodbIOException;
028: import com.mobixess.jodb.core.JODBConstants.COMPARE_RESULT;
029: import com.mobixess.jodb.core.io.IOBase;
030: import com.mobixess.jodb.core.io.JODBOperationContext;
031: import com.mobixess.jodb.core.io.ObjectDataContainer;
032: import com.mobixess.jodb.core.io.ObjectDataContainer.FieldRecord;
033: import com.mobixess.jodb.core.io.ObjectDataContainer.FieldsIterator;
034: import com.mobixess.jodb.core.plugin.IClassProcessor;
035: import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
036: import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
037: import com.mobixess.jodb.core.transaction.TransactionUtils.DataContainersCache;
038: import com.mobixess.jodb.util.ArrayUtils;
039: import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
040: import com.mobixess.jodb.util.PrimitiveJavaTypesUtil.PRIMITIVES_ENUMERATION;
041:
042: public class BaseProcessor implements IClassProcessor {
043:
044: public COMPARE_RESULT compare(Object value1, Object value2,
045: JODBOperationContext context, Field[] fieldsToIgnore) {
046: if (equals(value1, value2, context, fieldsToIgnore)) {
047: return COMPARE_RESULT.EQUAL;
048: }
049: return COMPARE_RESULT.UNKNOWN;
050: }
051:
052: public COMPARE_RESULT compare(Object value1,
053: ObjectDataContainer value2, JODBOperationContext context,
054: Field[] fieldsToIgnore) throws IOException {
055: if (equals(value1, value2, context, fieldsToIgnore)) {
056: return COMPARE_RESULT.EQUAL;
057: }
058: return COMPARE_RESULT.UNKNOWN;
059: }
060:
061: public Object composeInstance(Class type,
062: ObjectDataContainer persistentDataContainer,
063: JODBSession session) throws IOException {
064: ClassDescriptor classDescriptor;
065: try {
066: classDescriptor = session.getDescriptorForClass(type);
067: } catch (IllegalClassTypeException e) {
068: return null;
069: }
070:
071: if (persistentDataContainer.isArray()) {
072: return Array.newInstance(type, persistentDataContainer
073: .getActiveFieldsIterator()
074: .getRemainingInCurrentCategory());
075: } else {
076: return classDescriptor.newInstance();
077: }
078: }
079:
080: public boolean equals(Object value1, Object value2,
081: JODBOperationContext context, Field[] fieldsToIgnore) {
082: if (value1 == value2) {
083: return true;
084: }
085: if (value1 == null || value2 == null) {
086: return false;
087: }
088: if (value1.getClass() != value2.getClass()) {
089: return false;
090: }
091: if (value1.getClass().isArray()) {
092: return arraysAreEqual(value1, value2, context,
093: fieldsToIgnore);
094: } else {
095: return objectsAreEqual(value1, value2, context,
096: fieldsToIgnore);
097: }
098: }
099:
100: private boolean objectsAreEqual(Object value1, Object value2,
101: JODBOperationContext context, Field[] fieldsToIgnore) {
102: ClassDescriptor classDescriptor;
103: try {
104: classDescriptor = context.getSession()
105: .getDescriptorForClass(value1.getClass());
106: } catch (IllegalClassTypeException e) {
107: e.printStackTrace();
108: return false;
109: }
110: FieldAndIDRecord[] fields = classDescriptor.getFields();
111: for (int i = 0; i < fields.length; i++) {
112: Field field = fields[i]._field;
113: if (ArrayUtils.indexOf(fieldsToIgnore, field) != -1) {
114: continue;
115: }
116: try {
117: Object val1 = field.get(value1);
118: Object val2 = field.get(value2);
119: if (val1 == val2
120: || (field.getType().isPrimitive() && val1
121: .equals(val2))) {
122: continue;
123: }
124: if (val1 != null && (val1.getClass() == String.class)
125: && val1.equals(val2)) {
126: continue;
127: }
128: } catch (Exception e) {
129: e.printStackTrace();
130: }
131: return false;
132: }
133:
134: return true;
135: }
136:
137: public boolean arraysAreEqual(Object value1, Object value2,
138: JODBOperationContext context, Field[] fieldsToIgnore) {
139: int size1 = Array.getLength(value1);
140: int size2 = Array.getLength(value2);
141: if (size1 != size2) {
142: return false;
143: }
144: boolean isPrimitive = value1.getClass().getComponentType()
145: .isPrimitive();
146: for (int i = 0; i < size1; i++) {
147: Object val1 = Array.get(value1, i);
148: Object val2 = Array.get(value2, i);
149: if (isPrimitive) {
150: if (!val1.equals(val2)) {
151: return false;
152: }
153: } else {
154: if (val1 != val2) {
155: return false;
156: }
157: }
158: }
159: return false;
160: }
161:
162: public boolean equals(Object value1, ObjectDataContainer value2,
163: JODBOperationContext context, Field[] fieldsToIgnore)
164: throws IOException {
165: ClassDescriptor desc;
166: try {
167: desc = context.getSession().getDescriptorForClass(
168: value1.getClass());
169: if (desc.isArray()) {
170: return checkActiveArrayObjectUnchanged(context, value1,
171: value2, desc);
172: }
173: } catch (IllegalClassTypeException e) {
174: e.printStackTrace();
175: throw new JodbIOException(e);
176: }
177: return equalToPersistentCopy(context, value1, value2, desc,
178: fieldsToIgnore);
179: }
180:
181: public Object translate(Object objectToTranslate) {
182: return objectToTranslate;
183: }
184:
185: public Class getType() {
186: return Object.class;
187: }
188:
189: public void activate(Object incompleteInstance,
190: ObjectDataContainer persistentDataContainer,
191: JODBSession session, int activationDepth,
192: boolean delayedActivation) throws IOException {
193: if (persistentDataContainer.isArray()) {
194: fillArray(session, delayedActivation,
195: persistentDataContainer, incompleteInstance,
196: activationDepth);
197: } else {
198: fillObject(session, delayedActivation,
199: persistentDataContainer, incompleteInstance,
200: activationDepth);
201: }
202: }
203:
204: private static void fillObject(JODBSession session,
205: boolean delayedActivation,
206: ObjectDataContainer objectDataContainer, Object instance,
207: int remainingDepth) throws IOException {
208: ClassDescriptor classDescriptor;
209: try {
210: classDescriptor = session.getDescriptorForClass(instance
211: .getClass());
212: } catch (IllegalClassTypeException e1) {
213: e1.printStackTrace();
214: throw new JodbIOException(e1);
215: }
216: IOBase base = session.getBase();
217: FieldsIterator fieldsIterator = objectDataContainer
218: .getActiveFieldsIterator();
219: if (fieldsIterator == null) {
220: return;
221: }
222: BitSet processedFieldMask = new BitSet();
223: FieldRecord record = objectDataContainer.getRecordCache();
224: for (int i = 0; fieldsIterator.hasNext(); i++) {
225: fieldsIterator.next(record, base);
226: Field field = classDescriptor.getFieldForID(
227: record._fieldID, processedFieldMask);
228: if (field == null) {
229: continue;
230: }
231: if (field.getType().isPrimitive() && !delayedActivation) {
232: try {
233: field.set(instance, record._value);
234: } catch (Exception e) {
235: setDefaultValue(instance, field);
236: //TODO add debug level output
237: }
238: continue;
239: }
240: if (remainingDepth < 1) {
241: continue;
242: }
243: Object child = TransactionUtils.launchObject(session,
244: record._objectOffset, null, remainingDepth - 1);
245: try {
246: field.set(instance, child);
247: } catch (Exception e) {
248: setDefaultValue(instance, field);
249: //TODO add debug level output
250: continue;
251: }
252: }
253: if (!delayedActivation) {
254: FieldAndIDRecord[] fields = classDescriptor.getFields();
255: for (int i = 0; i < fields.length; i++) {//set default values for remaining fields
256: if (processedFieldMask.get(i)) {
257: continue;
258: }
259: setDefaultValue(instance, fields[i]._field);
260: }
261: }
262: }
263:
264: private static void fillArray(JODBSession session,
265: boolean activation,
266: ObjectDataContainer objectDataContainer, Object instance,
267: int remainingDepth) throws IOException {
268: IOBase base = session.getBase();
269: FieldsIterator fieldsIterator = objectDataContainer
270: .getActiveFieldsIterator();
271: if (fieldsIterator == null) {
272: return;
273: }
274: FieldRecord record = objectDataContainer.getRecordCache();
275: ClassDescriptor arrayTypeDescriptor;
276: try {
277: arrayTypeDescriptor = session
278: .getDescriptorForClass(instance.getClass()
279: .getComponentType());
280: } catch (IllegalClassTypeException e) {
281: e.printStackTrace();
282: throw new JodbIOException(e);
283: }
284: if (arrayTypeDescriptor.isPrimitive()) {
285: for (int i = 0; fieldsIterator.hasNext(); i++) {
286: fieldsIterator.next(record, base);
287: Array.set(instance, i, record._value);
288: }
289: } else {
290: for (int i = 0; fieldsIterator.hasNext(); i++) {
291: fieldsIterator.next(record, base);
292: Object child = TransactionUtils.launchObject(session,
293: record._objectOffset, null, remainingDepth - 1);
294: Array.set(instance, i, child);
295: }
296: }
297: }
298:
299: private static void setDefaultValue(Object obj, Field field) {
300: try {
301: Class type = field.getType();
302: if (type.isPrimitive()) {
303: Object value = PrimitiveJavaTypesUtil
304: .getDefaultWrapperInstance(type.getName());
305: field.set(obj, value);
306: } else {
307: field.set(obj, null);
308: }
309: } catch (Exception e) {
310: //TODO print for debug?
311: }
312: }
313:
314: private static boolean equalToPersistentCopy(
315: JODBOperationContext context, Object currentObject,
316: ObjectDataContainer persistentCopyObjectDataContainer,
317: ClassDescriptor desc, Field[] fieldsToIgnore)
318: throws IOException {
319: //Field[] fields = desc.getFields();
320: JODBSession session = context.getSession();
321: //int[] fieldsIDs = desc.getFieldsSubstitutionIDs();
322: //boolean[] processedFields = new boolean[fieldsIDs.length];
323: FieldRecord fieldRecord = persistentCopyObjectDataContainer
324: .getRecordCache();
325: FieldsIterator fieldsIterator = persistentCopyObjectDataContainer
326: .getActiveFieldsIterator();
327: if (fieldsIterator == null) {
328: return false;
329: }
330: while (fieldsIterator.hasNext()) {
331: fieldsIterator.next(fieldRecord, context.getBase(), false);
332: // int index = ArrayUtils.indexOf(fieldsIDs, fieldRecord._fieldID);
333: // if(index == -1){
334: // continue;//TODO the field is not exist anymore, should it indicate as "not equal" ?
335: // }
336: Field field = desc
337: .getFieldForID(fieldRecord._fieldID, null);
338: if (field == null) {
339: continue;//TODO the field is not exist anymore, should it indicate as "not equal" ?
340: }
341: // if( fieldsToIgnore!=null && ArrayUtils.indexOf(fieldsToIgnore, field)!=-1){
342: // processedFields[index] = true;
343: // continue;
344: // }
345: Object value;
346: try {
347: value = field.get(currentObject);
348: } catch (Exception e) {
349: throw new JodbIOException(e);
350: }
351: if (field.getType().isPrimitive()) {
352: if (PrimitiveJavaTypesUtil.comparePrimitives(value,
353: fieldRecord._primitiveRawDataBuffer) != 0) {
354: return false;
355: }
356: } else {
357: if (value == null) {//if object under the persistent offset is delete than we continue itteration
358: if (fieldRecord._objectOffset != 0) {
359: DataContainersCache dataContainersCache = TransactionUtils
360: .getObjectDataContainerCache();
361: ObjectDataContainer referencedObjectDataContainer = dataContainersCache
362: .pullObjectDataContainer();
363: try {
364: referencedObjectDataContainer.readHeader(
365: context.getIoTicket()
366: .getRandomAccessBuffer(),
367: fieldRecord._objectOffset, true);
368: if (!referencedObjectDataContainer
369: .isDeleted()) {
370: return false;
371: }
372: } finally {
373: dataContainersCache
374: .pushObjectDataContainer(referencedObjectDataContainer);
375: }
376: }
377: } else {
378: PersistentObjectHandle objectHandle = session
379: .getHandleForActiveObject(value);
380: if (objectHandle == null
381: || objectHandle.getObjectEntryOffset() != fieldRecord._objectOffset) {
382: return false;
383: }
384: }
385: }
386: //processedFields[index] = true;
387: }
388:
389: // TODO commented because iterrator now guarantee iterration through all field
390: // for (int i = 0; i < fieldsIDs.length; i++) {//cheking if remaining not found fields have default values
391: // if(fieldsIDs[i]==-1||processedFields[i]){
392: // continue;
393: // }
394: // Field field = fields[i];
395: // if(field.getType().isPrimitive()){
396: // if(!Utils.primitiveEquals(field, currentObject, 0)){
397: // return false;
398: // }
399: // }else{
400: // Object value;
401: // try {
402: // value = field.get(currentObject);
403: // } catch (Exception e) {
404: // e.printStackTrace();
405: // throw new IOException(e.getMessage());
406: // }
407: // if(value!=null){
408: // return false;
409: // }
410: // }
411: // }
412: return true;
413: }
414:
415: private static boolean checkActiveArrayObjectUnchanged(
416: JODBOperationContext context, Object array,
417: ObjectDataContainer objectDataContainer,
418: ClassDescriptor classDescriptor) throws IOException,
419: IllegalClassTypeException {
420: //TODO make size estimation here?
421: int arraySize = Array.getLength(array);
422: FieldsIterator fieldsIterator = objectDataContainer
423: .getActiveFieldsIterator();
424: if (fieldsIterator == null) {
425: return false;//TODO add warning?
426: }
427: if (arraySize != fieldsIterator.getRemainingInCurrentCategory()) {
428: return true;
429: }
430: IOBase base = context.getBase();
431: JODBSession session = context.getSession();
432: FieldRecord fieldRecord = objectDataContainer.getRecordCache();
433: if (!classDescriptor.getArrayType().isPrimitive()) {
434: for (int i = 0; i < arraySize; i++) {
435: fieldsIterator.next(fieldRecord, base);
436: Object value = Array.get(array, i);
437: if (value == null) {
438: if (fieldRecord._objectOffset != 0) {
439: return false;
440: }
441: continue;
442: }
443: PersistentObjectHandle handle = session
444: .getHandleForActiveObject(value);
445: if (handle == null
446: || handle.getObjectEntryOffset() != fieldRecord._objectOffset) {
447: return false;
448: }
449: }
450: } else {
451: PRIMITIVES_ENUMERATION enumeratedPrimitiveType = PrimitiveJavaTypesUtil
452: .getEnumeratedType(classDescriptor.getArrayType()
453: .getName());
454: for (int i = 0; i < arraySize; i++) {
455: fieldsIterator.next(fieldRecord, base, false);
456: Object value = Array.get(array, i);
457: if (PrimitiveJavaTypesUtil.comparePrimitives(value,
458: enumeratedPrimitiveType,
459: fieldRecord._primitiveRawDataBuffer) != 0) {
460: return false;
461: }
462: }
463: }
464: return true;
465: }
466: }
|