Initial commit from SVN.

This commit is contained in:
wcrisman
2014-05-30 10:31:51 -07:00
commit b45e56b890
1968 changed files with 370949 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public abstract class AbstractReflectData implements java.io.Externalizable {
/** The object identifying the reflection. */
long reflectionId = 0;
/** A reference to the reflected object. This will be set by collections when creating an array of reflection data objects for contained reflectable values. */
public IReflectable reflected = null;
/** A reference to the reflected object's class. The caller may not know the exact type for the reflection and thus must create the reflection after receiving this reflection data object. */
Class reflectedType = null;
/** The signature identifying which constructor to call when creating a new instance of the collection that will become the reflection. */
public Class[] reflectedTypeConstructorSignature = null;
/** The parameters passed to the constructor when creating a new instance of the collection that will become the reflection. */
public Object[] reflectedTypeConstructorParameters = null;
/** Used to pass the handler reference to the initializing reflection. This value will NOT be serialized. */
ReflectionContext context = null;
/** Whether the reflection data will include the referenced object's reflection data. This may be false if updating since it is currently impossible to collect referenced object's data outside the monitor due to the need to not lose the monitor during what ever operation is causing the update. */
private boolean includesReferencedData = false;
/** The reflection id of the reflection in the same context and of a component object of the same logical object, which will be used track the message index for all objects in the logical object reflected by the reflection context. */
public long mappedReflectionId = 0; //TODO: Change to 'categoryNumber' or 'categoryId'
/** The mapping number is passed only as a result of a synchronization, and only back to the synchronizing reflection context. It allows the synchronizing reflection context to reuse the models that are new (not shared) whose copies were sent as part of the synchronize operation. This reuse allows reflections of the new objects to be maintained. */
public int modelMappingNumber = -1;
/**
* AbstractReflectData constructor.
*/
public AbstractReflectData() {
super();
}//AbstractReflectData()//
/**
* Gets the reflected object.
* @return The reflected object. This value may be null at any given time.
*/
public IReflectable getReflected() {
return reflected;
}//getReflected()//
/**
* Whether the reflection data will include the referenced object's reflection data.
* This may be false if updating since it is currently impossible to collect referenced object's data outside the monitor due to the need to not lose the monitor during what ever operation is causing the update.
* @return
*/
public boolean includesReferencedData() {
return includesReferencedData;
}//includesReferencedData()//
/**
* Whether the reflection data will include the referenced object's reflection data.
* This may be false if updating since it is currently impossible to collect referenced object's data outside the monitor due to the need to not lose the monitor during what ever operation is causing the update.
* @param includesReferencedData
*/
public void includesReferencedData(boolean includesReferencedData) {
this.includesReferencedData = includesReferencedData;
}//includesReferencedData()//
/**
* Creates the reflection from this reflection data.
* <p>Warning: The caller must first ensure the context has been set for this data.</p>
* @return The reflection created.
*/
public abstract IReflectable createReflection() throws InstantiationException, IllegalAccessException;
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
/*byte version = */in.readByte();
reflectionId = in.readLong();
reflected = (IReflectable) in.readObject();
reflectedType = (Class) in.readObject();
reflectedTypeConstructorSignature = (Class[]) in.readObject();
reflectedTypeConstructorParameters = (Object[]) in.readObject();
mappedReflectionId = in.readLong();
modelMappingNumber = in.readInt();
includesReferencedData = in.readBoolean();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
out.writeByte(0);
out.writeLong(reflectionId);
out.writeObject(reflected);
out.writeObject(reflectedType);
out.writeObject(reflectedTypeConstructorSignature);
out.writeObject(reflectedTypeConstructorParameters);
out.writeLong(mappedReflectionId);
out.writeInt(modelMappingNumber);
out.writeBoolean(includesReferencedData);
}//readExternal()//
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return reflectedType != null ? reflectedType.getName() : super.toString();
}//toString()//
}//AbstractReflectData//

View File

