Initial commit from SVN.

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

View File

@@ -0,0 +1,381 @@
/*
* Copyright (c) 2004,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.tcv.server.util;
import com.common.util.*;
import com.common.debug.*;
import com.common.thread.*;
import com.foundation.tcv.view.IAbstractRemoteViewComponent;
import com.foundation.tcv.view.ViewMessage;
import com.foundation.tcv.server.controller.SessionViewController;
import com.foundation.view.IViewRequestHandler;
/**
* Manages interaction with the system of objects in a view.
* The purpose is to ensure single threaded access to all view and view related objects (includes model, controller, and view controllers associated with the view).
* <p>The design is for only one thread (not necessarily a single thread) to interact with view related objects at one time.
* Some round trip calls to the client must be allowed, such as a view synchronize, which may require resulting messages from the client
* to be processed prior to the round trip call completing. In order to accomplish this, the round trip call must yeild access to view
* objects to another thread until the round trip complete message is received from the server, at which time the yeilding thread must
* take over all view access responsibilities and complete its call.</p>
* <p><b>This is the THIN client event loop for SWT.</b></p>
*/
public class EventLoop implements Runnable, IViewRequestHandler, ISingleThreadedContext {
/** The queue that all requests are sent to. Requests made on the event thread are handled immediatly and are never queued. */
private Queue queue = new Queue(5);
/** The thread currently handing requests. */
private Thread queueRunner = null;
/** Whether the loop is running. */
private boolean isRunning = false;
/**
* Maintains request information and handles notification of completion.
*/
private static final class Request implements Runnable {
private IRunnable runnable = null;
private Object returnValue = null;
private boolean requestComplete = false;
/**
* Request constructor.
*/
private Request(IRunnable runnable) {
this.runnable = runnable;
}//Request()//
public synchronized void waitForCompletion() {
while(!requestComplete) {
try {
wait(1000);
}//try//
catch(InterruptedException e) {
Debug.handle(e);
}//catch//
}//while//
}//waitForCompletion()//
public void run() {
try {
if(runnable != null) {
returnValue = runnable.run();
}//if//
else {
//TODO: Remove me.
//returnValue = component.processRequest(requestNumber, value1, value2, value3, value4);
Debug.log(new RuntimeException("Not used any more."));
}//else//
}//try//
catch(Throwable e) {
Debug.log("Failed to complete the processing of a remote server swt view request.", e);
}//catch//
synchronized(this) {
requestComplete = true;
notifyAll();
}//synchronized//
}//run()//
}//Request//
/**
* Encapsulates an event thread which has reliquished its status for a time while it performs some unrelated processing which may take an arbitrary amount of time.
*/
public class EventThread {
/** Whether the held thread is once again the event thread. */
private boolean isEventThread = false;
/** The thread which requested a pause in it being the event thread. */
private Thread eventThread = null;
/**
* EventThread constructor.
*/
public EventThread() {
this.eventThread = Thread.currentThread();
}//EventThread()//
/**
* Requests that the calling thread become the event thread once more.
*/
public void requestResumeEventProcessing() {
processRequest(this);
}//resumeEventProcessing()//
/**
* Waits for the current event thread to make us the event thread.
*/
public void waitToResumeEventProcessing() {
//A little bit of error checking.//
if(eventThread != Thread.currentThread()) {
throw new IllegalArgumentException("Only the former event thread may request it become the event thread again.");
}//if//
//Synchronize so we can wait to be called on.//
synchronized(EventLoop.this) {
//Wait while we have not been called on to become the event thread again.//
while(!isEventThread) {
try {
EventLoop.this.wait(3000);
}//try//
catch(InterruptedException e) {
Debug.handle(e);
}//catch//
}//while//
}//synchronized//
ThreadService.setIsInSingleThreadedContext(EventLoop.this);
}//waitToResumeEventProcessing()//
/**
* Called by the current event thread to yield event processing to the held thread.
* <p>Note: The caller must hold a synch lock on the EventLoop object.</p>
*/
private void notifyEventThread() {
//Let the proper thread know it is now the event thread.//
isEventThread = true;
//Assign the new queue runner to this thread.//
queueRunner = eventThread;
//Notify all waiting threads.//
EventLoop.this.notifyAll();
}//notifyEventThread()//
}//EventThread//
/**
* EventLoop constructor.
*/
public EventLoop() {
}//EventLoop()//
/**
* Runs the request handler.
* <p>The handler is designed to run until there are no more requests, then it will quit. When new requests arrive they will start the handler if it is not already running.</p>
*/
public void run() {
boolean stop = false;
boolean isEventThread = true;
ThreadService.setIsInSingleThreadedContext(this);
isRunning = true;
while((isEventThread) && (!stop)) {
try {
Object next = null;
do {
next = null;
//Get the next runnable.//
synchronized(this) {
if(queue.getSize() > 0) {
//Check the message queue.//
next = queue.dequeue();
}//if//
}//synchronized//
if(next != null) {
if(next instanceof EventThread) {
EventThread eventThread = (EventThread) next;
synchronized(this) {
//Notify the event thread that it may now take over as the event thread again.//
eventThread.notifyEventThread();
}//synchronized//
//Set the flag to immediatly quit processing messages as the event thread.//
isEventThread = false;
}//if//
else if(next instanceof ViewMessage) {
ViewMessage message = (ViewMessage) next;
SessionViewController sessionViewController = (SessionViewController) message.getExtra();
IAbstractRemoteViewComponent component = (IAbstractRemoteViewComponent) sessionViewController.getComponent(message.getControlNumber());
Object result = null;
if(message.isTwoWayMessage()) {
sessionViewController.processingTwoWayStarted();
}//if//
//Process the message and retreive the result.//
result = component.processMessage(message);
if(message.isTwoWayMessage()) {
sessionViewController.processingTwoWayFinished();
//Save the result for the waiting ORB thread.//
message.setResult(result);
}//if//
}//if//
else {
((Runnable) next).run();
}//else//
}//if//
} while((isEventThread) && (!stop) && (next != null));
if((isEventThread) && (!stop)) {
synchronized(this) {
if(queue.getSize() == 0) {
//Wait a very short time to see if new messages are queued or event threads ready to restart. If not then reclaim this thread.//
try {
wait(100);
}//try//
catch(Throwable e) {
Debug.handle(e);
}//catch//
if(queue.getSize() == 0) {
stop = true;
queueRunner = null;
}//if//
}//if//
}//synchronized//
}//if//
}//try//
catch(Throwable e) {
Debug.log(e);
//Keep processing messages so the client might not lock up.//
}//catch//
}//while//
ThreadService.setIsInSingleThreadedContext(null);
isRunning = false;
}//run()//
/**
* Pauses the calling thread such that it is no longer the event thread and may block without affecting the event processing system.
* When the calling thread is ready to resume being the event thread then it must call the returned EventThread object's resumeEventProcessing() method which will block until the calling thread is once again the event thread.
* <p>Warning: The EventThread object should never be passed to another thread since it will corrupt the EventLoop state.</p>
* @return The EventThread instance which is necessary for resuming the mantel of event thread when the thread has finished waiting.
*/
public EventThread pauseEventProcessing() {
EventThread result = new EventThread();
ThreadService.setIsInSingleThreadedContext(this);
synchronized(this) {
//Ensure that all know we are no longer the event thread.//
queueRunner = null;
//If necessary, start another thread to be the event thread.//
if(queue.getSize() != 0) {
queueRunner = ThreadService.run(this, false);
}//if//
}//synchronized//
return result;
}//pauseEventProcessing()//
/**
* Adds the messages to the process queue and if necessary starts a thread to process them in order.
* @param messages The ordered messages to be processed.
* @param waitForResponse Whether to wait for the result of the last message.
* @return The result of the last message, or null.
*/
public void processMessages(SessionViewController sessionViewController, IList messages, boolean waitForResponse) {
//Note: The queue runner thread will never be this thread since this thread is always comming from the ORB.//
synchronized(this) {
IIterator iterator = messages.iterator();
while(iterator.hasNext()) {
ViewMessage next = (ViewMessage) iterator.next();
next.setExtra(sessionViewController);
queue.enqueue(next);
}//while//
if(queueRunner == null) {
//Start the QueueRunner thread.//
queueRunner = ThreadService.run(this, false);
}//if//
}//synchronized//
}//processMessages()//
/**
* Processes a request through the event thread. This is required to access any SWT method due to the design of SWT.
* @param request The object that will be run when the request is processed.
* @param synchronous Whether the thread should block until the request has been processed (should be true if a result is desired).
*/
public void processRequest(final Runnable request, boolean synchronous) {
execute(new IRunnable() {
public Object run() {
request.run();
return null;
}//run()//
}, synchronous);
}//processRequest()//
/**
* Processes a request through the event thread.
* @param request The request to be processed.
*/
private synchronized void processRequest(Runnable request) {
queue.enqueue(request);
if(queueRunner == null) {
//Start the QueueRunner thread.//
queueRunner = ThreadService.run(this, false);
}//if//
}//processRequest()//
/**
* Processes a request through the event thread.
* @param request The request to be processed.
*/
private synchronized void processRequest(EventThread request) {
queue.enqueue(request);
if(queueRunner == null) {
//Start the QueueRunner thread.//
queueRunner = ThreadService.run(this, false);
}//if//
}//processRequest()//
/* (non-Javadoc)
* @see com.foundation.event.IRequestHandler#isRunning()
*/
public boolean isRunning() {
return isRunning;
}//isRunning()//
/* (non-Javadoc)
* @see com.foundation.event.IRequestHandler#isRequestThread()
*/
public boolean isRequestThread() {
Thread currentThread = Thread.currentThread();
//This synchronization is necessary in order to ensure the local processor cache is updated.//
synchronized(this) {
return queueRunner == currentThread;
}//synchronized//
}//isRequestThread()//
/* (non-Javadoc)
* @see com.foundation.event.IRequestHandler#execute(com.common.thread.IRunnable, boolean)
*/
public Object execute(IRunnable runnable, boolean synchronous) {
Object result = null;
boolean isQueueRunner = false;
Thread currentThread = Thread.currentThread();
//This synchronization is necessary in order to ensure the local processor cache is updated.//
synchronized(this) {
isQueueRunner = queueRunner == currentThread;
}//synchronized//
//Make sure we don't have the event thread creating requests since it would deadlock the system.//
if(!isQueueRunner || !synchronous) {
Request request = new Request(runnable);
processRequest(request);
if(synchronous) {
request.waitForCompletion();
result = request.returnValue;
}//if//
}//if//
else {
//The calling thread is the event thread, so there is no need to pass the request through the event thread!.//
result = runnable.run();
}//else//
return result;
}//execute()//
/* (non-Javadoc)
* @see com.foundation.event.IRequestHandler#execute(com.common.thread.IRunnable)
*/
public Object execute(IRunnable runnable) {
return execute(runnable, true);
}//execute()//
/* (non-Javadoc)
* @see com.foundation.event.IRequestHandler#executeAsync(com.common.thread.IRunnable)
*/
public void executeAsync(IRunnable runnable) {
execute(runnable, false);
}//executeAsync()//
}//RequestHandler//