/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.internal;
import java.util.*;
import com.db4o.*;
import com.db4o.config.*;
import com.db4o.ext.*;
import com.db4o.foundation.*;
import com.db4o.internal.activation.*;
import com.db4o.internal.classindex.*;
import com.db4o.internal.delete.*;
import com.db4o.internal.diagnostic.*;
import com.db4o.internal.encoding.*;
import com.db4o.internal.handlers.*;
import com.db4o.internal.handlers.array.*;
import com.db4o.internal.marshall.*;
import com.db4o.internal.metadata.*;
import com.db4o.internal.metadata.HierarchyAnalyzer.*;
import com.db4o.internal.query.processor.*;
import com.db4o.internal.reflect.*;
import com.db4o.marshall.*;
import com.db4o.query.*;
import com.db4o.reflect.*;
import com.db4o.reflect.core.*;
import com.db4o.reflect.generic.*;
import com.db4o.typehandlers.*;
/**
* @exclude
*/
public class ClassMetadata extends PersistentBase implements StoredClass {
/**
* For reference types, _typeHandler always holds a StandardReferenceTypeHandler
* that will use the _aspects of this class to take care of its business. A custom
* type handler would appear as a TypeHandlerAspect in that case.
*
* For value types, _typeHandler always holds the actual value type handler be it
* a custom type handler or a builtin one.
*/
protected TypeHandler4 _typeHandler;
public ClassMetadata _ancestor;
private Config4Class _config;
public ClassAspect[] _aspects;
private ClassIndexStrategy _index;
private String i_name;
private final ObjectContainerBase _container;
byte[] i_nameBytes;
private ByteArrayBuffer i_reader;
private boolean _classIndexed;
private ReflectClass _classReflector;
private EventDispatcher _eventDispatcher;
private boolean _internal;
private boolean _unversioned;
private TernaryBool _canUpdateFast=TernaryBool.UNSPECIFIED;
private TranslatedAspect _translator;
private ModificationAware _modificationChecker = AlwaysModified.INSTANCE;
private FieldAccessor _fieldAccessor;
private Function4<UnmarshallingContext, Object> _constructor;
private TypeHandlerAspect _customTypeHandlerAspect;
private AspectTraversalStrategy _aspectTraversalStrategy;
private TernaryBool _isStruct = TernaryBool.UNSPECIFIED;
final boolean canUpdateFast(){
if(_canUpdateFast == TernaryBool.UNSPECIFIED){
_canUpdateFast = TernaryBool.forBoolean(checkCanUpdateFast());
}
return _canUpdateFast.booleanValue(false);
}
private final boolean checkCanUpdateFast() {
if(_ancestor != null && ! _ancestor.canUpdateFast()){
return false;
}
if(_config != null && _config.cascadeOnDelete() == TernaryBool.YES) {
return false;
}
final BooleanByRef result = new BooleanByRef(true);
traverseDeclaredFields(new Procedure4() {
public void apply(Object fieldMetadata) {
if(! ((FieldMetadata)fieldMetadata).canUpdateFast()){
result.value = false;
}
}
});
return result.value;
}
public boolean isInternal() {
return _internal;
}
private ClassIndexStrategy createIndexStrategy() {
return new BTreeClassIndexStrategy(this);
}
protected ClassMetadata(ObjectContainerBase container){
if (null == container) {
throw new ArgumentNullException();
}
_container = container;
_index = createIndexStrategy();
_classIndexed = true;
_fieldAccessor = new StrictFieldAccessor();
}
public ClassMetadata(ObjectContainerBase container, ReflectClass classReflector){
if (null == container) {
throw new ArgumentNullException();
}
_container = container;
classReflector(classReflector);
_index = createIndexStrategy();
_classIndexed = true;
if (_container.config().exceptionsOnNotStorable()) {
_fieldAccessor = new StrictFieldAccessor();
} else {
_fieldAccessor = new LenientFieldAccessor();
}
}
FieldAccessor fieldAccessor() {
return _fieldAccessor;
}
private TypeHandler4 createDefaultTypeHandler() {
// TODO: make sure initializeAspects has been executed
// before the actual type handler is required
// and remove this method
return new StandardReferenceTypeHandler(this);
}
public void cascadeActivation(final ActivationContext context) {
if(! objectCanActivate(context.transaction(), context.targetObject())){
return;
}
traverseAllAspects(new TraverseAspectCommand() {
public void processAspectOnMissingClass(ClassAspect aspect, int currentSlot) {
// do nothing
}
public void processAspect(ClassAspect aspect, int currentSlot) {
aspect.cascadeActivation(context);
}
public int declaredAspectCount(ClassMetadata classMetadata) {
return classMetadata.declaredAspectCount();
}
public boolean cancelled() {
return false;
}
});
}
public final void addFieldIndices(StatefulBuffer buffer) {
if(! standardReferenceTypeHandlerIsUsed()){
return;
}
if(hasClassIndex() || hasVirtualAttributes()){
ObjectHeader oh = new ObjectHeader(this, buffer);
ObjectIdContextImpl context = new ObjectIdContextImpl(buffer.transaction(), buffer, oh, buffer.getID());
Handlers4.fieldAwareTypeHandler(correctHandlerVersion(context)).addFieldIndices(context);
}
}
// FIXME: This method wants to be removed.
private boolean standardReferenceTypeHandlerIsUsed(){
return _typeHandler instanceof StandardReferenceTypeHandler;
}
void initializeAspects() {
bitTrue(Const4.CHECKED_CHANGES);
Collection4 aspects = new Collection4();
if (null != _aspects) {
aspects.addAll(_aspects);
}
final TypeHandler4 customTypeHandler = container().handlers().configuredTypeHandler(classReflector());
boolean dirty = isDirty();
if(installTranslator(aspects, customTypeHandler)){
dirty = true;
}
if (container().detectSchemaChanges()) {
if (generateCommitTimestamps()) {
if (!hasCommitTimestampField()) {
aspects.add(container().commitTimestampIndex());
dirty = true;
}
}
if (generateUUIDs()) {
if (!hasUUIDField()) {
aspects.add(container().uUIDIndex());
dirty = true;
}
}
}
if(installCustomTypehandler(aspects, customTypeHandler)){
dirty = true;
}
boolean defaultFieldBehaviour = _translator == null && customTypeHandler == null;
if (container().detectSchemaChanges()) {
if (defaultFieldBehaviour) {
if (collectReflectFields(aspects)) {
dirty = true;
}
}
if (dirty) {
_container.setDirtyInSystemTransaction(this);
}
}
validateTranslatorAspects(aspects);
if (dirty || ! defaultFieldBehaviour) {
_aspects = toClassAspectArray(aspects);
}
DiagnosticProcessor dp = _container._handlers.diagnosticProcessor();
if (dp.enabled()) {
dp.checkClassHasFields(this);
}
if (_aspects == null) {
_aspects = new FieldMetadata[0];
}
initializeConstructor(customTypeHandler);
if (stateDead()) {
return;
}
_container.callbacks().classOnRegistered(this);
setStateOK();
}
private void validateTranslatorAspects(Collection4 aspects) {
if (hasIncompatibleTranslatorAspect(aspects)) {
if (!configImpl().recoveryMode()) {
String newLine = System.getProperty("line.separator");
throw new Db4oFatalException(
"Class " + getName() + " was used with and without translators configured. Found aspects:" + newLine
+ Arrays4.toString(aspects.toArray()) + newLine
+ "No changes were made to the database. " + newLine
+ "If you want to run with this configuration you can configure recovery mode (see FileConfiguration#recoveryMode()).");
}
}
}
private boolean hasIncompatibleTranslatorAspect(Collection4 aspects) {
boolean translatorFound = false;
boolean enabledAspectFound = false;
int size = aspects.size();
AspectVersionContext context = AspectVersionContextImpl.forSize(size);
for(int i = 0; i < size; i++) {
ClassAspect current = (ClassAspect) aspects.get(i);
if (!current.isEnabledOn(context)) continue;
if (current.isVirtual()) continue;
if (current.aspectType() == AspectType.TRANSLATOR) {
translatorFound = true;
} else {
enabledAspectFound = true;
}
}
return enabledAspectFound && translatorFound;
}
private ClassAspect[] toClassAspectArray(Collection4 aspects) {
final ClassAspect[] array = new ClassAspect[aspects.size()];
aspects.toArray(array);
for (int i = 0; i < array.length; i++) {
array[i].setHandle(i);
}
return array;
}
private boolean installCustomTypehandler(Collection4 aspects, TypeHandler4 customTypeHandler) {
if (customTypeHandler == null) {
return false;
}
if(customTypeHandler instanceof ModificationAware){
_modificationChecker = (ModificationAware) customTypeHandler;
}
if(Handlers4.isStandaloneTypeHandler(customTypeHandler)){
_typeHandler = customTypeHandler;
return false;
}
boolean dirty = false;
TypeHandlerAspect typeHandlerAspect = new TypeHandlerAspect(this, customTypeHandler);
if (!replaceAspectByName(aspects, typeHandlerAspect)) {
aspects.add(typeHandlerAspect);
dirty = true;
}
disableAspectsBefore(aspects, typeHandlerAspect);
_customTypeHandlerAspect = typeHandlerAspect;
return dirty;
}
private void disableAspectsBefore(Collection4 aspects, TypeHandlerAspect typeHandlerAspect) {
int disableFromVersion = aspects.indexOf(typeHandlerAspect) + 1;
Iterator4 i = aspects.iterator();
while(i.moveNext()){
ClassAspect aspect = (ClassAspect) i.current();
if(aspect == typeHandlerAspect){
break;
}
aspect.disableFromAspectCountVersion(disableFromVersion);
}
}
private boolean installTranslator(Collection4 aspects, TypeHandler4 customTypeHandler) {
if( _config == null){
return false;
}
ObjectTranslator translator = _config.getTranslator();
if (translator == null) {
return false;
}
ClassAspect existingAspect = aspectByName(aspects, TranslatedAspect.fieldNameFor(translator));
if (null != existingAspect) {
return installTranslatorOnExistingAspect(translator, existingAspect, aspects);
}
if(customTypeHandler == null){
return installTranslatorOnNewAspect(translator, aspects);
}
return false;
}
private boolean installTranslatorOnNewAspect(ObjectTranslator translator,
Collection4 aspects) {
TranslatedAspect translatedAspect = new TranslatedAspect(this, translator);
aspects.add(translatedAspect);
_translator = translatedAspect;
return true;
}
private boolean installTranslatorOnExistingAspect(
ObjectTranslator translator, ClassAspect existingAspect,
Collection4 aspects) {
if (existingAspect instanceof TranslatedAspect) {
TranslatedAspect translatedAspect = (TranslatedAspect) existingAspect;
translatedAspect.initializeTranslator(translator);
_translator = translatedAspect;
return false;
}
// older versions didn't store the aspect type properly
_translator = new TranslatedAspect(this, translator);
aspects.replaceByIdentity(existingAspect, _translator);
return true;
}
private boolean replaceAspectByName(Collection4 aspects, ClassAspect aspect) {
ClassAspect existing = aspectByName(aspects, aspect.getName());
if (existing == null) {
return false;
}
aspects.replaceByIdentity(existing, aspect);
return true;
}
private ClassAspect aspectByName(Collection4 aspects,
final String aspectName) {
Iterator4 i = aspects.iterator();
while (i.moveNext()) {
ClassAspect current = (ClassAspect) i.current();
if (current.getName().equals(aspectName)) {
return current;
}
}
return null;
}
public boolean aspectsAreInitialized(){
if(_aspects == null){
return false;
}
if(_ancestor != null){
return _ancestor.aspectsAreInitialized();
}
return true;
}
private boolean collectReflectFields(Collection4 collectedAspects) {
boolean dirty=false;
for (ReflectField reflectField : reflectFields()) {
if (!storeField(reflectField)) {
continue;
}
final ClassMetadata classMetadata = Handlers4.erasedFieldType(container(), reflectField.getFieldType());
if (classMetadata == null) {
continue;
}
FieldMetadata field = new FieldMetadata(this, reflectField, classMetadata);
if (contains(collectedAspects, field)) {
continue;
}
dirty = true;
collectedAspects.add(field);
}
return dirty;
}
private boolean contains(Collection4 collectedAspects, FieldMetadata field) {
Iterator4 aspectIterator = collectedAspects.iterator();
while (aspectIterator.moveNext()) {
if (((ClassAspect)aspectIterator.current()).equals(field)) {
return true;
}
}
return false;
}
void addToIndex(Transaction trans, int id) {
if (! trans.container().maintainsIndices()) {
return;
}
addToIndex1(trans, id);
}
final void addToIndex1(Transaction a_trans, int a_id) {
if (_ancestor != null) {
_ancestor.addToIndex1(a_trans, a_id);
}
if (hasClassIndex()) {
_index.add(a_trans, a_id);
}
}
boolean allowsQueries() {
return hasClassIndex();
}
public boolean descendOnCascadingActivation() {
return true;
}
void checkChanges() {
if (stateOK()) {
if (!bitIsTrue(Const4.CHECKED_CHANGES)) {
bitTrue(Const4.CHECKED_CHANGES);
if (_ancestor != null) {
_ancestor.checkChanges();
// Ancestor first, so the object length calculates
// correctly
}
if (_classReflector != null) {
initializeAspects();
if (!_container.isClient() && !isReadOnlyContainer()) {
write(_container.systemTransaction());
}
}
}
}
}
public void checkType() {
ReflectClass claxx = classReflector();
if (claxx == null){
return;
}
if (_container._handlers.ICLASS_INTERNAL.isAssignableFrom(claxx)) {
_internal = true;
}
if (_container._handlers.ICLASS_UNVERSIONED.isAssignableFrom(claxx)) {
_unversioned = true;
}
if (isDb4oTypeImpl()) {
Db4oTypeImpl db4oTypeImpl = (Db4oTypeImpl) claxx.newInstance();
_classIndexed = (db4oTypeImpl == null || db4oTypeImpl.hasClassIndex());
} else if(_config != null){
_classIndexed = _config.indexed();
}
}
public boolean isDb4oTypeImpl() {
return _container._handlers.ICLASS_DB4OTYPEIMPL.isAssignableFrom(classReflector());
}
public final UpdateDepth adjustUpdateDepth(Transaction trans, UpdateDepth depth) {
return depth.adjust(this);
}
public boolean cascadesOnDeleteOrUpdate() {
Config4Class config = configOrAncestorConfig();
if(config == null){
return false;
}
boolean cascadeOnDelete = config.cascadeOnDelete() == TernaryBool.YES;
boolean cascadeOnUpdate = config.cascadeOnUpdate() == TernaryBool.YES;
return cascadeOnDelete || cascadeOnUpdate;
}
public FixedActivationDepth adjustCollectionDepthToBorders(FixedActivationDepth depth) {
if (! classReflector().isCollection()) {
return depth;
}
return depth.adjustDepthToBorders();
}
public final int updateDepthFromConfig() {
if (_config != null && _config.updateDepth() != Const4.UNSPECIFIED) {
return _config.updateDepth();
}
Config4Impl config = configImpl();
int depth = config.updateDepth();
if (_ancestor != null) {
int ancestordepth = _ancestor.updateDepthFromConfig();
if (ancestordepth > depth) {
return ancestordepth;
}
}
return depth;
}
public void collectConstraints(
final Transaction trans,
final QConObject parentConstraint,
final Object obj,
final Visitor4 visitor) {
traverseAllAspects(new TraverseFieldCommand() {
@Override
protected void process(FieldMetadata field) {
if(field.isEnabledOn(AspectVersionContextImpl.CHECK_ALWAYS_ENABLED)){
field.collectConstraints(trans, parentConstraint, obj, visitor);
}
}
});
}
public final void collectIDs(CollectIdContext context, final String fieldName) {
collectIDs(context, new Predicate4<ClassAspect>() {
public boolean match(ClassAspect candidate) {
return fieldName.equals(candidate.getName());
}
});
}
public final void collectIDs(CollectIdContext context) {
collectIDs(context, new Predicate4<ClassAspect>() {
public boolean match(ClassAspect candidate) {
return true;
}
});
}
private void collectIDs(CollectIdContext context, final Predicate4<ClassAspect> predicate) {
if(! standardReferenceTypeHandlerIsUsed()){
throw new IllegalStateException();
}
((StandardReferenceTypeHandler)correctHandlerVersion(context)).collectIDs(
context,
predicate);
}
public void collectIDs(final QueryingReadContext context) {
if(! standardReferenceTypeHandlerIsUsed()){
throw new IllegalStateException();
}
Handlers4.collectIDs(context, correctHandlerVersion(context));
}
public Config4Class config() {
return _config;
}
public Config4Class configOrAncestorConfig() {
if (_config != null) {
return _config;
}
if (_ancestor != null) {
return _ancestor.configOrAncestorConfig();
}
return null;
}
private void resolveClassReflector(String className) {
final ReflectClass reflectClass = _container.reflector().forName(className);
if (null == reflectClass) {
throw new IllegalStateException("Cannot initialize ClassMetadata for '" + className + "'.");
}
classReflector(reflectClass);
}
private void initializeConstructor(final TypeHandler4 customTypeHandler) {
if (isTransient()) {
_container.logMsg(23, getName());
setStateDead();
return;
}
if (isInterface() || isAbstract()) {
return;
}
Function4<UnmarshallingContext, Object> constructor = createConstructor(customTypeHandler);
if (constructor != null) {
_constructor = constructor;
return;
}
notStorable();
}
private boolean isAbstract() {
return classReflector().isAbstract();
}
private boolean isInterface() {
return classReflector().isInterface();
}
private Function4<UnmarshallingContext, Object> createConstructor(
final TypeHandler4 customTypeHandler) {
if (customTypeHandler instanceof InstantiatingTypeHandler) {
return new Function4<UnmarshallingContext, Object>() {
public Object apply(UnmarshallingContext context) {
return instantiateWithCustomTypeHandlerIfEnabled(context);
}
};
}
if (hasObjectConstructor()) {
return new Function4<UnmarshallingContext, Object>() {
public Object apply(UnmarshallingContext context) {
return _translator.construct(context);
}
};
}
if(classReflector().ensureCanBeInstantiated()) {
return new Function4<UnmarshallingContext, Object>() {
public Object apply(UnmarshallingContext context) {
return instantiateFromReflector(context.container());
}
};
}
return null;
}
private void notStorable() {
_container.logMsg(7, getName());
setStateDead();
}
private boolean isTransient() {
return _container._handlers.isTransient(classReflector());
}
private void classReflector(ReflectClass claxx) {
_classReflector = claxx;
if(claxx == null){
_typeHandler = null;
return;
}
_typeHandler = createDefaultTypeHandler();
}
public void deactivate(Transaction trans, ObjectInfo reference, ActivationDepth depth) {
final Object obj = reference.getObject();
if(objectCanDeactivate(trans, reference)){
forceDeactivation(trans, depth, obj);
objectOnDeactivate(trans, reference);
}
}
public void forceDeactivation(Transaction trans, ActivationDepth depth, final Object obj) {
deactivateFields(trans.container().activationContextFor(trans, obj, depth));
}
private void objectOnDeactivate(Transaction transaction, ObjectInfo obj) {
ObjectContainerBase container = transaction.container();
container.callbacks().objectOnDeactivate(transaction, obj);
dispatchEvent(transaction, obj.getObject(), EventDispatchers.DEACTIVATE);
}
private boolean objectCanDeactivate(Transaction transaction, ObjectInfo objectInfo) {
ObjectContainerBase container = transaction.container();
return container.callbacks().objectCanDeactivate(transaction, objectInfo)
&& dispatchEvent(transaction, objectInfo.getObject(), EventDispatchers.CAN_DEACTIVATE);
}
final void deactivateFields(final ActivationContext context) {
traverseAllAspects(new TraverseAspectCommand() {
public void processAspectOnMissingClass(ClassAspect aspect, int currentSlot) {
// do nothing
}
public void processAspect(ClassAspect aspect, int currentSlot) {
if(aspect.isEnabledOn(AspectVersionContextImpl.CHECK_ALWAYS_ENABLED)){
aspect.deactivate(context);
}
}
public int declaredAspectCount(ClassMetadata classMetadata) {
return classMetadata.declaredAspectCount();
}
public boolean cancelled() {
return false;
}
});
}
final void delete(StatefulBuffer buffer, Object obj) {
removeFromIndex(buffer.transaction(), buffer.getID());
cascadeDeletion(buffer, obj);
}
private void cascadeDeletion(StatefulBuffer buffer, Object obj) {
ObjectHeader oh = new ObjectHeader(this, buffer);
DeleteContextImpl context = new DeleteContextImpl(buffer, oh, classReflector(), null);
deleteMembers(context, arrayTypeFor(buffer, obj), false);
}
private ArrayType arrayTypeFor(StatefulBuffer buffer, Object obj) {
return buffer.transaction().container()._handlers.arrayType(obj);
}
public void delete(DeleteContext context) throws Db4oIOException {
correctHandlerVersion(context).delete(context);
}
void deleteMembers(DeleteContextImpl context, ArrayType arrayType, boolean isUpdate) {
StatefulBuffer buffer = (StatefulBuffer) context.buffer();
int preserveCascade = context.cascadeDeleteDepth();
try{
if (cascadeOnDelete()) {
if (classReflector().isCollection()) {
buffer.setCascadeDeletes(collectionDeleteDepth(context));
} else {
buffer.setCascadeDeletes(1);
}
}
Handlers4.fieldAwareTypeHandler(correctHandlerVersion(context)).deleteMembers(context, isUpdate);
}catch(Exception e){
// This a catch for changed class hierarchies.
// It's very ugly to catch all here but it does
// help to heal migration from earlier db4o
// versions.
DiagnosticProcessor dp = container()._handlers.diagnosticProcessor();
if(dp.enabled()){
dp.deletionFailed();
}
if(Debug4.atHome){
e.printStackTrace();
}
}
buffer.setCascadeDeletes(preserveCascade);
}
private int collectionDeleteDepth(DeleteContextImpl context) {
return 1;
}
/*
* If we use KEY as the parameter, this method can be more generic.
*/
public TernaryBool cascadeOnDeleteTernary() {
Config4Class config = config();
TernaryBool cascadeOnDelete = TernaryBool.UNSPECIFIED;
if(config != null && (cascadeOnDelete = config.cascadeOnDelete())!= TernaryBool.UNSPECIFIED) {
return cascadeOnDelete;
}
if(_ancestor == null) {
return cascadeOnDelete;
}
return _ancestor.cascadeOnDeleteTernary();
}
public boolean cascadeOnDelete() {
return cascadeOnDeleteTernary() == TernaryBool.YES;
}
public final boolean dispatchEvent(Transaction trans, Object obj, int message) {
return eventDispatcher().dispatch(trans, obj, message);
}
public final boolean hasEventRegistered(Transaction trans, int eventID) {
return eventDispatcher().hasEventRegistered(eventID);
}
private EventDispatcher eventDispatcher() {
if (null != _eventDispatcher) {
return _eventDispatcher;
}
_eventDispatcher = EventDispatchers.forClass(_container, classReflector());
return _eventDispatcher;
}
public final int declaredAspectCount(){
if(_aspects == null){
return 0;
}
return _aspects.length;
}
public final int aspectCount(){
int count = declaredAspectCount();
if(_ancestor != null){
count += _ancestor.aspectCount();
}
return count;
}
// Scrolls offset in passed reader to the offset the passed field should
// be read at.
public final HandlerVersion seekToField(Transaction trans, ByteArrayBuffer buffer, FieldMetadata field) {
if (buffer == null) {
return HandlerVersion.INVALID;
}
if(! standardReferenceTypeHandlerIsUsed()){
return HandlerVersion.INVALID;
}
buffer.seek(0);
ObjectHeader oh = new ObjectHeader(_container, buffer);
boolean res = oh.classMetadata().seekToField(new ObjectHeaderContext(trans, buffer, oh), field);
if(! res){
return HandlerVersion.INVALID;
}
return new HandlerVersion(oh.handlerVersion());
}
public final boolean seekToField(ObjectHeaderContext context, ClassAspect field){
if(! standardReferenceTypeHandlerIsUsed()){
return false;
}
return Handlers4.fieldAwareTypeHandler(correctHandlerVersion(context)).seekToField(context, field);
}
public boolean generateUUIDs() {
if(! generateVirtual()){
return false;
}
TernaryBool configValue = (_config == null) ? TernaryBool.UNSPECIFIED : _config.generateUUIDs();
return generate1(_container.config().generateUUIDs(), configValue);
}
public boolean generateCommitTimestamps() {
return _container.config().generateCommitTimestamps().definiteYes();
}
private boolean generateVirtual(){
if(_unversioned){
return false;
}
if(_internal){
return false;
}
return true;
}
private boolean generate1(ConfigScope globalConfig, TernaryBool individualConfig) {
return globalConfig.applyConfig(individualConfig);
}
public ClassMetadata getAncestor() {
return _ancestor;
}
public Object getComparableObject(Object forObject) {
if (_config != null) {
if (_config.queryAttributeProvider() != null) {
return _config.queryAttributeProvider().attribute(forObject);
}
}
return forObject;
}
public ClassMetadata getHigherHierarchy(ClassMetadata a_classMetadata) {
ClassMetadata yc = getHigherHierarchy1(a_classMetadata);
if (yc != null) {
return yc;
}
return a_classMetadata.getHigherHierarchy1(this);
}
private ClassMetadata getHigherHierarchy1(ClassMetadata a_classMetadata) {
if (a_classMetadata == this) {
return this;
}
if (_ancestor != null) {
return _ancestor.getHigherHierarchy1(a_classMetadata);
}
return null;
}
public ClassMetadata getHigherOrCommonHierarchy(ClassMetadata a_classMetadata) {
ClassMetadata yc = getHigherHierarchy1(a_classMetadata);
if (yc != null) {
return yc;
}
if (_ancestor != null) {
yc = _ancestor.getHigherOrCommonHierarchy(a_classMetadata);
if (yc != null) {
return yc;
}
}
return a_classMetadata.getHigherHierarchy1(this);
}
public byte getIdentifier() {
return Const4.YAPCLASS;
}
public long[] getIDs() {
synchronized(lock()){
if (! stateOK()) {
return new long[0];
}
return getIDs(_container.transaction());
}
}
public long[] getIDs(Transaction trans) {
synchronized(lock()){
if (! stateOK()) {
return new long[0];
}
if (! hasClassIndex()) {
return new long[0];
}
return trans.container().getIDsForClass(trans, this);
}
}
public boolean hasClassIndex() {
if(! _classIndexed){
return false;
}
return standardReferenceTypeHandlerIsUsed() || ! (Handlers4.isValueType(_typeHandler));
}
private boolean ancestorHasUUIDField(){
if(_ancestor == null) {
return false;
}
return _ancestor.hasUUIDField();
}
private boolean hasUUIDField() {
if(ancestorHasUUIDField()){
return true;
}
return Arrays4.containsInstanceOf(_aspects, UUIDFieldMetadata.class);
}
private boolean ancestorHasVersionField(){
if(_ancestor == null){
return false;
}
return _ancestor.hasVersionField();
}
private boolean ancestorHasCommitTimestampField(){
if(_ancestor == null){
return false;
}
return _ancestor.hasCommitTimestampField();
}
public boolean hasVersionField() {
if(ancestorHasVersionField()){
return true;
}
return Arrays4.containsInstanceOf(_aspects, VersionFieldMetadata.class);
}
private boolean hasCommitTimestampField() {
if(ancestorHasCommitTimestampField()){
return true;
}
return Arrays4.containsInstanceOf(_aspects, CommitTimestampFieldMetadata.class);
}
public ClassIndexStrategy index() {
return _index;
}
public int indexEntryCount(Transaction ta){
if(!stateOK()){
return 0;
}
return _index.entryCount(ta);
}
public ReflectClass classReflector(){
return _classReflector;
}
public String getName() {
if(i_name == null){
if(_classReflector != null){
setName(_classReflector.getName());
}
}
return i_name;
}
public StoredClass getParentStoredClass(){
return getAncestor();
}
public StoredField[] getStoredFields(){
synchronized(lock()){
if(_aspects == null){
return new StoredField[0];
}
final Collection4 storedFields = new Collection4();
traverseDeclaredFields(new Procedure4() {
public void apply(Object field) {
storedFields.add(field);
}
});
StoredField[] fields = new StoredField[storedFields.size()];
storedFields.toArray(fields);
return fields;
}
}
public final ObjectContainerBase container() {
return _container;
}
public FieldMetadata fieldMetadataForName(final String name) {
final ByRef byReference = new ByRef();
traverseAllAspects(new TraverseFieldCommand() {
@Override
protected void process(FieldMetadata field) {
if (name.equals(field.getName())) {
byReference.value = field;
}
}
});
return (FieldMetadata) byReference.value;
}
/** @param container */
public boolean hasField(ObjectContainerBase container, String fieldName) {
if(classReflector().isCollection()){
return true;
}
return fieldMetadataForName(fieldName) != null;
}
boolean hasVirtualAttributes(){
if(_internal){
return false;
}
return hasVersionField() || hasUUIDField();
}
public boolean holdsAnyClass() {
return classReflector().isCollection();
}
void incrementFieldsOffset1(ByteArrayBuffer a_bytes, HandlerVersionContext context) {
int length = readAspectCount(a_bytes);
for (int i = 0; i < length; i++) {
_aspects[i].incrementOffset(a_bytes, context);
}
}
final boolean init(ClassMetadata ancestor) {
if(DTrace.enabled){
DTrace.CLASSMETADATA_INIT.log(getID());
}
setConfig(configImpl().configClass(getName()));
setAncestor(ancestor);
checkType();
if (allowsQueries()) {
_index.initialize(_container);
}
bitTrue(Const4.CHECKED_CHANGES);
return true;
}
final void initConfigOnUp(Transaction systemTrans) {
Config4Class extendedConfig=Platform4.extendConfiguration(_classReflector, _container.configure(), _config);
if(extendedConfig!=null) {
_config=extendedConfig;
}
if (_config == null) {
return;
}
if (! stateOK()) {
return;
}
initializeFieldsConfiguration(systemTrans, extendedConfig);
checkAllConfiguredFieldsExist(extendedConfig);
}
private void initializeFieldsConfiguration(Transaction systemTrans, Config4Class extendedConfig) {
if (_aspects == null) {
return;
}
for (int i = 0; i < _aspects.length; i++) {
if(_aspects[i] instanceof FieldMetadata){
FieldMetadata field = (FieldMetadata) _aspects[i];
String fieldName = field.getName();
if(!field.hasConfig()
&& extendedConfig !=null
&& extendedConfig.configField(fieldName) != null) {
field.initConfiguration(fieldName);
}
field.initConfigOnUp(systemTrans);
}
}
}
private void checkAllConfiguredFieldsExist(Config4Class config) {
Hashtable4 exceptionalFields = config.exceptionalFieldsOrNull();
if (exceptionalFields == null) {
return;
}
Iterator4 i = exceptionalFields.valuesIterator();
while(i.moveNext()){
Config4Field fieldConfig = (Config4Field) i.current();
if(! fieldConfig.used()){
configImpl().diagnosticProcessor().objectFieldDoesNotExist(getName(), fieldConfig.getName());
}
}
}
void initOnUp(Transaction systemTrans) {
if (! stateOK()) {
return;
}
initConfigOnUp(systemTrans);
storeStaticFieldValues(systemTrans, false);
}
public Object instantiate(UnmarshallingContext context) {
// overridden in PrimitiveTypeMetadata
// never called for primitive YapAny
// FIXME: [TA] no longer necessary?
// context.adjustInstantiationDepth();
Object obj = context.persistentObject();
final boolean instantiating = (obj == null);
if (instantiating) {
obj = instantiateObject(context);
if (obj == null) {
return null;
}
shareTransaction(obj, context.transaction());
shareObjectReference(obj, context.objectReference());
onInstantiate(context, obj);
if (context.activationDepth().mode().isPrefetch()) {
context.objectReference().setStateDeactivated();
return obj;
}
if (!context.activationDepth().requiresActivation()) {
context.objectReference().setStateDeactivated();
return obj;
}
return activate(context);
}
if (activatingActiveObject(context.activationDepth().mode(), context.objectReference())) {
ActivationDepth child = context.activationDepth().descend(this);
if (child.requiresActivation()) {
cascadeActivation(new ActivationContext4(context.transaction(), obj, child));
}
return obj;
}
return activate(context);
}
protected final void onInstantiate(UnmarshallingContext context, Object obj) {
context.setObjectWeak(obj);
context.transaction().referenceSystem().addExistingReference(context.objectReference());
objectOnInstantiate(context.transaction(), context.objectReference());
}
public Object instantiateTransient(UnmarshallingContext context) {
// overridden in YapClassPrimitive
// never called for primitive YapAny
final Object obj = instantiateObject(context);
if (obj == null) {
return null;
}
context.container().peeked(context.objectId(), obj);
if(context.activationDepth().requiresActivation()){
instantiateFields(context);
}
return obj;
}
private boolean activatingActiveObject(final ActivationMode mode, ObjectReference ref) {
return !mode.isRefresh() && ref.isActive();
}
private Object activate(UnmarshallingContext context) {
final Object obj = context.persistentObject();
final ObjectReference objectReference = context.objectReference();
if(! objectCanActivate(context.transaction(), obj)){
objectReference.setStateDeactivated();
return obj;
}
objectReference.setStateClean();
if (context.activationDepth().requiresActivation()/* || cascadeOnActivate()*/) {
instantiateFields(context);
}
objectOnActivate(context.transaction(), objectReference);
return obj;
}
public boolean hasObjectConstructor(){
return _translator != null && _translator.isObjectConstructor();
}
public boolean isTranslated() {
return _translator != null ;
}
private Object instantiateObject(UnmarshallingContext context) {
Object obj = _constructor.apply(context);
context.persistentObject(obj);
return obj;
}
private void objectOnInstantiate(Transaction transaction, ObjectInfo reference) {
transaction.container().callbacks().objectOnInstantiate(transaction, reference);
}
private Object instantiateFromReflector(ObjectContainerBase stream) {
if (_classReflector == null) {
throw new IllegalStateException();
}
try {
return _classReflector.newInstance();
} catch (NoSuchMethodError e) {
container().logMsg(7, classReflector().getName());
return null;
} catch (Exception e) {
// TODO: be more helpful here
return null;
}
}
private void shareObjectReference(Object obj, ObjectReference ref) {
if (obj instanceof Db4oTypeImpl) {
((Db4oTypeImpl)obj).setObjectReference(ref);
}
}
private void shareTransaction(Object obj, Transaction transaction) {
if (obj instanceof TransactionAware) {
((TransactionAware)obj).setTrans(transaction);
}
}
private void objectOnActivate(Transaction transaction, ObjectInfo obj) {
ObjectContainerBase container = transaction.container();
container.callbacks().objectOnActivate(transaction, obj);
dispatchEvent(transaction, obj.getObject(), EventDispatchers.ACTIVATE);
}
private boolean objectCanActivate(Transaction transaction, Object obj) {
ObjectContainerBase container = transaction.container();
return container.callbacks().objectCanActivate(transaction, obj)
&& dispatchEvent(transaction, obj, EventDispatchers.CAN_ACTIVATE);
}
void instantiateFields(UnmarshallingContext context) {
TypeHandler4 handler = correctHandlerVersion((HandlerVersionContext)context);
Handlers4.activate(context, handler);
}
public boolean isArray() {
return classReflector().isCollection();
}
boolean isCollection(Object obj) {
return reflector().forObject(obj).isCollection();
}
public boolean isDirty() {
if (!stateOK()) {
return false;
}
return super.isDirty();
}
boolean isEnum() {
return Platform4.isJavaEnum(reflector(), classReflector());
}
public boolean hasIdentity(){
return true;
}
/**
* no any, primitive, array or other tricks. overridden in YapClassAny and
* YapClassPrimitive
*/
public boolean isStronglyTyped() {
return true;
}
public boolean isValueType(){
return Handlers4.holdsValueType(_typeHandler);
}
private final Object lock(){
return _container.lock();
}
public String nameToWrite() {
if(_config != null && _config.writeAs() != null){
return _config.writeAs();
}
if(i_name == null){
return "";
}
return configImpl().resolveAliasRuntimeName(i_name);
}
public final boolean callConstructor() {
TernaryBool specialized = callConstructorSpecialized();
// FIXME: If specified, return yes?!?
if(!specialized.isUnspecified()){
return specialized.definiteYes();
}
return configImpl().callConstructors().definiteYes();
}
private Config4Impl configImpl() {
return _container.configImpl();
}
private final TernaryBool callConstructorSpecialized(){
if(_config!= null){
TernaryBool res = _config.callConstructor();
if(!res.isUnspecified()){
return res;
}
}
if(isEnum()){
return TernaryBool.NO;
}
if(_ancestor != null){
return _ancestor.callConstructorSpecialized();
}
return TernaryBool.UNSPECIFIED;
}
public int ownLength() {
return MarshallerFamily.current()._class.marshalledLength(_container, this);
}
void purge() {
_index.purge();
// TODO: may want to add manual purge to Btree
// indexes here
}
public TypeHandler4 readCandidateHandler(QueryingReadContext context) {
TypeHandler4 typeHandler = correctHandlerVersion(context);
if(typeHandler instanceof CascadingTypeHandler){
return ((CascadingTypeHandler)typeHandler).readCandidateHandler(context);
}
return null;
}
public TypeHandler4 seekCandidateHandler(QueryingReadContext context) {
if (isArray()) {
if (Platform4.isCollectionTranslator(this._config)) {
context.seek(context.offset() + Const4.INT_LENGTH);
return new ArrayHandler(null, false);
}
incrementFieldsOffset1((ByteArrayBuffer)context.buffer(), context);
if (_ancestor != null) {
return _ancestor.seekCandidateHandler(context);
}
}
return null;
}
public final int readAspectCount(ReadBuffer buffer) {
int count = buffer.readInt();
if (count > _aspects.length) {
if (Debug4.atHome) {
System.out.println(
"ClassMetadata.readAspectCount "
+ getName()
+ " count to high:"
+ count
+ " _aspects:"
+ _aspects.length);
new Exception().printStackTrace();
}
return _aspects.length;
}
return count;
}
byte[] readName(Transaction a_trans) {
i_reader = a_trans.container().readBufferById(a_trans, getID());
return readName1(a_trans, i_reader);
}
public final byte[] readName1(Transaction trans, ByteArrayBuffer reader) {
if (reader == null)
return null;
i_reader = reader;
boolean ok = false;
try {
ClassMarshaller marshaller = MarshallerFamily.current()._class;
i_nameBytes = marshaller.readName(trans, reader);
marshaller.readMetaClassID(reader); // never used ???
setStateUnread();
bitFalse(Const4.CHECKED_CHANGES);
bitFalse(Const4.STATIC_FIELDS_STORED);
ok = true;
return i_nameBytes;
} finally {
if (!ok) {
setStateDead();
}
}
}
public void readVirtualAttributes(Transaction trans, ObjectReference ref, boolean lastCommitted) {
int id = ref.getID();
ObjectContainerBase container = trans.container();
ByteArrayBuffer buffer = container.readBufferById(trans, id, lastCommitted);
ObjectHeader oh = new ObjectHeader(this, buffer);
ObjectReferenceContext context = new ObjectReferenceContext(trans,buffer, oh, ref);
Handlers4.fieldAwareTypeHandler(correctHandlerVersion(context)).readVirtualAttributes(context);
}
public GenericReflector reflector() {
return _container.reflector();
}
public void rename(String newName){
if (_container.isClient()) {
Exceptions4.throwRuntimeException(58);
}
int tempState = _state;
setStateOK();
setName(newName);
i_nameBytes = asBytes(i_name);
setStateDirty();
write(_container.systemTransaction());
ReflectClass oldReflector = _classReflector;
classReflector(container().reflector().forName(newName));
container().classCollection().refreshClassCache(this, oldReflector);
refresh();
_state = tempState;
}
//TODO: duplicates ClassMetadataRepository#asBytes
private byte[] asBytes(String str) {
return container().stringIO().write(str);
}
final void resolveNameConfigAndReflector(ClassMetadataRepository repository, ReflectClass claxx) {
setName(resolveName(claxx));
if (i_nameBytes != null) {
repository.classMetadataNameResolved(this, i_nameBytes);
i_nameBytes = null;
}
setConfig(configImpl().configClass(getName()));
if (claxx == null) {
resolveClassReflector(getName());
} else {
classReflector(claxx);
}
}
String resolveName(ReflectClass claxx) {
if (i_nameBytes != null) {
String name = _container.stringIO().read(i_nameBytes);
return configImpl().resolveAliasStoredName(name);
}
if (claxx != null) {
return configImpl().resolveAliasStoredName(claxx.getName());
}
throw new IllegalStateException();
}
boolean readThis() {
boolean stateUnread = stateUnread();
if (stateUnread) {
setStateOK();
setStateClean();
}
if (stateUnread || stateDead()) {
forceRead();
return true;
}
return false;
}
final void forceRead(){
if(i_reader == null || bitIsTrue(Const4.READING)){
return;
}
bitTrue(Const4.READING);
try {
MarshallerFamily.forConverterVersion(_container.converterVersion())._class.read(_container, this, i_reader);
i_nameBytes = null;
i_reader = null;
} finally {
bitFalse(Const4.READING);
}
}
public void readThis(Transaction a_trans, ByteArrayBuffer a_reader) {
throw Exceptions4.virtualException();
}
public void refresh() {
if (!stateUnread()) {
resolveClassReflector(i_name);
bitFalse(Const4.CHECKED_CHANGES);
checkChanges();
traverseDeclaredFields(new Procedure4() {
public void apply(Object arg) {
((FieldMetadata)arg).refresh();
}
});
}
}
void removeFromIndex(Transaction ta, int id) {
if (hasClassIndex()) {
_index.remove(ta, id);
}
if (_ancestor != null) {
_ancestor.removeFromIndex(ta, id);
}
}
boolean renameField(final String oldName, final String newName) {
final BooleanByRef renamed = new BooleanByRef(false);
for (int i = 0; i < _aspects.length; i++) {
if (_aspects[i].getName().equals(newName)) {
_container.logMsg(9, "class:" + getName() + " field:" + newName);
return false;
}
}
traverseDeclaredFields(new Procedure4() {
public void apply(Object arg) {
FieldMetadata field = (FieldMetadata) arg;
if (field.getName().equals(oldName)) {
field.setName(newName);
renamed.value = true;
}
}
});
return renamed.value;
}
void setConfig(Config4Class config){
if(config == null){
return;
}
// The configuration can be set by a ObjectClass#readAs setting
// from YapClassCollection, right after reading the meta information
// for the first time. In that case we never change the setting
if(_config == null){
_config = config;
}
}
void setName(String a_name) {
i_name = a_name;
}
final void setStateDead() {
bitTrue(Const4.DEAD);
bitFalse(Const4.CONTINUE);
}
private final void setStateUnread() {
bitFalse(Const4.DEAD);
bitTrue(Const4.CONTINUE);
}
final void setStateOK() {
bitFalse(Const4.DEAD);
bitFalse(Const4.CONTINUE);
}
boolean stateDead(){
return bitIsTrue(Const4.DEAD);
}
final boolean stateOK() {
return bitIsFalse(Const4.CONTINUE)
&& bitIsFalse(Const4.DEAD)
&& bitIsFalse(Const4.READING);
}
boolean stateUnread() {
return bitIsTrue(Const4.CONTINUE)
&& bitIsFalse(Const4.DEAD)
&& bitIsFalse(Const4.READING);
}
boolean storeField(ReflectField field) {
if (field.isStatic()) {
return false;
}
if (isTransient(field)) {
if (!shouldStoreTransientFields()) {
return false;
}
}
return Platform4.canSetAccessible() || field.isPublic();
}
boolean shouldStoreTransientFields() {
Config4Class config = configOrAncestorConfig();
if (config == null) {
return false;
}
return config.storeTransientFields();
}
private boolean isTransient(ReflectField field) {
return field.isTransient() || Platform4.isTransient(field.getFieldType());
}
public StoredField storedField(final String fieldName, final Object fieldType) {
synchronized(lock()){
final ClassMetadata fieldTypeFilter = fieldType == null
? null
: _container.classMetadataForReflectClass(ReflectorUtils.reflectClassFor(reflector(), fieldType));
final ByRef foundField = new ByRef();
traverseAllAspects(new TraverseFieldCommand() {
@Override
protected void process(FieldMetadata field) {
if(foundField.value != null){
return;
}
if(field.getName().equals(fieldName)){
if(fieldTypeFilter == null || fieldTypeFilter == field.fieldType()){
foundField.value = field;
}
}
}
});
// TODO: implement field creation
return (StoredField) foundField.value;
}
}
void storeStaticFieldValues(Transaction trans, boolean force) {
if (bitIsTrue(Const4.STATIC_FIELDS_STORED) && !force) {
return;
}
bitTrue(Const4.STATIC_FIELDS_STORED);
if (!shouldStoreStaticFields(trans)) {
return;
}
final ObjectContainerBase stream = trans.container();
stream.showInternalClasses(true);
try {
StaticClass sc = queryStaticClass(trans);
if (sc == null) {
createStaticClass(trans);
} else {
updateStaticClass(trans, sc);
}
} finally {
stream.showInternalClasses(false);
}
}
private boolean shouldStoreStaticFields(Transaction trans) {
return !isReadOnlyContainer()
&& (staticFieldValuesArePersisted()
|| Platform4.storeStaticFieldValues(trans.reflector(), classReflector()));
}
private boolean isReadOnlyContainer() {
return container().config().isReadOnly();
}
private void updateStaticClass(final Transaction trans, final StaticClass sc) {
final ObjectContainerBase stream = trans.container();
stream.activate(trans, sc, new FixedActivationDepth(4));
final StaticField[] existingFields = sc.fields;
final Iterator4 staticFields = Iterators.map(
staticReflectFields(),
new Function4() {
public Object apply(Object arg) {
final ReflectField reflectField = (ReflectField)arg;
StaticField existingField = fieldByName(existingFields, reflectField.getName());
if (existingField != null) {
updateExistingStaticField(trans, existingField, reflectField);
return existingField;
}
return toStaticField(reflectField);
}
});
sc.fields = toStaticFieldArray(staticFields);
if (!stream.isClient()) {
setStaticClass(trans, sc);
}
}
private void createStaticClass(Transaction trans) {
if (trans.container().isClient()) {
return;
}
StaticClass sc = new StaticClass(getName(), toStaticFieldArray(staticReflectFieldsToStaticFields()));
setStaticClass(trans, sc);
}
private Iterator4 staticReflectFieldsToStaticFields() {
return Iterators.map(
staticReflectFields(),
new Function4() {
public Object apply(Object arg) {
return toStaticField((ReflectField) arg);
}
});
}
protected StaticField toStaticField(final ReflectField reflectField) {
return new StaticField(reflectField.getName(), staticReflectFieldValue(reflectField));
}
private Object staticReflectFieldValue(final ReflectField reflectField) {
return _fieldAccessor.get(reflectField, null);
}
private void setStaticClass(Transaction trans, StaticClass sc) {
// TODO: we should probably use a specific update depth here, 4?
trans.container().storeInternal(trans, sc, true);
}
private StaticField[] toStaticFieldArray(Iterator4 iterator4) {
return toStaticFieldArray(new Collection4(iterator4));
}
private StaticField[] toStaticFieldArray(Collection4 fields) {
return (StaticField[]) fields.toArray(new StaticField[fields.size()]);
}
private Iterator4 staticReflectFields() {
return Iterators.filter(reflectFields(), new Predicate4() {
public boolean match(Object candidate) {
return ((ReflectField)candidate).isStatic() && !((ReflectField)candidate).isTransient();
}
});
}
private ReflectField[] reflectFields() {
return classReflector().getDeclaredFields();
}
protected void updateExistingStaticField(Transaction trans, StaticField existingField, final ReflectField reflectField) {
final ObjectContainerBase stream = trans.container();
final Object newValue = staticReflectFieldValue(reflectField);
if (existingField.value != null
&& newValue != null
&& existingField.value.getClass() == newValue.getClass()) {
int id = stream.getID(trans, existingField.value);
if (id > 0) {
if (existingField.value != newValue) {
// This is the clue:
// Bind the current static member to it's old database identity,
// so constants and enums will work with '=='
stream.bind(trans, newValue, id);
// This may produce unwanted side effects if the static field object
// was modified in the current session. TODO:Add documentation case.
stream.refresh(trans, newValue, Integer.MAX_VALUE);
existingField.value = newValue;
}
return;
}
}
if(newValue == null){
try{
_fieldAccessor.set(reflectField, null, existingField.value);
}catch(Exception ex){
// fail silently
// TODO: why?
}
return;
}
existingField.value = newValue;
}
private boolean staticFieldValuesArePersisted() {
return (_config != null && _config.staticFieldValuesArePersisted());
}
protected StaticField fieldByName(StaticField[] fields, final String fieldName) {
for (int i = 0; i < fields.length; i++) {
final StaticField field = fields[i];
if (fieldName.equals(field.name)) {
return field;
}
}
return null;
}
private StaticClass queryStaticClass(Transaction trans) {
Query q = trans.container().query(trans);
q.constrain(Const4.CLASS_STATICCLASS);
q.descend("name").constrain(getName());
ObjectSet os = q.execute();
return os.size() > 0
? (StaticClass)os.next()
: null;
}
public String toString() {
if(i_name!=null) {
return i_name;
}
if(i_nameBytes==null){
return "*CLASS NAME UNKNOWN*";
}
LatinStringIO stringIO =
_container == null ?
Const4.stringIO
: _container.stringIO();
return stringIO.read(i_nameBytes);
}
@Override
public boolean writeObjectBegin() {
if (!stateOK()) {
return false;
}
return super.writeObjectBegin();
}
public final void writeThis(Transaction trans, ByteArrayBuffer writer) {
MarshallerFamily.current()._class.write(trans, this, writer);
}
public PreparedComparison prepareComparison(Context context, Object source) {
return Handlers4.prepareComparisonFor(_typeHandler, context, source);
}
public static void defragObject(DefragmentContextImpl context) {
ObjectHeader header = ObjectHeader.defrag(context);
DefragmentContextImpl childContext = new DefragmentContextImpl(context, header);
header.classMetadata().defragment(childContext);
}
public void defragment(DefragmentContext context) {
correctHandlerVersion(context).defragment(context);
}
public void defragClass(DefragmentContextImpl context, int classIndexID) {
MarshallerFamily mf = MarshallerFamily.forConverterVersion(container().converterVersion());
mf._class.defrag(this,_container.stringIO(), context, classIndexID);
}
public static ClassMetadata readClass(ObjectContainerBase stream, ByteArrayBuffer reader) {
ObjectHeader oh = new ObjectHeader(stream, reader);
return oh.classMetadata();
}
public boolean isAssignableFrom(ClassMetadata other) {
return classReflector().isAssignableFrom(other.classReflector());
}
public void setAncestor(ClassMetadata ancestor){
if(ancestor == this){
throw new IllegalStateException();
}
_ancestor = ancestor;
}
public Object wrapWithTransactionContext(Transaction transaction, Object value) {
if(value instanceof Integer){
return value;
}
return new TransactionContext(transaction, value);
}
public TypeHandler4 typeHandler(){
return _typeHandler;
}
public TypeHandler4 delegateTypeHandler(Context context){
if(context instanceof HandlerVersionContext){
return correctHandlerVersion((HandlerVersionContext)context);
}
return _typeHandler;
}
protected TypeHandler4 correctHandlerVersion(HandlerVersionContext context){
TypeHandler4 typeHandler = HandlerRegistry.correctHandlerVersion(context, _typeHandler);
if(typeHandler != _typeHandler){
if(typeHandler instanceof StandardReferenceTypeHandler){
((StandardReferenceTypeHandler) typeHandler).classMetadata(this);
}
}
return typeHandler;
}
public void traverseDeclaredFields(Procedure4 procedure) {
if(_aspects == null){
return;
}
for (int i = 0; i < _aspects.length; i++) {
if(_aspects[i] instanceof FieldMetadata){
procedure.apply(_aspects[i]);
}
}
}
public void traverseDeclaredAspects(Procedure4 procedure){
if(_aspects == null){
return;
}
for (int i = 0; i < _aspects.length; i++) {
procedure.apply(_aspects[i]);
}
}
public boolean aspectsAreNull(){
return _aspects == null;
}
private static final class AlwaysModified implements ModificationAware{
static final AlwaysModified INSTANCE = new AlwaysModified();
public boolean isModified(Object obj) {
return true;
}
}
public boolean isModified(Object obj) {
return _modificationChecker.isModified(obj);
}
public int instanceCount() {
return instanceCount(_container.transaction());
}
public int instanceCount(Transaction trans) {
return _container.instanceCount(this, trans);
}
public boolean isStorable() {
return !stateDead() && !isTransient();
}
private Object instantiateWithCustomTypeHandlerIfEnabled(final UnmarshallingContext context) {
if (!_customTypeHandlerAspect.isEnabledOn(context)) {
return instantiateForVersionWithoutCustomTypeHandler(context);
}
return instantiateWithCustomTypeHandler(context);
}
private Object instantiateForVersionWithoutCustomTypeHandler(final UnmarshallingContext context) {
final Function4<UnmarshallingContext, Object> oldVersionConstructor = createConstructor(null);
if (null == oldVersionConstructor) {
throw new IllegalStateException();
}
return oldVersionConstructor.apply(context);
}
private Object instantiateWithCustomTypeHandler(final UnmarshallingContext context) {
final ContextState contextState = context.saveState();
try {
final boolean fieldHasValue = seekToField(context, _customTypeHandlerAspect);
if (!fieldHasValue) {
context.restoreState(contextState);
return instantiateForVersionWithoutCustomTypeHandler(context);
}
final InstantiatingTypeHandler customTypeHandler = (InstantiatingTypeHandler)_customTypeHandlerAspect._typeHandler;
return context.slotFormat().doWithSlotIndirection(context, new Closure4<Object>() { public Object run() {
return customTypeHandler.instantiate(context);
}});
} finally {
context.restoreState(contextState);
}
}
public boolean isStruct() {
if(_isStruct == TernaryBool.UNSPECIFIED){
_isStruct = Platform4.isStruct(classReflector()) ? TernaryBool.YES : TernaryBool.NO;
}
return _isStruct == TernaryBool.YES;
}
public void dropClassIndex() {
if(container().isClient()){
throw new IllegalStateException();
}
_index = createIndexStrategy();
_index.initialize(container());
container().setDirtyInSystemTransaction(this);
}
public void traverseAllAspects(TraverseAspectCommand command) {
aspectTraversalStrategy().traverseAllAspects(command);
}
private AspectTraversalStrategy aspectTraversalStrategy() {
if(_aspectTraversalStrategy == null){
_aspectTraversalStrategy = detectAspectTraversalStrategy();
}
return _aspectTraversalStrategy;
}
protected AspectTraversalStrategy detectAspectTraversalStrategy() {
List<HierarchyAnalyzer.Diff> ancestors = compareAncestorHierarchy();
for (Diff diff: ancestors){
if(diff.isRemoved()){
return createRemovedAspectTraversalStrategy(ancestors);
}
}
return new StandardAspectTraversalStrategy(this);
}
private AspectTraversalStrategy createRemovedAspectTraversalStrategy(
List<Diff> ancestors) {
return new ModifiedAspectTraversalStrategy(this, ancestors);
}
private List<HierarchyAnalyzer.Diff> compareAncestorHierarchy() {
return new HierarchyAnalyzer(this, classReflector()).analyze();
}
}