Initial commit from SVN.
This commit is contained in:
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.common.debug.Debug;
|
||||
import com.common.thread.IRunnable;
|
||||
import com.foundation.attribute.ReflectionContext;
|
||||
import com.foundation.view.IView;
|
||||
import com.foundation.view.IViewContext;
|
||||
import com.foundation.view.ViewSystemMetadata;
|
||||
|
||||
/**
|
||||
* The base class for the RemoteViewController and the ViewController providing functionality common to both the remote and local views.
|
||||
*/
|
||||
public abstract class AbstractViewController extends Controller {
|
||||
public static final int OPTION_MODELESS = 0;
|
||||
public static final int OPTION_MODAL = 1;
|
||||
public static final int OPTION_APPLICATION_MODAL = 2;
|
||||
public static final int OPTION_SYSTEM_MODAL = 3;
|
||||
|
||||
/** The view controller's current view. */
|
||||
private IView view = null;
|
||||
/** Whether the view has been opened yet. This will stay true indefinately once the view has been opened. */
|
||||
private boolean isOpen = false;
|
||||
/** Whether the view has been closed. This will stay true indefinately once the view is closed. This is not true before the view is opened. */
|
||||
private boolean isClosed = false;
|
||||
/** The view context for the current view. This will be null if the view is null. */
|
||||
private IViewContext context = null;
|
||||
/** Prevents an opening view from being opened twice. */
|
||||
private boolean isOpening = false;
|
||||
/** The parent view's controller. This will only be set for modal views. */
|
||||
private AbstractViewController parent = null;
|
||||
/** Whether the view is actively in the process of closing. */
|
||||
private volatile boolean isClosing = false;
|
||||
/** The handler called prior to closing the view and which is capable of canceling the closure. */
|
||||
private IVetoableRunnable preCloseHandler = null;
|
||||
/** The handler called when the view closes (before control is returned to the parent view). */
|
||||
private Runnable onCloseHandler = null;
|
||||
/** The handler called when the view disposes (before control is returned to the parent view). */
|
||||
private Runnable onDisposeHandler = null;
|
||||
/** The reflection context for this view. All internal reflections should use this context since the context will be released when the view is closed. */
|
||||
private ReflectionManager reflectionManager = null;
|
||||
/** The options for this view. Currently this is either OPTION_MODAL or OPTION_MODELESS. */
|
||||
private int options = OPTION_MODAL;
|
||||
/** The parent component assigned when the view controller is controlling only part of a view. */
|
||||
private IView parentComponent = null;
|
||||
/** The manager used to control the decorations. */
|
||||
private DecorationManager decorationManager = new DecorationManager();
|
||||
/** Whether to validate the view upon opening it. */
|
||||
private boolean validateOnOpen = false;
|
||||
/**
|
||||
* AbstractViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
*/
|
||||
AbstractViewController(IViewContext context) {
|
||||
this(context, false);
|
||||
}//AbstractViewController()//
|
||||
/**
|
||||
* AbstractViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
*/
|
||||
AbstractViewController(IViewContext context, ReflectionContext reflectionContext) {
|
||||
this(context, reflectionContext, false);
|
||||
}//AbstractViewController()//
|
||||
/**
|
||||
* AbstractViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is false by default.
|
||||
*/
|
||||
AbstractViewController(IViewContext context, boolean validateOnOpen) {
|
||||
this.validateOnOpen = validateOnOpen;
|
||||
|
||||
if(context == null) {
|
||||
throw new IllegalArgumentException("A view context must be provided to the view.");
|
||||
}//if//
|
||||
|
||||
this.context = context;
|
||||
this.reflectionManager = new ReflectionManager(this, new ReflectionContext(context.getRequestHandler(), getViewClass(), new Runnable() {
|
||||
public void run() {
|
||||
validate();
|
||||
}//run()//
|
||||
}));
|
||||
}//AbstractViewController()//
|
||||
/**
|
||||
* AbstractViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is false by default.
|
||||
*/
|
||||
AbstractViewController(IViewContext context, ReflectionContext reflectionContext, boolean validateOnOpen) {
|
||||
this.validateOnOpen = validateOnOpen;
|
||||
|
||||
if(context == null) {
|
||||
throw new IllegalArgumentException("A view context must be provided to the view.");
|
||||
}//if//
|
||||
|
||||
if((reflectionContext != null) && (reflectionContext.getRequestHandler() != context.getRequestHandler())) {
|
||||
Debug.log(new RuntimeException(), "Error: Can't use the reflection context since it uses a different request handler from the view context.");
|
||||
reflectionContext = null;
|
||||
}//if//
|
||||
|
||||
this.context = context;
|
||||
|
||||
if(reflectionContext == null) {
|
||||
this.reflectionManager = new ReflectionManager(this, new ReflectionContext(context.getRequestHandler(), getViewClass(), new Runnable() {
|
||||
public void run() {
|
||||
validate();
|
||||
}//run()//
|
||||
}));
|
||||
}//if//
|
||||
else {
|
||||
this.reflectionManager = new ReflectionManager(this, reflectionContext);
|
||||
}//else//
|
||||
}//AbstractViewController()//
|
||||
/**
|
||||
* Gets the decoration manager for this view.
|
||||
* @return The view's decoration manager.
|
||||
*/
|
||||
public DecorationManager getDecorationManager() {
|
||||
return decorationManager;
|
||||
}//getDecorationManager()//
|
||||
/**
|
||||
* Closes the view if it is open.
|
||||
* All waiting threads will be notified after the view has been destroyed.
|
||||
* <p> This method may be called by any thread. </p>
|
||||
* @return Whether the close was actually performed.
|
||||
*/
|
||||
public final boolean close() {
|
||||
boolean result = false;
|
||||
boolean isOpened;
|
||||
boolean isClosed;
|
||||
boolean isClosing;
|
||||
|
||||
synchronized(this) {
|
||||
isOpened = this.isOpen;
|
||||
isClosed = this.isClosed;
|
||||
isClosing = this.isClosing;
|
||||
|
||||
if(isOpened && !isClosing && !isClosed) {
|
||||
this.isClosing = true;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
|
||||
//Prevent closing twice or calling it recursively.//
|
||||
if(isOpened && !isClosed && !isClosing) {
|
||||
final IView view;
|
||||
final Runnable onCloseHandler;
|
||||
final Runnable onDisposeHandler;
|
||||
boolean doClose = true;
|
||||
|
||||
try {
|
||||
if(preCloseHandler != null) {
|
||||
doClose = preCloseHandler.run();
|
||||
}//if//
|
||||
|
||||
if(doClose) {
|
||||
result = true;
|
||||
preClose();
|
||||
|
||||
synchronized(this) {
|
||||
if(this.view != null) {
|
||||
onCloseHandler = getOnCloseHandler();
|
||||
onDisposeHandler = getOnDisposeHandler();
|
||||
view = this.view;
|
||||
setOnCloseHandler(null);
|
||||
this.view = null;
|
||||
this.isClosed = true;
|
||||
}//if//
|
||||
else {
|
||||
view = null;
|
||||
onCloseHandler = null;
|
||||
onDisposeHandler = null;
|
||||
}//else//
|
||||
|
||||
//Unregister all reflections. Failure to do so will result in memory leaks, perticularly if the data is accessed over a network.//
|
||||
getReflectionManager().release();
|
||||
}//synchronized//
|
||||
|
||||
if(view != null) {
|
||||
//Note: Moved this out of the threaded code since we should always be calling this on the SWT event thread.//
|
||||
internalClose(view, onCloseHandler, onDisposeHandler);
|
||||
|
||||
synchronized(this) {
|
||||
context = null;
|
||||
notifyAll();
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
synchronized(this) {
|
||||
this.isClosing = false;
|
||||
}//synchronized//
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//close()//
|
||||
/*
|
||||
* TODO: The problem with this idea (to allow reusable partial view's) is that the reflection manager must be released sometime, but can't be released now, so when?
|
||||
* Closes the view if it is open.
|
||||
* All waiting threads will be notified after the view has been destroyed.
|
||||
* <p> This method is only to be called by the caller of openPartial. </p>
|
||||
*
|
||||
public final void closePartial(IView view) {
|
||||
//final IView view;
|
||||
final Runnable onCloseHandler;
|
||||
|
||||
synchronized(this) {
|
||||
if(this.view != null) {
|
||||
onCloseHandler = getOnCloseHandler();
|
||||
//view = this.view;
|
||||
//setOnCloseHandler(null);
|
||||
this.view = null;
|
||||
}//if//
|
||||
else {
|
||||
view = null;
|
||||
//onCloseHandler = null;
|
||||
}//else//
|
||||
|
||||
//Unregister all reflections. Failure to do so will result in memory leaks, perticularly if the data is accessed over a network.//
|
||||
getReflectionManager().release();
|
||||
getReflectionManager().getReflectionContext().release();
|
||||
}//synchronized//
|
||||
|
||||
if(view != null) {
|
||||
//Ensure that the close occurs on the proper thread.//
|
||||
//Note: Don't call the execute method since the view reference is no longer valid.//
|
||||
view.execute(new IRunnable() {
|
||||
public Object run() {
|
||||
internalClose(view, onCloseHandler);
|
||||
|
||||
return null;
|
||||
}//run()//
|
||||
});
|
||||
|
||||
synchronized(this) {
|
||||
context = null;
|
||||
notifyAll();
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//close()//
|
||||
*/
|
||||
/**
|
||||
* Creates the controller's primary view component.
|
||||
* @return This view controller's new view object.
|
||||
*/
|
||||
protected abstract IView createView();
|
||||
/**
|
||||
* Gets the controller's view's class.
|
||||
* @return The class identifying the view code for this controller.
|
||||
*/
|
||||
protected abstract Class getViewClass();
|
||||
/**
|
||||
* Requests that the view validate all the data (perticularly the altered reflection data when using reflections).
|
||||
* <p>Note: This method is automatically called when synchronizing one or more altered reflections without passing a validation handler.</p>
|
||||
* @return Whether the data was validated.
|
||||
*/
|
||||
public abstract boolean validate();
|
||||
/**
|
||||
* Disables the view associated with this controller.
|
||||
* <p>NOTE: This does not close the view.
|
||||
* @see #close()
|
||||
*/
|
||||
public synchronized void disable() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
view.setIsEnabled(false);
|
||||
}//if//
|
||||
}//disable()//
|
||||
/**
|
||||
* Enables the view associated with this controller so that it is usable by the user.
|
||||
*/
|
||||
public synchronized void enable() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
view.setIsEnabled(true);
|
||||
}//if//
|
||||
}//enable()//
|
||||
/**
|
||||
* Executes the runnable synchronously.
|
||||
* <p>This is a thread safe call.</p>
|
||||
* @param runnable The code block to execute.
|
||||
* @return The runnable's result.
|
||||
* @throws ViewClosedException If the view was closed prior to the call executing.
|
||||
*/
|
||||
public Object execute(IRunnable runnable) throws ViewClosedException {
|
||||
IView view = null;
|
||||
|
||||
synchronized(this) {
|
||||
view = getView();
|
||||
}//synchronized//
|
||||
|
||||
if(view == null) {
|
||||
throw new ViewClosedException();
|
||||
}//if//
|
||||
|
||||
return getView().execute(runnable);
|
||||
}//execute()//
|
||||
/**
|
||||
* @deprecated Use executeAsync(IRunnable) instead.
|
||||
* Do not use this method any more since it is not thead safe.
|
||||
*/
|
||||
public void executeAsynch(IRunnable runnable) {
|
||||
getView().executeAsync(runnable);
|
||||
}//executeAsynch()//
|
||||
/**
|
||||
* Executes the runnable asynchronously.
|
||||
* <p>This is a thread safe call.</p>
|
||||
* @param runnable The code block to execute.
|
||||
* @throws ViewClosedException If the view was closed prior to the call executing.
|
||||
*/
|
||||
public void executeAsync(IRunnable runnable) throws ViewClosedException {
|
||||
synchronized(this) {
|
||||
if(getView() != null) {
|
||||
getView().executeAsync(runnable);
|
||||
}//if//
|
||||
else {
|
||||
throw new ViewClosedException();
|
||||
}//else//
|
||||
}//synchronized//
|
||||
}//executeAsynch()//
|
||||
/**
|
||||
* Called by the GC thread upon destroying this object.
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
//Just in case we will unregister all reflections one more time. This should have already occured when the view closed.//
|
||||
getReflectionManager().release();
|
||||
}//finalize()//
|
||||
/**
|
||||
* Gets the view context provided when the view was opened.
|
||||
* Each view should have a context (view framework dependant) which can be created from any other view controller's context.
|
||||
* <p>Note: Views exist under the same context for the same client (or in the case of the thick client views, they all exist under the same context).
|
||||
* This is not a view specific context, but rather a view system context, one for each view system.</p>
|
||||
* @return The view framework dependant view context.
|
||||
*/
|
||||
public final IViewContext getContext() {
|
||||
return context;
|
||||
}//getContext()//
|
||||
/**
|
||||
* Gets the handler run before the view is closed.
|
||||
* @return The handler to be run just after before hiding or closing the view.
|
||||
*/
|
||||
public IVetoableRunnable getPreCloseHandler() {
|
||||
return preCloseHandler;
|
||||
}//getPreCloseHandler()//
|
||||
/**
|
||||
* Gets the handler run just before the view is closed.
|
||||
* @return The handler to be run just after hiding the view and before closing the view.
|
||||
*/
|
||||
public Runnable getOnCloseHandler() {
|
||||
return onCloseHandler;
|
||||
}//getOnCloseHandler()//
|
||||
/**
|
||||
* Gets the handler run just after the view is disposed.
|
||||
* @return The handler to be run just after the view has been completely destroyed.
|
||||
*/
|
||||
public Runnable getOnDisposeHandler() {
|
||||
return onDisposeHandler;
|
||||
}//getOnDisposeHandler()//
|
||||
/**
|
||||
* Gets the options specified when opening the view.
|
||||
* @return The options given when the view's controller was opened.
|
||||
* @see #OPTION_MODELESS
|
||||
* @see #OPTION_MODAL
|
||||
* @see #OPTION_APPLICATION_MODAL
|
||||
* @see #OPTION_SYSTEM_MODAL
|
||||
*/
|
||||
public final int getOptions() {
|
||||
return options;
|
||||
}//getOptions()//
|
||||
/**
|
||||
* Gets the parent view controller if one was supplied durring the opening of the view controller.
|
||||
* @return This view's parent view's controller object. This value will be null for partial views (embedded in another view), or for modeless views.
|
||||
*/
|
||||
public final AbstractViewController getParent() {
|
||||
return parent;
|
||||
}//getParent()//
|
||||
/**
|
||||
* Gets the view's parent view component. This will only be available if the view is an integrated component in another view.
|
||||
* @return The view component that this view controller's view is part of. For standalone view's, this value will be null.
|
||||
*/
|
||||
public final IView getParentComponent() {
|
||||
return parentComponent;
|
||||
}//getParentComponent()//
|
||||
/**
|
||||
* Sets the view's parent view component. This will only be available if the view is an integrated component in another view.
|
||||
* @param parentComponent The view component that this view controller's view is part of. For standalone view's, this value will be null.
|
||||
*/
|
||||
public final void setParentComponent(IView parentComponent) {
|
||||
this.parentComponent = parentComponent;
|
||||
}//setParentComponent()//
|
||||
/**
|
||||
* Gets the reflection manager for this view.
|
||||
* Each view has its own reflection manager which can be called upon to create, synchronize, and release reflections.
|
||||
* <p>Note: Currently the reflection manager is not usable after the view closes. Subsiquently all reflections are also may be unusable (will still be useable if the reflection context was shared and is still accessed by other views). They still exist, but are no longer connected to their reflections. Using them may cause problems since they may be missing unloaded attribute data.</p>
|
||||
* @return The view's reflection manager.
|
||||
*/
|
||||
public final ReflectionManager getReflectionManager() {
|
||||
return reflectionManager;
|
||||
}//getReflectionManager()//
|
||||
/**
|
||||
* Gets the associated view for this view controller. If there isn't yet a view (or the close() method was called and the view was disposed) then this method will return null.
|
||||
* @return Will be the view associated with the controller if the controller has been opened (and not subsquently closed), or getView(true) has been called.
|
||||
* @see #open()
|
||||
* @see #close()
|
||||
*/
|
||||
public final IView getView() {
|
||||
return view;
|
||||
}//getView()//
|
||||
/**
|
||||
* Hides the view associated with this controller.
|
||||
* <p>NOTE: This does not close the view.</p>
|
||||
* @see #close()
|
||||
*/
|
||||
public synchronized void hide() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
view.setIsVisible(false);
|
||||
}//if//
|
||||
}//hide()//
|
||||
/**
|
||||
* Closes the view and releases all components.
|
||||
* <p>Subclasses should override the preClose() and postClose() methods, or set the on close handler.</p>
|
||||
* @param view The view associated with the view controller.
|
||||
* @param onCloseHandler The handler to be called right before closing the view. This is normally set by the opener of the view to handle post processing of the view data.
|
||||
* @param onDisposeHandler The handler to be called right after disposing the view.
|
||||
* @see #preClose()
|
||||
* @see #postClose()
|
||||
* @see #setOnCloseHandler(Runnable)
|
||||
*/
|
||||
protected void internalClose(IView view, Runnable onCloseHandler, Runnable onDispose) {
|
||||
if(view != null) {
|
||||
view.setIsVisible(false);
|
||||
|
||||
//Run the on close handler.//
|
||||
if(onCloseHandler != null) {
|
||||
onCloseHandler.run();
|
||||
}//if//
|
||||
|
||||
view.viewReleaseAll();
|
||||
postClose();
|
||||
|
||||
//Run the on dispose handler.//
|
||||
if(onDispose != null) {
|
||||
onDispose.run();
|
||||
}//if//
|
||||
}//if//
|
||||
}//internalClose()//
|
||||
/**
|
||||
* Opens the view either by displaying the existing view, or by creating a new view.
|
||||
* <p>This method allows subclasses to override the way the newly created view is initialized.</p>
|
||||
* @return The open and visible view.
|
||||
*/
|
||||
protected IView internalInitialize() {
|
||||
return createView();
|
||||
}//internalInitialize()//
|
||||
/**
|
||||
* Initializes the view context.
|
||||
* <p>Note: This must get called immediatly AFTER the view has been created & initialized.
|
||||
* @param viewContext The context the view is being opened under.
|
||||
* @return The view context to be used by this view controller.
|
||||
*/
|
||||
protected void internalInitializeContext(IViewContext viewContext) {
|
||||
}//internalInitializeContext()//
|
||||
/**
|
||||
* Opens the view either by displaying the existing view, or by creating a new view.
|
||||
* <p>This method allows subclasses to override the way the newly created view is initialized.</p>
|
||||
* @return The open and visible view.
|
||||
*/
|
||||
protected void internalOpen(final IView view) {
|
||||
view.suspendLayouts();
|
||||
view.viewInitializeAll();
|
||||
view.resumeLayouts();
|
||||
view.layout();
|
||||
view.pack();
|
||||
postOpenInitialization(view);
|
||||
|
||||
if(validateOnOpen) {
|
||||
validate();
|
||||
}//if//
|
||||
}//internalOpen()//
|
||||
/**
|
||||
* Determines whether the view should validate upon opening. This is normally false.
|
||||
* @return Whether the view validates as soon as it is displayed.
|
||||
*/
|
||||
protected boolean validateOnOpen() {
|
||||
return validateOnOpen;
|
||||
}//validateOnOpen()//
|
||||
/**
|
||||
* Determines whether the view is open.
|
||||
* Note that this is different than isClosed since it reports whether the view has been opened, though it could be subsiquently closed and this method will still report true.
|
||||
* @return Whether the view is currently open (not necessarily visible or enabled).
|
||||
*/
|
||||
public synchronized boolean isOpen() {
|
||||
return isOpen;
|
||||
}//isOpen()//
|
||||
/**
|
||||
* Determines whether the view is open.
|
||||
* Note that this is different than isClosed since it reports whether the view has been opened, though it could be subsiquently closed and this method will still report true.
|
||||
* <p>Note: Not synchronized since it is generally set only while opening the view and synchronization is not necessary.</p>
|
||||
* @param isOpen Whether the view is currently open (not necessarily visible or enabled).
|
||||
*/
|
||||
protected void isOpen(boolean isOpen) {
|
||||
this.isOpen = isOpen;
|
||||
}//isOpen()//
|
||||
/**
|
||||
* Determines whether the view has been closed.
|
||||
* Note that this is different than isOpen since the view must be first opened to be then closed.
|
||||
* @return Whether the view is currently closed.
|
||||
*/
|
||||
public synchronized boolean isClosed() {
|
||||
return isClosed;
|
||||
}//isClosed()//
|
||||
/**
|
||||
* Creates and displays the modal view associated with this controller. A modal view is one which must be closed before the user may interact with any parent view.
|
||||
* The user should close the view by calling the close method.
|
||||
* <p>Note: The thread calling this method will return immediatly and will NOT block until the view is closed.</p>
|
||||
* @param parent The view controller associated with the parent view.
|
||||
* @see #show()
|
||||
* @see #close()
|
||||
*/
|
||||
public void open(AbstractViewController parent) {
|
||||
open(parent, -1, parent != null ? OPTION_MODAL : OPTION_MODELESS);
|
||||
}//open()//
|
||||
/**
|
||||
* Creates and displays the view associated with this controller.
|
||||
* The user should close the view by calling the close method.
|
||||
* <p><b>Warning: The caller should not block unless it is certain that the calling thread is not the message handler in a single threaded view environment. In such a case a handler should be provided to handle the view closure.</b></p>
|
||||
* @param parent The optional parent view controller.
|
||||
* @param timeout The amount of time to wait for the view to close before returning control. This should be zero if the thread should wait for ever. This should be less than zero if there should be no wait.
|
||||
* @param options The options used to open the view. Currently you can pass OPTION_MODELESS or OPTION_MODAL.
|
||||
* @see #show()
|
||||
* @see #close()
|
||||
*/
|
||||
protected final void open(AbstractViewController parent, long timeout, int options) {
|
||||
this.parent = parent;
|
||||
|
||||
open(timeout, options);
|
||||
}//open()//
|
||||
/**
|
||||
* Creates and displays the modeless view associated with this controller. A modeless view is one that does not exist within the life of a parent view. Any parent may close without affecting this view.
|
||||
* The user should close the view by calling the close method.
|
||||
* <p>Note: The thread calling this method will return immediatly and will NOT block until the view is closed.</p>
|
||||
* @see #show()
|
||||
* @see #close()
|
||||
*/
|
||||
public void open() {
|
||||
open(-1, OPTION_MODELESS);
|
||||
}//open()//
|
||||
/**
|
||||
* Creates and displays the view associated with this controller.
|
||||
* The user should close the view by calling the close method.
|
||||
* <p><b>Warning: The caller should not block unless it is certain that the calling thread is not the message handler in a single threaded view environment. In such a case a handler should be provided to handle the view closure.</b></p>
|
||||
* @param timeout The amount of time to wait for the view to close before returning control. This should be zero if the thread should wait for ever. This should be less than zero if there should be no wait.
|
||||
* @param options The options used to open the view. Currently you can pass OPTION_MODELESS or OPTION_MODAL.
|
||||
* @see #show()
|
||||
* @see #close()
|
||||
*/
|
||||
protected final void open(long timeout, int options) {
|
||||
try {
|
||||
//Since we don't want to be synchronized on the view controller while we are opening, we will just synchronize to check the open status.//
|
||||
synchronized(this) {
|
||||
if(view != null) {
|
||||
show();
|
||||
return;
|
||||
}//if//
|
||||
else if(isOpening) {
|
||||
return;
|
||||
}//else if//
|
||||
else {
|
||||
isOpening = true;
|
||||
}//else//
|
||||
}//synchronized//
|
||||
|
||||
this.parentComponent = null;
|
||||
this.options = options;
|
||||
internalInitializeContext(context);
|
||||
this.view = internalInitialize();
|
||||
decorationManager.initialize(view);
|
||||
this.isOpen = true;
|
||||
internalOpen(this.view);
|
||||
|
||||
//Warning: This should not be called if this is the one and only view event handler thread!//
|
||||
if(timeout >= 0) {
|
||||
waitForViewClosure(timeout);
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
synchronized(this) {
|
||||
isOpening = false;
|
||||
}//synchronized//
|
||||
}//finally//
|
||||
}//open()//
|
||||
/**
|
||||
* Opens a partial view given the view's parent view component reference and an optional view context.
|
||||
* <p>This is intended only to be called by the containing view when it requires the sub-component to be created.</p>
|
||||
* <p><b>Warning: This method is not thread safe. It is assumed that the view will be owned by one parent component and will be opened only by that component.</b></p>
|
||||
* @param parent The non-null parent view component passed by the view.
|
||||
* @param context The context for the view. The actual value is dependant upon the view framework being used. In a remote view this value may be the session context for example.
|
||||
* @return A view associated with this view controller that is a part of another view.
|
||||
*/
|
||||
public IView openPartial(IView parent, Object context) {
|
||||
IView result = null;
|
||||
|
||||
if(parent == null) {
|
||||
throw new RuntimeException("Error: Cannot open a partial view without a parent view part.");
|
||||
}//if//
|
||||
else if(context != this.context) {
|
||||
throw new RuntimeException("Error: Invalid view context. This view was initialized with a different context than it is being used under.");
|
||||
}//else if//
|
||||
|
||||
if(view == null) {
|
||||
this.options = 0;
|
||||
this.parentComponent = parent;
|
||||
this.view = createView();
|
||||
decorationManager.initialize(view);
|
||||
this.isOpen = true;
|
||||
this.view.setController(this);
|
||||
this.view.viewInitializeAll();
|
||||
this.view.layout();
|
||||
this.view.pack();
|
||||
postOpenInitialization(this.view);
|
||||
|
||||
if(validateOnOpen) {
|
||||
validate();
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
result = view;
|
||||
|
||||
return result;
|
||||
}//openPartialView()//
|
||||
/**
|
||||
* Called just after closing the view. Note that the reflection context will have been released and any reflections will not be useable (they won't return the correct hashCode, won't be able to load attributes, and will behave as non-reflected objects).
|
||||
* <p><b>Warning: If using a ModelListener, do not release it in this method. Instead use preClose() to release the model listener.</b></p>
|
||||
* <p>Note: This method will always be called by the view thread and can access non-multi-thread safe objects.</p>
|
||||
* @see #preClose()
|
||||
* @see #setOnCloseHandler(Runnable)
|
||||
*/
|
||||
protected void postClose() {
|
||||
}//postClose()//
|
||||
/**
|
||||
* Called after the view is opened but not yet visible to the user.
|
||||
* <p>This method allows the view controller an opportunity to modify how or whether the view is made visible to the user. The default behavior is to make the view visible and to give it the focus. Subclasses can also overload this to position the view.</p>
|
||||
* @param view The newly opened but not yet visible view.
|
||||
*/
|
||||
protected void postOpenInitialization(IView view) {
|
||||
view.setIsVisible(true);
|
||||
view.setFocus();
|
||||
}//postOpenInitialization()//
|
||||
/**
|
||||
* Called just prior to releasing the reflection context and calling the onCloseHandler and closing the view. This is called after calling the preCloseHandler which can veto the closure.
|
||||
* <p><b>Note: This is a good place to release any ModelListeners or other custom listeners that were setup by the view controller.</b></p>
|
||||
* <p>Warning: This method may not be called by the view thread. Implementations should consider this when affecting objects not in a multi-thread safe context. The postClose method is called on the view thread.</p>
|
||||
* @see #postClose()
|
||||
* @see #setOnCloseHandler(Runnable)
|
||||
*/
|
||||
protected void preClose() {
|
||||
}//preClose()//
|
||||
/**
|
||||
* Forces a resfresh of the view (pushing data from the model to the view).
|
||||
*/
|
||||
public synchronized void refresh() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
view.viewRefreshAll();
|
||||
}//if//
|
||||
}//refresh()//
|
||||
/**
|
||||
* Sets the handler run before the view is closed and is intended to allow the view creator to setup post processing of the view data external to the view logic with the ability to cancel the closure if there is a problem.
|
||||
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
|
||||
* Note that only one pre-close handler may be assigned to a view controller. Assigning a second will mean that the first assigned pre-close handler will not be called.
|
||||
* <p><b>Warning: This handler will never be called if the view is opened inside another view (openPartial versus a call to open) since the close cannot be cancelled.</b></p>
|
||||
* <p>This handler can be used to process the view results, interact with the view's reflections before they are disposed, and cancel the closing the view if processing the results fails.</p>
|
||||
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
|
||||
* @param preCloseHandler The handler to be run before any other close functionality. This handler is can veto the closure process.
|
||||
* @see #preClose()
|
||||
* @see #setOnCloseHandler()
|
||||
* @see #postClose()
|
||||
*/
|
||||
public void setPreCloseHandler(IVetoableRunnable preCloseHandler) {
|
||||
this.preCloseHandler = preCloseHandler;
|
||||
}//setPreCloseHandler()//
|
||||
/**
|
||||
* Sets the handler run just before the view is closed and is intended to allow the view creator to setup post processing of the view data external to the view logic.
|
||||
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
|
||||
* Note that only one on-close handler may be assigned to a view controller. Assigning a second will mean that the first assigned on-close handler will not be called.
|
||||
* <p>This handler can be used to cleanup after the view, and to process the view results if the opening thread is not able to wait for the view to be closed.</p>
|
||||
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
|
||||
* @param onCloseHandler The handler to be run just after hiding the view and before closing the view. This handler is run between the execution of the preClose() method and the actual view closing.
|
||||
* @see #setPreCloseHandler()
|
||||
* @see #preClose()
|
||||
* @see #postClose()
|
||||
*/
|
||||
public void setOnCloseHandler(Runnable onCloseHandler) {
|
||||
this.onCloseHandler = onCloseHandler;
|
||||
}//setOnCloseHandler()//
|
||||
/**
|
||||
* Sets the handler run just after the view is disposed.
|
||||
* To setup internal post processing of the view data, the view should override the preClose() or postClose() methods.
|
||||
* Note that only one on-dispose handler may be assigned to a view controller. Assigning a second will mean that the first assigned on-dispose handler will not be called.
|
||||
* <p>This handler can be used to cleanup after the view, and to process the view results if the opening thread is not able to wait for the view to be closed.</p>
|
||||
* <p><b>Warning: In a single threaded view environment (most of them), the handler will be called by the view's event thread, and thus the handler should do nothing that blocks or takes a long time.</b></p>
|
||||
* @param onDisposeHandler The handler to be run just after the view is completely disposed.
|
||||
* @see #preClose()
|
||||
* @see #postClose()
|
||||
*/
|
||||
public void setOnDisposeHandler(Runnable onDisposeHandler) {
|
||||
this.onDisposeHandler = onDisposeHandler;
|
||||
}//setOnDisposeHandler()//
|
||||
/**
|
||||
* Sets the options specified when opening the view.
|
||||
* @param options The options given when the view's controller was opened.
|
||||
* @see #OPTION_MODAL
|
||||
* @see #OPTION_MODELESS
|
||||
*/
|
||||
protected void setOptions(int options) {
|
||||
this.options = options;
|
||||
}//setOptions()//
|
||||
/**
|
||||
* Sets the view reference.
|
||||
* @param view The current view for this view controller.
|
||||
*/
|
||||
protected void setView(IView view) {
|
||||
this.view = view;
|
||||
decorationManager.initialize(view);
|
||||
}//setView()//
|
||||
/**
|
||||
* Shows the view associated with this controller so that it is visible to the user.
|
||||
* <p>Note: This does not open the view. The view must first be open.</p>
|
||||
*/
|
||||
public synchronized void show() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
//Set visible and bring to top.//
|
||||
view.show();
|
||||
}//if//
|
||||
}//show()//
|
||||
/**
|
||||
* Forces a synchronize of the view (pushing data from the view to the model).
|
||||
*/
|
||||
public synchronized void synchronize() {
|
||||
IView view = getView();
|
||||
|
||||
if(view != null) {
|
||||
view.viewSynchronizeAll();
|
||||
}//if//
|
||||
}//synchronize()//
|
||||
/**
|
||||
* Waits for the view to be closed before returning.
|
||||
*/
|
||||
public void waitForViewClosure() {
|
||||
waitForViewClosure(0);
|
||||
}//waitForViewClosure()//
|
||||
/**
|
||||
* Waits for the view to be closed or the time to run out before returning.
|
||||
* @param timeout The number of milliseconds to wait before giving up. If this value is zero then the thread may wait forever.
|
||||
*/
|
||||
public synchronized void waitForViewClosure(long timeout) {
|
||||
if(isOpen()) {
|
||||
try {
|
||||
wait(timeout);
|
||||
}//try//
|
||||
catch(InterruptedException e) {
|
||||
Debug.handle(e);
|
||||
}//catch//
|
||||
}//if//
|
||||
}//waitForViewClosure()//
|
||||
/**
|
||||
* Gets the display metadata which describes the view system such as information about the display locations and sizes.
|
||||
* @return The metadata describing the view system.
|
||||
*/
|
||||
public ViewSystemMetadata getViewSystemMetadata() {
|
||||
return getView().getViewContext().getViewSystemMetadata();
|
||||
}//getViewSystemMetadata()//
|
||||
/**
|
||||
* Verifies that the calling thread is allowed access to the view components.
|
||||
* <p>Note: This is really a debug only operation and should be turned off for production applications.</p>
|
||||
*/
|
||||
protected void verifyThread() {
|
||||
if((getView() != null) && (!getView().isViewThread())) {
|
||||
Debug.log(new RuntimeException("Error: Invalid thread."));
|
||||
}//if//
|
||||
}//verifyThread()//
|
||||
}//AbstractViewController()//
|
||||
28
Foundation/src/com/foundation/controller/Controller.java
Normal file
28
Foundation/src/com/foundation/controller/Controller.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2002,2007 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.controller;
|
||||
|
||||
import com.foundation.common.*;
|
||||
|
||||
/*
|
||||
* A controller manages the workflow in the application for a perticular situation.
|
||||
*/
|
||||
public abstract class Controller extends Entity implements IController {
|
||||
/**
|
||||
* Controller constructor.
|
||||
*/
|
||||
public Controller() {
|
||||
super();
|
||||
}//Controller()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.IController#getDecorationManager()
|
||||
*/
|
||||
public DecorationManager getDecorationManager() {
|
||||
return null;
|
||||
}//getDecorationManager()//
|
||||
}//Controller//
|
||||
487
Foundation/src/com/foundation/controller/DecorationManager.java
Normal file
487
Foundation/src/com/foundation/controller/DecorationManager.java
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright (c) 2007,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.controller;
|
||||
|
||||
import com.common.util.*;
|
||||
import com.foundation.metadata.Attribute;
|
||||
import com.foundation.view.AbstractDecoration;
|
||||
import com.foundation.view.IView;
|
||||
|
||||
public class DecorationManager {
|
||||
/** A mapping of DecorationMetadata instances by the object being decorated. The view components get notified of changes to the map and display the appropriate decoration. */
|
||||
private IHashMap decorationMap = new LiteHashMap(60);
|
||||
private IHashMap removedDecorations = new LiteHashMap(60);
|
||||
private IHashMap addedDecorations = new LiteHashMap(60);
|
||||
private IHashSet decorationListeners = new LiteHashSet(100, LiteHashSet.DEFAULT_LOAD_FACTOR, LiteHashSet.DEFAULT_COMPARATOR, LiteHashSet.STYLE_COUNT_DUPLICATES);
|
||||
/** The view the manager can use to add and remove message holds. */
|
||||
private IView view = null;
|
||||
|
||||
private static class DecorationMetadata {
|
||||
private Object object;
|
||||
private Attribute attribute;
|
||||
private AbstractDecoration decoration;
|
||||
private DecorationMetadata next = null;
|
||||
|
||||
/**
|
||||
* DecorationKey constructor.
|
||||
* @param object The object being decorated.
|
||||
* @param attribute The optional attribute to be decorated.
|
||||
* @param decoration The decoration to be applied.
|
||||
*/
|
||||
public DecorationMetadata(Object object, Attribute attribute, AbstractDecoration decoration) {
|
||||
this.object = object;
|
||||
this.attribute = attribute;
|
||||
this.decoration = decoration;
|
||||
}//DecorationMetadata()//
|
||||
/**
|
||||
* Gets the object that is being decorated.
|
||||
* @return The decorated object.
|
||||
*/
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}//getObject()//
|
||||
/**
|
||||
* Gets the attribute being decorated.
|
||||
* @return The decorated attribute, or null if the whole object is decorated.
|
||||
*/
|
||||
public Attribute getAttribute() {
|
||||
return attribute;
|
||||
}//getAttribute()//
|
||||
/**
|
||||
* Gets the decoration being applied.
|
||||
* @return The decoration for the object and attribute.
|
||||
*/
|
||||
public AbstractDecoration getDecoration() {
|
||||
return decoration;
|
||||
}//getDecoration()//
|
||||
/**
|
||||
* Gets the next decoration in the linked list.
|
||||
* @return The decoration metadata that follows this one.
|
||||
*/
|
||||
public DecorationMetadata getNext() {
|
||||
return next;
|
||||
}//getNext()//
|
||||
/**
|
||||
* Sets the next decoration in the linked list.
|
||||
* @param next The decoration metadata that follows this one.
|
||||
*/
|
||||
public void setNext(DecorationMetadata next) {
|
||||
this.next = next;
|
||||
}//setNext()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof DecorationMetadata ? (((DecorationMetadata) object).object == this.object) && (((DecorationMetadata) object).attribute == this.attribute) && (((DecorationMetadata) object).decoration.equals(this.decoration)) : false;
|
||||
}//equals()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
public int hashCode() {
|
||||
return object.hashCode() ^ attribute.hashCode();
|
||||
}//hashCode()//
|
||||
}//DecorationMetadata//
|
||||
/**
|
||||
* DecorationManager constructor.
|
||||
*/
|
||||
public DecorationManager() {
|
||||
}//DecorationManager()//
|
||||
/**
|
||||
* Initializes the manager.
|
||||
* @param view The view that the manager can use to add and remove message holds.
|
||||
*/
|
||||
public void initialize(IView view) {
|
||||
this.view = view;
|
||||
}//initialize()//
|
||||
/**
|
||||
* Registers a listener with the view's decorations.
|
||||
* @param listener The listener to be registered.
|
||||
*/
|
||||
public void registerDecorationListener(IDecorationListener listener) {
|
||||
decorationListeners.add(listener);
|
||||
|
||||
//Send the listener any decorations that apply.//
|
||||
for(IIterator iterator = decorationMap.valueIterator(); iterator.hasNext(); ) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if((listener.getDecoratedObject() == decoration.getObject()) && (listener.getDecoratedAttribute() == decoration.getAttribute())) {
|
||||
listener.addDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//for//
|
||||
}//registerDecorationListener()//
|
||||
/**
|
||||
* Unregisters a listener with the view's decorations.
|
||||
* @param listener The listener to be unregistered.
|
||||
*/
|
||||
public void unregisterDecorationListener(IDecorationListener listener, Object oldObject, Attribute oldAttribute) {
|
||||
decorationListeners.remove(listener);
|
||||
|
||||
//Send the listener any decorations that used to apply.//
|
||||
if(oldObject != null) {
|
||||
for(IIterator iterator = decorationMap.valueIterator(); iterator.hasNext(); ) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if((oldObject == decoration.getObject()) && (oldAttribute == decoration.getAttribute())) {
|
||||
listener.removeDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
}//unregisterDecorationListener()//
|
||||
/**
|
||||
* Registers a listener with the view's decorations.
|
||||
* @param listener The listener to be registered.
|
||||
*/
|
||||
public void registerDecorationListener(IDecorationMultiListener listener) {
|
||||
IIterator iterator = decorationMap.valueIterator();
|
||||
|
||||
decorationListeners.add(listener);
|
||||
|
||||
//Send the listener any decorations that apply.//
|
||||
while(iterator.hasNext()) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if(listener.isListening(decoration.getDecoration().getClass(), decoration.getObject(), decoration.getAttribute())) {
|
||||
listener.addDecoration(decoration.getDecoration(), decoration.getObject(), decoration.getAttribute());
|
||||
}//if//
|
||||
}//while//
|
||||
}//registerDecorationListener()//
|
||||
/**
|
||||
* Unregisters a listener with the view's decorations.
|
||||
* @param listener The listener to be unregistered.
|
||||
*/
|
||||
public void unregisterDecorationListener(IDecorationMultiListener listener) {
|
||||
IIterator iterator = decorationMap.valueIterator();
|
||||
|
||||
decorationListeners.remove(listener);
|
||||
|
||||
//Send the listener any decorations that used to apply.//
|
||||
while(iterator.hasNext()) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if(listener.isListening(decoration.getClass(), decoration.getObject(), decoration.getAttribute())) {
|
||||
listener.removeDecoration(decoration.getDecoration(), decoration.getObject(), decoration.getAttribute());
|
||||
}//if//
|
||||
}//while//
|
||||
}//unregisterDecorationListener()//
|
||||
/**
|
||||
* Notifies the decoration manager that an existing registered listener has changed which object and/or attribute it is interested in.
|
||||
* @param listener The currently registered listener.
|
||||
* @param oldObject The old object that the listener was interested in. This is used to send remove messages to the listener for old decorations.
|
||||
* @param oldAttribute The old attribute that the listener was interested in.
|
||||
*/
|
||||
public void updateDecorationListener(IDecorationListener listener, Object oldObject, Attribute oldAttribute) {
|
||||
//Send the listener any decorations that used to apply.//
|
||||
if(oldObject != null) {
|
||||
for(IIterator iterator = decorationMap.valueIterator(); iterator.hasNext(); ) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if((oldObject == decoration.getObject()) && (oldAttribute == decoration.getAttribute())) {
|
||||
listener.removeDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//Send the listener any decorations that apply.//
|
||||
for(IIterator iterator = decorationMap.valueIterator(); iterator.hasNext(); ) {
|
||||
DecorationMetadata decoration = (DecorationMetadata) iterator.next();
|
||||
|
||||
if((listener.getDecoratedObject() == decoration.getObject()) && (listener.getDecoratedAttribute() == decoration.getAttribute())) {
|
||||
listener.addDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//for//
|
||||
}//updateDecorationListener()//
|
||||
/**
|
||||
* Applies the decoration changes, notifying and updating the view.
|
||||
*/
|
||||
public void applyDecorationChanges() {
|
||||
try {
|
||||
IIterator iterator;
|
||||
|
||||
view.addMessageHold();
|
||||
iterator = removedDecorations.keyIterator();
|
||||
|
||||
//Collect the removed decorations.//
|
||||
while(iterator.hasNext()) {
|
||||
Object object = iterator.next();
|
||||
DecorationMetadata next = (DecorationMetadata) removedDecorations.get(object);
|
||||
|
||||
while(next != null) {
|
||||
internalRemoveDecoration(next);
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
}//while//
|
||||
|
||||
iterator = addedDecorations.valueIterator();
|
||||
|
||||
//Collect the added decorations and also transfer them to the current mapping.//
|
||||
while(iterator.hasNext()) {
|
||||
DecorationMetadata first = (DecorationMetadata) iterator.next();
|
||||
DecorationMetadata next = first;
|
||||
DecorationMetadata last = null;
|
||||
|
||||
while(next != null) {
|
||||
internalAddDecoration(next);
|
||||
last = next;
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
//Place the decoration metadata into the current mapping.//
|
||||
last.setNext((DecorationMetadata) decorationMap.get(last.getObject()));
|
||||
decorationMap.put(first.getObject(), first);
|
||||
}//while//
|
||||
|
||||
//Clear the removed and added decoration mappings.//
|
||||
addedDecorations.removeAll();
|
||||
removedDecorations.removeAll();
|
||||
}//try//
|
||||
finally {
|
||||
view.removeMessageHold();
|
||||
}//finally//
|
||||
}//applyDecorationChanges()//
|
||||
/**
|
||||
* Adds the decoration by sending it to the appropriate listeners.
|
||||
* @param decoration The decoration being added.
|
||||
*/
|
||||
protected void internalAddDecoration(DecorationMetadata decoration) {
|
||||
//TODO: Make this more efficient. There could be many many listeners? Determine if there are a lot of listeners for at least a sizeable portion of application views.
|
||||
IIterator iterator = decorationListeners.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof IDecorationMultiListener) {
|
||||
IDecorationMultiListener listener = (IDecorationMultiListener) next;
|
||||
|
||||
if(listener.isListening(decoration.getDecoration().getClass(), decoration.getObject(), decoration.getAttribute())) {
|
||||
listener.addDecoration(decoration.getDecoration(), decoration.getObject(), decoration.getAttribute());
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
IDecorationListener listener = (IDecorationListener) next;
|
||||
|
||||
if((listener.getDecoratedObject() == decoration.getObject()) && (listener.getDecoratedAttribute() == decoration.getAttribute())) {
|
||||
listener.addDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//else//
|
||||
}//while//
|
||||
}//internalAddDecoration()//
|
||||
/**
|
||||
* Removes the decoration by sending it to the appropriate listeners.
|
||||
* @param decoration The decoration being removed.
|
||||
*/
|
||||
protected void internalRemoveDecoration(DecorationMetadata decoration) {
|
||||
//TODO: Make this more efficient. There could be many many listeners? Determine if there are a lot of listeners for at least a sizeable portion of application views.
|
||||
IIterator iterator = decorationListeners.iterator();
|
||||
|
||||
while(iterator.hasNext()) {
|
||||
Object next = iterator.next();
|
||||
|
||||
if(next instanceof IDecorationMultiListener) {
|
||||
IDecorationMultiListener listener = (IDecorationMultiListener) next;
|
||||
|
||||
if(listener.isListening(decoration.getDecoration().getClass(), decoration.getObject(), decoration.getAttribute())) {
|
||||
listener.removeDecoration(decoration.getDecoration(), decoration.getObject(), decoration.getAttribute());
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
IDecorationListener listener = (IDecorationListener) next;
|
||||
|
||||
if((listener.getDecoratedObject() == decoration.getObject()) && (listener.getDecoratedAttribute() == decoration.getAttribute())) {
|
||||
listener.removeDecoration(decoration.getDecoration());
|
||||
}//if//
|
||||
}//else//
|
||||
}//while//
|
||||
}//internalRemoveDecoration()//
|
||||
/**
|
||||
* Clears all decorations.
|
||||
* <p>Note: Nothing is actually cleared until the apply method is called.</p>
|
||||
*/
|
||||
public void clearDecorations() {
|
||||
this.clearDecorations(null, null);
|
||||
}//clearDecorations()//
|
||||
/**
|
||||
* Clears all decorations associated with the given object.
|
||||
* @param object The object whose associated decorations should be cleared. If null then all object decorations will be cleared.
|
||||
* @param decorationType The optional decoration type to be cleared. If null then all decoration types will be cleared.
|
||||
*/
|
||||
public void clearDecorations(Object object, Class decorationType) {
|
||||
if(object != null) {
|
||||
//Removes the desired decoration metadata instances and places them in the removed mapping.//
|
||||
if(decorationType != null) {
|
||||
DecorationMetadata current = (DecorationMetadata) decorationMap.get(object);
|
||||
DecorationMetadata previous = null;
|
||||
DecorationMetadata removed = (DecorationMetadata) removedDecorations.get(object);
|
||||
|
||||
while(current != null) {
|
||||
if(decorationType.isAssignableFrom(current.getDecoration().getClass())) {
|
||||
DecorationMetadata next = current.getNext();
|
||||
|
||||
if(previous != null) {
|
||||
previous.setNext(current.getNext());
|
||||
}//if//
|
||||
else {
|
||||
decorationMap.put(object, current.getNext());
|
||||
}//else//
|
||||
|
||||
if(removed == null) {
|
||||
removed = current;
|
||||
removedDecorations.put(object, removed);
|
||||
}//if//
|
||||
else {
|
||||
current.setNext(removed.getNext());
|
||||
removed.setNext(current);
|
||||
}//else//
|
||||
|
||||
current = next;
|
||||
}//if//
|
||||
else {
|
||||
previous = current;
|
||||
current = current.getNext();
|
||||
}//else//
|
||||
}//while//
|
||||
}//if//
|
||||
else {
|
||||
DecorationMetadata removed = (DecorationMetadata) decorationMap.remove(object);
|
||||
|
||||
if(removed != null) {
|
||||
DecorationMetadata next = removed;
|
||||
|
||||
//Locate the last decoration metadata in the linked list.//
|
||||
while(next.getNext() != null) {
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
next.setNext((DecorationMetadata) removedDecorations.get(object));
|
||||
removedDecorations.put(object, removed);
|
||||
}//if//
|
||||
}//else//
|
||||
}//if//
|
||||
else {
|
||||
//Removes the desired decoration metadata instances and places them in the removed mapping.//
|
||||
if(decorationType != null) {
|
||||
IIterator objectIterator = decorationMap.keyIterator();
|
||||
|
||||
while(objectIterator.hasNext()) {
|
||||
DecorationMetadata current;
|
||||
DecorationMetadata previous = null;
|
||||
DecorationMetadata removed;
|
||||
|
||||
object = objectIterator.next();
|
||||
current = (DecorationMetadata) decorationMap.get(object);
|
||||
removed = (DecorationMetadata) removedDecorations.get(object);
|
||||
|
||||
while(current != null) {
|
||||
if(decorationType.isAssignableFrom(current.getDecoration().getClass())) {
|
||||
DecorationMetadata next = current.getNext();
|
||||
|
||||
if(previous != null) {
|
||||
previous.setNext(current.getNext());
|
||||
}//if//
|
||||
else {
|
||||
decorationMap.put(object, current.getNext());
|
||||
}//else//
|
||||
|
||||
if(removed == null) {
|
||||
removed = current;
|
||||
removedDecorations.put(object, removed);
|
||||
}//if//
|
||||
else {
|
||||
current.setNext(removed.getNext());
|
||||
removed.setNext(current);
|
||||
}//else//
|
||||
|
||||
current = next;
|
||||
}//if//
|
||||
else {
|
||||
previous = current;
|
||||
current = current.getNext();
|
||||
}//else//
|
||||
}//while//
|
||||
}//while//
|
||||
}//if//
|
||||
else {
|
||||
IIterator objectIterator = decorationMap.keyIterator();
|
||||
|
||||
while(objectIterator.hasNext()) {
|
||||
DecorationMetadata removed;
|
||||
|
||||
object = objectIterator.next();
|
||||
removed = (DecorationMetadata) decorationMap.remove(object);
|
||||
|
||||
if(removed != null) {
|
||||
DecorationMetadata next = removed;
|
||||
|
||||
//Locate the last decoration metadata in the linked list.//
|
||||
while(next.getNext() != null) {
|
||||
next = next.getNext();
|
||||
}//while//
|
||||
|
||||
next.setNext((DecorationMetadata) removedDecorations.get(object));
|
||||
removedDecorations.put(object, removed);
|
||||
}//if//
|
||||
}//while//
|
||||
}//else//
|
||||
}//else//
|
||||
}//clearDecorations()//
|
||||
/**
|
||||
* Adds a decoration to the given object and attached to the optional attribute.
|
||||
* @param object The object to be decorated.
|
||||
* @param attribute The optional attribute to be decorated.
|
||||
* @param decoration The decoration. Usually one of: ControlDecoration, HighlightDecoration, or ImageDecoration.
|
||||
*/
|
||||
public void addDecoration(Object object, Attribute attribute, AbstractDecoration decoration) {
|
||||
DecorationMetadata removedCurrent = (DecorationMetadata) removedDecorations.get(object);
|
||||
DecorationMetadata removedPrevious = null;
|
||||
DecorationMetadata newDecoration = new DecorationMetadata(object, attribute, decoration);
|
||||
|
||||
//Search the removed set for an identical decoration so we can simply move it back to the current set of decorations.//
|
||||
while(removedCurrent != null) {
|
||||
if(newDecoration.equals(removedCurrent)) {
|
||||
DecorationMetadata current = (DecorationMetadata) decorationMap.get(object);
|
||||
|
||||
//Extract the removed decoration metadata from the removed mapping.//
|
||||
if(removedPrevious == null) {
|
||||
removedDecorations.put(object, removedCurrent.getNext());
|
||||
}//if//
|
||||
else {
|
||||
removedPrevious.setNext(removedCurrent.getNext());
|
||||
}//else//
|
||||
|
||||
//Move the removed decoration metadata back into the current mapping.//
|
||||
if(current != null) {
|
||||
removedCurrent.setNext(current.getNext());
|
||||
current.setNext(removedCurrent);
|
||||
}//if//
|
||||
else {
|
||||
decorationMap.put(object, removedCurrent);
|
||||
removedCurrent.setNext(null);
|
||||
}//else//
|
||||
|
||||
//Exit the loop.//
|
||||
removedCurrent = null;
|
||||
newDecoration = null;
|
||||
}//if//
|
||||
else {
|
||||
removedCurrent = removedCurrent.getNext();
|
||||
}//else//
|
||||
}//while//
|
||||
|
||||
//If we really have a new decoration then place it in the added mapping.//
|
||||
if(newDecoration != null) {
|
||||
DecorationMetadata added = (DecorationMetadata) addedDecorations.get(object);
|
||||
|
||||
if(added != null) {
|
||||
newDecoration.setNext(added.getNext());
|
||||
added.setNext(newDecoration);
|
||||
}//if//
|
||||
else {
|
||||
addedDecorations.put(object, newDecoration);
|
||||
}//else//
|
||||
}//if//
|
||||
}//addDecoration()//
|
||||
}//DecorationManager//
|
||||
18
Foundation/src/com/foundation/controller/IController.java
Normal file
18
Foundation/src/com/foundation/controller/IController.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2003,2007 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.controller;
|
||||
|
||||
import com.foundation.common.IEntity;
|
||||
|
||||
public interface IController extends IEntity {
|
||||
/**
|
||||
* Gets the decoration manager for this view.
|
||||
* @return The view's decoration manager.
|
||||
*/
|
||||
public DecorationManager getDecorationManager();
|
||||
}//IController//
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2007,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.controller;
|
||||
|
||||
import com.foundation.metadata.Attribute;
|
||||
import com.foundation.view.AbstractDecoration;
|
||||
|
||||
public interface IDecorationListener {
|
||||
/**
|
||||
* Notifies the listener that a relevant decoration has been added.
|
||||
* @param decoration The decoration added.
|
||||
*/
|
||||
public void addDecoration(AbstractDecoration decoration);
|
||||
/**
|
||||
* Notifies the listener that a relevant decoration has been removed.
|
||||
* @param decoration The decoration removed.
|
||||
*/
|
||||
public void removeDecoration(AbstractDecoration decoration);
|
||||
/**
|
||||
* Gets the object being decorated or whose attribute is decorated (whose markup will be listened to for changes if the attribute is null).
|
||||
* @return The object decorated.
|
||||
*/
|
||||
public Object getDecoratedObject();
|
||||
/**
|
||||
* Gets the object's decorated attribute (whose markup will be listened to for changes).
|
||||
* @return The attribute decorated, or null if the object will be decorated.
|
||||
*/
|
||||
public Attribute getDecoratedAttribute();
|
||||
}//IDecorationListener//
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.foundation.metadata.Attribute;
|
||||
import com.foundation.view.AbstractDecoration;
|
||||
|
||||
public interface IDecorationMultiListener {
|
||||
/**
|
||||
* Determines whether the listener is interesting in listening to decorations attached to the given object and optional attribute.
|
||||
* @param decorationType The class of decoration.
|
||||
* @param object The object whose attribute (or which directly) has a decoration attached to it.
|
||||
* @param attribute The optional attribute on the given object, which if specified is decorated. If not specified then the object its self is decorated.
|
||||
* @return Whether the listener is interested in decorations attached to the given object/attribute.
|
||||
*/
|
||||
public boolean isListening(Class decorationType, Object object, Attribute attribute);
|
||||
/**
|
||||
* Notifies the listener that a relevant decoration has been added.
|
||||
* @param decoration The decoration added.
|
||||
* @param object The object whose attribute (or which directly) has a decoration attached to it.
|
||||
* @param attribute The optional attribute on the given object, which if specified is decorated. If not specified then the object its self is decorated.
|
||||
*/
|
||||
public void addDecoration(AbstractDecoration decoration, Object object, Attribute attribute);
|
||||
/**
|
||||
* Notifies the listener that a relevant decoration has been removed.
|
||||
* @param decoration The decoration removed.
|
||||
* @param object The object whose attribute (or which directly) has a decoration attached to it.
|
||||
* @param attribute The optional attribute on the given object, which if specified is decorated. If not specified then the object its self is decorated.
|
||||
*/
|
||||
public void removeDecoration(AbstractDecoration decoration, Object object, Attribute attribute);
|
||||
}//IDecorationMultiListener//
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
/**
|
||||
* The proxiable interface for the model manager.
|
||||
*/
|
||||
public interface IModelManager {
|
||||
}//IModelManager//
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.util.IList;
|
||||
import com.foundation.attribute.IReflectable;
|
||||
import com.foundation.attribute.IReflectableCollection;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.transaction.ReadTransaction;
|
||||
|
||||
/**
|
||||
* Manages models on a single process and maintains a list of all models at all times.
|
||||
* This is the simplest of model managers and should be used for small collections of shared models.
|
||||
*/
|
||||
public interface ISingleListModelManager extends IModelManager {
|
||||
/**
|
||||
* Adds the entity to the shared set of models and to any attached repository.
|
||||
* Note that this can also be performed by modifying the collection returned by getEntities(Class).
|
||||
* @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.
|
||||
* @return The result of the add operation.
|
||||
*/
|
||||
public ReflectionResult addEntity(IEntity entity, boolean returnAddition);
|
||||
/**
|
||||
* Adds the entities to the shared set of models and to any attached repository.
|
||||
* Note that this can also be performed by modifying the collection returned by getEntities(Class).
|
||||
* @param entities The entities to be added. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
* @param returnAdditions Whether to return the added values.
|
||||
* @return The result of the add operation.
|
||||
*/
|
||||
public ReflectionResult addEntities(IList entities, boolean returnAdditions);
|
||||
/**
|
||||
* Gets all entities of the given type.
|
||||
* @return The result object which, if of the type ReflectionSuccess, will reference a reflectable IManagedList that (once reflected) will contain reflections of all instances of the given type. This collection will be updated if any new instances are created within the system.
|
||||
*/
|
||||
public ReflectionResult getEntities();
|
||||
/**
|
||||
* Gets all the entities for the given set of keys.
|
||||
* @param keys The keys for the entities desired. These can be obtained by calling IEntity.entityGetKey().
|
||||
* @return The result object which, if of the type ReflectionSuccess, will reference a reflectable IManagedList that (once reflected) will contain reflections of all matching entities.
|
||||
*/
|
||||
public ReflectionResult findEntities(Object[] keys);
|
||||
/**
|
||||
* Gets all the entities matching the given query.
|
||||
* @param transaction The transaction that will be run to produce entities which will be used to find the shared entities. This is similar to getEntities(Object[] keys), except that the caller doesn't have to perform as much work (it will be performed in the manager). <b>This transaction MUST query for all key attributes in the entity (those marked in the class as AO_KEY when defined).</b>
|
||||
* @return The result object which, if of the type ReflectionSuccess, will reference a reflectable IManagedList that (once reflected) will contain reflections of all matching entities.
|
||||
*/
|
||||
public ReflectionResult findEntities(ReadTransaction transaction);
|
||||
/**
|
||||
* Removes (deletes) the entity from the shared set of models and from any attached repository.
|
||||
* @param entity The entity to be removed. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
*/
|
||||
public ReflectionResult removeEntity(IEntity entity);
|
||||
/**
|
||||
* Removes (deletes) the entities from the shared set of models and from any attached repository.
|
||||
* @param entities The collection of IReflectable instances to be removed. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
*/
|
||||
public ReflectionResult removeEntities(IList entities);
|
||||
}//ISingleListModelManager//
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.util.IList;
|
||||
import com.foundation.attribute.IReflectable;
|
||||
import com.foundation.attribute.IReflectableCollection;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.transaction.ReadTransaction;
|
||||
|
||||
/**
|
||||
* Manages models on a single process and maintains a map of models currently loaded into memory.
|
||||
* This should be used for large collections of shared models where a small number will be loaded at any given time.
|
||||
*/
|
||||
public interface ISingleMappedModelManager extends IModelManager {
|
||||
/**
|
||||
* Adds the entity to the shared set of models and to any attached repository.
|
||||
* @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.
|
||||
* @return The result of the add operation.
|
||||
*/
|
||||
public ReflectionResult addEntity(IEntity entity, boolean returnAddition);
|
||||
/**
|
||||
* Adds the entities to the shared set of models and to any attached repository.
|
||||
* @param entities The entities to be added. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
* @param returnAdditions Whether to return the added values.
|
||||
* @return The result of the add operation.
|
||||
*/
|
||||
public ReflectionResult addEntities(IList entities, boolean returnAdditions);
|
||||
/**
|
||||
* Removes (deletes) the entity from the shared set of models and from any attached repository.
|
||||
* @param entity The entity to be removed. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
*/
|
||||
public ReflectionResult removeEntity(IEntity entity);
|
||||
/**
|
||||
* Removes (deletes) the entities from the shared set of models and from any attached repository.
|
||||
* @param entities The collection of IReflectable instances to be removed. This object must be serializable in the event that the model management occurs on a remote process.
|
||||
*/
|
||||
public ReflectionResult removeEntities(IList entities);
|
||||
/**
|
||||
* Finds the first entity matching the query.
|
||||
* @param query The query by example object.
|
||||
* @return The IReflectable instance of the first result.
|
||||
*/
|
||||
public ReflectionResult findEntity(IEntity query);
|
||||
/**
|
||||
* Finds all entities matching the query.
|
||||
* @param query The query by example object.
|
||||
* @return The collection of IReflectable instances matching the query. Will never be null.
|
||||
*/
|
||||
public ReflectionResult findEntities(IEntity query);
|
||||
/**
|
||||
* Gets all the entities matching the given query.
|
||||
* @param transaction The transaction that will be run to produce entities which will be used to find the shared entities. This is similar to getEntities(Object[] keys), except that the caller doesn't have to perform as much work (it will be performed in the manager). <b>This transaction MUST query for all key attributes in the entity (those marked in the class as AO_KEY when defined).</b>
|
||||
* @return The IReflectable instance of the first result.
|
||||
*/
|
||||
public ReflectionResult findEntities(ReadTransaction transaction);
|
||||
/**
|
||||
* Gets all the entities for the given set of keys.
|
||||
* @param keys The keys for the entities desired. These can be obtained by calling IEntity.entityGetKey().
|
||||
* @return The IReflectable instance of the first result.
|
||||
*/
|
||||
public ReflectionResult findEntities(Object[] keys);
|
||||
}//ISingleMappedModelListener//
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2007,2008 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.controller;
|
||||
|
||||
public interface IVetoableRunnable {
|
||||
/**
|
||||
* Performs necessary actions with the result indicating whether the process that called the runnable should continue.
|
||||
* @return Whether the process should continue.
|
||||
*/
|
||||
public boolean run();
|
||||
}//IVetoableRunnable//
|
||||
640
Foundation/src/com/foundation/controller/ModelController.java
Normal file
640
Foundation/src/com/foundation/controller/ModelController.java
Normal file
@@ -0,0 +1,640 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.LiteList;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.exception.TransactionException;
|
||||
import com.foundation.transaction.TransactionContextHolder;
|
||||
import com.foundation.transaction.TransactionErrorInfo;
|
||||
import com.foundation.transaction.Transaction;
|
||||
import com.foundation.util.HashSetManager;
|
||||
import com.foundation.util.IManagedCollection;
|
||||
import com.foundation.util.ListManager;
|
||||
|
||||
public class ModelController extends Controller {
|
||||
/**
|
||||
* A list manager that stores the models in the repository when they are added to the list and removes them from the repository when they are removed from the list.
|
||||
* <p>Warning: This manager can only handle entities that are attached to the same repository. If the entities in the collection come from multiple repositories this manager should not be used.</p>
|
||||
*/
|
||||
public static class ModelListManager extends ListManager {
|
||||
private boolean suspendRepositoryHandling = false;
|
||||
/**
|
||||
* Gets the flag indicating that all repository interaction should be suspended.
|
||||
* This is handy for initializing the collection, or for manipulating it manually.
|
||||
* @return Whether the suspend adding/removing collection values to/from the repository.
|
||||
*/
|
||||
public boolean suspendRepositoryHandling() {
|
||||
return suspendRepositoryHandling;
|
||||
}//suspendRepositoryHandling()//
|
||||
/**
|
||||
* Sets the flag indicating that all repository interaction should be suspended.
|
||||
* This is handy for initializing the collection, or for manipulating it manually.
|
||||
* @param suspendRepositoryHandling Whether the suspend adding/removing collection values to/from the repository.
|
||||
*/
|
||||
public void suspendRepositoryHandling(boolean suspendRepositoryHandling) {
|
||||
this.suspendRepositoryHandling = suspendRepositoryHandling;
|
||||
}//suspendRepositoryHandling()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnAdd()
|
||||
*/
|
||||
public boolean checkOnAdd() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnRemove()
|
||||
*/
|
||||
public boolean checkOnRemove() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnReplace()
|
||||
*/
|
||||
public boolean checkOnReplace() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnReplace()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAdd(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate();
|
||||
|
||||
if(info != null) {
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, IManagedCollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.getSize() > 0) {
|
||||
boolean hasError = false;
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
|
||||
try {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
//TODO: Would be nice to do a bulk add to the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
while(result && iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.length > 0) {
|
||||
boolean hasError = false;
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
|
||||
try {
|
||||
//TODO: Would be nice to do a bulk add to the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
for(int valueIndex = values.length - 1; result && valueIndex >= 0; valueIndex--) {
|
||||
Object value = values[valueIndex];
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
if(!hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemove(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canRemove(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete();
|
||||
|
||||
if(info != null) {
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, byte context) {
|
||||
return canRemoveAll(managed, new LiteList(managed), context);
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.getSize() > 0) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
//TODO: Would be nice to do a bulk remove from the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
while(result && iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//while//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.length > 0) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
//TODO: Would be nice to do a bulk remove from the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
for(int valueIndex = values.length - 1; result && valueIndex >= 0; valueIndex--) {
|
||||
Object value = values[valueIndex];
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canReplace(com.common.util.IManagedCollection, java.lang.Object, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canReplace(IManagedCollection managed, Object oldValue, Object newValue, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
if(oldValue instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(oldValue) {
|
||||
TransactionErrorInfo info = ((IEntity) oldValue).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
|
||||
if(newValue instanceof IEntity && result) {
|
||||
TransactionErrorInfo info = ((IEntity) newValue).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canReplace()//
|
||||
}//ModelListManager//
|
||||
/**
|
||||
* A hash set manager that stores the models in the repository when they are added to the set and removes them from the repository when they are removed from the set.
|
||||
* <p>Warning: This manager can only handle entities that are attached to the same repository. If the entities in the collection come from multiple repositories this manager should not be used.</p>
|
||||
*/
|
||||
public static class ModelHashSetManager extends HashSetManager {
|
||||
private boolean suspendRepositoryHandling = false;
|
||||
/**
|
||||
* Gets the flag indicating that all repository interaction should be suspended.
|
||||
* This is handy for initializing the collection, or for manipulating it manually.
|
||||
* @return Whether the suspend adding/removing collection values to/from the repository.
|
||||
*/
|
||||
public boolean suspendRepositoryHandling() {
|
||||
return suspendRepositoryHandling;
|
||||
}//suspendRepositoryHandling()//
|
||||
/**
|
||||
* Sets the flag indicating that all repository interaction should be suspended.
|
||||
* This is handy for initializing the collection, or for manipulating it manually.
|
||||
* @param suspendRepositoryHandling Whether the suspend adding/removing collection values to/from the repository.
|
||||
*/
|
||||
public void suspendRepositoryHandling(boolean suspendRepositoryHandling) {
|
||||
this.suspendRepositoryHandling = suspendRepositoryHandling;
|
||||
}//suspendRepositoryHandling()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnAdd()
|
||||
*/
|
||||
public boolean checkOnAdd() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnRemove()
|
||||
*/
|
||||
public boolean checkOnRemove() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#checkOnReplace()
|
||||
*/
|
||||
public boolean checkOnReplace() {
|
||||
return !suspendRepositoryHandling;
|
||||
}//checkOnReplace()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAdd(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate();
|
||||
|
||||
if(info != null) {
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, IManagedCollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.getSize() > 0) {
|
||||
boolean hasError = false;
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
|
||||
try {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
//TODO: Would be nice to do a bulk add to the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
while(result && iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//while//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.length > 0) {
|
||||
boolean hasError = false;
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
|
||||
try {
|
||||
//TODO: Would be nice to do a bulk add to the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
for(int valueIndex = values.length - 1; result && valueIndex >= 0; valueIndex--) {
|
||||
Object value = values[valueIndex];
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
if(!hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemove(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canRemove(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete();
|
||||
|
||||
if(info != null) {
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, byte context) {
|
||||
return canRemoveAll(managed, new LiteList(managed), context);
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, ICollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.getSize() > 0) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
IIterator iterator = values.iterator();
|
||||
|
||||
//TODO: Would be nice to do a bulk remove from the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
while(result && iterator.hasNext()) {
|
||||
Object value = iterator.next();
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//while//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED && values.length > 0) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
//TODO: Would be nice to do a bulk remove from the repository using a single query if possible. Not all objects may use the exact same query however!
|
||||
for(int valueIndex = values.length - 1; result && valueIndex >= 0; valueIndex--) {
|
||||
Object value = values[valueIndex];
|
||||
|
||||
if(value instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(value) {
|
||||
TransactionErrorInfo info = ((IEntity) value).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canReplace(com.common.util.IManagedCollection, java.lang.Object, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canReplace(IManagedCollection managed, Object oldValue, Object newValue, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context != CONTEXT_TRUSTED) {
|
||||
TransactionContextHolder transactionContext = TransactionContextHolder.getInstance(null);
|
||||
boolean hasError = false;
|
||||
|
||||
try {
|
||||
if(oldValue instanceof IEntity) {
|
||||
/*
|
||||
* Note: This forces the thread to discard its cached object data and causes it to get the latest data from main memory.
|
||||
* This does not ensure another thread will not access the model at the same time.
|
||||
* We don't care about preventing other threads from accessing the entity since we will only be accessing sudo-static data for the deletion operation.//
|
||||
*/
|
||||
synchronized(oldValue) {
|
||||
TransactionErrorInfo info = ((IEntity) oldValue).entityDelete(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//synchronized//
|
||||
}//if//
|
||||
|
||||
if(newValue instanceof IEntity && result) {
|
||||
TransactionErrorInfo info = ((IEntity) newValue).entityUpdate(transactionContext);
|
||||
|
||||
if(info != null) {
|
||||
hasError = true;
|
||||
managed.setErrorInfo(info);
|
||||
result = false;
|
||||
}//if//
|
||||
}//if//
|
||||
}//try//
|
||||
finally {
|
||||
if(hasError || !transactionContext.commit()) {
|
||||
transactionContext.rollback();
|
||||
}//if//
|
||||
|
||||
transactionContext.close();
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//canReplace()//
|
||||
}//ModelHashSetManager//
|
||||
/**
|
||||
* ModelController constructor.
|
||||
*/
|
||||
public ModelController() {
|
||||
}//ModelController()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.IController#getDecorationManager()
|
||||
*/
|
||||
public DecorationManager getDecorationManager() {
|
||||
return null;
|
||||
}//getDecorationManager()//
|
||||
}//ModelController//
|
||||
477
Foundation/src/com/foundation/controller/ModelInterface.java
Normal file
477
Foundation/src/com/foundation/controller/ModelInterface.java
Normal file
@@ -0,0 +1,477 @@
|
||||
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.
|
||||
* <p>This is used for Mapped and List type models.</p>
|
||||
* @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.
|
||||
* <p>This is used for Mapped and List type models.</p>
|
||||
* @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.
|
||||
* <p>This is used for Mapped and List type models.</p>
|
||||
* @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.
|
||||
* <p>This is used for Mapped and List type models.</p>
|
||||
* @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 <code>type</code>.
|
||||
* @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//
|
||||
57
Foundation/src/com/foundation/controller/ModelManager.java
Normal file
57
Foundation/src/com/foundation/controller/ModelManager.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.debug.Debug;
|
||||
import com.foundation.application.IApplication;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.transaction.TransactionService;
|
||||
|
||||
/**
|
||||
* The automated model controller that is capable of all common model controller functionality.
|
||||
*/
|
||||
public abstract class ModelManager extends ModelController implements IModelManager {
|
||||
/** The type of model supported by this model manager. */
|
||||
private Class type;
|
||||
/** Whether to keep the models in sync with other managers in other processes. */
|
||||
private boolean sync;
|
||||
/** The application servicing this model. */
|
||||
private IApplication application;
|
||||
/**
|
||||
* ModelManager constructor.
|
||||
*/
|
||||
protected ModelManager(Class type, boolean sync) {
|
||||
this.type = type;
|
||||
this.sync = sync;
|
||||
|
||||
try {
|
||||
Object instance = type.newInstance();
|
||||
|
||||
application = ((IEntity) instance).getApplication();
|
||||
}//try//
|
||||
catch(InstantiationException e) {
|
||||
Debug.log("Caught exception while initializing an empty instance for framework use.", e);
|
||||
}//catch//
|
||||
catch(IllegalAccessException e) {
|
||||
Debug.log("All models must provide a public default constructor for framework initialization of an empty instance.", e);
|
||||
}//catch//
|
||||
}//ModelManager()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.common.Entity#getApplication()
|
||||
*/
|
||||
public IApplication getApplication() {
|
||||
return application;
|
||||
}//getApplication()//
|
||||
/**
|
||||
* Gets the class of model managed.
|
||||
* @return The model type being managed.
|
||||
*/
|
||||
public Class getType() {
|
||||
return type;
|
||||
}//getType()//
|
||||
/**
|
||||
* Gets whether to keep the models in sync with other managers in other processes.
|
||||
* @return If the models must be sync'd with other processes.
|
||||
*/
|
||||
public boolean sync() {
|
||||
return sync;
|
||||
}//sync()//
|
||||
}//ModelManager//
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.util.LiteHashMap;
|
||||
import com.foundation.metadata.MetadataService;
|
||||
import com.foundation.metadata.TypeMetadata;
|
||||
|
||||
public class ModelManagerContainer {
|
||||
/** The mapping of class to model manager instance hosted on this process. */
|
||||
private LiteHashMap typeToModelManagerMap = new LiteHashMap(40);
|
||||
/** The one and only instance of this class. */
|
||||
private static final ModelManagerContainer singleton = new ModelManagerContainer();
|
||||
/**
|
||||
* ModelManagerContainer constructor.
|
||||
*/
|
||||
private ModelManagerContainer() {
|
||||
}//ModelManagerContainer()//
|
||||
/**
|
||||
* Gets the only instance of this class.
|
||||
* @return The singleton instance.
|
||||
*/
|
||||
public static ModelManagerContainer getSingleton() {
|
||||
return singleton;
|
||||
}//getSingleton()//
|
||||
/**
|
||||
* Gets the local model manager.
|
||||
* @param type The type of model the manager supports.
|
||||
* @return The model manager.
|
||||
*/
|
||||
public synchronized ModelManager getModelManager(Class type) {
|
||||
ModelManager result = (ModelManager) typeToModelManagerMap.get(type);
|
||||
|
||||
if(result == null) {
|
||||
TypeMetadata metadata = MetadataService.getSingleton().getTypeMetadata(type);
|
||||
|
||||
switch(metadata.getManagementType()) {
|
||||
default:
|
||||
case TypeMetadata.MANAGEMENT_TYPE_NONE:
|
||||
break;
|
||||
case TypeMetadata.MANAGEMENT_TYPE_LOAD_ALL: {
|
||||
result = new SingleListModelManager(type, true);
|
||||
typeToModelManagerMap.put(type, result);
|
||||
break;
|
||||
}//case//
|
||||
case TypeMetadata.MANAGEMENT_TYPE_LOAD_AS_NEEDED: {
|
||||
result = new SingleMappedModelManager(type, true);
|
||||
typeToModelManagerMap.put(type, result);
|
||||
break;
|
||||
}//case//
|
||||
case TypeMetadata.MANAGEMENT_TYPE_LOAD_ALL_LOCAL_ONLY: {
|
||||
result = new SingleListModelManager(type, false);
|
||||
typeToModelManagerMap.put(type, result);
|
||||
break;
|
||||
}//case//
|
||||
case TypeMetadata.MANAGEMENT_TYPE_LOAD_AS_NEEDED_LOCAL_ONLY: {
|
||||
result = new SingleMappedModelManager(type, true);
|
||||
typeToModelManagerMap.put(type, result);
|
||||
break;
|
||||
}//case//
|
||||
}//switch//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//getModelManager()//
|
||||
}//ModelManagerContainer//
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a failure of the model to match the constraint requirements.
|
||||
*/
|
||||
public class ReflectionConstraintError extends ReflectionResult {
|
||||
/** The repository or application defined constraint identifier. */
|
||||
private String constraint = null;
|
||||
/**
|
||||
* ReflectionConstraintError constructor.
|
||||
*/
|
||||
public ReflectionConstraintError() {
|
||||
}//ReflectionConstraintError()//
|
||||
/**
|
||||
* ReflectionConstraintError constructor.
|
||||
* @param constraint The repository or application defined constraint identifier.
|
||||
*/
|
||||
public ReflectionConstraintError(String constraint) {
|
||||
this.constraint = constraint;
|
||||
}//ReflectionConstraintError()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_CONSTRAINT_ERROR;
|
||||
}//getResultType()//
|
||||
/**
|
||||
* Gets the constraint identifier useable by the application to re-attempt the synchronization or warn the user.
|
||||
* @return The repository or application defined constraint identifier.
|
||||
*/
|
||||
public String getConstraint() {
|
||||
return constraint;
|
||||
}//getConstraint()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
constraint = in.readUTF8();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeUTF8(constraint);
|
||||
}//writeExternal()//
|
||||
}//ReflectionConstraintError//
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a problem that could not be expressed with one of the other error result types.
|
||||
*/
|
||||
public class ReflectionCustomError extends ReflectionResult {
|
||||
/** The custom error object. */
|
||||
private Object errorValue = null;
|
||||
/**
|
||||
* ReflectionCustomError constructor.
|
||||
*/
|
||||
public ReflectionCustomError() {
|
||||
}//ReflectionCustomError()//
|
||||
/**
|
||||
* ReflectionCustomError constructor.
|
||||
* @param errorValue The custom error object.
|
||||
*/
|
||||
public ReflectionCustomError(Object errorValue) {
|
||||
this.errorValue = errorValue;
|
||||
}//ReflectionCustomError()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return 0;
|
||||
}//getResultType()//
|
||||
/**
|
||||
* Gets the error value assigned to the custom error.
|
||||
* @return The custom error object.
|
||||
*/
|
||||
public Object getErrorValue() {
|
||||
return errorValue;
|
||||
}//getErrorValue()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
errorValue = in.readObject();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeObject(errorValue);
|
||||
}//writeExternal()//
|
||||
}//ReflectionCustomError//
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a failure in the Brainstorm Framework.
|
||||
*/
|
||||
public class ReflectionFrameworkError extends ReflectionResult {
|
||||
/** An identifier for the error. */
|
||||
private int errorId = 0;
|
||||
/** Some optional text for the error. */
|
||||
private String errorText = null;
|
||||
/**
|
||||
* ReflectionFrameworkError constructor.
|
||||
*/
|
||||
public ReflectionFrameworkError() {
|
||||
}//ReflectionFrameworkError()//
|
||||
/**
|
||||
* ReflectionFrameworkError constructor.
|
||||
* @param errorId The identifier for the error.
|
||||
* @param errorText The text associated with the error.
|
||||
*/
|
||||
public ReflectionFrameworkError(int errorId, String errorText) {
|
||||
this.errorId = errorId;
|
||||
this.errorText = errorText;
|
||||
}//ReflectionFrameworkError()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_FRAMEWORK_ERROR;
|
||||
}//getResultType()//
|
||||
/**
|
||||
* Gets the error identifier.
|
||||
* @return An identifier for the error.
|
||||
*/
|
||||
public int getErrorId() {
|
||||
return errorId;
|
||||
}//getException()//
|
||||
/**
|
||||
* Gets the optional error text.
|
||||
* @return Some optional text for the error.
|
||||
*/
|
||||
public String getErrorText() {
|
||||
return errorText;
|
||||
}//getErrorText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
errorId = in.readInt();
|
||||
errorText = in.readUTF8();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeInt(errorId);
|
||||
out.writeUTF8(errorText);
|
||||
}//writeExternal()//
|
||||
}//ReflectionFrameworkError//
|
||||
174
Foundation/src/com/foundation/controller/ReflectionManager.java
Normal file
174
Foundation/src/com/foundation/controller/ReflectionManager.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2005,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.controller;
|
||||
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IList;
|
||||
import com.foundation.attribute.SynchronizeFailureCause;
|
||||
import com.foundation.attribute.IReflectable;
|
||||
import com.foundation.attribute.ReflectionContext;
|
||||
import com.foundation.attribute.ReflectionContext.IValidationHandler;
|
||||
|
||||
public class ReflectionManager extends Object implements IValidationHandler {
|
||||
/** The view controller associated with this reflection manager. All modifications to the reflections must occur via the view controller's event thread. */
|
||||
private AbstractViewController viewController = null;
|
||||
/** The reflection context (which may be shared) used to control the reflections. */
|
||||
private ReflectionContext reflectionContext = null;
|
||||
/**
|
||||
* ReflectionManager constructor.
|
||||
* <p>Note: This class will initialize the reflection context. The creator <b>must</b> release this instance when it is no longer needed.</p>
|
||||
* @param viewController The view controller associated with this reflection manager.
|
||||
* @param reflectionContext The reflection context used by the manager to create and control reflections.
|
||||
* @param updateRepository Whether the repository should be updated when reflections created by this reflection context are synchronized. By default this is true.
|
||||
*/
|
||||
public ReflectionManager(AbstractViewController viewController, ReflectionContext reflectionContext) {
|
||||
super();
|
||||
|
||||
if(viewController == null) {
|
||||
throw new IllegalArgumentException("Must provide a valid view controller when creating a reflection manager.");
|
||||
}//if//
|
||||
|
||||
if(reflectionContext == null) {
|
||||
throw new IllegalArgumentException("Must provide a valid reflection context when creating a reflection manager.");
|
||||
}//if//
|
||||
|
||||
this.viewController = viewController;
|
||||
this.reflectionContext = reflectionContext;
|
||||
reflectionContext.initialize();
|
||||
}//ReflectionManager()//
|
||||
/**
|
||||
* Gets the reflection context that is controlling the reflections for this reflection manager.
|
||||
* @return The underlying reflection context.
|
||||
*/
|
||||
public ReflectionContext getReflectionContext() {
|
||||
return reflectionContext;
|
||||
}//getReflectionContext()//
|
||||
/**
|
||||
* Releases this reflection manager when it is no longer required.
|
||||
* <p>This method will notify the underlying reflection context that it is no longer being used and any registered reflections may be unregistered.</p>
|
||||
*/
|
||||
public void release() {
|
||||
if(reflectionContext != null) {
|
||||
reflectionContext.release();
|
||||
reflectionContext = null;
|
||||
viewController = null;
|
||||
}//if//
|
||||
}//release()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.attribute.ReflectionContext.IValidationHandler#validate()
|
||||
*/
|
||||
public boolean validate() {
|
||||
return viewController.validate();
|
||||
}//validate()//
|
||||
/**
|
||||
* Creates a reflection of the given reflectable object. If the reflection already exists in this context or the value is a reflection in this context, then the existing reflection will be returned.
|
||||
* <p><b>Warning: As with all Entities (or subclasses thereof), the reflectable object should have a public default constructor which does not throw exceptions.</b></p>
|
||||
* @param value The value to be reflected.
|
||||
* @return The reflection of the value or the value if it is a reflection in this context. This will only be null if there was a problem constructing a new instance of the reflectable value.
|
||||
*/
|
||||
public IReflectable createReflection(IReflectable value) {
|
||||
return reflectionContext.createReflection(value);
|
||||
}//createReflection()//
|
||||
/**
|
||||
* Creates reflections of the given reflectable objects. If some or all of the reflections already exist in this context or some of the values are reflections in this context, then the existing reflections will be returned.
|
||||
* <p><b>Warning: As with all Entities (or subclasses thereof), the reflectable objects should have a public default constructor which does not throw exceptions.</b></p>
|
||||
* @param values The reflectable objects whose reflections will be retrieved.
|
||||
* @return The collection of reflections.
|
||||
*/
|
||||
public IList createReflections(IList values) {
|
||||
return reflectionContext.createReflections(values);
|
||||
}//createReflections()//
|
||||
/**
|
||||
* Synchronizes changes to a reflection with the object it reflects. In the case of a collection, the added and/or removed objects will be applied to the reflected collection.
|
||||
* @param reflection The reflection to synchronize.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeSingle(IReflectable reflection) {
|
||||
return synchronizeSingle(reflection, null, true);
|
||||
}//synchronizeSingle()//
|
||||
/**
|
||||
* Synchronizes changes to a reflection with the object it reflects. In the case of a collection, the added and/or removed objects will be applied to the reflected collection.
|
||||
* @param reflection The reflection to synchronize.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeSingle(IReflectable reflection, IValidationHandler validationHandler) {
|
||||
return synchronizeSingle(reflection, validationHandler, true);
|
||||
}//synchronizeSingle()//
|
||||
/**
|
||||
* Synchronizes changes to a reflection with the object it reflects. In the case of a collection, the added and/or removed objects will be applied to the reflected collection.
|
||||
* @param reflection The reflection to synchronize.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @param autoRetry Whether the synchronization should repeatedly retry until successful. If this is true then a failure will cause a re-call to the validation code before re-attempting synchronization.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeSingle(IReflectable reflection, IValidationHandler validationHandler, boolean autoRetry) {
|
||||
return reflectionContext.synchronizeSingle(reflection, validationHandler == null ? this : validationHandler, autoRetry);
|
||||
}//synchronizeSingle()//
|
||||
/**
|
||||
* Synchronizes changes to all given reflections with the objects they reflect.
|
||||
* <p>Warning: This will not synchronize the collection if the passed collection is a reflection!</p>
|
||||
* @param reflections The collection of reflections to be synchronized.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeMany(ICollection reflections) {
|
||||
return synchronizeMany(reflections, null, true);
|
||||
}//synchronizeMany()//
|
||||
/**
|
||||
* Synchronizes changes to all given reflections with the objects they reflect.
|
||||
* <p>Warning: This will not synchronize the collection if the passed collection is a reflection!</p>
|
||||
* @param reflections The collection of reflections to be synchronized.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeMany(ICollection reflections, IValidationHandler validationHandler) {
|
||||
return synchronizeMany(reflections, validationHandler, true);
|
||||
}//synchronizeMany()//
|
||||
/**
|
||||
* Synchronizes changes to all given reflections with the objects they reflect.
|
||||
* <p>Warning: This will not synchronize the collection if the passed collection is a reflection!</p>
|
||||
* @param reflections The collection of reflections to be synchronized.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @param autoRetry Whether the synchronization should repeatedly retry until successful. If this is true then a failure will cause a re-call to the validation code before re-attempting synchronization.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeMany(ICollection reflections, IValidationHandler validationHandler, boolean autoRetry) {
|
||||
return reflectionContext.synchronizeMany(reflections, validationHandler == null ? this : validationHandler, autoRetry);
|
||||
}//synchronizeMany()//
|
||||
/**
|
||||
* Gets the extended error information for the synchronization operation.
|
||||
* @return The cause for the failure of the last run synchronization operation. This will be null if there wasn't a failure.
|
||||
*/
|
||||
public SynchronizeFailureCause getSynchronizeFailureCause() {
|
||||
return getReflectionContext().getSynchronizationFailureCause();
|
||||
}//getSynchronizationFailureCause()//
|
||||
/**
|
||||
* Synchronizes changes to all reflections with the objects they reflect.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeAll() {
|
||||
return synchronizeAll(null, true);
|
||||
}//synchronizeAll()//
|
||||
/**
|
||||
* Synchronizes changes to all reflections with the objects they reflect.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeAll(IValidationHandler validationHandler) {
|
||||
return synchronizeAll(validationHandler, true);
|
||||
}//synchronizeAll()//
|
||||
/**
|
||||
* Synchronizes changes to all reflections with the objects they reflect.
|
||||
* @param validationHandler An optional validation handler which will be called prior to synchronizing. If null then the default validation will occur.
|
||||
* @param autoRetry Whether the synchronization should repeatedly retry until successful. If this is true then a failure will cause a re-call to the validation code before re-attempting synchronization.
|
||||
* @return Whether the synchronization was completely successful. Note that it could be partially successful since failures occur along virtual model lines.
|
||||
*/
|
||||
public boolean synchronizeAll(IValidationHandler validationHandler, boolean autoRetry) {
|
||||
return reflectionContext.synchronizeAll(validationHandler == null ? this : validationHandler, autoRetry);
|
||||
}//synchronizeAll()//
|
||||
}//ReflectionManager//
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.transaction.Transaction;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a problem in the model preparation or versioning system.
|
||||
*/
|
||||
public class ReflectionModelError extends ReflectionResult {
|
||||
/** The model error code identifier (IEntity.MODEL_ERROR_xxx). */
|
||||
private int modelErrorCode = IEntity.MODEL_ERROR_NONE;
|
||||
/**
|
||||
* ReflectionModelError constructor.
|
||||
*/
|
||||
public ReflectionModelError() {
|
||||
}//ReflectionModelError()//
|
||||
/**
|
||||
* ReflectionModelError constructor.
|
||||
* @param modelErrorCode The model error code identifier (IEntity.MODEL_ERROR_xxx).
|
||||
*/
|
||||
public ReflectionModelError(int modelErrorCode) {
|
||||
this.modelErrorCode = modelErrorCode;
|
||||
}//ReflectionModelError()//
|
||||
/**
|
||||
* Gets the model synchronization error code detailing the problem.
|
||||
* @return The model error code identifier (IEntity.MODEL_ERROR_xxx).
|
||||
*/
|
||||
public int getModelErrorCode() {
|
||||
return modelErrorCode;
|
||||
}//getModelErrorCode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_MODEL_ERROR;
|
||||
}//getResultType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
modelErrorCode = in.readInt();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeInt(modelErrorCode);
|
||||
}//writeExternal()//
|
||||
}//ReflectionModelError//
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a failure in the network.
|
||||
*/
|
||||
public class ReflectionNetworkError extends ReflectionResult {
|
||||
/** An identifier for the error. */
|
||||
private int errorId = 0;
|
||||
/** Some optional text for the error. */
|
||||
private String errorText = null;
|
||||
/**
|
||||
* ReflectionNetworkError constructor.
|
||||
*/
|
||||
public ReflectionNetworkError() {
|
||||
}//ReflectionNetworkError()//
|
||||
/**
|
||||
* ReflectionNetworkError constructor.
|
||||
* @param errorId The identifier for the error.
|
||||
* @param errorText The text associated with the error.
|
||||
*/
|
||||
public ReflectionNetworkError(int errorId, String errorText) {
|
||||
this.errorId = errorId;
|
||||
this.errorText = errorText;
|
||||
}//ReflectionNetworkError()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_FRAMEWORK_ERROR;
|
||||
}//getResultType()//
|
||||
/**
|
||||
* Gets the error identifier.
|
||||
* @return An identifier for the error.
|
||||
*/
|
||||
public int getErrorId() {
|
||||
return errorId;
|
||||
}//getException()//
|
||||
/**
|
||||
* Gets the optional error text.
|
||||
* @return Some optional text for the error.
|
||||
*/
|
||||
public String getErrorText() {
|
||||
return errorText;
|
||||
}//getErrorText()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
errorId = in.readInt();
|
||||
errorText = in.readUTF8();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeInt(errorId);
|
||||
out.writeUTF8(errorText);
|
||||
}//writeExternal()//
|
||||
}//ReflectionNetworkError//
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.io.IExternalizable;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.transaction.Transaction;
|
||||
import com.foundation.transaction.TransactionErrorInfo;
|
||||
|
||||
/**
|
||||
* A reflection operation result.
|
||||
*/
|
||||
public abstract class ReflectionResult implements IExternalizable {
|
||||
public static final int RESULT_TYPE_SUCCESS = 0;
|
||||
public static final int RESULT_TYPE_CONSTRAINT_ERROR = 1;
|
||||
public static final int RESULT_TYPE_TRANSACTIONAL_ERROR = 2;
|
||||
public static final int RESULT_TYPE_MODEL_ERROR = 3;
|
||||
public static final int RESULT_TYPE_NETWORK_ERROR = 4;
|
||||
public static final int RESULT_TYPE_FRAMEWORK_ERROR = 5;
|
||||
/**
|
||||
* Creates a result object from a given error object.
|
||||
* @param object An object that identifies the error.
|
||||
* @return The reflection result error object wrappering the passed object (will be the object if it is an instance of ReflectionResult).
|
||||
*/
|
||||
public static ReflectionResult createResult(Object object) {
|
||||
if(object instanceof ReflectionResult) {
|
||||
return (ReflectionResult) object;
|
||||
}//if//
|
||||
else if(object instanceof TransactionErrorInfo) {
|
||||
TransactionErrorInfo info = (TransactionErrorInfo) object;
|
||||
|
||||
switch(info.getTransactionErrorCode()) {
|
||||
default:
|
||||
case Transaction.ERROR_NONE: {
|
||||
switch(info.getModelErrorCode()) {
|
||||
case IEntity.MODEL_ERROR_UNKOWN_ERROR:
|
||||
case IEntity.MODEL_ERROR_BAD_VERSION:
|
||||
case IEntity.MODEL_ERROR_FAILED_PREPERATIONS: {
|
||||
return new ReflectionModelError(info.getModelErrorCode());
|
||||
}//case()//
|
||||
default:
|
||||
case IEntity.MODEL_ERROR_NONE: {
|
||||
return new ReflectionCustomError(info.getErrorData());
|
||||
}//case()//
|
||||
}//switch//
|
||||
}//case//
|
||||
case Transaction.ERROR_UNEXPECTED:
|
||||
case Transaction.ERROR_QUERY_GENERATION:
|
||||
case Transaction.ERROR_INCOMPATABLE_REPOSITORY:
|
||||
case Transaction.ERROR_COMMIT_FAILED:
|
||||
case Transaction.ERROR_RESOURCE_FAILURE:
|
||||
case Transaction.ERROR_RESOURCE_TIMEOUT: {
|
||||
return new ReflectionTransactionError(info.getTransactionErrorCode());
|
||||
}//case//
|
||||
case Transaction.ERROR_CONSTRAINT_VIOLATED: {
|
||||
return new ReflectionConstraintError(info.getErrorData() != null ? info.getErrorData().toString() : null);
|
||||
}//case//
|
||||
}//switch//
|
||||
}//else if//
|
||||
else {
|
||||
return new ReflectionCustomError(object);
|
||||
}//else//
|
||||
}//createResult()//
|
||||
/**
|
||||
* Gets the type code for the result.
|
||||
* @return One of the RESULT_TYPE_xxx identifiers.
|
||||
*/
|
||||
public abstract int getResultType();
|
||||
}//ReflectionResult//
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating the success of the operation and providing any available result.
|
||||
*/
|
||||
public class ReflectionSuccess extends ReflectionResult {
|
||||
/** The optional result object reference. */
|
||||
private Object result = null;
|
||||
/**
|
||||
* ReflectionSuccess constructor.
|
||||
* @param result The result of the synchronization, if there is one.
|
||||
*/
|
||||
public ReflectionSuccess() {
|
||||
}//ReflectionSuccess()//
|
||||
/**
|
||||
* ReflectionSuccess constructor.
|
||||
* @param result The result of the synchronization, if there is one.
|
||||
*/
|
||||
public ReflectionSuccess(Object result) {
|
||||
this.result = result;
|
||||
}//ReflectionSuccess()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_SUCCESS;
|
||||
}//getResultType()//
|
||||
/**
|
||||
* Gets the result of the operation.
|
||||
* @return The optional result object reference.
|
||||
*/
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}//getResult()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
result = in.readObject();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeObject(result);
|
||||
}//writeExternal()//
|
||||
}//ReflectionSuccess//
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.common.io.IObjectInputStream;
|
||||
import com.common.io.IObjectOutputStream;
|
||||
import com.foundation.transaction.Transaction;
|
||||
|
||||
/**
|
||||
* A reflection operation result indicating a problem in the transactional system (not including detected constraint errors).
|
||||
*/
|
||||
public class ReflectionTransactionError extends ReflectionResult {
|
||||
/** The transaction error code identifier (Transaction.ERROR_xxx). */
|
||||
private int transactionErrorCode = Transaction.ERROR_NONE;
|
||||
/**
|
||||
* ReflectionTransactionError constructor.
|
||||
*/
|
||||
public ReflectionTransactionError() {
|
||||
}//ReflectionTransactionError()//
|
||||
/**
|
||||
* ReflectionTransactionError constructor.
|
||||
* @param transactionErrorCode The transaction error code identifier (Transaction.ERROR_xxx).
|
||||
*/
|
||||
public ReflectionTransactionError(int transactionErrorCode) {
|
||||
this.transactionErrorCode = transactionErrorCode;
|
||||
}//ReflectionTransactionError()//
|
||||
/**
|
||||
* Gets the transaction system error code detailing the problem.
|
||||
* @return The transaction error code identifier (Transaction.ERROR_xxx).
|
||||
*/
|
||||
public int getTransactionErrorCode() {
|
||||
return transactionErrorCode;
|
||||
}//getTransactionErrorCode()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ReflectionResult#getResultType()
|
||||
*/
|
||||
public int getResultType() {
|
||||
return RESULT_TYPE_TRANSACTIONAL_ERROR;
|
||||
}//getResultType()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#readExternal(com.common.io.IObjectInputStream)
|
||||
*/
|
||||
public Object readExternal(IObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
transactionErrorCode = in.readInt();
|
||||
return null;
|
||||
}//readExternal()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IExternalizable#writeExternal(com.common.io.IObjectOutputStream)
|
||||
*/
|
||||
public void writeExternal(IObjectOutputStream out) throws IOException {
|
||||
out.writeInt(transactionErrorCode);
|
||||
}//writeExternal()//
|
||||
}//ReflectionTransactionError//
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2003,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.controller;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import com.common.debug.*;
|
||||
import com.common.thread.IRunnable;
|
||||
import com.foundation.attribute.ReflectionContext;
|
||||
import com.foundation.view.*;
|
||||
|
||||
/**
|
||||
* Provides extra support for remote views where the display occurs on a remote process from the model and controller code.
|
||||
*/
|
||||
public abstract class RemoteViewController extends AbstractViewController {
|
||||
/** The remote view context is a reference to the object supporting just this view (versus the view context which supports a system of remote views across a single connection). This must be null if this view is open inside another view. */
|
||||
private IRemoteViewContext remoteViewContext = null;
|
||||
/**
|
||||
* RemoteViewController constructor.
|
||||
* @param viewContext The view's context under which it will operate.
|
||||
*/
|
||||
public RemoteViewController(IViewContext viewContext) {
|
||||
super(viewContext);
|
||||
}//RemoteViewController()//
|
||||
/**
|
||||
* RemoteViewController constructor.
|
||||
* @param viewContext The view's context under which it will operate.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
*/
|
||||
public RemoteViewController(IViewContext context, ReflectionContext reflectionContext) {
|
||||
super(context, reflectionContext);
|
||||
}//RemoteViewController()//
|
||||
/**
|
||||
* RemoteViewController constructor.
|
||||
* @param viewContext The view's context under which it will operate.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is true by default.
|
||||
*/
|
||||
public RemoteViewController(IViewContext viewContext, boolean validateOnOpen) {
|
||||
super(viewContext, validateOnOpen);
|
||||
}//RemoteViewController()//
|
||||
/**
|
||||
* RemoteViewController constructor.
|
||||
* @param viewContext The view's context under which it will operate.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is true by default.
|
||||
*/
|
||||
public RemoteViewController(IViewContext context, ReflectionContext reflectionContext, boolean validateOnOpen) {
|
||||
super(context, reflectionContext, validateOnOpen);
|
||||
}//RemoteViewController()//
|
||||
/**
|
||||
* Gets the remote view context under which this view controller is operating.
|
||||
* @return The view context specific to this remote view controller.
|
||||
*/
|
||||
public IRemoteViewContext getRemoteViewContext() {
|
||||
//The remote view context will be null if this view is open inside another view.//
|
||||
return remoteViewContext != null ? remoteViewContext : ((RemoteViewController) getParentComponent().getController()).getRemoteViewContext();
|
||||
}//getRemoteViewContext()//
|
||||
/**
|
||||
* Creates the controller's primary view component.
|
||||
* @return This view controller's new view object.
|
||||
*/
|
||||
protected IView createView() {
|
||||
Class viewClass = getViewClass();
|
||||
IView result = null;
|
||||
|
||||
if(viewClass == null) {
|
||||
Debug.log("Error: getViewClass() must return a valid view class in the remote view controller " + getClass().getName());
|
||||
}//if//
|
||||
|
||||
try {
|
||||
if(getParentComponent() == null) {
|
||||
Constructor constructor = viewClass.getConstructor(new Class[] {RemoteViewController.class});
|
||||
|
||||
result = (IView) constructor.newInstance(new Object[] {this});
|
||||
}//if//
|
||||
else {
|
||||
Constructor constructor = viewClass.getConstructor(new Class[] {RemoteViewController.class, IView.class});
|
||||
|
||||
result = (IView) constructor.newInstance(new Object[] {this, getParentComponent()});
|
||||
}//else//
|
||||
}//try//
|
||||
catch(NoSuchMethodException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(InvocationTargetException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(InstantiationException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(IllegalAccessException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
|
||||
return result;
|
||||
}//createView()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.AbstractViewController#internalClose(com.foundation.view.IView, java.lang.Runnable, java.lang.Runnable)
|
||||
*/
|
||||
protected void internalClose(IView view, Runnable onCloseHandler, Runnable onDisposeHandler) {
|
||||
IRemoteViewContext viewContext = null;
|
||||
|
||||
synchronized(this) {
|
||||
viewContext = getParentComponent() == null ? this.remoteViewContext : null;
|
||||
this.remoteViewContext = null;
|
||||
}//synchronized//
|
||||
|
||||
//Hide the view and call the on close handler.//
|
||||
view.setIsVisible(false); //TODO: Can this be enclosed in the message hold area below?//
|
||||
|
||||
if(onCloseHandler != null) {
|
||||
onCloseHandler.run();
|
||||
}//if//
|
||||
|
||||
//Release the view on the client.//
|
||||
view.addMessageHold();
|
||||
view.viewReleaseAll();
|
||||
postClose();
|
||||
view.removeMessageHold();
|
||||
|
||||
if(viewContext != null && viewContext.isValid()) {
|
||||
//Notify the session view controller to release its self.//
|
||||
viewContext.close();
|
||||
}//if//
|
||||
|
||||
if(onDisposeHandler != null) {
|
||||
onDisposeHandler.run();
|
||||
}//if//
|
||||
}//internalClose()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.AbstractViewController#internalInitialize()
|
||||
*/
|
||||
protected IView internalInitialize() {
|
||||
IView result = null;
|
||||
|
||||
if(getContext() != null) {
|
||||
remoteViewContext.incrementMessageHoldCount();
|
||||
result = createView();
|
||||
}//if//
|
||||
else {
|
||||
Debug.log("Error: Cannot open the view without a proper view context.");
|
||||
}//else//
|
||||
|
||||
return result;
|
||||
}//internalInitialize()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.AbstractViewController#internalInitializeContext(com.foundation.view.IViewContext)
|
||||
*/
|
||||
protected void internalInitializeContext(IViewContext context) {
|
||||
if((context != null) && (context instanceof IRemoteSessionContext)) {
|
||||
//This creates a new remote session context which is a proxy to an object on the client that represents the view.//
|
||||
//This should not be done for inner views (views that exist inside other views). Instead those views should use their parent's context.//
|
||||
remoteViewContext = ((IRemoteSessionContext) context).createViewContext(this);
|
||||
}//if//
|
||||
else {
|
||||
Debug.log("Error: Cannot open the view without a proper view context.");
|
||||
}//else//
|
||||
}//internalInitializeContext()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.AbstractViewController#internalOpen(IView)
|
||||
*/
|
||||
protected void internalOpen(final IView view) {
|
||||
view.execute(new com.common.thread.IRunnable() {
|
||||
public Object run() {
|
||||
view.suspendLayouts();
|
||||
view.viewInitializeAll();
|
||||
view.resumeLayouts();
|
||||
view.layout();
|
||||
view.pack();
|
||||
postOpenInitialization(view);
|
||||
|
||||
if(validateOnOpen()) {
|
||||
validate();
|
||||
}//if//
|
||||
|
||||
remoteViewContext.decrementMessageHoldCount();
|
||||
|
||||
return null;
|
||||
}//run()//
|
||||
});
|
||||
}//internalOpen()//
|
||||
/**
|
||||
* Opens a partial view given the view's parent view component reference and an optional view context.
|
||||
* <p>This is intended only to be called by the containing view when it requires the sub-component to be created.</p>
|
||||
* <p><b>Warning: This method is not thread safe. It is assumed that the view will be owned by one parent component and will be opened only by that component.</b></p>
|
||||
* @param parent The non-null parent view component passed by the view.
|
||||
* @param context The context for the view. The actual value is dependant upon the view framework being used. In a remote view this value may be the session context for example.
|
||||
* @return A view associated with this view controller that is a part of another view.
|
||||
*/
|
||||
public IView openPartial(IView parent, Object context) {
|
||||
IView view = null;
|
||||
|
||||
if(parent == null) {
|
||||
throw new RuntimeException("Error: Cannot open a partial view without a parent view part.");
|
||||
}//if//
|
||||
else if(context != getContext()) {
|
||||
throw new RuntimeException("Error: Invalid view context. This view was initialized with a different context than it is being used under.");
|
||||
}//else if//
|
||||
|
||||
if(getView() == null) {
|
||||
setOptions(0);
|
||||
setParentComponent(parent);
|
||||
setView(view = createView());
|
||||
view.addMessageHold();
|
||||
view.suspendLayouts();
|
||||
getDecorationManager().initialize(getView());
|
||||
isOpen(true);
|
||||
view.setController(this);
|
||||
view.viewInitializeAll();
|
||||
view.resumeLayouts();
|
||||
view.layout();
|
||||
//view.pack();
|
||||
//postOpenInitialization(view);
|
||||
view.removeMessageHold();
|
||||
validate();
|
||||
}//if//
|
||||
|
||||
return view;
|
||||
}//openPartialView()//
|
||||
/**
|
||||
* Executes the runnable on the view's event thread.
|
||||
* <p>It is necessary to run most view related operations on the view thread since all views and all associated model and controller objects are not thread safe.</p>
|
||||
*/
|
||||
public final Object execute(IRunnable runnable) {
|
||||
return getRemoteViewContext().execute(runnable);
|
||||
}//execute()//
|
||||
/**
|
||||
* Executes the runnable on the view's event thread and returns immediatly.
|
||||
* <p>It is necessary to run most view related operations on the view thread since all views and all associated model and controller objects are not thread safe.</p>
|
||||
*/
|
||||
public final void executeAsync(IRunnable runnable) {
|
||||
getRemoteViewContext().executeAsync(runnable);
|
||||
}//executeAsync()//
|
||||
/**
|
||||
* Gets the display metadata which describes the client view system such as information about the display locations and sizes.
|
||||
* @return The metadata describing the client view system.
|
||||
*/
|
||||
public ViewSystemMetadata getViewSystemMetadata() {
|
||||
return getRemoteViewContext().getSessionContext().getViewSystemMetadata();
|
||||
}//getViewSystemMetadata()//
|
||||
}//RemoteViewController//
|
||||
@@ -0,0 +1,492 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import com.common.debug.Debug;
|
||||
import com.common.orb.Orb;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.IList;
|
||||
import com.common.util.LiteHashMap;
|
||||
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.exception.TransactionException;
|
||||
import com.foundation.transaction.ReadTransaction;
|
||||
import com.foundation.transaction.Transaction;
|
||||
import com.foundation.transaction.TransactionContextHolder;
|
||||
import com.foundation.transaction.TransactionErrorInfo;
|
||||
import com.foundation.util.HashMapAdapter;
|
||||
import com.foundation.util.IKeyExtractor;
|
||||
import com.foundation.util.IManagedCollection;
|
||||
import com.foundation.util.IManagedList;
|
||||
import com.foundation.util.ManagedList;
|
||||
import com.foundation.metadata.Attribute;
|
||||
|
||||
/**
|
||||
* Manages models on a single process and maintains a list of all models at all times.
|
||||
* This is the simplest of model managers and should be used for small collections of models.
|
||||
*
|
||||
* TODO: *** Ensure that modifying the list via a reflection of it does properly reset the list's change tracking such that a manual add that fails doesn't undo reflection synchronization changes. ***
|
||||
*
|
||||
*/
|
||||
public class SingleListModelManager extends ModelManager implements ISingleListModelManager {
|
||||
public static final Attribute MODELS = registerCollection(SingleListModelManager.class, "models", AO_REFERENCED | AO_LAZY);
|
||||
public static final Attribute MODELS_BY_KEY = registerAttribute(SingleListModelManager.class, "modelsByKey", AO_REFERENCED | AO_LAZY);
|
||||
|
||||
protected class ModelListManager extends ModelController.ModelListManager {
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAdd(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canAdd(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canAdd(value);
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
result &= super.canAdd(managed, value, context);
|
||||
|
||||
return result;
|
||||
}//canAdd()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, IManagedCollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED && values.getSize() > 0) {
|
||||
for(IIterator iterator = values.iterator(); result && iterator.hasNext(); ) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canAdd(iterator.next());
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//TODO: May wish to override the default functionality to use bulk query's and find the super set of added attributes, or group by similar attribute sets.
|
||||
result &= super.canAdd(managed, values, context);
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canAddAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canAddAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED && values.length > 0) {
|
||||
for(int index = 0; result && index < values.length; index++) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canAdd(values[index]);
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//TODO: May wish to override the default functionality to use bulk query's and find the super set of added attributes, or group by similar attribute sets.
|
||||
result &= super.canAdd(managed, values, context);
|
||||
|
||||
return result;
|
||||
}//canAddAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemove(com.common.util.IManagedCollection, java.lang.Object, byte)
|
||||
*/
|
||||
public boolean canRemove(IManagedCollection managed, Object value, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canRemove(value);
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//if//
|
||||
|
||||
result &= super.canRemove(managed, value, context);
|
||||
|
||||
return result;
|
||||
}//canRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, com.common.util.IManagedCollection, byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, IManagedCollection values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED && values.getSize() > 0) {
|
||||
for(IIterator iterator = values.iterator(); result && iterator.hasNext(); ) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canRemove(iterator.next());
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//TODO: May wish to override the default functionality to use bulk query's and find the super set of query attributes, or group by similar attribute sets.
|
||||
result &= super.canRemove(managed, values, context);
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.util.CollectionManager#canRemoveAll(com.common.util.IManagedCollection, java.lang.Object[], byte)
|
||||
*/
|
||||
public boolean canRemoveAll(IManagedCollection managed, Object[] values, byte context) {
|
||||
boolean result = true;
|
||||
|
||||
if(context == CONTEXT_UNTRUSTED && values.length > 0) {
|
||||
for(int index = 0; result && index < values.length; index++) {
|
||||
ReflectionResult reflectionResult = SingleListModelManager.this.canRemove(values[index]);
|
||||
|
||||
if(reflectionResult != null) {
|
||||
result = false;
|
||||
managed.setErrorInfo(reflectionResult);
|
||||
}//if//
|
||||
}//for//
|
||||
}//if//
|
||||
|
||||
//TODO: May wish to override the default functionality to use bulk query's and find the super set of query attributes, or group by similar attribute sets.
|
||||
result &= super.canRemove(managed, values, context);
|
||||
|
||||
return result;
|
||||
}//canRemoveAll()//
|
||||
}//ModelListManager//
|
||||
/**
|
||||
* SingleListModelManager constructor.
|
||||
* @param type The type of models being managed.
|
||||
* @param sync Whether to keep the models in sync with other managers in other processes.
|
||||
*/
|
||||
public SingleListModelManager(Class type, boolean sync) {
|
||||
super(type, sync);
|
||||
}//SingleListModelManager()//
|
||||
/**
|
||||
* Called prior to adding a value to the collection. Allows for customization of the add process.
|
||||
* @param value The value about to be added.
|
||||
* @return Result object if the operation should fail. The result should be null if the value CAN be added.
|
||||
*/
|
||||
protected ReflectionResult canAdd(Object value) {
|
||||
//TODO: Override to return a failure result if the object can't be added for what ever reason (generally a constraint error in which case return a ReflectionConstraintError.
|
||||
return null;
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Called prior to adding a value to the collection. Allows for customization of the add process.
|
||||
* @param value The value about to be added.
|
||||
* @return Result object if the operation should fail. The result should be null if the value CAN be added.
|
||||
*/
|
||||
protected ReflectionResult canAdd(IList values) {
|
||||
//TODO: Override to return a failure result if the object can't be added for what ever reason (generally a constraint error in which case return a ReflectionConstraintError.
|
||||
return null;
|
||||
}//canAdd()//
|
||||
/**
|
||||
* Called prior to removing a value to the collection. Allows for customization of the remove process.
|
||||
* @param value The value about to be removed.
|
||||
* @return Result object if the operation should fail. The result should be null if the value CAN be removed.
|
||||
*/
|
||||
protected ReflectionResult canRemove(Object value) {
|
||||
//TODO: Override to return a failure result if the object can't be removed for what ever reason (generally a constraint error in which case return a ReflectionConstraintError.
|
||||
return null;
|
||||
}//canRemove()//
|
||||
/**
|
||||
* Called prior to removing a value to the collection. Allows for customization of the remove process.
|
||||
* @param value The value about to be removed.
|
||||
* @return Result object if the operation should fail. The result should be null if the value CAN be removed.
|
||||
*/
|
||||
protected ReflectionResult canRemove(IList values) {
|
||||
//TODO: Override to return a failure result if the object can't be removed for what ever reason (generally a constraint error in which case return a ReflectionConstraintError.
|
||||
return null;
|
||||
}//canRemove()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#addEntity(com.foundation.common.IEntity, boolean)
|
||||
*/
|
||||
public ReflectionResult addEntity(IEntity entity, boolean returnAddition) {
|
||||
ReflectionResult result = null;
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if((result = canAdd(entity)) == null) {
|
||||
if(getModels().add(entity) != -1) {
|
||||
if(returnAddition) {
|
||||
result = new ReflectionSuccess(entity);
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
|
||||
//Clear any change tracking so we don't accidentially reverse the changes in the future.//
|
||||
getModels().resetChangeTracking();
|
||||
}//if//
|
||||
else {
|
||||
//Reverse the changes to the collection.//
|
||||
getModels().reverseObjectChanges();
|
||||
//Convert this error info into a reflection result.//
|
||||
result = ReflectionResult.createResult(getModels().getErrorInfo());
|
||||
}//else//
|
||||
}//if//
|
||||
}//try//
|
||||
catch(TransactionException e) {
|
||||
result = e.getErrorInfo().getTransactionErrorCode() != Transaction.ERROR_NONE ? (ReflectionResult) new ReflectionTransactionError(e.getErrorInfo().getTransactionErrorCode()) : (ReflectionResult) new ReflectionModelError(e.getErrorInfo().getModelErrorCode());
|
||||
}//catch//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//addEntity()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#addEntities(com.common.util.IList, boolean)
|
||||
*/
|
||||
public ReflectionResult addEntities(IList entities, boolean returnAdditions) {
|
||||
ReflectionResult result = null;
|
||||
LiteList results = new LiteList(entities.getSize());
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if((result = canAdd(entities)) == null) {
|
||||
if(getModels().addAll(entities)) {
|
||||
if(returnAdditions) {
|
||||
results.addAll(entities);
|
||||
result = new ReflectionSuccess(results);
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
|
||||
//Clear any change tracking so we don't accidentially reverse the changes in the future.//
|
||||
getModels().resetChangeTracking();
|
||||
}//if//
|
||||
else {
|
||||
//Reverse the changes to the collection.//
|
||||
getModels().reverseObjectChanges();
|
||||
//Convert this error info into a reflection result.//
|
||||
result = ReflectionResult.createResult(getModels().getErrorInfo());
|
||||
}//else//
|
||||
}//if//
|
||||
}//try//
|
||||
catch(TransactionException e) {
|
||||
result = e.getErrorInfo().getTransactionErrorCode() != Transaction.ERROR_NONE ? (ReflectionResult) new ReflectionTransactionError(e.getErrorInfo().getTransactionErrorCode()) : (ReflectionResult) new ReflectionModelError(e.getErrorInfo().getModelErrorCode());
|
||||
}//catch//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//addEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#removeEntity(com.foundation.common.IEntity)
|
||||
*/
|
||||
public ReflectionResult removeEntity(IEntity entity) {
|
||||
ReflectionResult result = null;
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if((result = canRemove(entity)) == null) {
|
||||
if(getModels().remove(entity)) {
|
||||
result = new ReflectionSuccess(null);
|
||||
//Clear any change tracking so we don't accidentially reverse the changes in the future.//
|
||||
getModels().resetChangeTracking();
|
||||
}//if//
|
||||
else {
|
||||
//Reverse the changes to the collection.//
|
||||
getModels().reverseObjectChanges();
|
||||
//Convert this error info into a reflection result.//
|
||||
result = ReflectionResult.createResult(getModels().getErrorInfo());
|
||||
}//else//
|
||||
}//if//
|
||||
}//try//
|
||||
catch(TransactionException e) {
|
||||
result = e.getErrorInfo().getTransactionErrorCode() != Transaction.ERROR_NONE ? (ReflectionResult) new ReflectionTransactionError(e.getErrorInfo().getTransactionErrorCode()) : (ReflectionResult) new ReflectionModelError(e.getErrorInfo().getModelErrorCode());
|
||||
}//catch//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//removeEntity()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#removeEntities(com.common.util.IList)
|
||||
*/
|
||||
public ReflectionResult removeEntities(IList entities) {
|
||||
ReflectionResult result = null;
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if((result = canRemove(entities)) == null) {
|
||||
if(getModels().removeAll(entities)) {
|
||||
result = new ReflectionSuccess(null);
|
||||
//Clear any change tracking so we don't accidentially reverse the changes in the future.//
|
||||
getModels().resetChangeTracking();
|
||||
}//if//
|
||||
else {
|
||||
//Reverse the changes to the collection.//
|
||||
getModels().reverseObjectChanges();
|
||||
//Convert this error info into a reflection result.//
|
||||
result = ReflectionResult.createResult(getModels().getErrorInfo());
|
||||
}//else//
|
||||
}//if//
|
||||
}//try//
|
||||
catch(TransactionException e) {
|
||||
result = e.getErrorInfo().getTransactionErrorCode() != Transaction.ERROR_NONE ? (ReflectionResult) new ReflectionTransactionError(e.getErrorInfo().getTransactionErrorCode()) : (ReflectionResult) new ReflectionModelError(e.getErrorInfo().getModelErrorCode());
|
||||
}//catch//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//removeEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#getEntities()
|
||||
*/
|
||||
public ReflectionResult getEntities() {
|
||||
return new ReflectionSuccess(getModels());
|
||||
}//getEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#findEntities(java.lang.Object[])
|
||||
*/
|
||||
public ReflectionResult findEntities(Object[] keys) {
|
||||
ReflectionResult result = null;
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
IManagedList list = new ManagedList(keys.length);
|
||||
LiteHashMap map = getModelsByKey();
|
||||
|
||||
for(int index = 0; index < keys.length; index++) {
|
||||
IEntity next = (IEntity) map.get(keys[index]);
|
||||
|
||||
if(next != null) {
|
||||
list.add(next);
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
list.resetChangeTracking();
|
||||
result = new ReflectionSuccess(list);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//getEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleListModelManager#findEntities(com.foundation.transaction.ReadTransaction)
|
||||
*/
|
||||
public ReflectionResult findEntities(ReadTransaction transaction) {
|
||||
ReflectionResult result = null;
|
||||
|
||||
try {
|
||||
Object queryResult = getTransactionService().process(transaction, false);
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if(queryResult instanceof ICollection) {
|
||||
ICollection queryList = (ICollection) queryResult;
|
||||
Object[] keys = new Object[queryList.getSize()];
|
||||
int index = 0;
|
||||
IManagedList list = new ManagedList(keys.length);
|
||||
LiteHashMap map = getModelsByKey();
|
||||
|
||||
//Generate the keys from the query results.//
|
||||
for(IIterator iterator = queryList.iterator(); iterator.hasNext(); index++) {
|
||||
keys[index] = ((IEntity) iterator.next()).entityGetKey();
|
||||
}//for//
|
||||
|
||||
//Search for shared models with the given keys.//
|
||||
for(index = 0; index < keys.length; index++) {
|
||||
IEntity next = (IEntity) map.get(keys[index]);
|
||||
|
||||
if(next != null) {
|
||||
list.add(next);
|
||||
}//if//
|
||||
}//for//
|
||||
|
||||
list.resetChangeTracking();
|
||||
result = new ReflectionSuccess(list);
|
||||
}//if//
|
||||
else if(queryResult instanceof IEntity) {
|
||||
Object key = ((IEntity) queryResult).entityGetKey();
|
||||
|
||||
if(key != null) {
|
||||
result = new ReflectionSuccess((IEntity) getModelsByKey().get(key));
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionModelError(IEntity.MODEL_ERROR_KEY_CREATION_FAILED);
|
||||
}//else//
|
||||
}//else//
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
result = new ReflectionTransactionError(transaction.getErrorCode());
|
||||
}//catch//
|
||||
|
||||
return result;
|
||||
}//getEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.common.Entity#lazyLoadAttribute(com.foundation.metadata.Attribute)
|
||||
*/
|
||||
protected Object lazyLoadAttribute(Attribute attribute) {
|
||||
Object result = null;
|
||||
|
||||
if(attribute == MODELS) {
|
||||
try {
|
||||
IManagedList models = new ManagedList(new ModelListManager(), 100);
|
||||
Entity query = (Entity) getType().newInstance();
|
||||
|
||||
if(query.isObjectRepositoryBound()) {
|
||||
result = query.getTransactionService().readMany(query, models);
|
||||
}//if//
|
||||
else {
|
||||
result = models;
|
||||
}//else//
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
}//if//
|
||||
else if(attribute == MODELS_BY_KEY) {
|
||||
result = new HashMapAdapter(getModels(), new IKeyExtractor() {
|
||||
public Object getKey(Object value) {
|
||||
return ((IEntity) value).entityGetKey();
|
||||
}//getKey()//
|
||||
});
|
||||
}//else if//
|
||||
else {
|
||||
result = super.lazyLoadAttribute(attribute);
|
||||
}//else//
|
||||
|
||||
return result;
|
||||
}//lazyLoadAttribute()//
|
||||
/**
|
||||
* Gets the collection of all models.
|
||||
* @return The models.
|
||||
*/
|
||||
private IManagedList getModels() {
|
||||
return (IManagedList) getAttributeValue(MODELS);
|
||||
}//getModels()//
|
||||
/**
|
||||
* Gets the modelsByKey value.
|
||||
* @return The modelsByKey value.
|
||||
*/
|
||||
private LiteHashMap getModelsByKey() {
|
||||
return (LiteHashMap) getAttributeValue(MODELS_BY_KEY);
|
||||
}//getModelsByKey()//
|
||||
}//SingleListModelManager//
|
||||
@@ -0,0 +1,402 @@
|
||||
package com.foundation.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
import com.common.comparison.Comparator;
|
||||
import com.common.comparison.IComparator;
|
||||
import com.common.debug.Debug;
|
||||
import com.common.orb.Orb;
|
||||
import com.common.util.ICollection;
|
||||
import com.common.util.IIterator;
|
||||
import com.common.util.IList;
|
||||
import com.common.util.LiteList;
|
||||
import com.common.util.SoftLiteHashSet;
|
||||
import com.foundation.attribute.IReflectable;
|
||||
import com.foundation.common.CompositeEntityKey;
|
||||
import com.foundation.common.Entity;
|
||||
import com.foundation.common.IEntity;
|
||||
import com.foundation.metadata.MetadataService;
|
||||
import com.foundation.metadata.TypeMetadata;
|
||||
import com.foundation.transaction.ReadTransaction;
|
||||
import com.foundation.transaction.TransactionErrorInfo;
|
||||
import com.foundation.util.IManagedList;
|
||||
import com.foundation.util.ManagedList;
|
||||
import com.foundation.util.SoftHashMap;
|
||||
|
||||
/**
|
||||
* Manages models on a single process and maintains a map of models currently loaded into memory.
|
||||
* This should be used for large collections of shared models where a small number will be loaded at any given time.
|
||||
*/
|
||||
public class SingleMappedModelManager extends ModelManager implements ISingleMappedModelManager {
|
||||
/** The set of models indexed using the model's hashCode() and equals(Object) methods. The set is soft such that values are GC'd as needed if there isn't a hard reference (such as a proxy to it held by a remote process). */
|
||||
private SoftLiteHashSet set = new SoftLiteHashSet(1000, SoftLiteHashSet.DEFAULT_LOAD_FACTOR, new IComparator() {
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}//writeExternal()//
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}//readExternal()//
|
||||
public int hash(Object value) {
|
||||
return value == null ? 0 : value instanceof IEntity ? ((IEntity) value).entityGetKey().hashCode() : value.hashCode();
|
||||
}//hash()//
|
||||
public int compare(Object value1, Object value2) {
|
||||
return (value1 instanceof IEntity && value2 instanceof IEntity ? value1.equals(value2) : value1 instanceof IEntity || value2 instanceof IEntity ? (value1 instanceof IEntity ? value1.equals(value2) : value2.equals(value1)) : Comparator.equals(value1, value2)) ? Comparator.EQUAL : Comparator.NOT_EQUAL;
|
||||
}//compare()//
|
||||
}, SoftLiteHashSet.STYLE_NO_DUPLICATES);
|
||||
/** The cache of the type metadata for the class of model managed. */
|
||||
private TypeMetadata metadata = null;
|
||||
/**
|
||||
* SingleMappedModelManager constructor.
|
||||
* @param type The type of models being managed.
|
||||
* @param sync Whether to keep the models in sync with other managers in other processes.
|
||||
*/
|
||||
public SingleMappedModelManager(Class type, boolean sync) {
|
||||
super(type, sync);
|
||||
metadata = MetadataService.getSingleton().getTypeMetadata(type);
|
||||
}//SingleMappedModelManager()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#addEntities(com.common.util.IList, boolean)
|
||||
*/
|
||||
public ReflectionResult addEntities(IList entities, boolean returnAddition) {
|
||||
ReflectionResult result;
|
||||
IList results = new LiteList(entities.getSize());
|
||||
|
||||
//Add each entity to the repository.//
|
||||
for(int index = 0, size = entities.getSize(); index < size; index++) {
|
||||
Entity entity = (Entity) entities.get(index);
|
||||
TransactionErrorInfo queryResult = entity.entityUpdate();
|
||||
|
||||
if(queryResult == null) {
|
||||
results.add(entity);
|
||||
}//if//
|
||||
else {
|
||||
//TODO: Detect a problem with a repository constraint and report it. This will require some changes to the structure here - to allow both successful and failed results. Perhaps return an array of results?
|
||||
//result = ReflectionResult.createResult(queryResult);
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
if(results.getSize() > 0) {
|
||||
lock(this);
|
||||
|
||||
//Ensure each result is in the map.//
|
||||
try {
|
||||
for(int index = 0, size = results.getSize(); index < size; index++) {
|
||||
Entity entity = (Entity) results.get(index);
|
||||
|
||||
//map.put(metadata.getKeyExtractor().getKey(entity), entity);//
|
||||
if(set.add(entity) == -1) {
|
||||
Debug.log(new RuntimeException("Shouldn't ever get here. The entity's hashCode() or equals(Object) method may be broken or undefined."));
|
||||
}//if//
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
result = new ReflectionSuccess(results);
|
||||
|
||||
return result;
|
||||
}//addEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#addEntity(com.foundation.common.IEntity, boolean)
|
||||
*/
|
||||
public ReflectionResult addEntity(IEntity entity, boolean returnAddition) {
|
||||
IReflectable result = null;
|
||||
TransactionErrorInfo queryResult = entity.entityUpdate();
|
||||
|
||||
if(queryResult == null) {
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if(set.add(entity) == -1) {
|
||||
Debug.log(new RuntimeException("Shouldn't ever get here. The entity's hashCode() or equals(Object) method may be broken or undefined."));
|
||||
}//if//
|
||||
|
||||
result = entity;
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//if//
|
||||
|
||||
return queryResult == null ? new ReflectionSuccess(result) : ReflectionResult.createResult(queryResult);
|
||||
}//addEntity()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#findEntities(java.lang.Object[])
|
||||
*/
|
||||
public ReflectionResult findEntities(Object[] keys) {
|
||||
ReflectionResult result;
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if(keys != null) {
|
||||
LiteList missing = new LiteList(keys.length);
|
||||
IManagedList results = new ManagedList(keys.length);
|
||||
|
||||
//Locate the entities already in memory, and save those keys not in memory for locating later.//
|
||||
for(int index = 0; index < keys.length; index++) {
|
||||
IEntity found = (IEntity) set.get(keys[index]);
|
||||
|
||||
if(found != null) {
|
||||
results.add(found);
|
||||
}//if//
|
||||
else {
|
||||
missing.add(keys[index]);
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
//Read the missing entities from the repository and pull them into memory as shared objects.//
|
||||
for(int index = 0; index < missing.getSize(); index++) {
|
||||
Object nextKey = missing.get(index);
|
||||
IEntity instance = (IEntity) metadata.getTypeClass().newInstance();
|
||||
|
||||
//Set the key values from the key.//
|
||||
instance.entitySetKey(nextKey);
|
||||
|
||||
//Read the entity from the repository and place it in the collections.//
|
||||
if(getTransactionService().readSingle(instance, true) != null) {
|
||||
set.add(instance);
|
||||
results.add(instance);
|
||||
}//if//
|
||||
else {
|
||||
Debug.log(new RuntimeException("Failed to read the object from the repository given the object's key."));
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
results.resetChangeTracking();
|
||||
result = new ReflectionSuccess(results);
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
}//try//
|
||||
catch(InstantiationException e) {
|
||||
Debug.log("Failed to create a new instance due to an uncaught exception in the default constructor.", e);
|
||||
result = new ReflectionModelError();
|
||||
}//catch//
|
||||
catch(IllegalAccessException e) {
|
||||
Debug.log("Every entity must have a public default constructor to allow the framework access to creating new instances.", e);
|
||||
result = new ReflectionModelError();
|
||||
}//catch//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return result;
|
||||
}//findEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#findEntities(com.foundation.transaction.ReadTransaction)
|
||||
*/
|
||||
public ReflectionResult findEntities(ReadTransaction transaction) {
|
||||
ReflectionResult result;
|
||||
|
||||
try {
|
||||
Object queryResult = getTransactionService().process(transaction, false);
|
||||
|
||||
if(queryResult != null) {
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
if(queryResult instanceof ICollection) {
|
||||
ICollection queryList = (ICollection) queryResult;
|
||||
IManagedList results = new ManagedList(queryList.getSize());
|
||||
|
||||
//Iterate over each result and either place it in the map, or if it already exists in the map then replace it in the result set.//
|
||||
for(IIterator iterator = queryList.iterator(); iterator.hasNext(); ) {
|
||||
IEntity next = (IEntity) iterator.next();
|
||||
Object key = next.entityGetKey();
|
||||
IEntity mapped;
|
||||
|
||||
if(key == null) {
|
||||
Debug.log(new RuntimeException("The class " + next.getClass().getName() + " must identify one or more attributes as being KEY attributes by adding AO_KEY to the attribute definition's options. Example: public static final Attribute ID = registerAttribute(User.class, \"id\", AO_KEY);"));
|
||||
}//if//
|
||||
|
||||
mapped = (IEntity) set.get(key);
|
||||
|
||||
if(mapped != null) {
|
||||
results.add(mapped);
|
||||
}//if//
|
||||
else {
|
||||
set.add(next);
|
||||
results.add(next);
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
results.resetChangeTracking();
|
||||
result = new ReflectionSuccess(results);
|
||||
}//if//
|
||||
else if(queryResult instanceof IEntity) {
|
||||
Object key = ((IEntity) queryResult).entityGetKey();
|
||||
IEntity mapped = (IEntity) set.get(key);
|
||||
|
||||
if(mapped != null) {
|
||||
result = new ReflectionSuccess(mapped);
|
||||
}//if//
|
||||
else {
|
||||
set.add(queryResult);
|
||||
result = new ReflectionSuccess(queryResult);
|
||||
}//else//
|
||||
}//else if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
}//try//
|
||||
catch(Throwable e) {
|
||||
result = new ReflectionTransactionError(transaction.getErrorCode());
|
||||
}//catch//
|
||||
|
||||
return result;
|
||||
}//findEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#findEntities(com.foundation.common.IEntity)
|
||||
*/
|
||||
public ReflectionResult findEntities(IEntity query) {
|
||||
ReflectionResult result;
|
||||
IList results;
|
||||
|
||||
results = (LiteList) query.getTransactionService().readMany(query, new LiteList(100, 1000));
|
||||
|
||||
if(results != null) {
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
//Iterate over each result and either place it in the map, or if it already exists in the map then replace it in the result set.//
|
||||
for(int index = 0, size = results.getSize(); index < size; index++) {
|
||||
IEntity next = (IEntity) results.get(index);
|
||||
Object key = next.entityGetKey();
|
||||
IEntity mapped;
|
||||
|
||||
if(key == null) {
|
||||
Debug.log(new RuntimeException("The class " + next.getClass().getName() + " must identify one or more attributes as being KEY attributes by adding AO_KEY to the attribute definition's options. Example: public static final Attribute ID = registerAttribute(User.class, \"id\", AO_KEY);"));
|
||||
}//if//
|
||||
|
||||
mapped = (IEntity) set.get(key);
|
||||
|
||||
if(mapped != null) {
|
||||
results.set(index, mapped);
|
||||
}//if//
|
||||
else {
|
||||
/*map.put(key, next);*/
|
||||
set.add(next);
|
||||
results.set(index, next);
|
||||
}//else//
|
||||
}//for//
|
||||
|
||||
result = new ReflectionSuccess(results);
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
|
||||
return result;
|
||||
}//findEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#findEntity(com.foundation.common.IEntity)
|
||||
*/
|
||||
public ReflectionResult findEntity(IEntity query) {
|
||||
ReflectionResult result;
|
||||
IEntity entity;
|
||||
|
||||
//TODO: If the key is already set then just use that.
|
||||
entity = (IEntity) query.getTransactionService().readSingle(query, false);
|
||||
|
||||
if(entity != null) {
|
||||
Object key = entity.entityGetKey();
|
||||
|
||||
if(key == null) {
|
||||
Debug.log(new RuntimeException("The class " + entity.getClass().getName() + " must identify one or more attributes as being KEY attributes by adding AO_KEY to the attribute definition's options. Example: public static final Attribute ID = registerAttribute(User.class, \"id\", AO_KEY);"));
|
||||
}//if//
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
IEntity mapped = (IEntity) set.get(key);
|
||||
|
||||
if(mapped != null) {
|
||||
entity = mapped;
|
||||
result = new ReflectionSuccess(entity);
|
||||
}//if//
|
||||
else {
|
||||
//map.put(key, result);
|
||||
set.add(entity);
|
||||
result = new ReflectionSuccess(entity);
|
||||
}//else//
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
}//if//
|
||||
else {
|
||||
result = new ReflectionSuccess(null);
|
||||
}//else//
|
||||
|
||||
return result;
|
||||
}//findEntity()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#removeEntities(com.common.util.IList)
|
||||
*/
|
||||
public ReflectionResult removeEntities(IList entities) {
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
//Iterate over the entities and remove them one at a time.//
|
||||
for(int index = 0, size = entities.getSize(); index < size; index++) {
|
||||
Object next = entities.get(index);
|
||||
IEntity entity = (IEntity) (Orb.isProxy(next) && Orb.isLocal(next) ? Orb.getLocal(next) : next);
|
||||
Object key = entity.entityGetKey();
|
||||
|
||||
if(key == null) {
|
||||
Debug.log(new RuntimeException("The class " + entity.getClass().getName() + " must identify one or more attributes as being KEY attributes by adding AO_KEY to the attribute definition's options. Example: public static final Attribute ID = registerAttribute(User.class, \"id\", AO_KEY);"));
|
||||
}//if//
|
||||
|
||||
//Note: We don't care if they were in the map, but they should be.//
|
||||
//map.remove(key);
|
||||
set.remove(key);
|
||||
entity.entityDelete();
|
||||
}//for//
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return new ReflectionSuccess(null);
|
||||
}//removeEntities()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.foundation.controller.ISingleMappedModelManager#removeEntity(com.foundation.common.IEntity)
|
||||
*/
|
||||
public ReflectionResult removeEntity(IEntity entity) {
|
||||
Object key = entity.entityGetKey();
|
||||
|
||||
if(key == null) {
|
||||
Debug.log(new RuntimeException("The class " + entity.getClass().getName() + " must identify one or more attributes as being KEY attributes by adding AO_KEY to the attribute definition's options. Example: public static final Attribute ID = registerAttribute(User.class, \"id\", AO_KEY);"));
|
||||
}//if//
|
||||
|
||||
lock(this);
|
||||
|
||||
try {
|
||||
//Note: We don't care if it is in the map, but it should be.//
|
||||
//map.remove(key);
|
||||
set.remove(key);
|
||||
((IEntity) entity).entityDelete();
|
||||
}//try//
|
||||
finally {
|
||||
unlock(this);
|
||||
}//finally//
|
||||
|
||||
return new ReflectionSuccess(null);
|
||||
}//removeEntity()//
|
||||
}//SingleMappedModelManager//
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
/**
|
||||
* Thrown by the view controller when the view has been closed.
|
||||
*/
|
||||
public class ViewClosedException extends Exception {
|
||||
/**
|
||||
* ViewClosedException constructor.
|
||||
*/
|
||||
public ViewClosedException() {
|
||||
}//ViewClosedException()//
|
||||
/**
|
||||
* ViewClosedException constructor.
|
||||
* @param message
|
||||
*/
|
||||
public ViewClosedException(String message) {
|
||||
super(message);
|
||||
}//ViewClosedException()//
|
||||
/**
|
||||
* ViewClosedException constructor.
|
||||
* @param cause
|
||||
*/
|
||||
public ViewClosedException(Throwable cause) {
|
||||
super(cause);
|
||||
}//ViewClosedException()//
|
||||
/**
|
||||
* ViewClosedException constructor.
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public ViewClosedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}//ViewClosedException()//
|
||||
}//ViewClosedException//
|
||||
95
Foundation/src/com/foundation/controller/ViewController.java
Normal file
95
Foundation/src/com/foundation/controller/ViewController.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2003,2008 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.controller;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import com.common.debug.*;
|
||||
import com.foundation.view.*;
|
||||
import com.foundation.attribute.*;
|
||||
|
||||
/**
|
||||
* The view controller manages the interaction between the view and the model.
|
||||
* Each view controller will control exactly one view or partial view.
|
||||
* A view may be modal or partial in which case the parent view controller will be set.
|
||||
* A view controller having a partial view will not open or close the view directly, but will instead rely on the containing view to open and close the view.
|
||||
*/
|
||||
public abstract class ViewController extends AbstractViewController {
|
||||
/**
|
||||
* ViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
*/
|
||||
public ViewController(IViewContext context) {
|
||||
super(context);
|
||||
}//ViewController()//
|
||||
/**
|
||||
* ViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
*/
|
||||
public ViewController(IViewContext context, ReflectionContext reflectionContext) {
|
||||
super(context, reflectionContext);
|
||||
}//ViewController()//
|
||||
/**
|
||||
* ViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is true by default.
|
||||
*/
|
||||
public ViewController(IViewContext context, boolean validateOnOpen) {
|
||||
super(context, validateOnOpen);
|
||||
}//ViewController()//
|
||||
/**
|
||||
* ViewController constructor.
|
||||
* @param context The context underwhich the view is being created. This context manages the threading, resources, and request handling for the view as well as ties together related views.
|
||||
* @param reflectionContext The reflection context to be used by the view.
|
||||
* @param validateOnOpen Whether the view should perform validation immediately after opening. This is true by default.
|
||||
*/
|
||||
public ViewController(IViewContext context, ReflectionContext reflectionContext, boolean validateOnOpen) {
|
||||
super(context, reflectionContext, validateOnOpen);
|
||||
}//ViewController()//
|
||||
/**
|
||||
* Creates the controller's primary view component.
|
||||
* @return This view controller's new view object.
|
||||
*/
|
||||
protected IView createView() {
|
||||
Class viewClass = getViewClass();
|
||||
IView result = null;
|
||||
|
||||
if(viewClass == null) {
|
||||
Debug.log("Error: getViewClass() must return a valid view class in the view controller " + getClass().getName());
|
||||
}//if//
|
||||
|
||||
try {
|
||||
if(getParentComponent() == null) {
|
||||
Constructor constructor = viewClass.getConstructor(new Class[] {ViewController.class});
|
||||
|
||||
result = (IView) constructor.newInstance(new Object[] {this});
|
||||
}//if//
|
||||
else {
|
||||
Constructor constructor = viewClass.getConstructor(new Class[] {ViewController.class, IView.class});
|
||||
|
||||
result = (IView) constructor.newInstance(new Object[] {this, getParentComponent()});
|
||||
}//else//
|
||||
}//try//
|
||||
catch(NoSuchMethodException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(InvocationTargetException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(InstantiationException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
catch(IllegalAccessException e) {
|
||||
Debug.log(e);
|
||||
}//catch//
|
||||
|
||||
return result;
|
||||
}//createView()//
|
||||
}//ViewController//
|
||||
Reference in New Issue
Block a user