0001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
0002:
0003: This file is part of the db4o open source object database.
0004:
0005: db4o is free software; you can redistribute it and/or modify it under
0006: the terms of version 2 of the GNU General Public License as published
0007: by the Free Software Foundation and as clarified by db4objects' GPL
0008: interpretation policy, available at
0009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
0010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
0011: Suite 350, San Mateo, CA 94403, USA.
0012:
0013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
0014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: for more details.
0017:
0018: You should have received a copy of the GNU General Public License along
0019: with this program; if not, write to the Free Software Foundation, Inc.,
0020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
0021: package com.db4o.internal;
0022:
0023: import java.io.IOException;
0024:
0025: import com.db4o.*;
0026: import com.db4o.config.*;
0027: import com.db4o.ext.*;
0028: import com.db4o.foundation.*;
0029: import com.db4o.internal.classindex.*;
0030: import com.db4o.internal.diagnostic.*;
0031: import com.db4o.internal.handlers.*;
0032: import com.db4o.internal.marshall.*;
0033: import com.db4o.internal.query.processor.*;
0034: import com.db4o.internal.slots.*;
0035: import com.db4o.marshall.*;
0036: import com.db4o.query.*;
0037: import com.db4o.reflect.*;
0038: import com.db4o.reflect.generic.*;
0039:
0040: /**
0041: * @exclude
0042: */
0043: public class ClassMetadata extends PersistentBase implements
0044: IndexableTypeHandler, FirstClassHandler, StoredClass {
0045:
0046: public ClassMetadata i_ancestor;
0047:
0048: private Config4Class i_config;
0049: public int _metaClassID;
0050:
0051: public FieldMetadata[] i_fields;
0052:
0053: private final ClassIndexStrategy _index;
0054:
0055: protected String i_name;
0056:
0057: private final ObjectContainerBase _container;
0058:
0059: byte[] i_nameBytes;
0060: private Buffer i_reader;
0061:
0062: private boolean _classIndexed;
0063:
0064: private ReflectClass _reflector;
0065:
0066: private boolean _isEnum;
0067:
0068: private EventDispatcher _eventDispatcher;
0069:
0070: private boolean _internal;
0071:
0072: private boolean _unversioned;
0073:
0074: // for indexing purposes.
0075: // TODO: check race conditions, upon multiple calls against the same class
0076: private int i_lastID;
0077:
0078: private TernaryBool _canUpdateFast = TernaryBool.UNSPECIFIED;
0079:
0080: public final ObjectContainerBase stream() {
0081: return _container;
0082: }
0083:
0084: public final boolean canUpdateFast() {
0085: return _canUpdateFast.booleanValue(checkCanUpdateFast());
0086: }
0087:
0088: private final boolean checkCanUpdateFast() {
0089: if (i_ancestor != null && !i_ancestor.canUpdateFast()) {
0090: return false;
0091: }
0092: if (i_config != null
0093: && i_config.cascadeOnDelete() == TernaryBool.YES) {
0094: return false;
0095: }
0096: for (int i = 0; i < i_fields.length; ++i) {
0097: if (i_fields[i].hasIndex()) {
0098: return false;
0099: }
0100: }
0101: return true;
0102: }
0103:
0104: boolean isInternal() {
0105: return _internal;
0106: }
0107:
0108: private ClassIndexStrategy createIndexStrategy() {
0109: return new BTreeClassIndexStrategy(this );
0110: }
0111:
0112: ClassMetadata(ObjectContainerBase container, ReflectClass reflector) {
0113: _container = container;
0114: _reflector = reflector;
0115: _index = createIndexStrategy();
0116: _classIndexed = true;
0117: }
0118:
0119: void activateFields(Transaction trans, Object obj, int depth) {
0120: if (objectCanActivate(trans, obj)) {
0121: activateFieldsLoop(trans, obj, depth);
0122: }
0123: }
0124:
0125: private final void activateFieldsLoop(Transaction trans,
0126: Object obj, int depth) {
0127: for (int i = 0; i < i_fields.length; i++) {
0128: i_fields[i].cascadeActivation(trans, obj, depth, true);
0129: }
0130: if (i_ancestor != null) {
0131: i_ancestor.activateFieldsLoop(trans, obj, depth);
0132: }
0133: }
0134:
0135: public final void addFieldIndices(StatefulBuffer a_writer,
0136: Slot oldSlot) {
0137: if (hasClassIndex() || hasVirtualAttributes()) {
0138: ObjectHeader oh = new ObjectHeader(_container, this ,
0139: a_writer);
0140: oh._marshallerFamily._object.addFieldIndices(this ,
0141: oh._headerAttributes, a_writer, oldSlot);
0142: }
0143: }
0144:
0145: void addMembers(ObjectContainerBase container) {
0146: bitTrue(Const4.CHECKED_CHANGES);
0147: if (installTranslator(container)) {
0148: return;
0149: }
0150:
0151: if (container.detectSchemaChanges()) {
0152: boolean dirty = isDirty();
0153:
0154: Collection4 members = new Collection4();
0155:
0156: if (null != i_fields) {
0157: members.addAll(i_fields);
0158: if (i_fields.length == 1
0159: && i_fields[0] instanceof TranslatedFieldMetadata) {
0160: setStateOK();
0161: return;
0162: }
0163: }
0164: if (generateVersionNumbers()) {
0165: if (!hasVersionField()) {
0166: members.add(container.versionIndex());
0167: dirty = true;
0168: }
0169: }
0170: if (generateUUIDs()) {
0171: if (!hasUUIDField()) {
0172: members.add(container.uUIDIndex());
0173: dirty = true;
0174: }
0175: }
0176: dirty = collectReflectFields(container, members) | dirty;
0177: if (dirty) {
0178: _container.setDirtyInSystemTransaction(this );
0179: i_fields = new FieldMetadata[members.size()];
0180: members.toArray(i_fields);
0181: for (int i = 0; i < i_fields.length; i++) {
0182: i_fields[i].setArrayPosition(i);
0183: }
0184: } else {
0185: if (members.size() == 0) {
0186: i_fields = new FieldMetadata[0];
0187: }
0188: }
0189:
0190: DiagnosticProcessor dp = _container._handlers._diagnosticProcessor;
0191: if (dp.enabled()) {
0192: dp.checkClassHasFields(this );
0193: }
0194:
0195: } else {
0196: if (i_fields == null) {
0197: i_fields = new FieldMetadata[0];
0198: }
0199: }
0200: _container.callbacks().classOnRegistered(this );
0201: setStateOK();
0202: }
0203:
0204: private boolean collectReflectFields(ObjectContainerBase container,
0205: Collection4 collectedFields) {
0206: boolean dirty = false;
0207: ReflectField[] fields = reflectFields();
0208: for (int i = 0; i < fields.length; i++) {
0209: if (storeField(fields[i])) {
0210: ClassMetadata fieldClassMetadata = container._handlers
0211: .classMetadataForClass(container, fields[i]
0212: .getFieldType());
0213: if (fieldClassMetadata == null) {
0214: continue;
0215: }
0216: TypeHandler4 handler = fieldClassMetadata.typeHandler();
0217: FieldMetadata field = new FieldMetadata(this ,
0218: fields[i], handler, fieldClassMetadata.getID());
0219: boolean found = false;
0220: Iterator4 m = collectedFields.iterator();
0221: while (m.moveNext()) {
0222: if (((FieldMetadata) m.current()).equals(field)) {
0223: found = true;
0224: break;
0225: }
0226: }
0227: if (found) {
0228: continue;
0229: }
0230: dirty = true;
0231: collectedFields.add(field);
0232: }
0233: }
0234: return dirty;
0235: }
0236:
0237: private boolean installTranslator(ObjectContainerBase ocb) {
0238: ObjectTranslator ot = getTranslator();
0239: if (ot == null) {
0240: return false;
0241: }
0242: if (isNewTranslator(ot)) {
0243: _container.setDirtyInSystemTransaction(this );
0244: }
0245: installCustomFieldMetadata(ocb, new TranslatedFieldMetadata(
0246: this , ot));
0247: return true;
0248: }
0249:
0250: private void installCustomFieldMetadata(ObjectContainerBase ocb,
0251: FieldMetadata customFieldMetadata) {
0252: int fieldCount = 1;
0253:
0254: boolean versions = generateVersionNumbers()
0255: && !ancestorHasVersionField();
0256: boolean uuids = generateUUIDs() && !ancestorHasUUIDField();
0257:
0258: if (versions) {
0259: fieldCount = 2;
0260: }
0261:
0262: if (uuids) {
0263: fieldCount = 3;
0264: }
0265:
0266: i_fields = new FieldMetadata[fieldCount];
0267:
0268: i_fields[0] = customFieldMetadata;
0269:
0270: // Some explanation on the thoughts here:
0271:
0272: // Since i_fields for the translator are generated every time,
0273: // we want to make sure that the order of fields is consistent.
0274:
0275: // Therefore it's easier to implement with fixed index places in
0276: // the i_fields array:
0277:
0278: // [0] is the translator
0279: // [1] is the version
0280: // [2] is the UUID
0281:
0282: if (versions || uuids) {
0283:
0284: // We don't want to have a null field, so let's add the version
0285: // number, if we have a UUID, even if it's not needed.
0286:
0287: i_fields[1] = ocb.versionIndex();
0288: }
0289:
0290: if (uuids) {
0291: i_fields[2] = ocb.uUIDIndex();
0292: }
0293:
0294: setStateOK();
0295: }
0296:
0297: private ObjectTranslator getTranslator() {
0298: return i_config == null ? null : i_config.getTranslator();
0299: }
0300:
0301: private boolean isNewTranslator(ObjectTranslator ot) {
0302: return !hasFields()
0303: || !ot.getClass().getName().equals(
0304: i_fields[0].getName());
0305: }
0306:
0307: private boolean hasFields() {
0308: return i_fields != null && i_fields.length > 0;
0309: }
0310:
0311: void addToIndex(LocalObjectContainer a_stream, Transaction a_trans,
0312: int a_id) {
0313: if (a_stream.maintainsIndices()) {
0314: addToIndex1(a_stream, a_trans, a_id);
0315: }
0316: }
0317:
0318: void addToIndex1(LocalObjectContainer a_stream,
0319: Transaction a_trans, int a_id) {
0320: if (i_ancestor != null) {
0321: i_ancestor.addToIndex1(a_stream, a_trans, a_id);
0322: }
0323: if (hasClassIndex()) {
0324: _index.add(a_trans, a_id);
0325: }
0326: }
0327:
0328: boolean allowsQueries() {
0329: return hasClassIndex();
0330: }
0331:
0332: public void cascadeActivation(Transaction a_trans, Object a_object,
0333: int a_depth, boolean a_activate) {
0334: Config4Class config = configOrAncestorConfig();
0335: if (config != null) {
0336: if (a_activate) {
0337: a_depth = config.adjustActivationDepth(a_depth);
0338: }
0339: }
0340: if (a_depth > 0) {
0341: ObjectContainerBase stream = a_trans.container();
0342: if (a_activate) {
0343: if (isValueType()) {
0344: activateFields(a_trans, a_object, a_depth - 1);
0345: } else {
0346: stream.stillToActivate(a_trans, a_object,
0347: a_depth - 1);
0348: }
0349: } else {
0350: stream.stillToDeactivate(a_trans, a_object,
0351: a_depth - 1, false);
0352: }
0353: }
0354: }
0355:
0356: void checkChanges() {
0357: if (stateOK()) {
0358: if (!bitIsTrue(Const4.CHECKED_CHANGES)) {
0359: bitTrue(Const4.CHECKED_CHANGES);
0360: if (i_ancestor != null) {
0361: i_ancestor.checkChanges();
0362: // Ancestor first, so the object length calculates
0363: // correctly
0364: }
0365: if (_reflector != null) {
0366: addMembers(_container);
0367: if (!_container.isClient()) {
0368: write(_container.systemTransaction());
0369: }
0370: }
0371: }
0372: }
0373: }
0374:
0375: public void checkType() {
0376: ReflectClass claxx = classReflector();
0377: if (claxx == null) {
0378: return;
0379: }
0380: if (_container._handlers.ICLASS_INTERNAL
0381: .isAssignableFrom(claxx)) {
0382: _internal = true;
0383: }
0384: if (_container._handlers.ICLASS_UNVERSIONED
0385: .isAssignableFrom(claxx)) {
0386: _unversioned = true;
0387: }
0388: if (_container._handlers.ICLASS_DB4OTYPEIMPL
0389: .isAssignableFrom(claxx)) {
0390: Db4oTypeImpl db4oTypeImpl = (Db4oTypeImpl) claxx
0391: .newInstance();
0392: _classIndexed = (db4oTypeImpl == null || db4oTypeImpl
0393: .hasClassIndex());
0394: } else if (i_config != null) {
0395: _classIndexed = i_config.indexed();
0396: }
0397: }
0398:
0399: public final int adjustUpdateDepth(Transaction trans, int depth) {
0400: Config4Class config = configOrAncestorConfig();
0401: if (depth == Const4.UNSPECIFIED) {
0402: depth = checkUpdateDepthUnspecified(trans.container()
0403: .configImpl());
0404: if (classReflector().isCollection()) {
0405: depth = adjustDepthToBorders(depth);
0406: }
0407: }
0408: if (config == null) {
0409: return depth - 1;
0410: }
0411: boolean cascadeOnDelete = config.cascadeOnDelete() == TernaryBool.YES;
0412: boolean cascadeOnUpdate = config.cascadeOnUpdate() == TernaryBool.YES;
0413:
0414: if (cascadeOnDelete || cascadeOnUpdate) {
0415: depth = adjustDepthToBorders(depth);
0416: }
0417: return depth - 1;
0418: }
0419:
0420: private int adjustDepthToBorders(int depth) {
0421: int depthBorder = reflector().collectionUpdateDepth(
0422: classReflector());
0423: if (depth > Integer.MIN_VALUE && depth < depthBorder) {
0424: depth = depthBorder;
0425: }
0426: return depth;
0427: }
0428:
0429: private final int checkUpdateDepthUnspecified(Config4Impl config) {
0430: int depth = config.updateDepth() + 1;
0431: if (i_config != null && i_config.updateDepth() != 0) {
0432: depth = i_config.updateDepth() + 1;
0433: }
0434: if (i_ancestor != null) {
0435: int ancestordepth = i_ancestor
0436: .checkUpdateDepthUnspecified(config);
0437: if (ancestordepth > depth) {
0438: return ancestordepth;
0439: }
0440: }
0441: return depth;
0442: }
0443:
0444: public void collectConstraints(Transaction a_trans,
0445: QConObject a_parent, Object a_object, Visitor4 a_visitor) {
0446: if (i_fields != null) {
0447: for (int i = 0; i < i_fields.length; i++) {
0448: i_fields[i].collectConstraints(a_trans, a_parent,
0449: a_object, a_visitor);
0450: }
0451: }
0452: if (i_ancestor != null) {
0453: i_ancestor.collectConstraints(a_trans, a_parent, a_object,
0454: a_visitor);
0455: }
0456: }
0457:
0458: public final TreeInt collectFieldIDs(MarshallerFamily mf,
0459: ObjectHeaderAttributes attributes, TreeInt tree,
0460: StatefulBuffer a_bytes, String name) {
0461: return mf._object.collectFieldIDs(tree, this , attributes,
0462: a_bytes, name);
0463: }
0464:
0465: public boolean customizedNewInstance() {
0466: return configInstantiates();
0467: }
0468:
0469: public Config4Class config() {
0470: return i_config;
0471: }
0472:
0473: public Config4Class configOrAncestorConfig() {
0474: if (i_config != null) {
0475: return i_config;
0476: }
0477: if (i_ancestor != null) {
0478: return i_ancestor.configOrAncestorConfig();
0479: }
0480: return null;
0481: }
0482:
0483: private boolean createConstructor(ObjectContainerBase container,
0484: String className) {
0485: ReflectClass claxx = container.reflector().forName(className);
0486: return createConstructor(container, claxx, className, true);
0487: }
0488:
0489: public boolean createConstructor(ObjectContainerBase a_stream,
0490: ReflectClass a_class, String a_name, boolean errMessages) {
0491:
0492: _reflector = a_class;
0493:
0494: _eventDispatcher = EventDispatcher.forClass(a_stream, a_class);
0495:
0496: if (!Deploy.csharp) {
0497: if (a_class != null) {
0498: _isEnum = Platform4.jdk().isEnum(reflector(), a_class);
0499: }
0500: }
0501:
0502: if (customizedNewInstance()) {
0503: return true;
0504: }
0505:
0506: if (a_class != null) {
0507: if (a_stream._handlers.ICLASS_TRANSIENTCLASS
0508: .isAssignableFrom(a_class)
0509: || Platform4.isTransient(a_class)) {
0510: a_class = null;
0511: }
0512: }
0513: if (a_class == null) {
0514: if (a_name == null || !Platform4.isDb4oClass(a_name)) {
0515: if (errMessages) {
0516: a_stream.logMsg(23, a_name);
0517: }
0518: }
0519: setStateDead();
0520: return false;
0521: }
0522:
0523: if (a_stream._handlers.createConstructor(a_class,
0524: !callConstructor())) {
0525: return true;
0526: }
0527:
0528: setStateDead();
0529: if (errMessages) {
0530: a_stream.logMsg(7, a_name);
0531: }
0532:
0533: if (a_stream.configImpl().exceptionsOnNotStorable()) {
0534: throw new ObjectNotStorableException(a_class);
0535: }
0536:
0537: return false;
0538:
0539: }
0540:
0541: public void deactivate(Transaction trans, Object obj, int depth) {
0542: if (objectCanDeactivate(trans, obj)) {
0543: deactivate1(trans, obj, depth);
0544: objectOnDeactivate(trans, obj);
0545: }
0546: }
0547:
0548: private void objectOnDeactivate(Transaction transaction, Object obj) {
0549: ObjectContainerBase container = transaction.container();
0550: container.callbacks().objectOnDeactivate(transaction, obj);
0551: dispatchEvent(container, obj, EventDispatcher.DEACTIVATE);
0552: }
0553:
0554: private boolean objectCanDeactivate(Transaction transaction,
0555: Object obj) {
0556: ObjectContainerBase container = transaction.container();
0557: return container.callbacks().objectCanDeactivate(transaction,
0558: obj)
0559: && dispatchEvent(container, obj,
0560: EventDispatcher.CAN_DEACTIVATE);
0561: }
0562:
0563: void deactivate1(Transaction a_trans, Object a_object, int a_depth) {
0564:
0565: for (int i = 0; i < i_fields.length; i++) {
0566: i_fields[i].deactivate(a_trans, a_object, a_depth);
0567: }
0568: if (i_ancestor != null) {
0569: i_ancestor.deactivate1(a_trans, a_object, a_depth);
0570: }
0571: }
0572:
0573: final void delete(StatefulBuffer a_bytes, Object a_object) {
0574: ObjectHeader oh = new ObjectHeader(_container, this , a_bytes);
0575: delete1(oh._marshallerFamily, oh._headerAttributes, a_bytes,
0576: a_object);
0577: }
0578:
0579: private final void delete1(MarshallerFamily mf,
0580: ObjectHeaderAttributes attributes, StatefulBuffer a_bytes,
0581: Object a_object) {
0582: removeFromIndex(a_bytes.getTransaction(), a_bytes.getID());
0583: deleteMembers(mf, attributes, a_bytes, a_bytes.getTransaction()
0584: .container()._handlers.arrayType(a_object), false);
0585: }
0586:
0587: public void deleteEmbedded(MarshallerFamily mf,
0588: StatefulBuffer a_bytes) throws Db4oIOException {
0589: if (a_bytes.cascadeDeletes() > 0) {
0590: int id = a_bytes.readInt();
0591: if (id > 0) {
0592: deleteEmbedded1(mf, a_bytes, id);
0593: }
0594: } else {
0595: a_bytes.incrementOffset(linkLength());
0596: }
0597: }
0598:
0599: /** @param mf */
0600: public void deleteEmbedded1(MarshallerFamily mf,
0601: StatefulBuffer a_bytes, int a_id) throws Db4oIOException {
0602: if (a_bytes.cascadeDeletes() > 0) {
0603:
0604: ObjectContainerBase stream = a_bytes.getStream();
0605:
0606: // short-term reference to prevent WeakReference-gc to hit
0607: Transaction transaction = a_bytes.getTransaction();
0608: Object obj = stream.getByID2(transaction, a_id);
0609:
0610: int cascade = a_bytes.cascadeDeletes() - 1;
0611: if (obj != null) {
0612: if (isCollection(obj)) {
0613: cascade += reflector().collectionUpdateDepth(
0614: reflector().forObject(obj)) - 1;
0615: }
0616: }
0617:
0618: ObjectReference yo = transaction.referenceForId(a_id);
0619: if (yo != null) {
0620: a_bytes.getStream().delete2(transaction, yo, obj,
0621: cascade, false);
0622: }
0623: }
0624: }
0625:
0626: void deleteMembers(MarshallerFamily mf,
0627: ObjectHeaderAttributes attributes, StatefulBuffer a_bytes,
0628: int a_type, boolean isUpdate) {
0629: try {
0630: Config4Class config = configOrAncestorConfig();
0631: if (config != null
0632: && (config.cascadeOnDelete() == TernaryBool.YES)) {
0633: int preserveCascade = a_bytes.cascadeDeletes();
0634: if (classReflector().isCollection()) {
0635: int newCascade = preserveCascade
0636: + reflector().collectionUpdateDepth(
0637: classReflector()) - 3;
0638: if (newCascade < 1) {
0639: newCascade = 1;
0640: }
0641: a_bytes.setCascadeDeletes(newCascade);
0642: } else {
0643: a_bytes.setCascadeDeletes(1);
0644: }
0645: mf._object.deleteMembers(this , attributes, a_bytes,
0646: a_type, isUpdate);
0647: a_bytes.setCascadeDeletes(preserveCascade);
0648: } else {
0649: mf._object.deleteMembers(this , attributes, a_bytes,
0650: a_type, isUpdate);
0651: }
0652: } catch (Exception e) {
0653:
0654: // This a catch for changed class hierarchies.
0655: // It's quite ugly to catch all here but it does
0656: // help to heal migration from earlier db4o
0657: // versions.
0658:
0659: if (Debug.atHome) {
0660: e.printStackTrace();
0661: }
0662: }
0663: }
0664:
0665: public final boolean dispatchEvent(ObjectContainerBase stream,
0666: Object obj, int message) {
0667: if (!dispatchingEvents(stream)) {
0668: return true;
0669: }
0670: return _eventDispatcher.dispatch(stream, obj, message);
0671: }
0672:
0673: private boolean dispatchingEvents(ObjectContainerBase stream) {
0674: return _eventDispatcher != null && stream.dispatchsEvents();
0675: }
0676:
0677: public boolean hasEventRegistered(ObjectContainerBase stream,
0678: int eventID) {
0679: if (!dispatchingEvents(stream)) {
0680: return true;
0681: }
0682: return _eventDispatcher.hasEventRegistered(eventID);
0683: }
0684:
0685: public final int fieldCount() {
0686: int count = i_fields.length;
0687:
0688: if (i_ancestor != null) {
0689: count += i_ancestor.fieldCount();
0690: }
0691:
0692: return count;
0693: }
0694:
0695: private static class FieldMetadataIterator implements Iterator4 {
0696: private final ClassMetadata _initialClazz;
0697: private ClassMetadata _curClazz;
0698: private int _curIdx;
0699:
0700: public FieldMetadataIterator(ClassMetadata clazz) {
0701: _initialClazz = clazz;
0702: reset();
0703: }
0704:
0705: public Object current() {
0706: return _curClazz.i_fields[_curIdx];
0707: }
0708:
0709: public boolean moveNext() {
0710: if (_curClazz == null) {
0711: _curClazz = _initialClazz;
0712: _curIdx = 0;
0713: } else {
0714: _curIdx++;
0715: }
0716: while (_curClazz != null && !indexInRange()) {
0717: _curClazz = _curClazz.i_ancestor;
0718: _curIdx = 0;
0719: }
0720: return _curClazz != null && indexInRange();
0721: }
0722:
0723: public void reset() {
0724: _curClazz = null;
0725: _curIdx = -1;
0726: }
0727:
0728: private boolean indexInRange() {
0729: return _curIdx < _curClazz.i_fields.length;
0730: }
0731: }
0732:
0733: public Iterator4 fields() {
0734: return new FieldMetadataIterator(this );
0735: }
0736:
0737: // Scrolls offset in passed reader to the offset the passed field should
0738: // be read at.
0739: public final HandlerVersion findOffset(Buffer buffer,
0740: FieldMetadata field) {
0741: if (buffer == null) {
0742: return HandlerVersion.INVALID;
0743: }
0744: buffer._offset = 0;
0745: ObjectHeader oh = new ObjectHeader(_container, this , buffer);
0746: boolean res = oh.objectMarshaller().findOffset(this ,
0747: oh._headerAttributes, buffer, field);
0748: if (!res) {
0749: return HandlerVersion.INVALID;
0750: }
0751: return new HandlerVersion(oh.handlerVersion());
0752: }
0753:
0754: void forEachFieldMetadata(Visitor4 visitor) {
0755: if (i_fields != null) {
0756: for (int i = 0; i < i_fields.length; i++) {
0757: visitor.visit(i_fields[i]);
0758: }
0759: }
0760: if (i_ancestor != null) {
0761: i_ancestor.forEachFieldMetadata(visitor);
0762: }
0763: }
0764:
0765: public static ClassMetadata forObject(Transaction trans,
0766: Object obj, boolean allowCreation) {
0767: ReflectClass reflectClass = trans.reflector().forObject(obj);
0768:
0769: // TODO: The following conditions look strange. Check !
0770: if (reflectClass != null
0771: && reflectClass.getSuperclass() == null && obj != null) {
0772: throw new ObjectNotStorableException(obj.toString());
0773: }
0774:
0775: if (allowCreation) {
0776: return trans.container().produceClassMetadata(reflectClass);
0777: }
0778: return trans.container().classMetadataForReflectClass(
0779: reflectClass);
0780: }
0781:
0782: public boolean generateUUIDs() {
0783: if (!generateVirtual()) {
0784: return false;
0785: }
0786: boolean configValue = (i_config == null) ? false : i_config
0787: .generateUUIDs();
0788: return generate1(_container.config().generateUUIDs(),
0789: configValue);
0790: }
0791:
0792: private boolean generateVersionNumbers() {
0793: if (!generateVirtual()) {
0794: return false;
0795: }
0796: boolean configValue = (i_config == null) ? false : i_config
0797: .generateVersionNumbers();
0798: return generate1(_container.config().generateVersionNumbers(),
0799: configValue);
0800: }
0801:
0802: private boolean generateVirtual() {
0803: if (_unversioned) {
0804: return false;
0805: }
0806: if (_internal) {
0807: return false;
0808: }
0809: return true;
0810: }
0811:
0812: private boolean generate1(ConfigScope globalConfig,
0813: boolean individualConfig) {
0814: return globalConfig.applyConfig(individualConfig);
0815: }
0816:
0817: ClassMetadata getAncestor() {
0818: return i_ancestor;
0819: }
0820:
0821: public Object getComparableObject(Object forObject) {
0822: if (i_config != null) {
0823: if (i_config.queryAttributeProvider() != null) {
0824: return i_config.queryAttributeProvider().attribute(
0825: forObject);
0826: }
0827: }
0828: return forObject;
0829: }
0830:
0831: public ClassMetadata getHigherHierarchy(ClassMetadata a_yapClass) {
0832: ClassMetadata yc = getHigherHierarchy1(a_yapClass);
0833: if (yc != null) {
0834: return yc;
0835: }
0836: return a_yapClass.getHigherHierarchy1(this );
0837: }
0838:
0839: private ClassMetadata getHigherHierarchy1(ClassMetadata a_yapClass) {
0840: if (a_yapClass == this ) {
0841: return this ;
0842: }
0843: if (i_ancestor != null) {
0844: return i_ancestor.getHigherHierarchy1(a_yapClass);
0845: }
0846: return null;
0847: }
0848:
0849: public ClassMetadata getHigherOrCommonHierarchy(
0850: ClassMetadata a_yapClass) {
0851: ClassMetadata yc = getHigherHierarchy1(a_yapClass);
0852: if (yc != null) {
0853: return yc;
0854: }
0855: if (i_ancestor != null) {
0856: yc = i_ancestor.getHigherOrCommonHierarchy(a_yapClass);
0857: if (yc != null) {
0858: return yc;
0859: }
0860: }
0861: return a_yapClass.getHigherHierarchy1(this );
0862: }
0863:
0864: public byte getIdentifier() {
0865: return Const4.YAPCLASS;
0866: }
0867:
0868: public long[] getIDs() {
0869: synchronized (lock()) {
0870: if (!stateOK()) {
0871: return new long[0];
0872: }
0873: return getIDs(_container.transaction());
0874: }
0875: }
0876:
0877: public long[] getIDs(Transaction trans) {
0878: synchronized (lock()) {
0879: if (!stateOK()) {
0880: return new long[0];
0881: }
0882: if (!hasClassIndex()) {
0883: return new long[0];
0884: }
0885: return trans.container().getIDsForClass(trans, this );
0886: }
0887: }
0888:
0889: public boolean hasClassIndex() {
0890: return _classIndexed;
0891: }
0892:
0893: private boolean ancestorHasUUIDField() {
0894: if (i_ancestor == null) {
0895: return false;
0896: }
0897: return i_ancestor.hasUUIDField();
0898: }
0899:
0900: private boolean hasUUIDField() {
0901: if (ancestorHasUUIDField()) {
0902: return true;
0903: }
0904: return Arrays4.containsInstanceOf(i_fields,
0905: UUIDFieldMetadata.class);
0906: }
0907:
0908: private boolean ancestorHasVersionField() {
0909: if (i_ancestor == null) {
0910: return false;
0911: }
0912: return i_ancestor.hasVersionField();
0913: }
0914:
0915: private boolean hasVersionField() {
0916: if (ancestorHasVersionField()) {
0917: return true;
0918: }
0919: return Arrays4.containsInstanceOf(i_fields,
0920: VersionFieldMetadata.class);
0921: }
0922:
0923: public ClassIndexStrategy index() {
0924: return _index;
0925: }
0926:
0927: public int indexEntryCount(Transaction ta) {
0928: if (!stateOK()) {
0929: return 0;
0930: }
0931: return _index.entryCount(ta);
0932: }
0933:
0934: public Object indexEntryToObject(Transaction trans,
0935: Object indexEntry) {
0936: if (indexEntry == null) {
0937: return null;
0938: }
0939: int id = ((Integer) indexEntry).intValue();
0940: return container().getByID2(trans, id);
0941: }
0942:
0943: public ReflectClass classReflector() {
0944: return _reflector;
0945: }
0946:
0947: public String getName() {
0948: if (i_name == null) {
0949: if (_reflector != null) {
0950: i_name = _reflector.getName();
0951: }
0952: }
0953: return i_name;
0954: }
0955:
0956: public StoredClass getParentStoredClass() {
0957: return getAncestor();
0958: }
0959:
0960: public StoredField[] getStoredFields() {
0961: synchronized (lock()) {
0962: if (i_fields == null) {
0963: return new StoredField[0];
0964: }
0965: StoredField[] fields = new StoredField[i_fields.length];
0966: System.arraycopy(i_fields, 0, fields, 0, i_fields.length);
0967: return fields;
0968: }
0969: }
0970:
0971: final ObjectContainerBase container() {
0972: return _container;
0973: }
0974:
0975: public FieldMetadata fieldMetadataForName(final String name) {
0976: final FieldMetadata[] yf = new FieldMetadata[1];
0977: forEachFieldMetadata(new Visitor4() {
0978: public void visit(Object obj) {
0979: if (name.equals(((FieldMetadata) obj).getName())) {
0980: yf[0] = (FieldMetadata) obj;
0981: }
0982: }
0983: });
0984: return yf[0];
0985:
0986: }
0987:
0988: /** @param container */
0989: public boolean hasField(ObjectContainerBase container,
0990: String fieldName) {
0991: if (classReflector().isCollection()) {
0992: return true;
0993: }
0994: return fieldMetadataForName(fieldName) != null;
0995: }
0996:
0997: boolean hasVirtualAttributes() {
0998: if (_internal) {
0999: return false;
1000: }
1001: return hasVersionField() || hasUUIDField();
1002: }
1003:
1004: public boolean holdsAnyClass() {
1005: return classReflector().isCollection();
1006: }
1007:
1008: void incrementFieldsOffset1(Buffer a_bytes) {
1009: int length = readFieldCount(a_bytes);
1010: for (int i = 0; i < length; i++) {
1011: i_fields[i].incrementOffset(a_bytes);
1012: }
1013: }
1014:
1015: final boolean init(ObjectContainerBase a_stream,
1016: ClassMetadata a_ancestor, ReflectClass claxx) {
1017:
1018: if (DTrace.enabled) {
1019: DTrace.YAPCLASS_INIT.log(getID());
1020: }
1021:
1022: setAncestor(a_ancestor);
1023:
1024: Config4Impl config = a_stream.configImpl();
1025: String className = claxx.getName();
1026: setConfig(config.configClass(className));
1027:
1028: if (!createConstructor(a_stream, claxx, className, false)) {
1029: return false;
1030: }
1031:
1032: checkType();
1033: if (allowsQueries()) {
1034: _index.initialize(a_stream);
1035: }
1036: i_name = className;
1037: i_ancestor = a_ancestor;
1038: bitTrue(Const4.CHECKED_CHANGES);
1039:
1040: return true;
1041: }
1042:
1043: final void initConfigOnUp(Transaction systemTrans) {
1044: Config4Class extendedConfig = Platform4.extendConfiguration(
1045: _reflector, _container.configure(), i_config);
1046: if (extendedConfig != null) {
1047: i_config = extendedConfig;
1048: }
1049: if (i_config == null) {
1050: return;
1051: }
1052: if (!stateOK()) {
1053: return;
1054: }
1055:
1056: if (i_fields == null) {
1057: return;
1058: }
1059:
1060: for (int i = 0; i < i_fields.length; i++) {
1061: FieldMetadata curField = i_fields[i];
1062: String fieldName = curField.getName();
1063: if (!curField.hasConfig() && extendedConfig != null
1064: && extendedConfig.configField(fieldName) != null) {
1065: curField.initIndex(this , fieldName);
1066: }
1067: curField.initConfigOnUp(systemTrans);
1068: }
1069: }
1070:
1071: void initOnUp(Transaction systemTrans) {
1072: if (!stateOK()) {
1073: return;
1074: }
1075: initConfigOnUp(systemTrans);
1076: storeStaticFieldValues(systemTrans, false);
1077: }
1078:
1079: public Object instantiate(UnmarshallingContext context) {
1080:
1081: // overridden in YapClassPrimitive
1082: // never called for primitive YapAny
1083:
1084: context.adjustInstantiationDepth();
1085:
1086: Object obj = context.persistentObject();
1087:
1088: final boolean instantiating = (obj == null);
1089: if (instantiating) {
1090: obj = instantiateObject(context);
1091: if (obj == null) {
1092: return null;
1093: }
1094:
1095: shareTransaction(obj, context.transaction());
1096: shareObjectReference(obj, context.reference());
1097:
1098: context.setObjectWeak(obj);
1099:
1100: context.transaction().referenceSystem()
1101: .addExistingReferenceToObjectTree(
1102: context.reference());
1103:
1104: objectOnInstantiate(context.transaction(), obj);
1105: }
1106:
1107: context.addToIDTree();
1108:
1109: if (instantiating) {
1110: if (context.activationDepth() == 0) {
1111: context.reference().setStateDeactivated();
1112: } else {
1113: activate(context);
1114: }
1115: } else {
1116: if (activatingActiveObject(context.container(), context
1117: .reference())) {
1118: if (context.activationDepth() > 1) {
1119: activateFields(context.transaction(), obj, context
1120: .activationDepth() - 1);
1121: }
1122: } else {
1123: activate(context);
1124: }
1125: }
1126: return obj;
1127: }
1128:
1129: public Object instantiateTransient(UnmarshallingContext context) {
1130:
1131: // overridden in YapClassPrimitive
1132: // never called for primitive YapAny
1133:
1134: Object obj = instantiateObject(context);
1135: if (obj == null) {
1136: return null;
1137: }
1138: context.container().peeked(context.objectID(), obj);
1139: instantiateFields(context);
1140: return obj;
1141:
1142: }
1143:
1144: private boolean activatingActiveObject(
1145: final ObjectContainerBase container, ObjectReference ref) {
1146: return !container._refreshInsteadOfActivate && ref.isActive();
1147: }
1148:
1149: private void activate(UnmarshallingContext context) {
1150: if (!objectCanActivate(context.transaction(), context
1151: .persistentObject())) {
1152: context.reference().setStateDeactivated();
1153: return;
1154: }
1155: context.reference().setStateClean();
1156: if (context.activationDepth() > 0 || cascadeOnActivate()) {
1157: instantiateFields(context);
1158: }
1159: objectOnActivate(context.transaction(), context
1160: .persistentObject());
1161: }
1162:
1163: private boolean configInstantiates() {
1164: return config() != null && config().instantiates();
1165: }
1166:
1167: private Object instantiateObject(UnmarshallingContext context) {
1168: Object obj = configInstantiates() ? instantiateFromConfig(context)
1169: : instantiateFromReflector(context.container());
1170: context.persistentObject(obj);
1171: return obj;
1172: }
1173:
1174: private void objectOnInstantiate(Transaction transaction,
1175: Object instance) {
1176: transaction.container().callbacks().objectOnInstantiate(
1177: transaction, instance);
1178: }
1179:
1180: Object instantiateFromReflector(ObjectContainerBase stream) {
1181: if (_reflector == null) {
1182: return null;
1183: }
1184:
1185: stream.instantiating(true);
1186: try {
1187: return _reflector.newInstance();
1188: } catch (NoSuchMethodError e) {
1189: stream.logMsg(7, classReflector().getName());
1190: return null;
1191: } catch (Exception e) {
1192: // TODO: be more helpful here
1193: return null;
1194: } finally {
1195: stream.instantiating(false);
1196: }
1197: }
1198:
1199: private Object instantiateFromConfig(UnmarshallingContext context) {
1200:
1201: int offset = context.offset();
1202:
1203: // Field length is always 1
1204: context.seek(offset + Const4.INT_LENGTH);
1205:
1206: try {
1207: return i_config.instantiate(context.container(),
1208: i_fields[0].read(context));
1209: } finally {
1210: context.seek(offset);
1211: }
1212: }
1213:
1214: private boolean cascadeOnActivate() {
1215: return i_config != null
1216: && (i_config.cascadeOnActivate() == TernaryBool.YES);
1217: }
1218:
1219: private void shareObjectReference(Object obj, ObjectReference ref) {
1220: if (obj instanceof Db4oTypeImpl) {
1221: ((Db4oTypeImpl) obj).setObjectReference(ref);
1222: }
1223: }
1224:
1225: private void shareTransaction(Object obj, Transaction transaction) {
1226: if (obj instanceof TransactionAware) {
1227: ((TransactionAware) obj).setTrans(transaction);
1228: }
1229: }
1230:
1231: private void objectOnActivate(Transaction transaction, Object obj) {
1232: ObjectContainerBase container = transaction.container();
1233: container.callbacks().objectOnActivate(transaction, obj);
1234: dispatchEvent(container, obj, EventDispatcher.ACTIVATE);
1235: }
1236:
1237: private boolean objectCanActivate(Transaction transaction,
1238: Object obj) {
1239: ObjectContainerBase container = transaction.container();
1240: return container.callbacks()
1241: .objectCanActivate(transaction, obj)
1242: && dispatchEvent(container, obj,
1243: EventDispatcher.CAN_ACTIVATE);
1244: }
1245:
1246: void instantiateFields(UnmarshallingContext context) {
1247: MarshallerFamily.version(context.handlerVersion())._object
1248: .instantiateFields(context);
1249: }
1250:
1251: public boolean isArray() {
1252: return classReflector().isCollection();
1253: }
1254:
1255: boolean isCollection(Object obj) {
1256: return reflector().forObject(obj).isCollection();
1257: }
1258:
1259: public boolean isDirty() {
1260: if (!stateOK()) {
1261: return false;
1262: }
1263: return super .isDirty();
1264: }
1265:
1266: boolean isEnum() {
1267: return _isEnum;
1268: }
1269:
1270: public boolean isPrimitive() {
1271: return false;
1272: }
1273:
1274: /**
1275: * no any, primitive, array or other tricks. overriden in YapClassAny and
1276: * YapClassPrimitive
1277: */
1278: public boolean isStrongTyped() {
1279: return true;
1280: }
1281:
1282: public boolean isValueType() {
1283: return Platform4.isValueType(classReflector());
1284: }
1285:
1286: private final Object lock() {
1287: return _container.lock();
1288: }
1289:
1290: public String nameToWrite() {
1291: if (i_config != null && i_config.writeAs() != null) {
1292: return i_config.writeAs();
1293: }
1294: if (i_name == null) {
1295: return "";
1296: }
1297: return _container.configImpl().resolveAliasRuntimeName(i_name);
1298: }
1299:
1300: public final boolean callConstructor() {
1301: TernaryBool specialized = callConstructorSpecialized();
1302: // FIXME: If specified, return yes?!?
1303: if (!specialized.unspecified()) {
1304: return specialized.definiteYes();
1305: }
1306: return _container.configImpl().callConstructors().definiteYes();
1307: }
1308:
1309: private final TernaryBool callConstructorSpecialized() {
1310: if (i_config != null) {
1311: TernaryBool res = i_config.callConstructor();
1312: if (!res.unspecified()) {
1313: return res;
1314: }
1315: }
1316: if (_isEnum) {
1317: return TernaryBool.NO;
1318: }
1319: if (i_ancestor != null) {
1320: return i_ancestor.callConstructorSpecialized();
1321: }
1322: return TernaryBool.UNSPECIFIED;
1323: }
1324:
1325: public int ownLength() {
1326: return MarshallerFamily.current()._class.marshalledLength(
1327: _container, this );
1328: }
1329:
1330: void purge() {
1331: _index.purge();
1332:
1333: // TODO: may want to add manual purge to Btree
1334: // indexes here
1335: }
1336:
1337: public Object readValueType(Transaction trans, int id, int depth) {
1338: // for C# value types only:
1339: // they need to be instantiated fully before setting them
1340: // on the parent object because the set call modifies identity.
1341:
1342: // We also have to instantiate structs completely every time.
1343: int newDepth = Math.max(1, depth);
1344:
1345: // TODO: Do we want value types in the ID tree?
1346: // Shouldn't we treat them like strings and update
1347: // them every time ???
1348: ObjectReference ref = trans.referenceForId(id);
1349: if (ref != null) {
1350: Object obj = ref.getObject();
1351: if (obj == null) {
1352: trans.removeReference(ref);
1353: } else {
1354: ref.activate(trans, obj, newDepth, false);
1355: return ref.getObject();
1356: }
1357: }
1358: return new ObjectReference(id).read(trans, newDepth,
1359: Const4.ADD_TO_ID_TREE, false);
1360: }
1361:
1362: public TypeHandler4 readArrayHandler(Transaction a_trans,
1363: MarshallerFamily mf, Buffer[] a_bytes) {
1364: if (isArray()) {
1365: return this ;
1366: }
1367: return null;
1368: }
1369:
1370: public TypeHandler4 readArrayHandler1(Buffer[] a_bytes) {
1371: if (DTrace.enabled) {
1372: if (a_bytes[0] instanceof StatefulBuffer) {
1373: DTrace.READ_ARRAY_WRAPPER
1374: .log(((StatefulBuffer) a_bytes[0]).getID());
1375: }
1376: }
1377: if (isArray()) {
1378: if (Platform4.isCollectionTranslator(this .i_config)) {
1379: a_bytes[0].incrementOffset(Const4.INT_LENGTH);
1380: return new ArrayHandler(_container, null, false);
1381: }
1382: incrementFieldsOffset1(a_bytes[0]);
1383: if (i_ancestor != null) {
1384: return i_ancestor.readArrayHandler1(a_bytes);
1385: }
1386: }
1387: return null;
1388: }
1389:
1390: public ObjectID readObjectID(InternalReadContext context) {
1391: int id = context.readInt();
1392: return id == 0 ? ObjectID.IS_NULL : new ObjectID(id);
1393: }
1394:
1395: public void readCandidates(int handlerVersion, final Buffer buffer,
1396: final QCandidates candidates) {
1397: int id = 0;
1398:
1399: int offset = buffer._offset;
1400: try {
1401: id = buffer.readInt();
1402: } catch (Exception e) {
1403: }
1404: buffer._offset = offset;
1405:
1406: if (id != 0) {
1407: final Transaction trans = candidates.i_trans;
1408: Object obj = trans.container().getByID(trans, id);
1409: if (obj != null) {
1410:
1411: candidates.i_trans.container().activate(trans, obj, 2);
1412: Platform4.forEachCollectionElement(obj, new Visitor4() {
1413: public void visit(Object elem) {
1414: candidates.addByIdentity(new QCandidate(
1415: candidates, elem, trans.container()
1416: .getID(trans, elem), true));
1417: }
1418: });
1419: }
1420:
1421: }
1422: }
1423:
1424: public final int readFieldCount(Buffer buffer) {
1425: int count = buffer.readInt();
1426: if (count > i_fields.length) {
1427: if (Debug.atHome) {
1428: System.out.println("ClassMetadata.readFieldCount "
1429: + getName() + " count to high:" + count
1430: + " i_fields:" + i_fields.length);
1431: new Exception().printStackTrace();
1432: }
1433: return i_fields.length;
1434: }
1435: return count;
1436: }
1437:
1438: public Object readIndexEntry(Buffer a_reader) {
1439: return new Integer(a_reader.readInt());
1440: }
1441:
1442: public Object readIndexEntry(MarshallerFamily mf,
1443: StatefulBuffer a_writer) throws CorruptionException {
1444: return readIndexEntry(a_writer);
1445: }
1446:
1447: byte[] readName(Transaction a_trans) {
1448: i_reader = a_trans.container().readReaderByID(a_trans, getID());
1449: return readName1(a_trans, i_reader);
1450: }
1451:
1452: public final byte[] readName1(Transaction trans, Buffer reader) {
1453: if (reader == null)
1454: return null;
1455:
1456: i_reader = reader;
1457: boolean ok = false;
1458: try {
1459: ClassMarshaller marshaller = MarshallerFamily.current()._class;
1460: i_nameBytes = marshaller.readName(trans, reader);
1461: _metaClassID = marshaller.readMetaClassID(reader);
1462:
1463: setStateUnread();
1464:
1465: bitFalse(Const4.CHECKED_CHANGES);
1466: bitFalse(Const4.STATIC_FIELDS_STORED);
1467:
1468: ok = true;
1469: return i_nameBytes;
1470:
1471: } finally {
1472: if (!ok) {
1473: setStateDead();
1474: }
1475: }
1476: }
1477:
1478: void readVirtualAttributes(Transaction a_trans,
1479: ObjectReference a_yapObject) {
1480: int id = a_yapObject.getID();
1481: ObjectContainerBase stream = a_trans.container();
1482: Buffer reader = stream.readReaderByID(a_trans, id);
1483: ObjectHeader oh = new ObjectHeader(stream, this , reader);
1484: oh.objectMarshaller().readVirtualAttributes(a_trans, this ,
1485: a_yapObject, oh._headerAttributes, reader);
1486: }
1487:
1488: GenericReflector reflector() {
1489: return _container.reflector();
1490: }
1491:
1492: public void rename(String newName) {
1493: if (!_container.isClient()) {
1494: int tempState = _state;
1495: setStateOK();
1496: i_name = newName;
1497: setStateDirty();
1498: write(_container.systemTransaction());
1499: _state = tempState;
1500: } else {
1501: Exceptions4.throwRuntimeException(58);
1502: }
1503: }
1504:
1505: final void createConfigAndConstructor(Hashtable4 a_byteHashTable,
1506: ReflectClass claxx, String name) {
1507: i_name = name;
1508: setConfig(_container.configImpl().configClass(i_name));
1509: if (claxx == null) {
1510: createConstructor(_container, i_name);
1511: } else {
1512: createConstructor(_container, claxx, i_name, true);
1513: }
1514: if (i_nameBytes != null) {
1515: a_byteHashTable.remove(i_nameBytes);
1516: i_nameBytes = null;
1517: }
1518: }
1519:
1520: String resolveName(ReflectClass claxx) {
1521: if (claxx != null) {
1522: return claxx.getName();
1523: }
1524: if (i_nameBytes != null) {
1525: String name = _container.stringIO().read(i_nameBytes);
1526: return _container.configImpl().resolveAliasStoredName(name);
1527: }
1528: throw new IllegalStateException();
1529: }
1530:
1531: boolean readThis() {
1532: if (stateUnread()) {
1533: setStateOK();
1534: setStateClean();
1535: forceRead();
1536: return true;
1537: }
1538: return false;
1539: }
1540:
1541: final void forceRead() {
1542: if (i_reader == null || bitIsTrue(Const4.READING)) {
1543: return;
1544: }
1545:
1546: bitTrue(Const4.READING);
1547:
1548: MarshallerFamily.forConverterVersion(_container
1549: .converterVersion())._class.read(_container, this ,
1550: i_reader);
1551:
1552: i_nameBytes = null;
1553: i_reader = null;
1554: bitFalse(Const4.READING);
1555: }
1556:
1557: public void readThis(Transaction a_trans, Buffer a_reader) {
1558: throw Exceptions4.virtualException();
1559: }
1560:
1561: public void refresh() {
1562: if (!stateUnread()) {
1563: createConstructor(_container, i_name);
1564: bitFalse(Const4.CHECKED_CHANGES);
1565: checkChanges();
1566: if (i_fields != null) {
1567: for (int i = 0; i < i_fields.length; i++) {
1568: i_fields[i].refresh();
1569: }
1570: }
1571: }
1572: }
1573:
1574: void removeFromIndex(Transaction ta, int id) {
1575: if (hasClassIndex()) {
1576: _index.remove(ta, id);
1577: }
1578: if (i_ancestor != null) {
1579: i_ancestor.removeFromIndex(ta, id);
1580: }
1581: }
1582:
1583: boolean renameField(String a_from, String a_to) {
1584: boolean renamed = false;
1585: for (int i = 0; i < i_fields.length; i++) {
1586: if (i_fields[i].getName().equals(a_to)) {
1587: _container.logMsg(9, "class:" + getName() + " field:"
1588: + a_to);
1589: return false;
1590: }
1591: }
1592: for (int i = 0; i < i_fields.length; i++) {
1593: if (i_fields[i].getName().equals(a_from)) {
1594: i_fields[i].setName(a_to);
1595: renamed = true;
1596: }
1597: }
1598: return renamed;
1599: }
1600:
1601: void setConfig(Config4Class config) {
1602:
1603: if (config == null) {
1604: return;
1605: }
1606:
1607: // The configuration can be set by a ObjectClass#readAs setting
1608: // from YapClassCollection, right after reading the meta information
1609: // for the first time. In that case we never change the setting
1610: if (i_config == null) {
1611: i_config = config;
1612: }
1613: }
1614:
1615: void setName(String a_name) {
1616: i_name = a_name;
1617: }
1618:
1619: final void setStateDead() {
1620: bitTrue(Const4.DEAD);
1621: bitFalse(Const4.CONTINUE);
1622: }
1623:
1624: private final void setStateUnread() {
1625: bitFalse(Const4.DEAD);
1626: bitTrue(Const4.CONTINUE);
1627: }
1628:
1629: private final void setStateOK() {
1630: bitFalse(Const4.DEAD);
1631: bitFalse(Const4.CONTINUE);
1632: }
1633:
1634: boolean stateDead() {
1635: return bitIsTrue(Const4.DEAD);
1636: }
1637:
1638: private final boolean stateOK() {
1639: return bitIsFalse(Const4.CONTINUE) && bitIsFalse(Const4.DEAD)
1640: && bitIsFalse(Const4.READING);
1641: }
1642:
1643: final boolean stateOKAndAncestors() {
1644: if (!stateOK() || i_fields == null) {
1645: return false;
1646: }
1647: if (i_ancestor != null) {
1648: return i_ancestor.stateOKAndAncestors();
1649: }
1650: return true;
1651: }
1652:
1653: boolean stateUnread() {
1654: return bitIsTrue(Const4.CONTINUE) && bitIsFalse(Const4.DEAD)
1655: && bitIsFalse(Const4.READING);
1656: }
1657:
1658: boolean storeField(ReflectField a_field) {
1659: if (a_field.isStatic()) {
1660: return false;
1661: }
1662: if (a_field.isTransient()) {
1663: Config4Class config = configOrAncestorConfig();
1664: if (config == null) {
1665: return false;
1666: }
1667: if (!config.storeTransientFields()) {
1668: return false;
1669: }
1670: }
1671: return Platform4.canSetAccessible() || a_field.isPublic();
1672: }
1673:
1674: public StoredField storedField(String name, Object clazz) {
1675: synchronized (lock()) {
1676:
1677: ClassMetadata classMetadata = _container
1678: .classMetadataForReflectClass(ReflectorUtils
1679: .reflectClassFor(reflector(), clazz));
1680:
1681: if (i_fields != null) {
1682: for (int i = 0; i < i_fields.length; i++) {
1683: if (i_fields[i].getName().equals(name)) {
1684:
1685: // FIXME: The == comparison in the following line could be wrong.
1686:
1687: if (classMetadata == null
1688: || classMetadata == i_fields[i]
1689: .handlerClassMetadata(_container)) {
1690: return (i_fields[i]);
1691: }
1692: }
1693: }
1694: }
1695:
1696: //TODO: implement field creation
1697:
1698: return null;
1699: }
1700: }
1701:
1702: void storeStaticFieldValues(Transaction trans, boolean force) {
1703: if (bitIsTrue(Const4.STATIC_FIELDS_STORED) && !force) {
1704: return;
1705: }
1706: bitTrue(Const4.STATIC_FIELDS_STORED);
1707:
1708: if (!shouldStoreStaticFields(trans)) {
1709: return;
1710: }
1711:
1712: final ObjectContainerBase stream = trans.container();
1713: stream.showInternalClasses(true);
1714: try {
1715: StaticClass sc = queryStaticClass(trans);
1716: if (sc == null) {
1717: createStaticClass(trans);
1718: } else {
1719: updateStaticClass(trans, sc);
1720: }
1721: } finally {
1722: stream.showInternalClasses(false);
1723: }
1724: }
1725:
1726: private boolean shouldStoreStaticFields(Transaction trans) {
1727: return !trans.container().config().isReadOnly()
1728: && (staticFieldValuesArePersisted() || Platform4
1729: .storeStaticFieldValues(trans.reflector(),
1730: classReflector()));
1731: }
1732:
1733: private void updateStaticClass(final Transaction trans,
1734: final StaticClass sc) {
1735: final ObjectContainerBase stream = trans.container();
1736: stream.activate(trans, sc, 4);
1737:
1738: final StaticField[] existingFields = sc.fields;
1739: final Iterator4 staticFields = Iterators.map(
1740: staticReflectFields(), new Function4() {
1741: public Object apply(Object arg) {
1742: final ReflectField reflectField = (ReflectField) arg;
1743: StaticField existingField = fieldByName(
1744: existingFields, reflectField.getName());
1745: if (existingField != null) {
1746: updateExistingStaticField(trans,
1747: existingField, reflectField);
1748: return existingField;
1749: }
1750: return toStaticField(reflectField);
1751: }
1752: });
1753: sc.fields = toStaticFieldArray(staticFields);
1754: if (!stream.isClient()) {
1755: setStaticClass(trans, sc);
1756: }
1757: }
1758:
1759: private void createStaticClass(Transaction trans) {
1760: if (trans.container().isClient()) {
1761: return;
1762: }
1763: StaticClass sc = new StaticClass(i_name,
1764: toStaticFieldArray(staticReflectFieldsToStaticFields()));
1765: setStaticClass(trans, sc);
1766: }
1767:
1768: private Iterator4 staticReflectFieldsToStaticFields() {
1769: return Iterators.map(staticReflectFields(), new Function4() {
1770: public Object apply(Object arg) {
1771: return toStaticField((ReflectField) arg);
1772: }
1773: });
1774: }
1775:
1776: protected StaticField toStaticField(final ReflectField reflectField) {
1777: return new StaticField(reflectField.getName(),
1778: staticReflectFieldValue(reflectField));
1779: }
1780:
1781: private Object staticReflectFieldValue(
1782: final ReflectField reflectField) {
1783: reflectField.setAccessible();
1784: return reflectField.get(null);
1785: }
1786:
1787: private void setStaticClass(Transaction trans, StaticClass sc) {
1788: // TODO: we should probably use a specific update depth here, 4?
1789: trans.container().setInternal(trans, sc, true);
1790: }
1791:
1792: private StaticField[] toStaticFieldArray(Iterator4 iterator4) {
1793: return toStaticFieldArray(new Collection4(iterator4));
1794: }
1795:
1796: private StaticField[] toStaticFieldArray(Collection4 fields) {
1797: return (StaticField[]) fields.toArray(new StaticField[fields
1798: .size()]);
1799: }
1800:
1801: private Iterator4 staticReflectFields() {
1802: return Iterators.filter(reflectFields(), new Predicate4() {
1803: public boolean match(Object candidate) {
1804: return ((ReflectField) candidate).isStatic();
1805: }
1806: });
1807: }
1808:
1809: private ReflectField[] reflectFields() {
1810: return classReflector().getDeclaredFields();
1811: }
1812:
1813: protected void updateExistingStaticField(Transaction trans,
1814: StaticField existingField, final ReflectField reflectField) {
1815: final ObjectContainerBase stream = trans.container();
1816: final Object newValue = staticReflectFieldValue(reflectField);
1817:
1818: if (existingField.value != null
1819: && newValue != null
1820: && existingField.value.getClass() == newValue
1821: .getClass()) {
1822: int id = stream.getID(trans, existingField.value);
1823: if (id > 0) {
1824: if (existingField.value != newValue) {
1825:
1826: // This is the clue:
1827: // Bind the current static member to it's old database identity,
1828: // so constants and enums will work with '=='
1829: stream.bind(trans, newValue, id);
1830:
1831: // This may produce unwanted side effects if the static field object
1832: // was modified in the current session. TODO:Add documentation case.
1833:
1834: stream.refresh(trans, newValue, Integer.MAX_VALUE);
1835:
1836: existingField.value = newValue;
1837: }
1838: return;
1839: }
1840: }
1841:
1842: if (newValue == null) {
1843: try {
1844: reflectField.set(null, existingField.value);
1845: } catch (Exception ex) {
1846: // fail silently
1847: // TODO: why?
1848: }
1849: return;
1850: }
1851:
1852: existingField.value = newValue;
1853: }
1854:
1855: private boolean staticFieldValuesArePersisted() {
1856: return (i_config != null && i_config
1857: .staticFieldValuesArePersisted());
1858: }
1859:
1860: protected StaticField fieldByName(StaticField[] fields,
1861: final String fieldName) {
1862: for (int i = 0; i < fields.length; i++) {
1863: final StaticField field = fields[i];
1864: if (fieldName.equals(field.name)) {
1865: return field;
1866: }
1867: }
1868: return null;
1869: }
1870:
1871: private StaticClass queryStaticClass(Transaction trans) {
1872: Query q = trans.container().query(trans);
1873: q.constrain(Const4.CLASS_STATICCLASS);
1874: q.descend("name").constrain(i_name);
1875: ObjectSet os = q.execute();
1876: return os.size() > 0 ? (StaticClass) os.next() : null;
1877: }
1878:
1879: public String toString() {
1880: if (i_name != null) {
1881: return i_name;
1882: }
1883: if (i_nameBytes == null) {
1884: return "*CLASS NAME UNKNOWN*";
1885: }
1886: LatinStringIO stringIO = _container == null ? Const4.stringIO
1887: : _container.stringIO();
1888: return stringIO.read(i_nameBytes);
1889: }
1890:
1891: public boolean writeObjectBegin() {
1892: if (!stateOK()) {
1893: return false;
1894: }
1895: return super .writeObjectBegin();
1896: }
1897:
1898: public void writeIndexEntry(Buffer a_writer, Object a_object) {
1899:
1900: if (a_object == null) {
1901: a_writer.writeInt(0);
1902: return;
1903: }
1904:
1905: a_writer.writeInt(((Integer) a_object).intValue());
1906: }
1907:
1908: public final void writeThis(Transaction trans, Buffer writer) {
1909: MarshallerFamily.current()._class.write(trans, this , writer);
1910: }
1911:
1912: // Comparison_______________________
1913:
1914: private ReflectClass i_compareTo;
1915:
1916: public Comparable4 prepareComparison(Object obj) {
1917: if (obj == null) {
1918: i_lastID = 0;
1919: i_compareTo = null;
1920: return this ;
1921: }
1922: if (obj instanceof Integer) {
1923: i_lastID = ((Integer) obj).intValue();
1924: } else if (obj instanceof TransactionContext) {
1925: TransactionContext tc = (TransactionContext) obj;
1926: obj = tc._object;
1927: i_lastID = _container.getID(tc._transaction, obj);
1928: } else {
1929: throw new IllegalComparisonException();
1930: }
1931: i_compareTo = reflector().forObject(obj);
1932: return this ;
1933: }
1934:
1935: public int compareTo(Object obj) {
1936: if (obj instanceof TransactionContext) {
1937: obj = ((TransactionContext) obj)._object;
1938: }
1939: if (obj instanceof Integer) {
1940: return ((Integer) obj).intValue() - i_lastID;
1941: }
1942: if (obj == null) {
1943: if (i_compareTo == null) {
1944: return 0;
1945: }
1946: return -1;
1947: }
1948: if (i_compareTo != null) {
1949: if (i_compareTo
1950: .isAssignableFrom(reflector().forObject(obj))) {
1951: return 0;
1952: }
1953: }
1954: throw new IllegalComparisonException();
1955: }
1956:
1957: public static void defragObject(BufferPair readers) {
1958: ObjectHeader header = ObjectHeader.defrag(readers);
1959: header._marshallerFamily._object.defragFields(header
1960: .classMetadata(), header, readers);
1961: if (Deploy.debug) {
1962: readers.readEnd();
1963: }
1964: }
1965:
1966: public void defrag(MarshallerFamily mf, BufferPair readers,
1967: boolean redirect) {
1968: if (hasClassIndex()) {
1969: readers.copyID();
1970: } else {
1971: readers.copyUnindexedID();
1972: }
1973: int restLength = (linkLength() - Const4.INT_LENGTH);
1974: readers.incrementOffset(restLength);
1975: }
1976:
1977: public void defragClass(BufferPair readers, int classIndexID)
1978: throws CorruptionException, IOException {
1979: MarshallerFamily mf = MarshallerFamily.current();
1980: mf._class.defrag(this , _container.stringIO(), readers,
1981: classIndexID);
1982: }
1983:
1984: public static ClassMetadata readClass(ObjectContainerBase stream,
1985: Buffer reader) {
1986: ObjectHeader oh = new ObjectHeader(stream, reader);
1987: return oh.classMetadata();
1988: }
1989:
1990: public boolean isAssignableFrom(ClassMetadata other) {
1991: return classReflector()
1992: .isAssignableFrom(other.classReflector());
1993: }
1994:
1995: public final void defragIndexEntry(BufferPair readers) {
1996: readers.copyID();
1997: }
1998:
1999: public void setAncestor(ClassMetadata ancestor) {
2000: if (ancestor == this ) {
2001: throw new IllegalStateException();
2002: }
2003: i_ancestor = ancestor;
2004: }
2005:
2006: public Object wrapWithTransactionContext(Transaction transaction,
2007: Object value) {
2008: if (value instanceof Integer) {
2009: return value;
2010: }
2011: return new TransactionContext(transaction, value);
2012: }
2013:
2014: public Object read(ReadContext context) {
2015:
2016: // FIXME: .NET value types should get their own TypeHandler and it
2017: // should do the following:
2018: if (isValueType()) {
2019: return readValueType(context.transaction(), context
2020: .readInt(), ((UnmarshallingContext) context)
2021: .activationDepth() - 1);
2022: }
2023:
2024: return context.readObject();
2025: }
2026:
2027: public void write(WriteContext context, Object obj) {
2028: context.writeObject(obj);
2029: }
2030:
2031: public TypeHandler4 typeHandler() {
2032: return this;
2033: }
2034:
2035: }
|