package com.foundation.controller; import java.io.IOException; import com.common.debug.Debug; import com.common.exception.MethodNotSupportedException; import com.common.io.IExternalizable; import com.common.io.IObjectInputStream; import com.common.io.IObjectOutputStream; import com.common.orb.Orb; import com.common.util.IList; import com.common.util.LiteList; import com.foundation.attribute.IReflectable; import com.foundation.attribute.IReflectableCollection; import com.foundation.common.Entity; import com.foundation.common.IEntity; import com.foundation.metadata.Attribute; import com.foundation.transaction.ReadTransaction; import com.foundation.util.IManagedList; /** * The interface used by application components to access shared models regardless of where they are located. * * TODO: Reflect all results from a remote source. This should be "pass-through" in that any synchronizations automatically get forwarded to the reflected object and don't get applied if the reflected object rejects the change set. * * TODO: Listen to remote sources for lost connections - automatically reconnect the reflection(s) when a source is lost. * * TODO: Allow calls to some methods to not return the reflected object; Allow additional result information to be returned - such as the "duplicate value for Customer.LOGIN found" error. * */ public class ModelInterface { /** The one and only instance of this class. */ private static final ModelInterface singleton = new ModelInterface(); /** * ModelInterface constructor. */ private ModelInterface() { }//ModelInterface()// /** * Adds the entity to the shared set of models. *

This is used for Mapped and List type models.

* @param entity The entity to be added. This object must be serializable in the event that the model management occurs on a remote process. * @param returnAddition Whether to return the added value. This will be a local reflection if the model management is remote. * @return A result object containing the reflection of the added value if successful. */ public static ReflectionResult addEntity(IEntity entity, boolean returnAddition) { ReflectionResult result = null; Class type = entity != null ? entity.getClass() : null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(entity.isObjectRepositoryBound()) { if(!entity.isObjectNew()) { throw new IllegalArgumentException("Must only add new objects to the manager."); }//if// else if(entity.isReflection()) { throw new IllegalArgumentException("Cannot send a reflection."); }//else if// }//if// if(modelManager != null) { if(modelManager instanceof ISingleListModelManager) { result = ((ISingleListModelManager) modelManager).addEntity(entity, returnAddition); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).addEntity(entity, returnAddition); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// //Reflect the added value if it is returned and the management is remote.// if(returnAddition && !Orb.isLocal(modelManager) && result instanceof ReflectionSuccess && ((ReflectionSuccess) result).getResult() != null) { //TODO: Reflect the result with a weak & pass through reflection manager. //TODO: Must ensure that synchronization to the reflection propegates automatically to the remote reflected object and any failures propegate back to the synchronizer. // reflect((IReflectable) ((ReflectionSuccess) result).getResult()); }//if// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// return result; }//addEntity()// /** * Adds the entities to the shared set of models. *

This is used for Mapped and List type models.

* @param entities The list of entity instances to be added. This object must be serializable in the event that the model management occurs on a remote process. * @param returnAdditions * @return A result object containing an IList collection of reflectable references to the entities added. These may not be the same objects as was passed to this method. */ public static ReflectionResult addEntities(IList entities, boolean returnAdditions) { ReflectionResult result = null; Class type = entities == null || entities.getSize() == 0 || entities.getFirst() == null ? null : entities.getFirst().getClass(); if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { for(int index = 0, size = entities.getSize(); index < size; index++) { Entity next = (Entity) entities.get(index); if(!next.isObjectNew()) { throw new IllegalArgumentException("Must only add new objects to the manager."); }//if// else if(next.isReflection()) { throw new IllegalArgumentException("Cannot send a reflection."); }//else if// }//for// if(modelManager instanceof ISingleListModelManager) { result = ((ISingleListModelManager) modelManager).addEntities(entities, returnAdditions); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).addEntities(entities, returnAdditions); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// //If results were returned then reflect them using a pass through & weak reflection manager so that we have a single point to recover from failures.// if(returnAdditions && !Orb.isLocal(modelManager) && result instanceof ReflectionSuccess && ((ReflectionSuccess) result).getResult() instanceof IList && ((IList) ((ReflectionSuccess) result).getResult()).getSize() > 0) { //Reflect the results.// // reflectAll((IList) ((ReflectionSuccess) result).getResult()); }//if// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { result = new ReflectionSuccess(LiteList.EMPTY_LIST); }//else// return result; }//addEntity()// /** * Removes (deletes) the entity from the shared set of models. The values will also be deleted to any attached repository. *

This is used for Mapped and List type models.

* @param entity The entity to be removed. This object must be serializable in the event that the model management occurs on a remote process. The value may be a reflection or proxy - the code will de-reflect and de-proxy where possible. * @return A result object reporting success or failure of the operation. */ public static ReflectionResult removeEntity(IEntity entity) { ReflectionResult result = null; try { if(entity != null) { Class type = Orb.isProxy(entity) ? Orb.getNonProxyClass(entity) : entity.getClass(); if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { //First ensure we are not using a local proxy.// if(Orb.isProxy(entity) && Orb.isLocal(entity)) { entity = (IEntity) Orb.getLocal(entity); }//if// //Ensure we don't send a reflection (it can't be a reflection if it is a proxy).// while(!Orb.isProxy(entity) && entity.isReflection()) { entity = (IEntity) entity.getReflected(); //De-proxy the object if possible.// if(Orb.isProxy(entity) && Orb.isLocal(entity)) { entity = (IEntity) Orb.getLocal(entity); }//if// }//while// if(modelManager instanceof ISingleListModelManager) { ((ISingleListModelManager) modelManager).removeEntity(entity); }//if// else if(modelManager instanceof ISingleMappedModelManager) { ((ISingleMappedModelManager) modelManager).removeEntity(entity); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// result = new ReflectionSuccess(null); }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { //Shouldn't ever get here.// throw new ClassNotFoundException(); }//else// }//if// else { throw new NullPointerException(); }//else// }//try// catch(ClassNotFoundException e) { Debug.log(e); result = new ReflectionCustomError(e); }//catch// return result; }//removeEntity()// /** * Removes (deletes) the entities from the shared set of models. The values will also be deleted to any attached repository. *

This is used for Mapped and List type models.

* @param entities The list of entity instances to be removed. This object must be serializable in the event that the model management occurs on a remote process. List values may be reflections or proxies - the code will de-reflect and de-proxy where possible. * @return A result object reporting success or failure of the operation. */ public static ReflectionResult removeEntities(IList entities) { ReflectionResult result; try { IReflectable first = entities == null || entities.getSize() == 0 || entities.getFirst() == null ? null : (IReflectable) entities.getFirst(); Class type = Orb.isProxy(first) ? Orb.getNonProxyClass(first) : first.getClass(); if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { //Iterate over the entities and de-reflect and de-proxy where ever possible.// for(int index = 0, size = entities.getSize(); index < size; index++) { IReflectable next = (IReflectable) entities.get(index); //First ensure we are not using a local proxy.// if(Orb.isProxy(next) && Orb.isLocal(next)) { next = (IReflectable) Orb.getLocal(next); }//if// //Ensure we don't send a reflection (it can't be a reflection if it is a proxy).// while(!Orb.isProxy(next) && next.isReflection()) { next = next.getReflected(); //De-proxy the object if possible.// if(Orb.isProxy(next) && Orb.isLocal(next)) { next = (IReflectable) Orb.getLocal(next); }//if// }//while// entities.set(index, next); }//for// if(modelManager instanceof ISingleListModelManager) { ((ISingleListModelManager) modelManager).removeEntities(entities); }//if// else if(modelManager instanceof ISingleMappedModelManager) { ((ISingleMappedModelManager) modelManager).removeEntities(entities); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// result = new ReflectionSuccess(null); }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { //Shouldn't ever get here.// throw new ClassNotFoundException(); }//else// }//try// catch(ClassNotFoundException e) { Debug.log(e); result = new ReflectionCustomError(e); }//catch// return result; }//removeEntities()// /** * Finds the first entity matching the query. * @param query The query by example object. * @return A result object containing an IReflectable instance of the first result if the operation was successful. */ public static ReflectionResult findEntity(IEntity query) { ReflectionResult result = null; try { Class type = query != null ? query.getClass() : null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { if(query.isReflection()) { throw new IllegalArgumentException("Cannot send a reflection."); }//if// if(modelManager instanceof ISingleListModelManager) { throw new MethodNotSupportedException("The class " + type.getName() + " uses a list model manager which doesn't support querying for elements."); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).findEntity(query); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { throw new IllegalArgumentException(); }//else// }//try// // catch(ClassNotFoundException e) { // Debug.log(e); // result = new ReflectionCustomError(e); // }//catch// finally {} return result; }//findEntity()// /** * Finds all entities matching the query. * @param query The query by example object. * @return A result object containing an IList containing IReflectable instances matching the query if the operation was successful. */ public static ReflectionResult findEntities(IEntity query) { ReflectionResult result = null; Class type = query != null ? query.getClass() : null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { if(query.isReflection()) { throw new IllegalArgumentException("Cannot send a reflection."); }//if// if(modelManager instanceof ISingleListModelManager) { throw new MethodNotSupportedException("The class " + type.getName() + " uses a list model manager which doesn't support querying for elements."); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).findEntities(query); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { throw new IllegalArgumentException(); }//else// return result; }//findEntity()// /** * Gets all entities of the given type. * @param type The model type whose instances will be returned. * @return A result object containing an IReflectableCollection (reflect this which will contain reflections of all instances of the given type) if the operation was successful. */ public static ReflectionResult getEntities(Class type) { ReflectionResult result = null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { if(modelManager instanceof ISingleListModelManager) { result = ((ISingleListModelManager) modelManager).getEntities(); }//if// else if(modelManager instanceof ISingleMappedModelManager) { throw new MethodNotSupportedException("The class " + type.getName() + " uses a mapped model manager which doesn't support retrieving a collection of all elements."); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { throw new IllegalArgumentException(); }//else// return result; }//getEntities()// /** * Gets all (or first) entities of the given type. * @param type The model type whose instances will be returned. * @param transaction The read many or read single transaction to be run. The transaction must result in instance(s) of the passed type. * @return A result object containing an IReflectableCollection (reflect this which will contain reflections of all instances of the given type) if the operation was successful. */ public static ReflectionResult findEntities(Class type, ReadTransaction transaction) { ReflectionResult result = null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { if(modelManager instanceof ISingleListModelManager) { result = ((ISingleListModelManager) modelManager).findEntities(transaction); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).findEntities(transaction); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { throw new IllegalArgumentException(); }//else// return result; }//findEntities()// /** * Gets all entities of the given type. * @param type The model type whose instances will be returned. * @param keys The set of keys that uniquely identify each model to be found. * @return A result object containing an IReflectableCollection (reflect this which will contain reflections of all instances of the given type) if the operation was successful. */ public static ReflectionResult findEntities(Class type, Object[] keys) { ReflectionResult result = null; if(type != null) { IModelManager modelManager = singleton.locateModelManager(type); if(modelManager != null) { if(modelManager instanceof ISingleListModelManager) { result = ((ISingleListModelManager) modelManager).findEntities(keys); }//if// else if(modelManager instanceof ISingleMappedModelManager) { result = ((ISingleMappedModelManager) modelManager).findEntities(keys); }//else if// else { throw new IllegalArgumentException("Invalid model manager type."); }//else// }//if// else { //TODO: Specify an identifier. result = new ReflectionNetworkError(0, "Failed to locate a Model Manager."); }//else// }//if// else { throw new IllegalArgumentException(); }//else// return result; }//findEntities()// /** * Locates the model manager * @param type The class whose model manager is to be found. * @return The non-null model manager reference. */ private IModelManager locateModelManager(Class type) { IModelManager result = null; //The model manager will always be local. Each process has its own model manager which synchronizes with others via the ADA server network (when the app is deployed).// result = ModelManagerContainer.getSingleton().getModelManager(type); if(result == null) { throw new IllegalArgumentException("The class " + type.getName() + " either is not marked for management or a model manager could not be found. The type should contain something similar to this code: static {registerTypeMetadata(xxxx.class, Entity.AO_MANAGEMENT_TYPE_LOAD_AS_NEEDED);}"); }//if// return result; }//locateModelManager()// }//ModelInterface//