Files
Brainstorm/Foundation/src/com/foundation/controller/RemoteViewController.java
2014-05-30 10:31:51 -07:00

247 lines
9.3 KiB
Java

/*
* 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//