@@ -0,0 +1,652 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.debug.Debug;
import com.common.orb.Orb;
import com.common.thread.Monitor;
import com.common.util.EmptyIterator;
import com.common.util.IIterator;
import com.common.util.LiteHashMap;
import com.common.util.LiteHashSet;
import com.common.util.LiteList;
import com.common.util.optimized.LongArray;
import com.foundation.common.IEntity;
import com.foundation.metadata.TypeCallbackHandler;
public abstract class AbstractReflectSupport extends Monitor implements IReflectSupport {
/** The thread local used to delay reflection updates while synchronizing. */
private static final ThreadLocal delayedReflectionUpdateHandler = new ThreadLocal();
/** A reference to the entity that this entity is a part of. If the entity is not a part of another entity then this will be null. */
private transient volatile IEntity partOfEntity = null;
/** The number of times the part of entity has been set to the same value. */
private transient volatile int partOfEntityCounter = 0;
/** The map used to store the next message number for use when sending updates to reflections of this object. This will be null if this object is part-of another object. */
private LiteHashMap nextMessageIndexMap = null;
/** The set of all ReflectionHolder instances, one for each reflection of the supported object. The reflection holder can be retrieved by using the reflection update handler (they are .equals comparable). */
private LiteHashSet registeredReflections = null;
/** The context object used to support this reflection. If this object is not a reflection then this value will be null. The context also handles incomming messages. */
private ReflectionContext reflectionContext = null;
/** The object identifying the reflection within its context. */
private Long reflectionId = null;
/** The category id number (which is one of the reflection id numbers issued by the reflection context to the reflected objects) which is used by the reflected object to group updates to reflections of a logical object. This value may change. */
private long categoryNumber = 0;
/** The hash code for the reflectable. The hash should be the same for all reflections and the reflected object. */
private int hash = 0;
/**
* Holds the message index and related data for the registered reflections in a logical object (one made up of one or more objects that reference each other as part-of).
*/
protected static class NextMessageHolder {
/** The last used message index which is used to order the messages and to verify that the synchronized data was verified based on the lastest from the reflected objects. */
public int messageIndex = 0;
/** The category number (one of the reflection id's issued by the reflection context that created the reflections) provides the reflection's context a way to group the message index for objects that are part-of. Note that the number won't change even if the reflection with that id is released. */
public long categoryNumber = -1;
/** The count of how many times the holder has been referenced. This is incremented every time a reflection is created by the same reflection context within this logical object. */
public int counter = 1;
}//NextMessageHolder//
protected static abstract class AbstractReflectTypeCallbackHandler extends TypeCallbackHandler {
/**
* Gets the count of times the part-of entity has been set to the current value.
* @return The counter for setting the part of entity.
*/
protected int getPartOfEntityCounter(AbstractReflectSupport instance) {
return instance.getPartOfEntityCounter();
}//getPartOfEntityCounter()//
/**
* Sets the count of times the part-of entity has been set to the current value.
* @param partOfEntityCounter The counter for setting the part of entity.
*/
protected void setPartOfEntityCounter(AbstractReflectSupport instance, int partOfEntityCounter) {
instance.setPartOfEntityCounter(partOfEntityCounter);
}//setPartOfEntityCounter()//
/**
* Gets the entity the collection is part of.
* @return The entity that this collection is a part of. This may be null.
*/
protected IEntity getPartOfEntity(AbstractReflectSupport instance) {
return instance.getPartOfEntity();
}//getPartOfEntity()//
/**
* Sets the entity the collection is part of.
* @param partOfEntity The entity that this collection is a part of. This may be null.
*/
protected void setPartOfEntity(AbstractReflectSupport instance, IEntity partOfEntity) {
instance.setPartOfEntity(partOfEntity);
}//setPartOfEntity()//
}//AbstractReflectTypeCallbackHandler//
/**
* A single update that is being delayed.
*/
private static class DelayedReflectionUpdate {
public NextMessageHolder holder;
public IReflectUpdateHandler handler;
public long reflectionId;
public AbstractReflectData data;
public DelayedReflectionUpdate(NextMessageHolder holder, IReflectUpdateHandler handler, long reflectionId, AbstractReflectData data) {
this.holder = holder;
this.handler = handler;
this.reflectionId = reflectionId;
this.data = data;
}//DelayedReflectionUpdate()//
}//DelayedReflectionUpdate//
/**
* The handler that is used to delay a set of reflection updates and execute them at a later time.
*/
private static class DelayedReflectionUpdateHandler {
protected int startCount = 1;
private LiteList updates = new LiteList(100, 1000);
/**
* DelayedReflectionUpdateHandler constructor.
*/
private DelayedReflectionUpdateHandler() {
}//DelayedReflectionUpdateHandler()//
public void addUpdate(NextMessageHolder holder, IReflectUpdateHandler handler, long reflectionId, AbstractReflectData data) {
updates.add(new DelayedReflectionUpdate(holder, handler, reflectionId, data));
}//addUpdate()//
public void executeUpdates() {
//Execute each queued update in order.//
for(int index = 0; index < updates.getSize(); index++) {
DelayedReflectionUpdate next = (DelayedReflectionUpdate) updates.get(index);
int messageNumber = ++next.holder.messageIndex;
long categoryNumber = next.holder.categoryNumber;
if(!Orb.isLocal(next.handler)) {
Orb.setOneWayCall(next.handler);
}//if//
//Send the reflected index and message index along with the data so that the receiver knows which reflection is being updated and what the ordering is for the update.//
next.handler.update(next.reflectionId, next.data, messageNumber, categoryNumber);
}//for//
updates.removeAll();
}//executeUpdates()//
}//DelayedReflectionUpdateHandler//
/**
* Begins delaying all reflection updates.
* This method may be called repeatedly, but for each call to start delaying updates there must be a corresponding call to stop delaying updates.
* Updates will be executed when the last call to stop delaying updates is made.
*/
public static void startDelayingReflectionUpdates() {
DelayedReflectionUpdateHandler handler = (DelayedReflectionUpdateHandler) delayedReflectionUpdateHandler.get();
if(handler == null) {
handler = new DelayedReflectionUpdateHandler();
delayedReflectionUpdateHandler.set(handler);
}//if//
else {
handler.startCount++;
}//else//
}//startDelayingReflectionUpdates()//
/**
* Stops delaying reflection updates.
* This method must be called exactly once for each call to start delaying updates.
* @param sendUpdates Whether send the updates. This is only valid for the last stop call, if multiple start calls were made.
*/
public static void stopDelayingReflectionUpdates(boolean sendUpdates) {
DelayedReflectionUpdateHandler handler = (DelayedReflectionUpdateHandler) delayedReflectionUpdateHandler.get();
if(--handler.startCount == 0) {
delayedReflectionUpdateHandler.set(null);
if(sendUpdates) {
handler.executeUpdates();
}//if//
}//if//
}//stopDelayingReflectionUpdates()//
/**
* AbstractReflectSupport constructor.
*/
public AbstractReflectSupport() {
super();
//Should this be here? This code was pushed down from ReflectObjectSupport and ReflectCollectionSupport, but for some reason they were implemented differently.//
//ReflectCollectionSupport had this line in the constructors. ReflectObjectSupport relied on the Entity calling it, but nothing called the entity's method.//
//Note: I have removed this code because it fails to work when an object is deserialized and then placed in a single threaded context.
//this.singleThreadedContext = ThreadService.getSingleThreadedContext();
this.hash = super.hashCode();
}//AbstractReflectSupport()//
/**
* AbstractReflectSupport constructor.
* @param supported The object being supported. This is passed on to the monitor.
*/
public AbstractReflectSupport(Object supported) {
super(supported);
//Should this be here? This code was pushed down from ReflectObjectSupport and ReflectCollectionSupport, but for some reason they were implemented differently.//
//ReflectCollectionSupport had this line in the constructors. ReflectObjectSupport relied on the Entity calling it, but nothing called the entity's method.//
//Note: I have removed this code because it fails to work when an object is deserialized and then placed in a single threaded context.
//this.singleThreadedContext = ThreadService.getSingleThreadedContext();
this.hash = super.hashCode();
}//AbstractReflectSupport()//
/**
* Gets the reflection's context object.
* @return The reflection context, or null if the supported object is not a reflection.
*/
protected ReflectionContext getReflectionContext() {
return reflectionContext;
}//getReflectionContext()//
/**
* Sets the reflection's context object.
* @param reflectionContext The reflection context, or null if the supported object is not a reflection.
*/
public void setReflectionContext(ReflectionContext reflectionContext) {
this.reflectionContext = reflectionContext;
}//setReflectionContext()//
/**
* Determines whether the supported object is a reflection.
* @return Whether the supported collection is a reflection of another object.
*/
public boolean isReflection() {
return getReflectionId() != null;
}//isReflection()//
/**
* Determines whether this reflectable object is a reflection created within the given context.
* @param reflectionContext The optional context used to check whether this is a reflection. If null then the response will be true if the object is a reflection in any context.
* @return Whether this object is a reflection of another object and was created in the given context.
*/
protected boolean isReflection(ReflectionContext reflectionContext) {
return (reflectionContext == null || reflectionContext == this.reflectionContext) && getReflectionId() != null;
}//isReflection()//
/**
* Gets the reflection's identifying object.
* @return The object which identifies the reflection within the context of the reflection context (aka reflection manager).
*/
protected Object getReflectionId() {
return reflectionId;
}//getReflectionId()//
/**
* Initializes this object as a reflection of another object of the same type.
* @param reflectionData The data necessary to initialize the object as a reflection of another object.
* @return A replacement reflection if another reflection exists for the reflected object, or null if the initialization went smoothly.
*/
protected Object reflectionInitialize(AbstractReflectData reflectionData) {
//Register this reflection support with the handler.//
reflectionContext = reflectionData.context;
reflectionId = new Long(reflectionData.reflectionId);
setCategoryNumber(reflectionData.mappedReflectionId);
return reflectionContext.register(reflectionId, this);
}//reflectionInitialize()//
/**
* Destroys this object as a reflection of another object of the same type.
* The actual object will not be destroyed, but it will no longer reflect another object.
* <p>Warning: This method must be called for every reflection. Not calling this method may result in a memory leak.</p>
*/
public void destroyReflection() {
//This value may be null if the reflection is being destroyed due to another identical reflection already existing.//
if(reflectionContext != null) {
//Unregister this reflection support with the handler.//
reflectionContext.unregister(reflectionId);
}//if//
reflectionId = null;
reflectionContext = null;
}//destroyReflection()//
/**
* Gets the last sent update message's number for a perticular reflection.
* @param updateHandler The update handler for the reflection whose previous update number should be accessed.
* @return The reflection's last sent message number.
*/
protected int reflectionGetLastUpdateMessageNumber(IReflectUpdateHandler updateHandler) {
int result = -1;
if(getPartOfEntity() == null) {
NextMessageHolder holder = (NextMessageHolder) nextMessageIndexMap.get(updateHandler);
result = holder.messageIndex;
}//if//
else {
result = ((IReflectable) getPartOfEntity()).zzrReflectionGetLastUpdateMessageNumber(getPartOfEntity(), updateHandler);
}//else//
if(result == -1) {
Debug.log(new RuntimeException("Failed to locate a last update number for the given reflect update handler."));
}//if//
return result;
}//reflectionGetLastUpdateMessageNumber()//
/**
* Initializes the update message number for this reflectable object.
* @param updateHandler The handler for the reflection context that is creating a reflection.
* @return The reflection identifier for the first reflection from this update handler to be created within the logical object.
*/
public long initializeUpdateMessageNumber(IReflectUpdateHandler updateHandler, long reflectionId) {
long result = -1;
//TODO: If this object is part of a single threaded context, then delegate the next message number handling to it.
if(getPartOfEntity() == null) {
NextMessageHolder holder;
if(nextMessageIndexMap == null) {
nextMessageIndexMap = new LiteHashMap(20);
}//if//
holder = (NextMessageHolder) nextMessageIndexMap.get(updateHandler);
if(holder == null) {
holder = new NextMessageHolder();
holder.categoryNumber = reflectionId;
holder.messageIndex = 0;
result = reflectionId;
nextMessageIndexMap.put(updateHandler, holder);
}//if//
else {
result = holder.categoryNumber;
holder.counter++;
}//else//
}//if//
else {
result = getPartOfEntity().getAttributeSupport().initializeUpdateMessageNumber(updateHandler, reflectionId);
}//else//
return result;
}//initializeUpdateMessageNumber()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getCategoryNumber()
*/
public long getCategoryNumber() {
return categoryNumber;
}//getCategoryNumber()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#setCategoryNumber(long)
*/
public void setCategoryNumber(long categoryNumber) {
this.categoryNumber = categoryNumber;
}//setCategoryNumber()//
/**
* Gets the next update message holder for the reflection context represented by the update handler and within this logical object.
* @param updateHandler The update handler which represents the reflection and reflection context.
* @return The next message number usable to send a message to the reflection.
*/
protected NextMessageHolder getNextUpdateMessageHolder(IReflectUpdateHandler updateHandler) {
AbstractReflectSupport root = getLogicalObjectRoot();
if(root.nextMessageIndexMap == null) {
Debug.log(new RuntimeException("Failed to locate a last update number for the given reflect update handler."));
}//if//
return (NextMessageHolder) root.nextMessageIndexMap.get(updateHandler);
}//getNextUpdateMessageHolder()//
/**
* Removes the next update message holder for the reflection context represented by the update handler and within this logical object.
* @param updateHandler The update handler which represents the reflection and reflection context.
*/
protected void removeNextUpdateMessageHolder(IReflectUpdateHandler updateHandler) {
AbstractReflectSupport root = getLogicalObjectRoot();
if(root.nextMessageIndexMap == null) {
Debug.log(new RuntimeException("Failed to locate a last update number for the given reflect update handler."));
}//if//
root.nextMessageIndexMap.remove(updateHandler);
if(root.nextMessageIndexMap.getSize() == 0) {
root.nextMessageIndexMap = null;
}//if//
}//removeNextUpdateMessageHolder()//
/**
* Gets the root object for this logical object by traversing the part of entity references.
* @return The root abstract reflect support reference for this logical object. The root object will hold the nextMessageIndexMap for the logical object.
*/
protected AbstractReflectSupport getLogicalObjectRoot() {
AbstractReflectSupport result = this;
//Iteratively search for the top of the logical object.//
while(result.getPartOfEntity() != null) {
result = result.getPartOfEntity().getAttributeSupport();
}//while//
return result;
}//getLogicalObjectRoot()//
/**
* Updates a reflection with the latest data from this reflected object.
* @param reflectData The collection of changes.
*/
protected void updateReflection(ReflectionHolder holder, AbstractReflectData reflectData) {
DelayedReflectionUpdateHandler handler = (DelayedReflectionUpdateHandler) delayedReflectionUpdateHandler.get();
if(handler != null) {
handler.addUpdate(getNextUpdateMessageHolder(holder.getHandler()), holder.getHandler(), holder.getReflectionId(), reflectData);
}//if//
else {
NextMessageHolder nextMessageHolder = getNextUpdateMessageHolder(holder.getHandler());
int messageNumber = ++nextMessageHolder.messageIndex;
long categoryNumber = nextMessageHolder.categoryNumber;
if(!Orb.isLocal(holder.getHandler())) {
Orb.setOneWayCall(holder.getHandler());
}//if//
//Send the reflected index and message index along with the data so that the receiver knows which reflection is being updated and what the ordering is for the update.//
holder.getHandler().update(holder.getReflectionId(), reflectData, messageNumber, categoryNumber);
}//else//
}//updateReflection()//
/**
* Gets a reflectable proxy given the reflectable object.
* @param reflectable The reflectable object.
* @return The proper reflectable proxy.
*/
public IReflectable getReflectionProxy(IReflectable reflectable) {
IReflectable result = null;
if(reflectable instanceof IReflectableObject) {
result = (IReflectable) Orb.getProxy(reflectable, IReflectableObject.class);
}//if//
else {
result = (IReflectable) Orb.getProxy(reflectable, IReflectableCollection.class);
}//else//
return result;
}//getReflectionProxy()//
/**
* Gets the count of times the part-of entity has been set to the current value.
* @return The counter for setting the part of entity.
*/
protected int getPartOfEntityCounter() {
return partOfEntityCounter;
}//getPartOfEntityCounter()//
/**
* Sets the count of times the part-of entity has been set to the current value.
* @param partOfEntityCounter The counter for setting the part of entity.
*/
protected void setPartOfEntityCounter(int partOfEntityCounter) {
this.partOfEntityCounter = partOfEntityCounter;
}//setPartOfEntityCounter()//
/**
* Gets the entity the collection is part of.
* @return The entity that this collection is a part of. This may be null.
*/
protected IEntity getPartOfEntity() {
return partOfEntity;
}//getPartOfEntity()//
/**
* Provides internal, back door access to set or clear the part of entity.
* @param entity The new entity this supported object is part-of, or null if the part-of entity should be cleared.
*/
protected void internalSetPartOfEntity(IEntity partOfEntity) {
if(partOfEntity == null) {
this.partOfEntity = null;
setPartOfEntityCounter(0);
}//if//
else {
//Leave the counter alone. We are simply swaping parents.//
this.partOfEntity = partOfEntity;
}//else//
}//internalClearPartOfEntity()//
/**
* Sets the entity the collection is part of.
* <p>Note that this is never called with a null value, and the caller always makes sure that the current partOfEntity is null. The counter is also handled by the caller.</p>
* @param partOfEntity The entity that this collection is a part of. This will never be null.
*/
protected void setPartOfEntity(IEntity partOfEntity) {
if(this.partOfEntity != null) {
if(this.partOfEntity != partOfEntity) {
throw new RuntimeException("A model or collection cannot be part-of two different objects (even within a single logical object).");
}//if//
else {
//TODO: Do anything?
}//else//
}//if//
else {
this.partOfEntity = partOfEntity;
//Combine the nextMessageIndexMap with the top of the new logical object.//
//Send the reflections a notice with the new category number.//
if((nextMessageIndexMap != null) && (nextMessageIndexMap.getSize() > 0)) {
AbstractReflectSupport root = getLogicalObjectRoot();
IIterator iterator = nextMessageIndexMap.keyIterator();
if(root.nextMessageIndexMap == null) {
root.nextMessageIndexMap = new LiteHashMap(20);
}//if//
while(iterator.hasNext()) {
IReflectUpdateHandler handler = (IReflectUpdateHandler) iterator.next();
NextMessageHolder oldHolder = (NextMessageHolder) nextMessageIndexMap.get(handler);
NextMessageHolder newHolder = (NextMessageHolder) root.nextMessageIndexMap.get(handler);
if(newHolder == null) {
root.nextMessageIndexMap.put(handler, oldHolder);
}//if//
else {
newHolder.counter += oldHolder.counter;
//Tell the reflection context to join the reflection message indices and pass the next index number for each holder so that it gets handled at the correct time.//
handler.joinReflections(oldHolder.categoryNumber, newHolder.categoryNumber, ++oldHolder.messageIndex, ++newHolder.messageIndex);
}//else//
}//while//
}//if//
//Clear the next message index map since it will now be maintained by the new logical object root.//
nextMessageIndexMap = null;
}//else//
}//setPartOfEntity()//
/**
* Collects the reflect update handlers and associates them with the LongArray of refection id numbers for the objects reflected by the handler.
* <p>Note: This method normally kicks off the call to internalCollectReflectUpdateHandlers which recursively searches for reflect update handlers.</p>
* @param reflectedMap The map of LongArray's containing reflection id's, indexed by the IReflectUpdateHandler that created the reflections.
*/
protected void collectReflectUpdateHandlers(LiteHashMap reflectedMap) {
internalCollectReflectUpdateHandlers(reflectedMap);
}//collectReflectUpdateHandlers()//
/** TODO: Make this protected..
* Collects the reflect update handlers and associates them with the LongArray of refection id numbers for the objects reflected by the handler.
* <p>Note: This method should be overloaded to provide recursion such that all child objects in the logical obecjt are searched.</p>
* @param reflectedMap The map of LongArray's containing reflection id's, indexed by the IReflectUpdateHandler that created the reflections.
*/
public void internalCollectReflectUpdateHandlers(LiteHashMap reflectedMap) {
IIterator iterator = getRegisteredReflections();
//Search through the reflections of this object.//
while(iterator.hasNext()) {
ReflectionHolder next = (ReflectionHolder) iterator.next();
LongArray array = (LongArray) reflectedMap.get(next);
if(array == null) {
array = new LongArray(20, 100);
reflectedMap.put(next.getHandler(), array);
}//if//
array.add(next.getReflectionId());
}//while//
}//internalCollectReflectUpdateHandlers()//
/**
* Determines whether the supported object has any active reflections.
* @return Whether there are any reflections of the supported object.
*/
protected boolean hasReflections() {
return (registeredReflections != null) && (registeredReflections.getSize() > 0);
}//hasReflections()//
/**
* Determines whether this object is reflected in the given reflection context (represented by the update handler).
* @param updateHandler The handler that represents the requesting reflection context.
* @return Whether there is already a reflection for this reflectable object in the given context.
*/
public boolean isReflected(IReflectUpdateHandler updateHandler) {
return registeredReflections != null && registeredReflections.containsValue(updateHandler);
}//isReflected()//
/**
* Gets the reflection holder for the previously registered reflection.
* @param updateHandler The update handler that represents the previously registered reflection.
* @return The holder for the reflection releated data.
*/
protected ReflectionHolder getRegisteredReflection(IReflectUpdateHandler updateHandler) {
return registeredReflections != null ? (ReflectionHolder) registeredReflections.get(updateHandler) : null;
}//getRegisteredReflection()//
/**
* Sets the reflection holder for the registering reflection.
* @param holder The holder that represents the registering reflection.
*/
protected void setRegisteredReflection(ReflectionHolder holder) {
if(registeredReflections == null) {
registeredReflections = new LiteHashSet(10);
}//if//
registeredReflections.add(holder);
}//setRegisteredReflection()//
/**
* Gets the ReflectionHolder instances for the registered reflections.
* @return An iterator over the registered reflection's holders.
*/
protected IIterator getRegisteredReflections() {
return registeredReflections == null ? EmptyIterator.getSingleton() : registeredReflections.iterator();
}//getRegisteredReflections()//
/**
* Unregisters a refection.
* @param refection The refection to be unregistered.
*/
public void unregisterReflection(IReflectUpdateHandler updateHandler) {
if(hasReflections()) {
ReflectionHolder reflectionHolder = (ReflectionHolder) registeredReflections.get(updateHandler);
NextMessageHolder nextMessageHolder = getNextUpdateMessageHolder(updateHandler);
//TODO: If this object is part of a single threaded context, then delegate the next message number handling to it.
if(reflectionHolder != null && nextMessageHolder != null) {
registeredReflections.remove(updateHandler);
reflectionHolder.unregisterDisconnectHandler();
ReflectionContext.getReflectionIdHolder(updateHandler).releaseId();
//Clean up after the next message holder map.//
if(--nextMessageHolder.counter == 0) {
removeNextUpdateMessageHolder(updateHandler);
}//if//
}//if//
else {
if(reflectionHolder == null) {
Debug.log(new RuntimeException("Error: Unable to unregister the collection reflection. Could not locate the ReflectionHolder."));
}//if//
else {
Debug.log(new RuntimeException("Error: Unable to unregister the collection reflection. Could not locate the NextMessageHolder."));
}//else//
}//else//
if(registeredReflections.getSize() == 0) {
registeredReflections = null;
}//if//
}//if//
}//unregisterReflection()//
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
protected Object clone() throws CloneNotSupportedException {
AbstractReflectSupport clone = (AbstractReflectSupport) super.clone();
clone.partOfEntity = null;
clone.partOfEntityCounter = 0;
clone.registeredReflections = null;
clone.reflectionContext = null;
clone.reflectionId = null;
return clone;
}//clone()//
/**
* Encapsulates cloning a value.
* <p>Note: The reason we return the original object if it is not cloneable is because it could be immutable and we simply have no way of knowing. We will for now assume it is immutable.</p>
* @param value The value to be cloned.
* @return The cloned value, or the original value if the value was not clonable.
*/
protected Object cloneValue(Object value) {
try {
if(value instanceof com.foundation.clone.ICloneable) {
value = ((com.foundation.clone.ICloneable) value).cloneObject(null, null);
}//if//
else if(value instanceof java.util.Date) {
value = ((java.util.Date) value).clone();
}//else if//
else {
//Do nothing, assume the value is immutable.//
//There is currently no way to call the clone method, even if the Cloneable interface is implemented.//
}//else//
}//try//
catch(Throwable e) {
//This should not normally occur.//
Debug.log(e);
}//catc//
return value;
}//cloneValue()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getHash()
*/
public int getHash() {
return hash;
}//getHash()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#setHash(int)
*/
public void setHash(int hash) {
this.hash = hash;
}//setHash()//
}//AbstractReflectSupport//

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.orb.Orb;
import com.common.thread.Monitor;
import com.common.util.LiteList;
import com.foundation.common.MetadataContainer;
import com.foundation.metadata.MetadataService;
/**
* <p>
* Note: We don't track which objects were reflected since that information can easily be obtained by asking the reflectable object if it has a ReflectionHolder for the updateHandler.
* Also note that ReflectionHolder is comparable with IReflectUpdateHandler since that is how it is hashed and indexed.
* </p>
*/
public class CreateReflectDataContext {
/** The update handler which is called when the reflected object changes. This must be the same or comparable value used to unregister the reflection. */
private IReflectUpdateHandler updateHandler;
/** The optional metadata container used to determine what is to be reflected. */
private MetadataContainer metadataContainer;
/** The optional metadata container's index used to lookup the metadata container. */
private String metadataIndex = null;
/** The identifier holder for the reflection context. */
private ReflectionContext.IdHolder idHolder = null;
/** The collection of reflectable objects that need to be reflected, but do not share a monitor with the logical object currently being reflected. */
private LiteList reflectionDataContainer;
/** The collection of reflectable objects that need to be reflected, but do not share a monitor with the logical object currently being reflected. */
private LiteList pendingExternalReflectables;
/** The monitor currently locked. This is used to determine whether reflectable objects that need reflecting should be inlined in this context or held for processing later. */
private Monitor monitor = null;
/** A flag that tells the code that creates the reflection data to reflect all attributes and look for model identifiers. If this is false then the metadata will first be used if available, otherwise standard reflection rules apply. This flag allows the synchronizing reflection context to receive reflection data for new objects that includes all possible attribute values. */
private boolean isSynchronizationResult = false;
/**
* CreateReflectDataContext constructor.
* @param updateHandler
* @param metadataContainer
* @param metadataIndex
* @param monitor
* @param isSynchronizationResult Whether the context should be reflecting all possible attributes for the objects it creates reflections of.
*/
public CreateReflectDataContext(IReflectUpdateHandler updateHandler, MetadataContainer metadataContainer, String metadataIndex, Monitor monitor, boolean isSynchronizationResult) {
super();
this.monitor = monitor;
this.updateHandler = updateHandler;
this.metadataContainer = metadataContainer;
this.metadataIndex = metadataIndex;
this.reflectionDataContainer = new LiteList(10);
this.pendingExternalReflectables = new LiteList(10);
this.isSynchronizationResult = isSynchronizationResult;
}//CreateReflectDataContext()//
/**
* Gets the flag telling the code that creates the reflection data to reflect all attributes.
* If this is false then the metadata will first be used if available, otherwise standard reflection rules apply.
* This flag allows the synchronizing reflection context to receive reflection data for new objects that includes all possible attribute values.
* @return Whether the context should be reflecting all possible attributes for the objects it creates reflections of.
*/
public boolean isSynchronizationResult() {
return isSynchronizationResult;
}//isSynchronizationResult()//
/**
* Gets the identifier holder and generator for the reflection context whether that context is remote or local.
* @return The holder that can generate unique identifiers within the reflection context.
*/
public ReflectionContext.IdHolder getIdHolder() {
if(idHolder == null) {
idHolder = ReflectionContext.getReflectionIdHolder(updateHandler);
}//if//
return idHolder;
}//getIdHolder()//
/**
* Gets the update handler which is called when the reflected object changes. This must be the same or comparable value used to unregister the reflection.
* @return The update handler that represents the caller requesting the reflection(s).
*/
public IReflectUpdateHandler getUpdateHandler() {
return updateHandler;
}//getUpdateHandler()//
/**
* Gets the optional metadata container used to determine what is to be reflected.
* @return The metadata describing what to reflect.
*/
public MetadataContainer getMetadataContainer() {
return metadataContainer;
}//getMetadataContainer()//
/**
* Gets the optional metadata container index used to get the metadata container on any process.
* @return The index of the metadata describing what to reflect.
*/
public String getMetadataIndex() {
return metadataIndex;
}//getMetadataIndex()//
/**
* Gets the collection of AbstractReflectData instances, one for each reflection generated by this context.
* @return The collection of reflection data generated by this context.
*/
public LiteList getReflectionDataContainer() {
return reflectionDataContainer;
}//getReflectionDataContainer()//
/**
* Gets the collection of reflectable objects that need to be reflected, but do not share a monitor with the logical object currently being reflected.
* @return The collection of pending reflectable objects that should be reflected under a separate lock.
*/
public LiteList getPendingExternalReflectables() {
return pendingExternalReflectables;
}//getPendingExternalReflectables()//
/**
* Processes all pending external reflectables by registering reflections of them.
* The results are added to the reflection data container.
* <p>Warning: This should always be called after releasing any locks and needing to access the reflection data container.</p>
*/
public void processPendingExternalReflectables() {
if(pendingExternalReflectables.getSize() > 0) {
ReflectRegistrationData registrationData = getMetadataIndex() != null ? new ReflectRegistrationData(getMetadataIndex()) : new ReflectRegistrationData(getMetadataContainer());
//TODO: The single threaded context code must be moved. It cannot be here because a proxy might be to an object in a single threaded context and this code won't run it on the context's thread.
//Handle remote reflectables.
//Handle reflectables with different monitors.
//Handle reflectables that are reflections or are in single threaded contexts.
for(int index = 0; index < pendingExternalReflectables.getSize(); index++) {
IReflectable reflectable = (IReflectable) pendingExternalReflectables.get(index);
ReflectDataContainer result = null;
if(Orb.isLocal(reflectable)) {
/*
ISingleThreadedContext singleThreadedContext = reflectable.getSingleThreadedContext();
if(singleThreadedContext != null) {
result = singleThreadedContext.execute(new IRunnable() {
public Object run() {
return reflectable.reflectionRegister(getUpdateHandler(), registrationData);
}//run()//
});
}//if//
else {
ThreadService.ResultRunnable runnable = new ThreadService.ResultRunnable(new IRunnable() {
public Object run() {
return reflectable.reflectionRegister(getUpdateHandler(), registrationData);
}//run()//
});
ThreadService.run(runnable);
runnable.block();
result = runnable.getResult();
}//else//
*/
result = reflectable.zzrReflectionRegister(getUpdateHandler(), registrationData);
}//if//
else {
result = reflectable.zzrReflectionRegister((IReflectUpdateHandler) (Orb.isProxy(getUpdateHandler()) ? getUpdateHandler() : Orb.getProxy(getUpdateHandler(), IReflectUpdateHandler.class)), registrationData);
}//else//
//Ignore the result if it is null since it is already in the calling context.//
if(result != null) {
reflectionDataContainer.addAll(((ReflectDataContainer) result).getReflectionData());
}//if//
}//for//
}//if//
}//processPendingExternalReflectables()//
/**
* Includes the reflectable in the creation of reflection data so that its reflection data will be sent.
* <p>Note: This method may proccess the reflection data immediatly, or may delay the processing until later.</p>
* @param reflectable The reflectable whose reflection data should be generated.
*/
public void include(IReflectable reflectable) {
if((Orb.isLocal(reflectable)) && ((monitor == null) || (reflectable.getMonitor() == monitor))) {
reflectable.zzrReflectionLocalRegister(Orb.isProxy(reflectable) ? Orb.getLocal(reflectable) : reflectable, this);
}//if//
else {
getPendingExternalReflectables().add(reflectable);
}//else//
}//include()//
}//CreateReflectDataContext//

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.foundation.metadata.Attribute;
/**
* The custom lazy load handler that may be used with models supported by AttributeSupport.
*/
public interface ICustomLazyLoadHandler {
/**
* Lazy loads the passed attribute for the given object that defines the attribute.
* @param model The model object defining the attribute. This primarily allows one handler to handle many different objects.
* @param attribute The attribute being lazily loaded. This primarily allows one handler to handle many different attributes.
* @return The value for the given attribute and object.
*/
public Object lazyLoadAttribute(Object model, Attribute attribute);
}//ICustomLazyLoadHandler//

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public interface IReflectCollectionSupport extends IReflectSupport {
/**
* Synchronizes changes from a refection of this object.
* @param updateHandler The handler used to identify the reflection that is performing the synchronization of data. The synchronizing reflection will only receive notification of the changes through this method's return value.
* @param data The collection of added and removed values.
* @return The collection of changes actually applied to the collection.
*/
public ReflectCollectionData synchronizeReflection(IReflectUpdateHandler updateHandler, AbstractReflectData data);
/**
* Unregisters a refection.
* @param refection The refection to be unregistered.
*/
public void unregisterReflection(IReflectUpdateHandler refection);
}//IReflectCollectionSupport//

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.foundation.metadata.CloneContext;
public interface IReflectSupport {
/**
* Completes the synchronization process by clearing the add/remove buffers and applying any actual changes, and rolling back changes that did not get applied.
* @param proposedChanges The changes proposed by this reflection.
* @param appliedChanges The changes actually applied to the reflected object.
*/
public void completeSynchronization(AbstractReflectData proposedChanges, AbstractReflectData appliedChanges);
/**
* Destroys this reflection so that it no longer reflects another object of the same type.
* The actual object will not be destroyed, but it will no longer reflect another object.
* <p>Warning: This method must be called for every reflection. Not calling this method may result in a memory leak.</p>
*/
public void destroyReflection();
/**
* Gets the object being reflected.
* @return The reflected object.
*/
public IReflectable getReflectedObject();
/**
* Gets the supported object that is a reflection.
* @return The object being supported.
*/
public IReflectable getReflectionObject();
/**
* Gets the supported object.
* @return The object supported by this support object.
*/
public IReflectable getSupportedObject();
/**
* Gets the data necessary to synchronize the reflection changes.
* @return A collection of changes that can be applied to the reflected object, or null if there are no changes, and thus no need to synchronize.
*/
public AbstractReflectData getSynchronizationData(CloneContext cloneContext);
/**
* Updates the supported object given a collection of changes that were made to the reflected object.
* <p>Note: Since the user thread should have locked the changable data (in some application dependant way) so that it is the only user thread that can make the changes, we don't really have
* to worry about synchronization. We still have to synchronize on the entity when making the changes so that caches are properly updated. The reason why two user threads can't make changes
* at the same time is one would over write the other's changes at best, at worst they would cause an inconsistent set of clones (some clones may not properly reflect the entity's state).</p>
* @param reflectData The collection of changes.
*/
public void updateReflection(AbstractReflectData reflectData);
/**
* Gets the category number used by the reflection context to group reflections into logical objects which receive updates using a common ordering index.
* @return The number used to group a set of reflections into a logical object since not all components of a logical object may be reflected within the context.
*/
public long getCategoryNumber();
/**
* Gets the category number used by the reflection context to group reflections into logical objects which receive updates using a common ordering index.
* @param categoryNumber The number used to group a set of reflections into a logical object since not all components of a logical object may be reflected within the context.
*/
public void setCategoryNumber(long categoryNumber);
/**
* Gets the hash for the supported reflectable.
* @return The hash number for the reflectable. This number will be the same for all reflections and the reflected object.
*/
public int getHash();
/**
* Sets the hash for the supported reflectable.
* @param hash The hash number for the reflectable. This number will be the same for all reflections and the reflected object.
*/
public void setHash(int hash);
}//IReflectSupport//

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public interface IReflectUpdateHandler {
/**
* Updates the values of the supported reflection given the set of changes.
* @param reflectionId The identifier for the reflection that is being updated.
* @param reflectData The collection of added and/or removed values.
* @param messageIndex The order index allowing the handler to process updates in order.
* @param messageCategory The category number used to qualify the message index. The category number will be one of the reflection id's issued by the reflection context.
*/
public void update(long reflectionId, AbstractReflectData reflectData, int messageIndex, long messageCategory);
/**
* Gets the reflection context's next available process id number.
* @return The next process id number. This will then be incremented by the reflection context.
*/
public int getNextProcessId();
/**
* Joins two message index categories together since the reflected objects are now part of the same logical object.
* The code should only perform the join when the old category processes all messages up to the old message index, and the new category processes all messages to the new message index.
* @param oldCategoryNumber The message index category that is going away.
* @param newCategoryNumber The message index category that the old category will join with.
* @param oldMessageIndex The index of the message (order it should be processed) within the old category.
* @param newMessageIndex The index of the message (order it should be processed) within the joined category.
*/
public void joinReflections(long oldCategoryNumber, long newCategoryNumber, int oldMessageIndex, int newMessageIndex);
}//IReflectUpdateHandler//

View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.foundation.common.IEntity;
import com.foundation.metadata.ISupportsContainment;
public interface IReflectable extends com.foundation.clone.ICloneable, ISupportsContainment {
/**
* Gets the reference to the reflected object. If the reflected object is remote, then this will be a proxy to the reflected object.
* <p>Note: Reflections are not serializable, but the reflected reference may be serializable.</p>
* <p>Note: This method is not intended for remote use, but is included in this interface for convenience sake since it is called a lot.</p>
* @return A reference to the object being reflected, or null if this is not a reflection of another object.
*/
public IReflectable getReflected();
/**
* Determines whether this reflectable object is a reflection.
* <p>Note: Reflections are not serializable, but the reflected reference may be serializable.</p>
* <p>Note: This method is not intended for remote use, but is included in this interface for convenience sake since it is called a lot.</p>
* @return Whether this object is a reflection of another object.
*/
public boolean isReflection();
/**
* Determines whether this reflectable object is a reflection.
* <p>Note: Reflections are not serializable, but the reflected reference may be serializable.</p>
* <p>Note: This method is not intended for remote use, but is included in this interface for convenience sake since it is called a lot.</p>
* @param reflectionContext The optional reflection context. If provided then the result will only be true if this is a reflection within the given reflection context.
* @return Whether this object is a reflection of another object.
*/
public boolean isReflection(ReflectionContext reflectionContext);
/**
* Gets the reflection context associated with this reflectable.
* @return The reflection context associated with this reflectable object, or null if the object is not a reflection.
*/
public ReflectionContext getReflectionContext();
/**
* Registers a reflection given the reflection's update handler reference.
* @param updateHandler A reference to the reflection's update handler.
* @param registrationData The data used to register a reflection.
* @return The data necessary to create the reflection(s). This is either a ReflectDataContainer instance containing the reflection data where the first is the reflection being registered, or it is null.
*/
public ReflectDataContainer zzrReflectionRegister(IReflectUpdateHandler updateHandler, ReflectRegistrationData registrationData);
/**
* Synchronizes data from a reflection to this reflected object.
* <p>Note: The synchronizing reflection will only receive notification of the changes through this method's return value. An event will not be sent via the update handler.
* The returned data will contain the last update message number sent to the reflection. This can be used to ensure that messages are processed in order.</p>
* @param updateHandler The handler used to identify the reflection that is performing the synchronization of data.
* @param data The set of changed data.
* @param createReflectDataContext The context for creating reflections of the IReflectable changes for the synchronizing reflection context.
* @return The collection of changes actually applied to the reflected object.
*/
public AbstractReflectData reflectionSynchronize(IReflectUpdateHandler updateHandler, AbstractReflectData data, CreateReflectDataContext createReflectDataContext);
/**
* Unregisters a previously registered reflection.
* @param updateHandler A reference to the reflection's update handler.
*/
public void reflectionUnregister(IReflectUpdateHandler updateHandler);
/**
* Determines whether this reflectable object is a reflection created within the given context.
* <p>Note: Reflections are not serializable, but the reflected reference may be serializable.</p>
* @param reflectionContext The optional context used to check whether this is a reflection. If null then the response will be true if the object is a reflection in any context.
* @return Whether this object is a reflection of another object and was created in the given context.
*/
public boolean zzrIsReflection(Object reflectable, ReflectionContext reflectionContext);
/**
* Gets the reflection context if this is a reflection.
* @return The reflection context that created this reflection, or null if this isn't a reflection.
*/
public ReflectionContext zzrGetReflectionContext(Object reflectable);
/**
* Gets the reflection's identifying object.
* @return The object which identifies the reflection within the context of the reflection context (aka reflection manager).
*/
public Object zzrGetReflectionId(Object reflectable);
/**
* Creates a 'reflection safe' copy of this reflectable object.
* That means each attribute (or contained value in the case of collections) must be examined.
* If the value is an IReflectable and is a reflection then it must be dereferenced (the reflected reference used in its stead).
* If the value is an IReflectable and it isn't a reflection then it must have a safe copy made and used in place of the value.
* All other value types are simply referenced as is.
* <p>This is useful when synchronizing a reflection which references a new object which may reference other new objects or existing objects (as reflections).
* In such a case the synchronized object notices that it has a non-reflection value reference that should be a reflection and it assumes that it is new.
* The new value needs to be copied so that the copy doesn't have preconcieved notions of its monitor
* @param reflectionContext The reflection context for the copy.
* @return The safe copy of this reflection, which can either be the reflected value, or a copy of this non-reflected value.
*/
public IReflectable zzrReflectionCreateSafeCopy(Object reflectable, ReflectionContext reflectionContext);
/**
* Recursively prepares the reflectable (non-reflection) prior to being part of a synchronize action via the current reflection context.
* <p>For example, if a view creates a new model object and makes it part of an existing reflection of a logical model, then this method will be called on the new model object prior to synchronizing the changes.</p>
* <p>Note: This method only gets called if this object is not a reflection in the current context (in which case it is never going to be a reflection at all), but is referenced by a reflection that is being synchronized.
* This method should prepare a non-reflection for being moved to a different reflection context (or no reflection context) by replacing any references to reflections in the current context.</p>
* <p>This method does not copy this object, but does make permenant changes.</p>
* @param currentContext The current reflection context that is preparing to synchronize this object. This object might not be a reflection in the current context if this object is newly created.
* @param destinationContext The reflection context that this object is being synchronized to, if known. This may be null if the context is remote, or if not synchronizing to another reflection context. This is primarily used to make coding views more flexable since one view may base some but not all its data on the previous view's reflections.
* @param newPartOfEntity The part of entity reference that should be set during a recursive call. Initial callers should ALWAYS pass null.
* @param cloned The reflectable that this reflectable is a clone of. All non-reflections are cloned prior to synchronization so that the new shared objects will not have any ties to old proxies. Proxies to the non-clone will continue to work since the synchronization will either fail (in which case the proxied non-clone object doesn't change), or will succeed and pass the reflection data back to the reflection context which will utilize the non-clone object as the reflection object.
* @param synchronizingContext The reflection context that is performing the synchronization operation.
*/
public void zzrReflectionPreSynchronize(Object reflectable, ReflectionContext currentContext, ReflectionContext destinationContext, IEntity newPartOfEntity, IReflectable cloned, ReflectionContext synchronizingContext);
/**
* Destroys this object as a reflection of another object of the same type.
* The actual object will not be destroyed, but it will no longer reflect another object.
* <p>Warning: This method must be called for every reflection. Not calling this method may result in a memory leak.</p>
*/
public void zzrReflectionDestroy(Object reflectable);
/**
* Initializes this object as a reflection of another object of the same type.
* @param reflectionData The data necessary to initialize the reflection.
* @param reflectionContext The context that the reflection exists within.
* @return A replacement reflection if another reflection exists for the reflected object, or null if the initialization went smoothly.
*/
public Object zzrReflectionInitialize(Object reflectable, AbstractReflectData reflectionData);
/**
* Called after the reflectionInitialize method and after all reflections in a bundle have been initialized.
* Allows the reflection to replace reflected references with their reflections.
* @param reflectionData The data necessary to initialize the reflection.
*/
public void zzrReflectionPostInitialize(Object reflectable, AbstractReflectData reflectionData);
/**
* Performs a local registration of a new reflection for this reflectable.
* This is local because it is caused by the container (parent or object that this object is part-of) being reflected.
* @param createReflectDataContext The context for the reflection creation.
*/
public void zzrReflectionLocalRegister(Object reflectable, CreateReflectDataContext createReflectDataContext);
/**
* Gets the last sent update message's number for a perticular reflection.
* @param updateHandler The update handler for the reflection whose previous update number should be accessed.
* @return The reflection's last sent message number.
*/
public int zzrReflectionGetLastUpdateMessageNumber(Object reflectable, IReflectUpdateHandler updateHandler);
/**
* Collects the IReflectable instances that should be reflected and returned to the synchronizing reflection context, upon completing a synchronization.
* @param reflectable The reflectable instance that this interface supports.
* @param createReflectDataContext The context used to add IReflectable objects for later reflecting.
*/
public void zzrCollectPostSynchronizeReflectables(Object reflectable, CreateReflectDataContext createReflectDataContext);
}//IReflectable//

View File

@@ -0,0 +1,11 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public interface IReflectableCollection extends IReflectable {
}//IReflectableCollection//

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public interface IReflectableObject extends IReflectable {
/**
* Loads the specified attribute value.
* @param attributeName The name of the attribute whose value is to be retrieved.
* @param updateHandler The update handler to be used if the value is reflectable.
* @return The attribute value, or if the value is reflectable, the data necessary to create the reflection(s). This is either an object, or a ReflectDataContainer instance containing the reflection data where the first is the reflection being registered, or it is an IReflectable instance or proxy if the instance is already reflected in the calling context.
*/
public Object reflectionLoadAttribute(String attributeName, IReflectUpdateHandler updateHandler, ReflectRegistrationData reflectionData);
}//IReflectableObject//

View File

@@ -0,0 +1,454 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.util.*;
import com.common.util.optimized.IntArray;
/**
* This class is designed to transfer collection values to a new reflection of the collection, and to transfer changes to a collection reflection.
*/
public class ReflectCollectionData extends AbstractReflectData {
private static final byte OPTION_READ_ONLY = 0x01;
private static final byte OPTION_PART_OF = 0x02;
/** This operation has no followup values and places nothing in the values collection. */
public static final byte OPERATION_REMOVE_ALL = 0x01;
/** For un-indexed collections this will be followed by the number of elements in the values collection, otherwise it will be followed by the number of elements in the operations collection - one per index removed. */
public static final byte OPERATION_REMOVE = 0x02;
/** For un-indexed collections this will be followed by the number of elements in the values collection, otherwise it will be followed by the number of elements in the operations collection and values collection - one per index/value added. */
public static final byte OPERATION_ADD = 0x03;
/** For indexed collectons only: The values collection will contain exactly one int[] for the new order mapping. */
public static final byte OPERATION_ORDER = 0x04;
/** The ordered set of operations to be performed by the receiving collection. Some operations are followed by parameters such as a count of values that apply to the operation. */
public IntArray operations = null;
/** The index into the operations integer collection of the last operation identifier. This is useful for condensing multiple operations of the same type. */
public int lastOperationIndex = -1;
/** The values, used as specified by the operation and its parameters. */
public LiteList values = null;
/** Whether the collection is marked as read only. This is only valid in the reflection registration result since the flag is set in the collection when it is created. */
public boolean isReadOnly = false;
/** Whether the collection values are marked as part of the collection. This is only valid in the reflection registration result since the flag is set in the collection when it is created. */
public boolean isPartOf = false;
/** A non-serialized reference to a reflection holder. This is used to simplify passing the data and holder outside the synch block before creating reflections. */
public ReflectionHolder holder = null;
/**
* ReflectCollectionData constructor.
*/
public ReflectCollectionData() {
super();
}//ReflectCollectionData()//
/**
* Determines whether the data set has changes or is empty and not worth sending to any reflections or reflected objects.
* @return Whether there is significant data in this set.
*/
public boolean hasChanges() {
return operations != null && operations.getSize() > 0;
}//hasChanges()//
/**
* Adds an ADD operation to the data set.
* <p>A collection should only ever use indexed adds or non-indexed adds, these should never be mixed!</p>
* @param addedValue The value being added.
* @param index The index (this is the index after all previous operations have been applied) of the value (range checking not performed).
*/
public void addAddOperation(Object addedValue, int index) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_ADD) {
operations.ensureCapacity(1);
values.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + 1);
operations.add(index);
values.add(addedValue);
}//if//
else {
if(operations == null) {
operations = new IntArray(3, 100);
}//if//
else {
operations.ensureCapacity(3);
}//else//
if(values == null) {
values = new LiteList(1, 100);
}//if//
else {
values.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_ADD);
operations.add(1);
operations.add(index);
values.add(addedValue);
}//else//
}//addAddOperation()//
/**
* Adds an ADD operation to the data set.
* <p>A collection should only ever use indexed adds or non-indexed adds, these should never be mixed!</p>
* @param addedValues The values being added.
* @param indices The indices (the index at N+1 should be valid only after the add of the value at index N is applied) of the values (range checking not performed, the collections of indices and added values must be identically sized - this check is not performed).
*/
public void addAddOperation(ICollection addedValues, IntArray indices) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_ADD) {
operations.ensureCapacity(indices.getSize());
values.ensureCapacity(addedValues.getSize());
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + indices.getSize());
operations.addAll(indices);
values.addAll(addedValues);
}//if//
else {
if(operations == null) {
operations = new IntArray(indices.getSize() + 2, 100);
}//if//
else {
operations.ensureCapacity(indices.getSize() + 2);
}//else//
if(values == null) {
values = new LiteList(addedValues.getSize(), 100);
}//if//
else {
values.ensureCapacity(addedValues.getSize());
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_ADD);
operations.add(indices.getSize());
operations.addAll(indices);
values.addAll(addedValues);
}//else//
}//addAddOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param index The index of the value removed (this is the index after all previous operations have been applied).
*/
public void addRemoveOperation(int index) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
operations.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + 1);
operations.add(index);
}//if//
else {
if(operations == null) {
operations = new IntArray(3, 100);
}//if//
else {
operations.ensureCapacity(3);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(1);
operations.add(index);
}//else//
}//addRemoveOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param removedValue The value removed.
* @param index The index of the value removed (this is the index after all previous operations have been applied).
*/
public void addRemoveOperation(Object removedValue, int index) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
operations.ensureCapacity(1);
values.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + 1);
operations.add(index);
values.add(removedValue);
}//if//
else {
if(operations == null) {
operations = new IntArray(3, 100);
}//if//
else {
operations.ensureCapacity(3);
}//else//
if(values == null) {
values = new LiteList(1, 100);
}//if//
else {
values.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(1);
operations.add(index);
values.add(removedValue);
}//else//
}//addRemoveOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param indices The indices of the values removed (the index at N+1 should be valid only after the remove of the value at index N is applied).
*/
public void addRemoveOperation(IntArray indices) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
operations.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + indices.getSize());
operations.addAll(indices);
}//if//
else {
if(operations == null) {
operations = new IntArray(indices.getSize() + 2, 100);
}//if//
else {
operations.ensureCapacity(indices.getSize() + 2);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(indices.getSize());
operations.addAll(indices);
}//else//
}//addRemoveOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param removedValues The values that have been removed from the collection.
* @param indices The indices of the values removed (the index at N+1 should be valid only after the remove of the value at index N is applied).
*/
public void addRemoveOperation(ICollection removedValues, IntArray indices) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
operations.ensureCapacity(indices.getSize());
values.ensureCapacity(removedValues.getSize());
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + indices.getSize());
operations.addAll(indices);
values.addAll(removedValues);
}//if//
else {
if(operations == null) {
operations = new IntArray(indices.getSize() + 2, 100);
}//if//
else {
operations.ensureCapacity(indices.getSize() + 2);
}//else//
if(values == null) {
values = new LiteList(removedValues.getSize(), 100);
}//if//
else {
values.ensureCapacity(removedValues.getSize());
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(indices.getSize());
operations.addAll(indices);
values.addAll(removedValues);
}//else//
}//addRemoveOperation()//
/**
* Adds a ORDER operation to the data set.
* @param mapping The mapping between the current indices and the new indices for all values in the collection (as of the application of the previous operation).
*/
public void addOrderOperation(int[] mapping) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_ORDER) {
values.replace(values.getSize() - 1, mapping);
}//if//
else {
if(operations == null) {
operations = new IntArray(1, 100);
}//if//
else {
operations.ensureCapacity(1);
}//else//
if(values == null) {
values = new LiteList(1, 100);
}//if//
else {
values.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_ORDER);
values.add(mapping);
}//else//
}//addOrderOperation()//
/**
* Adds an ADD operation to the data set.
* <p>A collection should only ever use indexed adds or non-indexed adds, these should never be mixed!</p>
* @param addedValue The value being added.
*/
public void addAddOperation(Object addedValue) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_ADD) {
operations.ensureCapacity(1);
values.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + 1);
values.add(addedValue);
}//if//
else {
if(operations == null) {
operations = new IntArray(2, 100);
}//if//
else {
operations.ensureCapacity(2);
}//else//
if(values == null) {
values = new LiteList(1, 100);
}//if//
else {
values.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_ADD);
operations.add(1);
values.add(addedValue);
}//else//
}//addAddOperation()//
/**
* Adds an ADD operation to the data set.
* <p>A collection should only ever use indexed adds or non-indexed adds, these should never be mixed!</p>
* @param addedValues The values being added.
*/
public void addAddOperation(ICollection addedValues) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_ADD) {
values.ensureCapacity(addedValues.getSize());
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + addedValues.getSize());
values.addAll(addedValues);
}//if//
else {
if(operations == null) {
operations = new IntArray(2, 100);
}//if//
else {
operations.ensureCapacity(2);
}//else//
if(values == null) {
values = new LiteList(addedValues.getSize(), 100);
}//if//
else {
values.ensureCapacity(addedValues.getSize());
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_ADD);
operations.add(addedValues.getSize());
values.addAll(addedValues);
}//else//
}//addAddOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param removedValue The value removed.
*/
public void addRemoveOperation(Object removedValue) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
values.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + 1);
values.add(removedValue);
}//if//
else {
if(operations == null) {
operations = new IntArray(2, 100);
}//if//
else {
operations.ensureCapacity(2);
}//else//
if(values == null) {
values = new LiteList(1, 100);
}//if//
else {
values.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(1);
values.add(removedValue);
}//else//
}//addRemoveOperation()//
/**
* Adds a REMOVE operation to the data set.
* <p>A collection should only ever use indexed removes or non-indexed removes, these should never be mixed!</p>
* @param removedValues The values removed.
*/
public void addRemoveOperation(ICollection removedValues) {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE) {
values.ensureCapacity(1);
operations.replace(lastOperationIndex + 1, operations.get(lastOperationIndex + 1) + removedValues.getSize());
values.addAll(removedValues);
}//if//
else {
if(operations == null) {
operations = new IntArray(2, 100);
}//if//
else {
operations.ensureCapacity(2);
}//else//
if(values == null) {
values = new LiteList(removedValues.getSize(), 100);
}//if//
else {
values.ensureCapacity(removedValues.getSize());
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE);
operations.add(removedValues.getSize());
values.addAll(removedValues);
}//else//
}//addRemoveOperation()//
/**
* Adds a REMOVE_ALL operation to the data set.
*/
public void addRemoveAllOperation() {
if(lastOperationIndex != -1 && operations.get(lastOperationIndex) == OPERATION_REMOVE_ALL) {
//Do nothing.//
}//if//
else {
if(operations == null) {
operations = new IntArray(1, 100);
}//if//
else {
operations.ensureCapacity(1);
}//else//
lastOperationIndex = operations.getSize();
operations.add(OPERATION_REMOVE_ALL);
}//else//
}//addRemoveAllOperation()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectData#createReflection()
*/
public IReflectable createReflection() throws InstantiationException, IllegalAccessException {
return ReflectCollectionSupport.createReflection(this);
}//createReflection()//
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
super.readExternal(in);
short options = in.readByte();
isReadOnly = (options & OPTION_READ_ONLY) != 0;
isPartOf = (options & OPTION_PART_OF) != 0;
operations = (IntArray) in.readObject();
values = (LiteList) in.readObject();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
super.writeExternal(out);
out.writeByte((byte) ((isReadOnly ? OPTION_READ_ONLY : 0) | (isPartOf ? OPTION_PART_OF : 0)));
out.writeObject(operations);
out.writeObject(values);
}//readExternal()//
}//ReflectCollectionData//

View File

@@ -0,0 +1,481 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import java.lang.reflect.InvocationTargetException;
import com.common.orb.*;
import com.common.util.*;
import com.common.util.optimized.IntArray;
import com.common.debug.*;
import com.foundation.common.IEntity;
import com.foundation.common.MetadataContainer;
import com.foundation.exception.ReflectionSynchronizationException;
import com.foundation.transaction.Transaction;
import com.foundation.transaction.TransactionContextHolder;
import com.foundation.transaction.TransactionErrorInfo;
import com.foundation.util.*;
/**
* Supports a collection capable of being & having a reflection.
* This class provides common functionality for collections that implement IReflactableCollection.
*/
public abstract class ReflectCollectionSupport extends AbstractReflectSupport implements IReflectCollectionSupport {
/** The object that is being reflected. This should be null if this object is supporting the original object. */
private IReflectableCollection reflectedObject = null;
/** This will be non-null while changes are being synchronized to this reflected collection. The changes that are applied will be collected in this object and the synchronize code will send this event to registered reflections after all changes have been applied. */
private ReflectCollectionData eventData = null;
/**
* ReflectCollectionSupport constructor.
*/
protected ReflectCollectionSupport() {
super();
}//ReflectCollectionSupport()//
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
protected Object clone() {
ReflectCollectionSupport clone = null;
try {
clone = (ReflectCollectionSupport) super.clone();
}//try//
catch(CloneNotSupportedException e) {
Debug.log(e);
}//catch//
//None of the attributes should be copied.//
clone.reflectedObject = null;
clone.eventData = null;
return clone;
}//clone()//
/**
* Gets the event data used to update reflections after another reflection synchronizes with this reflected object.
* @return The data container for the post synchronize update to all registered reflections of this object.
*/
protected ReflectCollectionData getEventData() {
return eventData;
}//getEventData()//
/**
* Creates a reflection given a reflectable object.
* A reflection can be used to create a local copy that gets updated and can delay changes to the reflected object.
* @param reflected The object to be reflected.
* @return The reflection of the reflected object.
* @see IReflectableCollection.TYPE_DEFAULT
*/
public static IReflectable createReflection(ReflectCollectionData reflectionData) throws InstantiationException, IllegalAccessException {
IReflectable reflection = null;
IReflectable replacementReflection = null;
//Create a reflection object of the specified type.//
//TODO: It would be nice to have the original collection pass initialization parameters so that the correct constructor can be called with some reasonable parameters.
try {
if(reflectionData.reflectedTypeConstructorParameters != null && reflectionData.reflectedTypeConstructorSignature != null) {
reflection = (IReflectable) reflectionData.reflectedType.getConstructor(reflectionData.reflectedTypeConstructorSignature).newInstance(reflectionData.reflectedTypeConstructorParameters);
}//if//
else {
reflection = (IReflectable) reflectionData.reflectedType.newInstance();
}//else//
}//try//
catch(NoSuchMethodException e) {
Debug.log(e);
//Attempt to use the default constructor and keep the app running.//
reflection = (IReflectable) reflectionData.reflectedType.newInstance();
}//catch//
catch(InvocationTargetException e) {
Debug.log(e);
//Attempt to use the default constructor and keep the app running.//
reflection = (IReflectable) reflectionData.reflectedType.newInstance();
}//catch//
//Set the reflection's initial state.//
replacementReflection = (IReflectable) reflection.zzrReflectionInitialize(reflection, reflectionData); //The reflection will call its reflect support's initializeReflection(CollectionReflectionData) method.//
if(replacementReflection != null) {
reflection.zzrReflectionDestroy(reflection);
}//if//
return replacementReflection != null ? replacementReflection : reflection;
}//createReflection()//
/**
* Prepares a reflection data object containing all of the added values for a given reflection.
* <p>Note: This is only to be used when creating a reflection of the collection, not when updating a reflection.</p>
* @param reflectionData The container for the data that holds the added values that may be reflected.
* @param createReflectDataContext The context for the process of creating reflections of IReflectable references.
*/
protected void prepareReflectionData(ReflectCollectionData reflectionData, CreateReflectDataContext createReflectDataContext) {
boolean isRemote = !Orb.isLocal(createReflectDataContext.getUpdateHandler());
if(reflectionData.values != null && reflectionData.values.getSize() > 0) {
for(int index = 0, length = reflectionData.values.getSize(); index < length; index++) {
Object value = reflectionData.values.get(index);
if(value instanceof IReflectable) {
value = isRemote ? Orb.getProxy(value, IReflectable.class) : value;
createReflectDataContext.include((IReflectable) value);
if(isPartOf() && createReflectDataContext.isSynchronizationResult()) {
((IReflectable) value).zzrCollectPostSynchronizeReflectables(value, createReflectDataContext);
}//if//
}//else if//
else {
//TODO: When we have metadata for the reflection generation, we should perhaps pass it to this clone method which can pass it to ICloneable values.
value = isRemote ? value : cloneValue(value);
}//else//
reflectionData.values.set(index, value);
}//for//
}//if//
}//prepareReflectionData()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getReflectedObject()
*/
public IReflectable getReflectedObject() {
return reflectedObject != null ? reflectedObject : (IReflectable) this;
}//getReflectedObject()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getReflectionObject()
*/
public IReflectable getReflectionObject() {
return (IReflectableCollection) getSupportedCollection();
}//getReflectionObject()//
/**
* Gets the supported collection.
* @return The collection supported by this reflect support object.
*/
protected abstract ICollection getSupportedCollection();
/**
* Gets whether the collection and its collected values are contained by another object.
* @return Whether the collected values are part of this collection's referencer.
*/
protected abstract boolean isPartOf();
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getSupportedObject()
*/
public IReflectable getSupportedObject() {
return (IReflectable) getSupportedCollection();
}//getSupportedObject()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#collectReflectUpdateHandlers(com.common.util.LiteHashMap)
*/
protected void collectReflectUpdateHandlers(LiteHashMap reflectedMap) {
//TODO: Ensure this goes to the AbstractReflectSupport's method and not an overload of the method.
super.internalCollectReflectUpdateHandlers(reflectedMap);
}//collectReflectUpdateHandlers()//
/**
* Initializes this object as a reflection of another object of the same type.
* @param reflectionData The data necessary to initialize the object as a reflection of another object.
* @return A replacement reflection if another reflection exists for the reflected object, or null if the initialization went smoothly.
*/
protected Object reflectionInitialize(ReflectCollectionData reflectionData) {
//Save the reflected reference.//
reflectedObject = (IReflectableCollection) ((ReflectCollectionData) reflectionData).reflected;
return super.reflectionInitialize(reflectionData);
}//initializeReflection()//
/**
* Called after the initializeReflection method and after all reflections in a bundle have been initialized.
* Allows the reflection to replace reflected references with their reflections.
* @param reflectionData The data necessary to initialize the reflection.
*/
protected abstract void reflectionPostInitialize(ReflectCollectionData reflectionData);
/**
* Adds a value to the supported collection without marking the added value as being a change.
* This method is only called when the supported collection is a reflection and the reflected collection sends updates.
* @param value The value added to the collection.
* @param recordChanges Whether the changes should be recorded by the collection (trusted change versus untrusted).
*/
protected abstract void reflectSupportAddValue(Object value, boolean recordChanges, boolean ignoreContainment);
/**
* Adds values to the supported collection without marking the added values as being a change.
* This method is only called when the supported collection is a reflection and the reflected collection sends updates.
* @param values The values added to the collection.
* @param recordChanges Whether the changes should be recorded by the collection (trusted change versus untrusted).
*/
protected abstract void reflectSupportAddValues(ICollection values, boolean recordChanges);
/**
* Releases all suppressed events so that they will be fired as one event.
* @see #reflectSupportSuppressEvents()
*/
protected abstract void reflectSupportReleaseEvents();
/**
* Removes a value from the supported collection without marking the removed value as being a change.
* This method is only called when the supported collection is a reflection and the reflected collection sends updates.
* @param value The value removed from the collection.
* @param recordChanges Whether the changes should be recorded by the collection (trusted change versus untrusted).
*/
protected abstract void reflectSupportRemoveValue(Object value, boolean recordChanges, boolean ignoreContainment);
/**
* Removes values from the supported collection without marking the removed values as being a change.
* This method is only called when the supported collection is a reflection and the reflected collection sends updates.
* @param values The values removed from the collection.
* @param recordChanges Whether the changes should be recorded by the collection (trusted change versus untrusted).
*/
protected abstract void reflectSupportRemoveValues(ICollection values, boolean recordChanges);
/**
* Resets the collections of added and removed values.
*/
protected abstract void reflectSupportResetChangeTracking();
/**
* Suppresses all events so that they will be fired as one event at a later time.
*/
protected abstract void reflectSupportSuppressEvents();
/**
* Registers a new reflection of the collection.
* @param reflectDataContext The context for the creation of this object's reflection.
*/
protected void registerReflection(CreateReflectDataContext createReflectDataContext) {
IReflectUpdateHandler updateHandler = createReflectDataContext.getUpdateHandler();
if(Orb.isProxy(updateHandler) && Orb.isLocal(updateHandler)) {
updateHandler = (IReflectUpdateHandler) Orb.getLocal(updateHandler);
}//if//
//Don't collect reflection data for objects that are already reflected in the given reflection context (represented by the update handler).//
if(!isReflected(updateHandler)) {
ReflectCollectionData reflectionData = null;
try {
ReflectionHolder reflectionHolder = null;
long reflectionId = createReflectDataContext.getIdHolder().generateId();
//Setup the reflection holder and add it to the collection of registered reflections.//
reflectionHolder = new ReflectionHolder(updateHandler, reflectionId, createReflectDataContext.getMetadataContainer());
setRegisteredReflection(reflectionHolder);
reflectionHolder.registerDisconnectHandler((IReflectable) getSupportedObject());
//Initialize the reflection data object containing all of the values in the reflection.//
reflectionData = createReflectCollectionData();
reflectionData.holder = reflectionHolder;
reflectionData.reflectionId = reflectionId;
reflectionData.reflected = Orb.isLocal(createReflectDataContext.getUpdateHandler()) ? (IReflectable) this : (IReflectable) Orb.getProxy(this, IReflectableCollection.class);
reflectionData.reflectedType = getSupportedCollection().getClass();
setupReflectionDataConstructor(reflectionData);
reflectionData.mappedReflectionId = initializeUpdateMessageNumber(updateHandler, reflectionId);
initializeReflectCollectionData(reflectionData);
//Add the reflection data to the container.//
createReflectDataContext.getReflectionDataContainer().add(reflectionData);
//Prepare the reflection data by proxing and generating reflections and cloning as necessary.//
prepareReflectionData(reflectionData, createReflectDataContext);
reflectionData.includesReferencedData(true);
}//try//
catch(Throwable e) {
Debug.log("Reflection data collection failed.", e);
reflectionData = null;
}//catch//
}//if//
}//registerReflection()//
/**
* Sets up the specific collection class parameters for instantiating a new collection that will be used as a reflection of the original.
* @param reflectionData The reflection data that must be initialized with the signature and parameter values for creating a new reflection of the collection.
*/
protected void setupReflectionDataConstructor(ReflectCollectionData reflectionData) {
//Should be overloaded by each instantiatable collection class to provide the reflectionData.reflectedTypeConstructorSignature and reflectionData.reflectedTypeConstructorParameters values.//
//reflectionData.reflectedTypeConstructorSignature = new Class[] {...}
//reflectionData.reflectedTypeConstructorParameters = new Object[] {...}
}//setupReflectionDataConstructor()//
/**
* Initializes the reflect collection data. This method provides subclasses an opportunity to add data.
* @param reflectionData The reflection data container for this reflected collection. This may be a subclass whose type is defined by the createReflectCollectionData() method.
* @see #createReflectCollectionData()
*/
protected void initializeReflectCollectionData(ReflectCollectionData reflectionData) {
reflectionData.addAddOperation(new LiteList((ICollection) getSupportedCollection()));
}//registerReflection()//
/**
* Notifies reflections when this reflected collection is modified.
* @param data The change data that identifies the added and removed values for the reflections.
* @param ignoredUpdateHandler The handler that should be ignored, or null if all handlers should receive the data.
* @return The reflection collection data for the ignored update handler. This will be null if the ignored update handler is null.
*/
protected ReflectCollectionData sendUpdate(ReflectCollectionData data, IReflectUpdateHandler ignoredUpdateHandler) {
ReflectCollectionData result = null;
if(hasReflections()) {
IIterator iterator = getRegisteredReflections();
while(iterator.hasNext()) {
ReflectionHolder reflectionHolder = (ReflectionHolder) iterator.next();
if(Orb.checkExactEquality(reflectionHolder.getHandler(), ignoredUpdateHandler)) {
result = data;
result.holder = reflectionHolder;
}//if//
else {
ReflectCollectionData reflectionData = createReflectCollectionData();
boolean isRemote = !reflectionHolder.isLocal(); //Whether the reflection is remote or local.//
//TODO: This code must create reflections of the data as necessary.
//TODO: The method should be able to get the metadata for creating reflections from the reflection holder.
//TODO: The method will either have to be passed a CreateReflectDataContext or will have to create one.
reflectionData.reflectionId = reflectionHolder.getReflectionId(); //This identifies who is sending the message through the handler.//
reflectionData.reflectedType = getSupportedCollection().getClass(); //Is this always necessary? This may only be necessary if we are creating a new reflection.//
reflectionData.reflected = null;
reflectionData.operations = data.operations == null ? null : (IntArray) data.operations.clone();
reflectionData.values = data.values == null ? null : (LiteList) data.values.clone();
//Prepare the values for sending.//
for(int index = 0, length = reflectionData.values == null ? 0 : reflectionData.values.getSize(); index < length; index++) {
Object value = reflectionData.values.get(index);
if(value instanceof IReflectableObject) {
value = isRemote ? Orb.getProxy(value, IReflectableObject.class) : value;
}//else if//
else {
//TODO: When we have metadata for the reflection generation, we should perhaps pass it to this clone method which can pass it to ICloneable values.
value = isRemote ? value : cloneValue(value);
}//else//
reflectionData.values.set(index, value);
}//for//
try {
//Update the holder using a customized reflection data object. It must be customized because the adds and removes must take into account the reflection type and remoteness of the reflection.//
updateReflection(reflectionHolder, reflectionData);
}//try//
catch(Throwable e) {
if(Orb.isInvalidProxyException(e)) {
//Do nothing. The reflection should be unregistered automatically.//
}//if//
else {
Debug.log(e);
}//else//
}//catch//
}//else//
}//while//
}//if//
return result;
}//sendUpdate()//
/**
* Creates a new collection data for this reflected collection or reflection of a collection.
* @return The data object for this collection type.
*/
protected ReflectCollectionData createReflectCollectionData() {
return new ReflectCollectionData();
}//createReflectCollectionData()//
/**
* Synchronizes changes from a refection of this object.
* @param updateHandler The handler used to identify the reflection that is performing the synchronization of data. The synchronizing reflection will only receive notification of the changes through this method's return value.
* @param abstractData The collection of added and removed values.
* @return The collection of changes actually applied to the collection.
*/
public final ReflectCollectionData synchronizeReflection(IReflectUpdateHandler updateHandler, AbstractReflectData abstractData) {
ReflectCollectionData result = null;
TransactionContextHolder contextHolder = null;
try {
contextHolder = TransactionContextHolder.getInstance(null);
//Setup a data container to which the changes will be added so that after synchronizing we can update all reflections.//
eventData = createReflectCollectionData();
//Give subclasses an opportunity to prepare for a synchronize event. For example, ordered lists may want to store some ordering info prior to being updated so that the new ordering can be sent out after the changes are applied.//
preReflectionSynchronization();
try {
//Perform the synchronization which will change this reflected object.//
internalSynchronizeReflection(updateHandler, (ReflectCollectionData) abstractData);
}//try//
finally {
//Notify the subclasses that the synchronization has completed.//
postReflectionSynchronization();
}//finally//
//Commit any changes to the collection.//
if(!contextHolder.commit()) {
if(!contextHolder.rollback()) {
Debug.log(new RuntimeException("Error: Failed to commit, and then rollback the transaction. The repository may be in an unexpected state (repository specific behavior unknown)."));
}//if//
throw new ReflectionSynchronizationException(new TransactionErrorInfo(Transaction.ERROR_COMMIT_FAILED, IEntity.MODEL_ERROR_NONE));
}//if//
//If there were any significant changes applied to this reflected object then update the reflections.//
if(getEventData().hasChanges()) {
result = sendUpdate(getEventData(), updateHandler);
}//if//
}//try//
finally {
eventData = null;
if(contextHolder != null) {
contextHolder.close();
contextHolder = null;
}//if//
}//finally//
return result;
}//synchronizeReflection()//
/**
* Called prior to synchronizing a reflection with this reflected object (changes being applied to this object).
*/
protected void preReflectionSynchronization() {
}//preReflectionSynchronization()//
/**
* Called after synchronizing a reflection with this reflected object (changes being applied to this object).
*/
protected void postReflectionSynchronization() {
}//postReflectionSynchronization()//
/**
* Called prior to updating a reflection with changes made by the reflected object (changes being applied to this object).
*/
protected void preReflectionUpdate() {
}//preReflectionUpdate()//
/**
* Called after updating a reflection with changes made by the reflected object (changes being applied to this object).
*/
protected void postReflectionUpdate() {
}//postReflectionUpdate()//
/**
* Synchronizes changes from a refection of this object. This internal method allows easy overloading for subclasses.
* @param updateHandler The handler used to identify the reflection that is performing the synchronization of data. The synchronizing reflection will only receive notification of the changes through this method's return value.
* @param data The collection of added and removed values.
*/
protected abstract void internalSynchronizeReflection(IReflectUpdateHandler updateHandler, ReflectCollectionData data);
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#updateReflection(com.foundation.attribute.AbstractReflectData)
*/
public void updateReflection(AbstractReflectData abstractData) {
ReflectCollectionData data = (ReflectCollectionData) abstractData;
try {
if(hasReflections()) {
//Set the event data to collect changes to be sent to other reflections of this reflection.//
eventData = createReflectCollectionData();
}//if//
//TODO: It might be nice to move this to this method's caller so that queued messages get processed as one unit from the perspective of the reflection.
preReflectionUpdate();
try {
internalUpdateReflection(data);
}//try//
catch(Throwable e) {
Debug.log("Reflection update failed.", e);
}//catch//
postReflectionUpdate();
//If there were any significant changes applied to this reflected object then update the reflections.//
if((hasReflections()) && (getEventData().hasChanges())) {
sendUpdate(getEventData(), null);
}//if//
}//try//
finally {
eventData = null;
}//finally//
}//updateReflection()//
/**
* Performs the actual update of the collection reflection using the given change data.
* The reflected object is sending a set of changes to this reflection.
* @param data The set of changes to be applied to this collection.
*/
protected abstract void internalUpdateReflection(ReflectCollectionData data);
}//ReflectCollectionSupport//

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.util.LiteList;
/**
* Contains a set of reflection data generated by a reflected object in its call to reflectionRegister(..).
* Also passes the last reflection process identifier used to generate the reflection datas on remote processes without making calls to the reflection context to get identifiers.
*/
public class ReflectDataContainer implements java.io.Externalizable {
/** The collection of AbstractReflectData objects that make up the reflection data that were generated. */
private LiteList reflectionData = null;
/**
* ReflectDataContainer constructor.
* For serialization use only.
*/
public ReflectDataContainer() {
super();
}//ReflectDataContainer()//
/**
* ReflectDataContainer constructor.
* @param reflectionData The collection of AbstractReflectData objects that make up the reflection data that were generated.
*/
public ReflectDataContainer(LiteList reflectionData) {
super();
this.reflectionData = reflectionData;
}//ReflectDataContainer()//
/**
* Gets the collection of AbstractReflectData objects that make up the reflection data that were generated.
* @return The set of reflection data objects for the objects that were reflected.
*/
public LiteList getReflectionData() {
return reflectionData;
}//getReflectionData()//
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
reflectionData = (LiteList) in.readObject();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
out.writeObject(reflectionData);
}//readExternal()//
}//ReflectDataContainer//

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.util.optimized.IntArray;
public class ReflectIndexedCollectionData extends ReflectCollectionData {
/** Whether the collection should retain its ordering information (and consiquentially not allow an order comparator). */
public boolean retainOrdering = false;
/**
* ReflectIndexedCollectionData constructor.
*/
public ReflectIndexedCollectionData() {
super();
}//ReflectIndexedCollectionData()//
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
super.readExternal(in);
retainOrdering = in.readBoolean();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
super.writeExternal(out);
out.writeBoolean(retainOrdering);
}//readExternal()//
}//ReflectIndexedCollectionData//

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
public class ReflectObjectData extends AbstractReflectData {
/** The collection of the reflected object's attributes. */
public AttributeSupport.AttributeCollection data = null;
/**
* ReflectObjectData constructor.
*/
public ReflectObjectData() {
super();
}//ReflectObjectData()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectData#createReflection()
*/
public IReflectable createReflection() throws InstantiationException, IllegalAccessException {
return ReflectObjectSupport.createReflection(this);
}//createReflection()//
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
super.readExternal(in);
/*byte version = */in.readByte();
data = (AttributeSupport.AttributeCollection) in.readObject();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
super.writeExternal(out);
out.writeByte(0);
out.writeObject(data);
}//readExternal()//
}//ReflectObjectData//

View File

@@ -0,0 +1,414 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.orb.*;
import com.common.util.*;
import com.common.debug.*;
import com.foundation.attribute.AttributeSupport;
import com.foundation.common.IEntity;
import com.foundation.metadata.Attribute;
import com.foundation.metadata.CloneContext;
/*
* Supports an entity by allowing for local and remote registered clones or copies of the entity. The clones can be modified without affecting the entity until the changes are synchronized.
* The application should obtain a lock (application dependant) to prevent two user threads from trying to synchronize changes at the same time. Normally this should be done when a view is
* opened that could change some entities. All other user threads should be prevented from changing those entities until the view is closed and any changes are applied or discarded. At the
* very least the user thread should prevent other user threads from synchronizing changes why it is synchronizing changes. Failure to do this will allow for inconsistent clone states.
*/
public abstract class ReflectObjectSupport extends AbstractReflectSupport {
/** The object supported by this reflectable support. */
private IReflectableObject supportedObject = null;
/** The object that is being reflected. This should be null if this object is supporting the original object. */
private IReflectableObject reflectedObject = null;
/** The reflected object's attribute support reference. */
private AttributeSupport supportedObjectAttributeSupport = null;
/** The model mapping number used only when synchronizing a non-reflection such that the reflection data created upon a successful synchronize passes the number back to the synchronizing reflection context so that it may reuse its copy of the model for the new reflecton, thus preserving any reflections of it. */
private int modelMappingNumber = -1;
/**
* ReflectSupport constructor.
*/
ReflectObjectSupport() {
super();
//this.singleThreadedContext = ThreadService.getSingleThreadedContext();
}//ReflectSupport()//
/**
* ReflectSupport constructor.
* @param supportedObject The supported object.
* @param supportedEntityAttributeSupport The supported object's attribute support object used to update attribute values.
* @param supportedObjectEventEmitterSupport The supported object's event emitter support object used to fire attribute changed events.
*/
ReflectObjectSupport(Object supportedObject) {
super(supportedObject);
//this.singleThreadedContext = ThreadService.getSingleThreadedContext();
this.supportedObject = (IReflectableObject) supportedObject;
this.supportedObjectAttributeSupport = (AttributeSupport) this;
if(supportedObject == null) {
Debug.log("Error: supported object = null");
}//if//
}//ReflectSupport()//
/**
* Sets the model mapping number used only when synchronizing a model that doesn't yet existing in the shared context.
* @param modelMappingNumber The number used by the synchronizing reflection context to map the data sent in the synchronize to the models when the synchronized data is reflected at the end of the synchronization.
*/
public int getModelMappingNumber() {
return modelMappingNumber;
}//getModelMappingNumber()//
/**
* Sets the model mapping number used only when synchronizing a model that doesn't yet existing in the shared context.
* @param modelMappingNumber The number used by the synchronizing reflection context to map the data sent in the synchronize to the models when the synchronized data is reflected at the end of the synchronization.
*/
public void setModelMappingNumber(int modelMappingNumber) {
this.modelMappingNumber = modelMappingNumber;
}//setModelMappingNumber()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#completeSynchronization(com.foundation.attribute.AbstractReflectData, com.foundation.attribute.AbstractReflectData)
*/
public void completeSynchronization(AbstractReflectData proposedChanges, AbstractReflectData appliedChanges) {
AttributeSupport.AttributeCollection attributeCollection = ((ReflectObjectData) appliedChanges).data;
try {
//Note: I commented out the reset of the change flags since it was doing the job of the applyAttributeCollection without firing the proper events, so the apply attribute collection then did nothing.//
//Reset the change flags so that when we apply the updates they are not applied to the original values.//
//supportedObjectAttributeSupport.resetObjectChangeFlags();
//Apply the changes.//
supportedObjectAttributeSupport.applyAttributeCollection((AttributeSupport.AttributeCollection) attributeCollection, AttributeSupport.CONTEXT_UNTRUSTED, false);
attributeCollection = null;
}//try//
catch(Throwable e) {
Debug.log("Reflection update failed.", e);
}//catch//
//All changes will (currently) always be accepted by the reflected object.//
//Only need to reset all change flags.//
supportedObjectAttributeSupport.resetObjectChangeFlags();
}//completeSynchronization()//
/**
* Creates a reflection given a reflectable object.
* A reflection can be used to create a local copy that gets updated and can delay changes to the reflected object.
* @param reflected The object to be reflected.
* @return The reflection of the reflected object.
*/
public static IReflectable createReflection(ReflectObjectData reflectionData) throws InstantiationException, IllegalAccessException {
IReflectable reflection = null;
IReflectable replacementReflection = null;
//Create a reflection object of the specified type.//
reflection = (IReflectable) reflectionData.reflectedType.newInstance();
//Set the reflection's initial state.//
replacementReflection = (IReflectable) reflection.zzrReflectionInitialize(reflection, reflectionData); //The reflection will call its reflect support's initializeReflection(ReflectionData) method.//
//Just in case (should also happen in the ReflectionContext) we will destroy the reflection we were trying to create if another reflection already exists for the given reflected object.//
if(replacementReflection != null) {
reflection.zzrReflectionDestroy(reflection);
}//if//
return replacementReflection != null ? replacementReflection : reflection;
}//createReflection()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#destroyReflection()
*/
public void destroyReflection() {
//Clear the reflected reference.//
//reflectedObject = null;
super.destroyReflection();
}//destroyReflection()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getReflectedObject()
*/
public IReflectable getReflectedObject() {
return reflectedObject;
}//getReflectedObject()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getReflectionObject()
*/
public IReflectable getReflectionObject() {
return supportedObject;
}//getReflectionObject()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getSupportedObject()
*/
public IReflectable getSupportedObject() {
return getReflectionObject();
}//getSupportedObject()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#getSynchronizationData()
*/
public AbstractReflectData getSynchronizationData(CloneContext cloneContext) {
ReflectObjectData proposedChanges = null;
//Check to see if there is something to synchronize to.//
if(getReflectionId() != null) {
try {
AttributeSupport.AttributeCollection attributeCollection = supportedObjectAttributeSupport.getDeltaAttributeCollection(null, true, false); //Note: We want to serialize or clone, not proxy, changes in attributes referencing IReflectable objects.//
//Return null if the object has not been changed in any significant way.//
if(attributeCollection != null) {
//TODO: What if we are using a remote single threaded reflection context? Will this still work? If it is remote it won't operate on the same thread. Should we test to see if the destination context shares a thread with this context?
ReflectionContext destinationContext = Orb.isLocal(getReflectedObject()) && getReflectedObject().isReflection() ? getReflectedObject().zzrGetReflectionContext(getReflectedObject()) : null;
//Convert reflections to the reflected references.//
attributeCollection.dereflect(getReflectionContext(), destinationContext, supportedObjectAttributeSupport.getTypeMetadata(), cloneContext);
//Build our proposed changes object.//
proposedChanges = new ReflectObjectData();
proposedChanges.data = attributeCollection;
}//if//
}//try//
catch(Throwable e) {
Debug.log("Dirty reflection data collection failed.", e);
}//catch//
}//if//
return proposedChanges;
}//getSynchronizationData()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#initializeReflection(com.foundation.attribute.AbstractReflectData)
*/
public Object reflectionInitialize(AbstractReflectData reflectionData) {
//Save the reflected reference.//
reflectedObject = (IReflectableObject) ((ReflectObjectData) reflectionData).reflected;
return super.reflectionInitialize(reflectionData);
}//reflectionInitialize()//
/**
* Called after initializing this reflection.
* Allows the references to reflected objects to be replaced with their reflections.
*/
public void reflectionPostInitialize(ReflectObjectData reflectionData) {
AttributeSupport.AttributeCollection attributeCollection = reflectionData.data;
//Copy the attribute data into is new reflection.//
//Note: Changed this to TRUSTED because with a value of UNTRUSTED it was causing the values to be placed in the altered array, and even worse was forcing the loading of some values from the reflected object (why when we are already applying those values here?).//
supportedObjectAttributeSupport.applyAttributeCollection(attributeCollection, AttributeSupport.CONTEXT_TRUSTED, false);
}//reflectionPostInitialize()//
/**
* Gets the attribute number for the given attribute name.
* @param attributeName The name of the attribute whose number is to be found.
* @return The attribute's number, or -1 if the attribute could not be found.
*/
protected abstract int getAttributeNumber(String attributeName);
/**
* Loads the reflection's attribute by requesting the attribute value from the reflected object.
* If the result is an AbstractReflectData then the caller should inflate the result into a full reflection before setting the attribute value.
* @param attributeName The name of the attribute whose value is desired.
* @return Either a serialized value, null if the attribute's value is null, or an instance of AbstractReflectData.
*/
protected Object loadReflectionAttribute(String attributeName) throws InstantiationException, IllegalAccessException {
return getReflectionContext().loadReflectionAttribute((IReflectableObject) getReflectedObject(), attributeName);
}//loadReflectionAttribute()//
/**
* Sets the object this reflect object support is supporting.
* @param supportedObject The object being supported.
*/
public Object loadReflectionAttribute(Attribute attribute, IReflectUpdateHandler updateHandler, ReflectRegistrationData registrationData) {
ReflectionHolder reflectionHolder = (ReflectionHolder) getRegisteredReflection(updateHandler);
int attributeNumber = attribute.getNumber();
Object result = null;
if(attributeNumber != -1) {
result = supportedObjectAttributeSupport.getAttributeValue(attributeNumber);
reflectionHolder.getIsAttributeReflected()[attributeNumber] = true;
}//if//
return result;
}//loadReflectionAttribute()//
/**
* Registers a reflection with the supported reflectable object.
* <p>Warning: This code assumes that the reflectable object extends this support class, or it receives the register method invocation and synchronizes before calling this register method.
* This class does not specifically synchronize on the supported object.</p>
* @param createReflectDataContext The context object for the creation of the reflect data.
* @return The last used reflection identifier.
*/
public void registerReflection(CreateReflectDataContext createReflectDataContext) {
IReflectUpdateHandler updateHandler = createReflectDataContext.getUpdateHandler();
if(Orb.isProxy(updateHandler) && Orb.isLocal(updateHandler)) {
updateHandler = (IReflectUpdateHandler) Orb.getLocal(updateHandler);
}//if//
//Don't collect reflection data for objects that are already reflected in the given reflection context (represented by the update handler).//
if(!isReflected(updateHandler)) {
ReflectObjectData reflectionData = new ReflectObjectData();
createReflectDataContext.getReflectionDataContainer().add(reflectionData);
try {
AttributeSupport.AttributeCollection attributeCollection = new AttributeSupport.AttributeCollection();
boolean[] isAttributeReflected = null;
ReflectionHolder reflectionHolder = null;
boolean isRemote = !Orb.isLocal(updateHandler);
long reflectionId = createReflectDataContext.getIdHolder().generateId();
//Add the reflection to the collection so that it is updated when attributes change their values.//
reflectionHolder = new ReflectionHolder(updateHandler, reflectionId, isAttributeReflected, createReflectDataContext.getMetadataContainer());
setRegisteredReflection(reflectionHolder);
//Collect the attribute values.//
isAttributeReflected = supportedObjectAttributeSupport.createReflectionAttributeCollection(attributeCollection, isRemote, createReflectDataContext);
reflectionHolder.setIsAttributeReflected(isAttributeReflected);
reflectionHolder.registerDisconnectHandler((IReflectable) getSupportedObject());
//Setup the reflection data.//
reflectionData.includesReferencedData(true);
reflectionData.modelMappingNumber = getModelMappingNumber();
setModelMappingNumber(-1);
reflectionData.reflectionId = reflectionId;
reflectionData.reflected = isRemote ? (IReflectable) Orb.getProxy(supportedObject, IReflectableObject.class) : supportedObject;
reflectionData.reflectedType = supportedObject.getClass();
reflectionData.data = attributeCollection;
reflectionData.mappedReflectionId = initializeUpdateMessageNumber(updateHandler, reflectionId);
}//try//
catch(Throwable e) {
Debug.log(e, "Reflection data collection failed");
reflectionData = null;
}//catch//
}//if//
}//registerReflection()//
/**
* Sets the object this reflect object support is supporting.
* @param supportedObject The object being supported.
*/
protected void setSupportedObject(IReflectableObject supportedObject) {
this.supportedObject = supportedObject;
super.setSupported(supportedObject);
}//setSupportedObject()//
/**
* Sets the attribute support used by the supported object.
* @param supportedObjectAttributeSupport The attribute support object being used by the supported object.
*/
protected void setSupportedObjectAttributeSupport(AttributeSupport supportedObjectAttributeSupport) {
this.supportedObjectAttributeSupport = supportedObjectAttributeSupport;
}//setSupportedObjectAttributeSupport()//
/**
* Synchronizes data from a reflection to this reflected object.
* <p>Note: The synchronizing reflection will only receive notification of the changes through this method's return value. An event will not be sent via the update handler.
* The returned data will contain the last update message number sent to the reflection. This can be used to ensure that messages are processed in order.</p>
* @param updateHandler The handler used to identify the reflection that is performing the synchronization of data.
* @param data The set of changed data.
* @param createReflectDataContext The context for creating reflections of the IReflectable changes for the synchronizing reflection context.
* @return The collection of changes actually applied to the reflected object.
*/
public AbstractReflectData synchronizeReflection(IReflectUpdateHandler updateHandler, AbstractReflectData reflectData, CreateReflectDataContext createReflectDataContext) {
//Update this object with the collection of changed attributes.//
//Note: Changed this from TRUSTED to UNTRUSTED because things were not being persisted since it thought nothing had changed after the synchronize.//
supportedObjectAttributeSupport.applyAttributeCollection(((ReflectObjectData) reflectData).data, AttributeSupport.CONTEXT_UNTRUSTED, false);
//Proxy any reflectable values so that the reflections and the caller can properly create a reflection from the reflectable proxies.//
((ReflectObjectData) reflectData).data.proxyValues(IReflectableObject.class);
((ReflectObjectData) reflectData).data.proxyValues(IReflectableCollection.class);
((ReflectObjectData) reflectData).data.reflectValues(createReflectDataContext, supportedObjectAttributeSupport.getTypeMetadata());
reflectData.includesReferencedData(true);
//TODO: The updates should be bundled together to be more efficient.
//Update any reflections of this reflection.//
updateReflections(((ReflectObjectData) reflectData).data, updateHandler);
return reflectData;
}//synchronizeReflection()//
/* (non-Javadoc)
* @see com.foundation.attribute.IReflectSupport#updateReflection(com.foundation.attribute.AbstractReflectData)
*/
public void updateReflection(AbstractReflectData reflectData) {
AttributeSupport.AttributeCollection attributeCollection = ((ReflectObjectData) reflectData).data;
try {
//TODO: When the update includes the reflection data for referenced IReflectables we must be certain to apply the changes after creating all the reflections.
//Apply the changes.//
supportedObjectAttributeSupport.applyAttributeCollection((AttributeSupport.AttributeCollection) attributeCollection, AttributeSupport.CONTEXT_TRUSTED | AttributeSupport.CONTEXT_UPDATE, true);
}//try//
catch(Throwable e) {
Debug.log(e, "Reflection update failed.");
}//catch//
}//updateReflection()//
/**
* Updates the registered reflections with the specified attribute's value.
* @param attributeNumber The number of the attribute whose value should be updated in all reflections.
*/
public void updateReflections(int attributeNumber) {
if(hasReflections()) {
//Note: This next method will filter out reflections that don't care.//
updateReflections(supportedObjectAttributeSupport.getAttributeCollection(attributeNumber, null), null);
}//if//
}//updateReflections()//
/**
* Updates the registered reflections with the collection of attribute changes.
* @param attributeCollection The collection of changes to the attributes of the supported object.
* @param ignoredUpdateHandler An optional reference to an update handler that should be ignored. This allows synchronizations of data to avoid updating the synchronizing reflection.
*/
private void updateReflections(AttributeSupport.AttributeCollection attributeCollection, IReflectUpdateHandler ignoredUpdateHandler) {
if(hasReflections()) {
IIterator iterator = getRegisteredReflections();
//Update the reflections.//
while(iterator.hasNext()) {
ReflectionHolder reflectionHolder = (ReflectionHolder) iterator.next();
//Don't send updates to the ignored reflection.//
if(!Orb.checkExactEquality(reflectionHolder.getHandler(), ignoredUpdateHandler)) {
ReflectObjectData reflectData = new ReflectObjectData();
//Note: this operation should not be threaded, and the attribute mask should only be used if the object is serialized (to avoid unnecessary serialization).//
attributeCollection.attributeMask = reflectionHolder.getIsAttributeReflected();
if(attributeCollection.getFilteredCount() > 0) {
if(reflectionHolder.isLocal()) {
reflectData.data = attributeCollection.getFilteredCollection();
}//if//
else {
reflectData.data = attributeCollection.getFilteredCollection();
reflectData.data.proxyValues(IReflectableCollection.class);
reflectData.data.proxyValues(IReflectableObject.class);
}//else//
try {
//Notify the reflection of the changes.//
updateReflection(reflectionHolder, reflectData);
}//try//
catch(Throwable e) {
if(Orb.isInvalidProxyException(e)) {
//Do nothing. The reflection should be unregistered automatically.//
}//if//
else {
Debug.log(e);
}//else//
}//catch//
}//if//
}//if//
}//while//
}//if//
}//updateReflections()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#reflectionGetLastUpdateMessageNumber(com.foundation.attribute.IReflectUpdateHandler)
*/
public int reflectionGetLastUpdateMessageNumber(IReflectUpdateHandler updateHandler) {
//Note: This is here to simply make the method visible for access by the Entity's IReflectableInterface implementation.//
return super.reflectionGetLastUpdateMessageNumber(updateHandler);
}//reflectionGetLastUpdateMessageNumber()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#isReflection(com.foundation.attribute.ReflectionContext)
*/
public boolean isReflection(ReflectionContext reflectionContext) {
//Note: This is here to simply make the method visible for access by the Entity's IReflectableInterface implementation.//
return super.isReflection(reflectionContext);
}//isReflection()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#getReflectionId()
*/
public Object getReflectionId() {
//Note: This is here to simply make the method visible for access by the Entity's IReflectableInterface implementation.//
return super.getReflectionId();
}//getReflectionId()//
/* (non-Javadoc)
* @see com.foundation.attribute.AbstractReflectSupport#getReflectionContext()
*/
public ReflectionContext getReflectionContext() {
//Note: This is here to simply make the method visible for access by the Entity's IReflectableInterface implementation.//
return super.getReflectionContext();
}//getReflectionContext()//
}//ReflectObjectSupport//

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.foundation.common.MetadataContainer;
public class ReflectRegistrationData implements java.io.Externalizable {
public static byte OPTIONS_NONE = 0x00;
public static byte OPTIONS_INCLUDE_REFLECTED = 0x01;
public static byte OPTIONS_INCLUDE_REFLECTED_PROXY = 0x02;
public static byte OPTIONS_DEFAULT = OPTIONS_NONE;
/** The optional class name which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object. */
private String metadataIndex = null;
/** The optional metadata container. This can be specified instead of a metadata index if custom metadata is desired. */
private MetadataContainer metadataContainer = null;
/** TODO: Is this still used? */
private byte resultOptions = OPTIONS_DEFAULT;
/**
* ReflectRegistrationData constructor.
*/
public ReflectRegistrationData() {
super();
}//ReflectRegistrationData()//
/**
* ReflectRegistrationData constructor.
* @param metadataIndex The optional class name which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object.
*/
public ReflectRegistrationData(String metadataIndex) {
super();
this.metadataIndex = metadataIndex;
}//ReflectRegistrationData()//
/**
* ReflectRegistrationData constructor.
* @param metadataIndex The optional class which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object.
*/
public ReflectRegistrationData(Class metadataIndex) {
this(metadataIndex != null ? metadataIndex.getName() : null);
}//ReflectRegistrationData()//
/**
* ReflectRegistrationData constructor.
* @param metadataContainer The optional metadata container. This can be specified instead of a metadata index if custom metadata is desired.
*/
public ReflectRegistrationData(MetadataContainer metadataContainer) {
super();
this.metadataContainer = metadataContainer;
}//ReflectRegistrationData()//
/**
* ReflectRegistrationData constructor.
* @param metadataIndex The optional class which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object.
* @param resultOptions Options specifying whether the result should reference the reflected object, and whether the reference should be to a proxy of the reflected object.
* @see #OPTION_NONE
* @see #OPTIONS_INCLUDE_REFLECTED
* @see #OPTIONS_INCLUDE_REFLECTED_PROXY
*/
public ReflectRegistrationData(Class metadataIndex, byte resultOptions) {
super();
this.metadataIndex = metadataIndex != null ? metadataIndex.getName() : null;
this.resultOptions = resultOptions;
}//ReflectRegistrationData()//
/**
* Gets the optional index used to lookup the metadata container.
* @return The index used to obtain the metadata container.
*/
public String getMetadataIndex() {
return metadataIndex;
}//getMetadataIndex()//
/**
* Gets the optional metadata container that identifies what to reflect.
* @return The metadata identifying what to reflect.
*/
public MetadataContainer getMetadataContainer() {
return metadataContainer;
}//getMetadataContainer()//
/**
* TODO: Is this still used?
*/
public byte getResultOptions() {
return resultOptions;
}//getResultOptions()//
/**
* Reads the object from a stream.
* @param in The input stream to read from.
*/
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
/*byte version = */in.readByte();
metadataIndex = (String) in.readObject();
metadataContainer = (MetadataContainer) in.readObject();
resultOptions = in.readByte();
}//readExternal()//
/**
* Writes the object to a stream.
* @param out The stream to write to.
*/
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
out.writeByte(0);
out.writeObject(metadataIndex);
out.writeObject(metadataContainer);
out.writeByte(resultOptions);
}//readExternal()//
}//ReflectRegistrationData//

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import com.common.orb.Orb;
import com.common.thread.IRunnable;
import com.common.util.IIterator;
import com.common.util.IList;
import com.common.util.LiteHashMap;
import com.common.util.LiteList;
/*
* An agent which will be sent to a remote process to create one or more reflections (actually returns reflection data objects which must be reconstituted into reflections).
* The result of the agent is an IList of ReflectDataContainers where the last container has the last used reflection identifier that is valid.
* The first result in each of the containers is the reflection that was asked for.
* <p>
* Warning: This agent is not a good way to get reflections. It is better to use metadata and load all the collection's reflections at the time the collection is reflected.
* This is possible because all reflection contexts are single threaded meaning that they can start reflecting data and the process can use as many id's as necessary since
* another thread cannot start loading other reflections at the same time from the same context. This agent is made to be functional, but may be inefficient.
* </p>
*/
public class ReflectionCreationAgent implements IRunnable, java.io.Externalizable {
/** The collection of references to reflectable objects requiring reflection. */
private IList reflectables = null;
/** The update handler that the reflected objects will notify when the reflection requires updating. */
private IReflectUpdateHandler updateHandler = null;
/** The optional class which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object. */
private Class metadataIndex = null;
/**
* ReflectionCreationAgent default constructor.
*/
public ReflectionCreationAgent() {
}//ReflectionCreationAgent()//
/**
* ReflectionCreationAgent constructor.
* @param reflectables The collection of reflectable proxies which either exist on the target process or exist furthor down the virtual network connection.
* @param updateHandler The update handler that will handle updates from the created reflections.
*/
public ReflectionCreationAgent(IList reflectables, IReflectUpdateHandler updateHandler, Class metadataIndex) {
this.reflectables = reflectables;
this.updateHandler = Orb.isLocal(updateHandler) ? (IReflectUpdateHandler) Orb.getProxy(updateHandler, IReflectUpdateHandler.class) : updateHandler;
}//ReflectionCreationAgent()//
/* (non-Javadoc)
* @see com.common.thread.IRunnable#run()
*/
public Object run() {
IList result = new LiteList(reflectables.getSize());
LiteHashMap binnedReflectables = new LiteHashMap(10);
//Organize the reflectable references into lists indexed by the process (identified by the connectionIdentifier) they exist on, where null is the local process.//
for(int index = 0; index < reflectables.getSize(); index++) {
IReflectable value = (IReflectable) reflectables.get(index);
Object connectionIdentifier = Orb.getConnectionIdentifier(value);
IList reflectables = null;
//Get the collection of reflectable objects for this connection (the bin).//
reflectables = (IList) binnedReflectables.get(connectionIdentifier);
//Lazily create the reflectables collection for this bin.//
if(reflectables == null) {
reflectables = new LiteList(this.reflectables.getSize());
binnedReflectables.put(connectionIdentifier, reflectables);
}//if//
//Add the reflectable value to the bin based on its related network connection.//
reflectables.add(value);
}//for//
//Collect the sorted reflection data into the result list.//
if(binnedReflectables != null) {
IIterator connectionIdentifierIterator = binnedReflectables.keyIterator();
while(connectionIdentifierIterator.hasNext()) {
Object connectionIdentifier = connectionIdentifierIterator.next();
IList reflectables = (IList) binnedReflectables.get(connectionIdentifier);
//If this is the local process then collect the reflectable's reflection data, otherwise forward the agent to the remote process.//
if(connectionIdentifier == null) {
LiteHashMap resultMap = new LiteHashMap(reflectables.getSize()); //Note: Used to handle multiple requests for the same object.//
for(int index = 0; index < reflectables.getSize(); index++) {
IReflectable value = (IReflectable) reflectables.get(index);
ReflectDataContainer reflectDataContainer = (ReflectDataContainer) resultMap.get(value);
//If we haven't already created the reflection data then do so now (it is possible to have more than one reference to the same object in a collection).//
if(reflectDataContainer == null) {
reflectDataContainer = value.zzrReflectionRegister(updateHandler, new ReflectRegistrationData(metadataIndex, ReflectRegistrationData.OPTIONS_INCLUDE_REFLECTED_PROXY));
if(reflectDataContainer != null) {
resultMap.put(value, reflectDataContainer);
}//if//
}//if//
result.add(reflectDataContainer);
}//for//
}//if//
else {
ReflectionCreationAgent agent = new ReflectionCreationAgent(reflectables, updateHandler, metadataIndex);
IList reflectionData = null;
//Send an agent to perform this same bit of code on the remote machine.//
//TODO: Should handle exceptions?//
reflectionData = (IList) Orb.sendAgent(agent, connectionIdentifier, false, 600000, null);
if(reflectionData != null) {
result.addAll(reflectionData);
}//if//
}//else//
}//while//
}//while//
return result;
}//run()//
/* (non-Javadoc)
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
*/
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
/*byte version = */in.readByte();
reflectables = (IList) in.readObject();
updateHandler = (IReflectUpdateHandler) in.readObject();
metadataIndex = (Class) in.readObject();
}//readExternal()//
/* (non-Javadoc)
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeByte(0);
out.writeObject(reflectables);
out.writeObject(updateHandler);
out.writeObject(metadataIndex);
}//writeExternal()//
}//ReflectionCreationAgent//

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.orb.*;
import com.foundation.common.MetadataContainer;
/**
* Used by the reflection support classes to pair the reflection handler with an index.
* The index allows the handler to be used with mutliple reflections when reflections are batch created.
* Each index represents one reflection that the handler manages messages for.
*/
public class ReflectionHolder {
/** The remote identifier for the reflection. */
private long reflectionId = 0;
/** The handler called when the reflection requires updating due to changes in the reflected value. */
private IReflectUpdateHandler handler = null;
/** The listener for a lost connection to remote reflections. */
private IInvalidProxyListener listener = null;
/** The array of flags indicating which attributes were reflected (and thus which attribute value changes should be sent to the reflection). Collection reflections ignore this attribute. */
private boolean[] isAttributeReflected = null;
/** The optional metadata used for determining what is reflected. */
private MetadataContainer metadataContainer = null;
/**
* ReflectionHolder constructor.
* Constructs a reflection holder for an object reflection.
*/
public ReflectionHolder(IReflectUpdateHandler handler, long reflectionId, boolean[] isAttributeReflected, MetadataContainer metadataContainer) {
super();
this.handler = handler;
this.reflectionId = reflectionId;
this.isAttributeReflected = isAttributeReflected;
this.metadataContainer = metadataContainer;
}//ReflectionHolder()//
/**
* ReflectionHolder constructor.
* Constructs a reflection holder for a collection reflection.
*/
public ReflectionHolder(IReflectUpdateHandler handler, long reflectionId, MetadataContainer metadataContainer) {
super();
this.handler = handler;
this.reflectionId = reflectionId;
this.metadataContainer = metadataContainer;
}//ReflectionHolder()//
/**
* @return Returns the reflectionId.
*/
public long getReflectionId() {
return reflectionId;
}//getReflectionId()//
/**
* Gets the handler called when the reflection requires updating due to changes in the reflected value.
* @return The update handler for the reflection.
*/
public IReflectUpdateHandler getHandler() {
return handler;
}//getHandler()//
/**
* Gets the listener for a lost connection to remote reflections.
* @return The invalid proxy listener registered with the reflection's update handler proxy (if the reflection is remote).
*/
public IInvalidProxyListener getListener() {
return listener;
}//getListener()//
/**
* Gets the array of flags indicating which attributes were reflected (and thus which attribute value changes should be sent to the reflection).
* Collection reflections ignore this attribute.
* @return The metadata regarding the reflection's already reflected attributes.
*/
public boolean[] getIsAttributeReflected() {
return isAttributeReflected;
}//getIsAttributeReflected()//
/**
* Sets the array of flags indicating which attributes were reflected (and thus which attribute value changes should be sent to the reflection).
* Collection reflections ignore this attribute.
* @param isAttributeReflected The metadata regarding the reflection's already reflected attributes.
*/
public void setIsAttributeReflected(boolean[] isAttributeReflected) {
this.isAttributeReflected = isAttributeReflected;
}//setIsAttributeReflected()//
/**
* Gets the optional metadata used for determining what is reflected.
* @return The reflection metadata or null if no metadata is available.
*/
public MetadataContainer getMetadataContainer() {
return metadataContainer;
}//getMetadataContainer()//
/**
* Checks to see if the value is equivalent to this value.
* @param value Either a reflection holder or an update handler.
* @return Whether the two objects are equivalent.
*/
public boolean equals(Object value) {
IReflectUpdateHandler handler = Orb.isProxy(this.handler) && Orb.isLocal(this.handler) ? (IReflectUpdateHandler) Orb.getLocal(this.handler) : this.handler;
return (value instanceof ReflectionHolder ? ((ReflectionHolder) value).handler : (IReflectUpdateHandler) value).equals(handler);
}//equals()//
/**
* Gets a hash value representing the holder.
* @return A representative semi-unique number.
*/
public int hashCode() {
return handler.hashCode();
}//hashCode()//
/**
* Determines whether the reflection is in this process.
* @return Whether the reflection is local to this process.
*/
public boolean isLocal() {
return Orb.isLocal(handler);
}//isLocal()//
/**
* Registers a disconnect handler if necessary.
* @param reflected The object being reflected.
*/
public void registerDisconnectHandler(final IReflectable reflected) {
if((Orb.isProxy(handler)) && (!Orb.isLocal(handler))) {
Orb.registerInvalidProxyListener(handler, listener = new IInvalidProxyListener() {
public void evaluate(Object proxy) {
reflected.reflectionUnregister((IReflectUpdateHandler) proxy);
}//evaluate()//
});
}//if//
}//registerDisconnectHandler()//
/**
* Unregisters the disconnect handler if one was necessary.
*/
public void unregisterDisconnectHandler() {
if(listener != null) {
Orb.unregisterInvalidProxyListener(handler, listener);
}//if//
}//unregisterDisconnectHandler()//
}//ReflectionHolder//

View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2006,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
import com.common.debug.Debug;
import com.common.thread.IRunnable;
import com.common.thread.ISingleThreadedContext;
import com.common.thread.ThreadService;
import com.common.util.Queue;
import com.foundation.event.IRequestHandler;
/**
* Uses a dedicated thread to manage the reflection context.
* The user calls the execute methods to have functionality get executed by the dedicated thread which has authority to interact with the reflections under this context.
*/
public class SingleThreadedReflectionContext extends ReflectionContext implements ISingleThreadedContext {
private static final int WAIT_TIME = 1000;
private volatile boolean isStopped = true;
private Queue requestQueue = new Queue(10);
private volatile Thread requestThread = null;
/**
* A simple runnable that wrappers another runnable and notifies waiting threads when the execution is complete.
*/
private static class SynchronousRunnable implements Runnable {
private IRunnable runnable = null;
private Object result = null;
private boolean hasResult = false;
/**
* SynchronousRunnable constructor.
* @param runnable The runnable that will be executed and whose result will be passed to waiting threads.
*/
public SynchronousRunnable(IRunnable runnable) {
this.runnable = runnable;
}//SynchronousRunnable()//
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
Object result = runnable.run();
synchronized(this) {
hasResult = true;
this.result = result;
notifyAll();
}//synchronized//
}//run()//
/**
* Gets the result of the runnable after it has completed.
* <p>Warning: This is a blocking operation.</p>
* @return The wrappered runnable's result.
*/
public synchronized Object getResult() {
if(!hasResult) {
try {
wait(0);
}//try//
catch(InterruptedException e) {
Debug.handle(e);
}//catch//
}//if//
return result;
}//getResult()//
}//SynchronousRunnable//
/**
* A request handler which single threads all incomming requests via the single threaded reflection context.
*/
private static class RequestHandler implements IRequestHandler {
private SingleThreadedReflectionContext context = null;
public RequestHandler() {
}//RequestHandler()//
public boolean isRunning() {
return !context.isStopped();
}//isRunning()//
public Object execute(final IRunnable runnable, boolean synchronous) {
Object result = null;
if(synchronous) {
SynchronousRunnable queuedRunnable = new SynchronousRunnable(runnable);
synchronized(context) {
context.requestQueue.enqueue(queuedRunnable);
}//synchronized//
result = queuedRunnable.getResult();
}//if//
else {
synchronized(context) {
context.requestQueue.enqueue(new Runnable() {
public void run() {
runnable.run();
}//run()//
});
}//synchronized//
}//else//
return result;
}//execute()//
public void executeAsync(IRunnable runnable) {
execute(runnable, false);
}//executeAsync()//
public Object execute(IRunnable runnable) {
return execute(runnable, true);
}//execute()//
public boolean isRequestThread() {
return Thread.currentThread() == context.requestThread;
}//isRequestThread()//
public void setContext(SingleThreadedReflectionContext context) {
this.context = context;
}//setContext()//
}//RequestHandler//
/**
* SingleThreadedReflectionContext constructor.
*/
public SingleThreadedReflectionContext() {
this(null);
}//SingleThreadedReflectionContext()//
/**
* SingleThreadedReflectionContext constructor.
* @param metadataIndex The optional class which defines metadata used for determining what is reflected. The defining class' metadata will be indexed in the metadata service by the class object.
*/
public SingleThreadedReflectionContext(Class metadataIndex) {
super(new RequestHandler(), metadataIndex, null);
((RequestHandler) getRequestHandler()).setContext(this);
}//SingleThreadedReflectionContext()//
/* (non-Javadoc)
* @see com.foundation.attribute.ReflectionContext#internalInitialize()
*/
protected void internalInitialize() {
super.internalInitialize();
isStopped = false;
ThreadService.run(new Runnable() {
public void run() {
ThreadService.setIsInSingleThreadedContext(SingleThreadedReflectionContext.this);
requestThread = Thread.currentThread();
processRequests();
}//run()//
});
}//internalInitialize()//
/* (non-Javadoc)
* @see com.foundation.attribute.ReflectionContext#internalRelease()
*/
protected void internalRelease() {
super.internalRelease();
isStopped = true;
}//internalRelease()//
/**
* Begins a request processing loop that will run until the context is released.
*/
private void processRequests() {
boolean stop = false;
while(!stop) {
try {
Runnable request = null;
synchronized(this) {
stop = this.isStopped;
if(requestQueue.getSize() == 0) {
wait(WAIT_TIME);
}//if//
if(requestQueue.getSize() > 0) {
request = (Runnable) requestQueue.dequeue();
}//if//
}//synchronized//
if(request != null) {
request.run();
}//if//
}//try//
catch(InterruptedException e) {
Debug.handle(e);
}//catch//
catch(Throwable e) {
Debug.log(e);
}//catch//
}//while//
}//processRequests()//
/**
* Determines whether the context is currently not running.
* @return Whether the reflection context is non-operational.
*/
private boolean isStopped() {
return isStopped;
}//isStopped()//
}//SingleThreadedReflectionContext//

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 1999,2009 Declarative Engineering LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Declarative Engineering LLC
* verson 1 which accompanies this distribution, and is available at
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
*/
package com.foundation.attribute;
/**
* Reports the cause of a failure in the synchronization of a reflection.
*/
public class SynchronizeFailureCause {
/** This cause indicates that the failure occured because the local model was not up to date. The synchronization will not return until the model is up to date, so the caller can retry if so desired. */
public static final int ID_MISSING_UPDATES = 1;
/** The unkown cause. This cause indicates that the system couldn't pinpoint a reason for the failure. */
public static final int ID_UNKOWN = 0;
private int failureId = ID_UNKOWN;
private Object cause = null;
/**
* SynchronizeFailureCause constructor.
* @param failureId The cause of the failure. This should only be null for predefined failure causes (see ReflectionContext's FAILURE_CAUSE_xx identifiers).
*/
public SynchronizeFailureCause(int failureId) {
this.failureId = failureId;
}//SynchronizeFailureCause()//
/**
* SynchronizeFailureCause constructor.
* @param failureId The cause identifier. One of the FailureCause.ID_xxx identifiers.
* @param cause The cause of the failure. This should only be null for predefined failure causes (see ReflectionContext's FAILURE_CAUSE_xx identifiers).
*/
public SynchronizeFailureCause(int failureId, Object cause) {
this.failureId = failureId;
this.cause = cause;
}//SynchronizeFailureCause()//
/**
* SynchronizeFailureCause constructor.
* @param cause The cause of the failure. This should only be null for predefined failure causes (see ReflectionContext's FAILURE_CAUSE_xx identifiers).
*/
public SynchronizeFailureCause(Object cause) {
this.cause = cause;
}//SynchronizeFailureCause()//
/**
* Gets the identifier of the failure.
* @return One of the FailureCause.ID_xxx identifiers.
*/
public int getFailureId() {
return failureId;
}//getFailureId()//
/**
* A custom cause value.
* @return The failure cause value. This will be null for predefined causes (see ReflectionContext's FAILURE_CAUSE_xx identifiers).
*/
public Object getCause() {
return cause;
}//getCause()//
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return failureId == ID_UNKOWN ? "Reflection Sync Failure: " + cause : failureId == ID_MISSING_UPDATES ? "Reflection Sync Failure: Missing Updates." : "Reflection Sync Failure: Unexpected.";
}//toString()//
}//SynchronizeFailureCause//