Author: gtrasuk
Date: Mon May 27 01:21:24 2013
New Revision: 1486497
URL: http://svn.apache.org/r1486497
Log:
Can successfully start, stop and restart reggie as a hosted application through
the JMX interface. Can also shut down the container through the JMX interface.
Currently, the container shutdown is not particularly clean - it notifies all
components that shutdown is happening, but doesn't take into account any order
of shutdown, or waiting for apps to close. Currently ends with a
System.exit(0). However, it's probably good enough for many purposes.
Removed:
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/TaskClass.java
Modified:
river/jtsk/skunk/surrogate/nbproject/genfiles.properties
river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
river/jtsk/skunk/surrogate/src/org/apache/river/container/ShutdownListener.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/codebase/ClassServer.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/ApplicationEnvironment.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceDeployer.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StatusEvents.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/PlainStateMachineExecutor.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/BasicWorkManager.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/ContextualWorkManager.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkManager.java
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkingContext.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedMachineTest.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSM.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSMInterface.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/PlainMachineExecutorTest.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/BasicWorkManagerTest.java
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/ContextualWorkManagerTest.java
river/jtsk/skunk/surrogate/testfiles/testroot/profile/default/config.xml
Modified: river/jtsk/skunk/surrogate/nbproject/genfiles.properties
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/nbproject/genfiles.properties?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/nbproject/genfiles.properties (original)
+++ river/jtsk/skunk/surrogate/nbproject/genfiles.properties Mon May 27
01:21:24 2013
@@ -5,7 +5,7 @@ [email protected]
# Do not edit this file. You may delete it but then the IDE will never
regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=8f1c53be
nbproject/build-impl.xml.script.CRC32=4f16d38a
-nbproject/[email protected]
+nbproject/[email protected]
nbproject/management-build-impl.xml.data.CRC32=318d2fde
nbproject/management-build-impl.xml.script.CRC32=630dcf8f
nbproject/[email protected]
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
(original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
Mon May 27 01:21:24 2013
@@ -74,6 +74,8 @@ public class MessageNames {
CREATED_THREAD="createdThread",
DUPLICATE_CLASSPATH="duplicateClasspath",
EXCEPTION_THROWN="exceptionThrown",
+ EXCEPTION_WHILE_STOPPING="exceptionWhileStopping",
+ FAILED_CLEAN_SHUTDOWN="failedCleanShutdown",
FAILED_DEPLOY_SERVICE="failedDeployService",
FAILED_READ_PROPERTIES="failedReadProperties",
FOUND_NO_SERVICE_ARCHIVES="foundNoServiceArchives",
@@ -89,6 +91,7 @@ public class MessageNames {
INJECT="inject",
MISSING_PROPERTY_ENTRY="missingPropertyEntry",
MISSING_SPECIAL_VALUE="missingSpecialValue",
+ N_THREADS_LEFT="nThreadsLeft",
NO_DEPLOYMENT_DIRECTORY="noDeploymentDirectory",
PARENT_CLASS_LOADER_IS="parentClassLoaderIs",
POLICY_DECLINED="policyDeclined",
@@ -106,6 +109,7 @@ public class MessageNames {
SECURITY_INIT_WRONG_POLICY="securityInitializationWrongPolicy",
SERVICE_PARENT_CLASSLOADER_IS="serviceParentClassloaderIs",
SHOW_COMMAND_LINE_ARGUMENTS="showCommandLineArguments",
+ SHUTDOWN_FAILED="shutdownFailed",
SHUTDOWN_METHOD_HAS_PARAMETERS="shutdownMethodHasParameters",
SHUTDOWN_METHOD_NOT_VOID="shutdownMethodIsntVoid",
STARTER_SERVICE_DEPLOYER_FAILED_INIT="starterServiceDeployerFailedInit",
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
Mon May 27 01:21:24 2013
@@ -53,6 +53,8 @@ contextItem=Context key {0} refers to ''
createdThread=Created thread named ''{0}'' in thread group ''{1}''.
duplicateClasspath=Duplicate class path entry for id ''{0}''.
exceptionThrown=Exception thrown:\n{0}
+exceptionWhileStopping=Exception thrown during stop operation:\n{0}
+failedCleanShutdown=Application ''{0}'' failed to shutdown cleanly, so we're
interrupting it.
failedDeployService=Deployment of service archive at ''{0}'' failed.
failedReadProperties=Failed to read one or more properties files.
foundNoServiceArchives=Found no service archives for deployment dir ''{0}''.
@@ -73,6 +75,7 @@ missingSpecialValue=Deployer configurati
''{1}'' to be created with value expression ''{2}'', but the value resolves to
null.\n\
This is unlikely to be the desired behavior, so check to see if you''re
missing\n\
value ''{2}'' in other configurations or command line parameters.
+nThreadsLeft=Application ''{0}'' has {1} threads currently running.
noDeploymentDirectory=No deployment directory called {0} found in {1}; \
skipping deployment.
parentClassLoaderIs=Parent class loader is {0}.
@@ -91,6 +94,7 @@ securityInitializationSucceeded=Security
securityInitializationWrongPolicy=After security manager setup, the wrong
policy is installed: {0}.
serviceParentClassloaderIs=Parent of service classloader is {0}.
showCommandLineArguments=Command line arguments were: {0}.
+shutdownFailed=Application ''{0}'' has failed to shut down - there are threads
still running.
shutdownMethodHasParameters=A method flagged as @Shutdown must take no
parameters. \
Method ''{1}'' on class ''{0}'' has parameters.
shutdownMethodIsntVoid=A method flagged as @Shutdown must be void return type.
\
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/ShutdownListener.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShutdownListener.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/ShutdownListener.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/ShutdownListener.java
Mon May 27 01:21:24 2013
@@ -34,6 +34,7 @@ public class ShutdownListener implements
try {
wait();
context.shutDown();
+ System.exit(0);
} catch (InterruptedException ex) {
Logger.getLogger(ShutdownListener.class.getName()).log(Level.SEVERE, null, ex);
}
Modified: river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
(original)
+++ river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java Mon
May 27 01:21:24 2013
@@ -44,6 +44,7 @@ public class Strings {
DOT_PROPERTIES=".properties",
DOT_SSAR=".ssar",
EMPTY = "",
+ GET_ADMIN="getAdmin",
FILE_UTILITY="fileUtility",
INIT_COMPLETE="initComplete",
JAR="jar",
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/codebase/ClassServer.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/codebase/ClassServer.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/codebase/ClassServer.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/codebase/ClassServer.java
Mon May 27 01:21:24 2013
@@ -42,7 +42,6 @@ import org.apache.river.container.Inject
import org.apache.river.container.LocalizedRuntimeException;
import org.apache.river.container.MessageNames;
import org.apache.river.container.Shutdown;
-import org.apache.river.container.work.TaskClass;
import org.apache.river.container.work.WorkManager;
/**
@@ -91,7 +90,7 @@ public class ClassServer implements Code
public void init() {
try {
establishServerSocket();
- workManager.queueTask(TaskClass.SYSTEM_TASK,
Thread.currentThread().getContextClassLoader(),
+
workManager.queueTask(Thread.currentThread().getContextClassLoader(),
new Runnable() {
@Override
@@ -144,7 +143,7 @@ public class ClassServer implements Code
/*
* Boy, would this be a nice spot to have closures!
*/
- workManager.queueTask(TaskClass.SYSTEM_TASK,
+ workManager.queueTask(
Thread.currentThread().getContextClassLoader(),
new Runnable() {
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/ApplicationEnvironment.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/ApplicationEnvironment.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/ApplicationEnvironment.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/ApplicationEnvironment.java
Mon May 27 01:21:24 2013
@@ -21,6 +21,7 @@ package org.apache.river.container.deplo
import org.apache.commons.vfs.FileObject;
import org.apache.river.container.classloading.VirtualFileSystemClassLoader;
import org.apache.river.container.codebase.CodebaseContext;
+import org.apache.river.container.work.WorkingContext;
/**
* Everything the host needs to know about the surrogate.
@@ -84,4 +85,14 @@ public class ApplicationEnvironment {
this.serviceInstance = serviceInstance;
}
+ WorkingContext workingContext=null;
+
+ public WorkingContext getWorkingContext() {
+ return workingContext;
+ }
+
+ public void setWorkingContext(WorkingContext workingContext) {
+ this.workingContext = workingContext;
+ }
+
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceDeployer.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceDeployer.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceDeployer.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceDeployer.java
Mon May 27 01:21:24 2013
@@ -39,7 +39,6 @@ import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jini.security.policy.DynamicPolicyProvider;
-import net.jini.security.Security;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
@@ -61,7 +60,7 @@ import org.apache.river.container.codeba
import org.apache.river.container.codebase.CodebaseHandler;
import org.apache.river.container.el.ArgsParser;
import org.apache.river.container.liaison.VirtualFileSystemConfiguration;
-import org.apache.river.container.work.TaskClass;
+import org.apache.river.container.work.ContextualWorkManager;
import org.apache.river.container.work.WorkManager;
/**
@@ -100,6 +99,9 @@ public class StarterServiceDeployer impl
@Injected(style = InjectionStyle.BY_TYPE)
WorkManager workManager = null;
+ @Injected(style=InjectionStyle.BY_TYPE)
+ ContextualWorkManager contextualWorkManager=null;
+
@Injected(style = InjectionStyle.BY_TYPE)
private DynamicPolicyProvider securityPolicy = null;
@@ -220,19 +222,9 @@ public class StarterServiceDeployer impl
}
}
};
- workManager.queueTask(TaskClass.APPLICATION_TASK,
env.getClassLoader(), task);
+
env.getWorkingContext().getWorkManager().queueTask(env.getClassLoader(), task);
}
- public void stopService(ApplicationEnvironment env) {
- /*
- * TODO: Write the implementation of this method.
- * Should do something like:
- * - Call destroy() on the service proxy if possible.
- * - Check to make sure all the threads are gone.
- * - Interrupt the threads if necessary.
- */
- }
-
public Properties readStartProperties(FileObject serviceRoot) throws
FileSystemException, LocalizedRuntimeException, IOException {
/*
Read the start.properties file.
@@ -364,6 +356,10 @@ public class StarterServiceDeployer impl
grantPermissions(cl, perms);
setupLiaisonConfiguration(env.getServiceArchive(),
env.getServiceRoot(), cl);
+ /*
+ * Create a working context (work manager).
+ */
+
env.setWorkingContext(contextualWorkManager.createContext(env.getServiceName()));
}
void launchService(ApplicationEnvironment env) throws FileSystemException,
IOException {
@@ -451,4 +447,27 @@ public class StarterServiceDeployer impl
constructor.setAccessible(true);
return constructor.newInstance(parms, null);
}
+
+ /**
+ * Attempt to stop the service in an orderly fashion.
+ * Go to the service, see if it implements Administrable, then get the
+ * admin proxy and see if it implements DestroyAdmin. If so, call it.
+ * @param env
+ */
+ public void stopService(ApplicationEnvironment env) {
+ /* Option 1 - Service has a getAdmin() method - it probably implements
+ * Administrable.
+ */
+ Object serviceInstance=env.getServiceInstance();
+ Method getAdmin=null;
+ try {
+ getAdmin=serviceInstance.getClass().getMethod(Strings.GET_ADMIN,
new Class[0]);
+ } catch (Exception ex) {
+ // Silent catch - leave it null;
+ }
+ if (getAdmin != null) {
+
+ }
+
+ }
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
Mon May 27 01:21:24 2013
@@ -19,17 +19,22 @@ package org.apache.river.container.deplo
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.river.container.MessageNames;
+import org.apache.river.container.Utils;
import org.apache.river.container.hsm.Controller;
+import org.apache.river.container.hsm.Guard;
import org.apache.river.container.hsm.Initial;
+import org.apache.river.container.hsm.OnEntry;
+import org.apache.river.container.hsm.OnExit;
import org.apache.river.container.hsm.PlainStateMachineExecutor;
import org.apache.river.container.hsm.RootState;
import org.apache.river.container.hsm.State;
import org.apache.river.container.hsm.StateMachineInfo;
import org.apache.river.container.hsm.Transition;
-import org.apache.river.container.work.TaskClass;
/**
* Life cycle controller for "service-starter" services. Idle --> Starting -->
@@ -38,6 +43,8 @@ import org.apache.river.container.work.T
@RootState({ServiceLifeCycle.class, StatusEvents.class})
public class StarterServiceLifeCycleSM {
+ public static final int MAX_RETRY_COUNT=10;
+
private static final Logger logger =
Logger.getLogger(StarterServiceLifeCycleSM.class.getName(),
MessageNames.BUNDLE_NAME);
private ApplicationEnvironment appEnv = null;
@@ -54,7 +61,9 @@ public class StarterServiceLifeCycleSM {
machine.lifeCycleProxy = (ServiceLifeCycle) machine.eventProxy;
return machine.lifeCycleProxy;
}
- @State({Idle.class, Preparing.class, Prepared.class, Starting.class,
Failed.class, Running.class, Stopping.class, Idle.class})
+ @State({Idle.class, Preparing.class, Prepared.class, Starting.class,
+ Failed.class, Running.class, Stopping.class, DirtyShutdown.class,
+ Idle.class})
@Initial(Idle.class)
private Object state;
@Controller
@@ -88,13 +97,12 @@ public class StarterServiceLifeCycleSM {
deployer.prepareService(appEnv);
eventProxy.prepareSucceeded();
lifeCycleProxy.start();
- eventProxy.startSucceeded();
} catch (Exception ex) {
eventProxy.exception(ex);
}
}
};
- deployer.workManager.queueTask(TaskClass.SYSTEM_TASK, null,
command);
+ deployer.workManager.queueTask(null, command);
}
@Transition(Preparing.class)
@@ -111,7 +119,7 @@ public class StarterServiceLifeCycleSM {
}
}
};
- deployer.workManager.queueTask(TaskClass.SYSTEM_TASK, null,
command);
+ deployer.workManager.queueTask(null, command);
}
}
@@ -127,14 +135,6 @@ public class StarterServiceLifeCycleSM {
exceptions.add(ex);
}
- public void start() {
- throw new IllegalStateException(getStatus());
- }
-
- public void stop() {
- throw new IllegalStateException(getStatus());
- }
-
}
public class Prepared {
@@ -152,7 +152,7 @@ public class StarterServiceLifeCycleSM {
}
}
};
- deployer.workManager.queueTask(TaskClass.SYSTEM_TASK, null,
command);
+ deployer.workManager.queueTask( null, command);
}
@@ -169,26 +169,98 @@ public class StarterServiceLifeCycleSM {
/* Prepare the application environment. */
try {
deployer.stopService(appEnv);
- eventProxy.stopSucceeded();
+
if(appEnv.getWorkingContext().getActiveThreadCount()==0) {
+ eventProxy.stopSucceeded();
+ } else {
+ eventProxy.stopFailed();
+ }
} catch (Exception ex) {
eventProxy.exception(ex);
}
}
};
- deployer.workManager.queueTask(TaskClass.SYSTEM_TASK, null,
command);
-
+ deployer.workManager.queueTask(null, command);
}
}
- public class Failed {
+ /**
+ * We want the state to show as "Failed" but in reality, you can do all
+ * the same commands as if you were in "Idle". So we just extend "Idle".
+ */
+ public class Failed extends Idle {
}
public class Stopping {
/* TODO: Implement the state machine from here to check for proper
* shutdown.
*/
+
+ @Transition(Idle.class)
+ public void stopSucceeded() {}
+
+ @Transition(DirtyShutdown.class)
+ public void stopFailed() {}
+
+ @Guard(Idle.class)
+ public boolean areThreadsGone() {
+ return appEnv.getWorkingContext().getActiveThreadCount()==0;
+ }
+
+ public void exception(Exception ex) {
+ logger.log(Level.WARNING, MessageNames.EXCEPTION_WHILE_STOPPING,
+ new Object[] { Utils.stackTrace(ex) });
+ }
}
+ public class DirtyShutdown {
+ int retryCount=0;
+
+ @OnEntry
+ public void enter() {
+ try {
+ logger.log(Level.INFO, MessageNames.FAILED_CLEAN_SHUTDOWN,
+ new Object[] { appEnv.getServiceName() });
+ retryCount=0;
+ /* Interrupt threads, then start interval timer to repeat. */
+ appEnv.getWorkingContext().shutdown();
+ setTimer();
+ } catch(Throwable t) {
+ System.out.println("Got exception while entering
DirtyShutdown");
+ t.printStackTrace();
+ }
+ }
+
+ @Transition(Idle.class)
+ public void stopped() {}
+
+ @OnExit
+ public void exit() {
+ clearTimer();
+ }
+
+ public void timeout() {
+ appEnv.getWorkingContext().shutdown();
+ appEnv.getWorkingContext().interrupt();
+ retryCount++;
+ }
+
+ @Guard(Failed.class)
+ public boolean isRetryCountExceeded() {
+ if (retryCount > MAX_RETRY_COUNT) {
+ logger.log(Level.INFO, MessageNames.SHUTDOWN_FAILED,
+ new Object[] { appEnv.getServiceName()});
+ }
+ return retryCount > MAX_RETRY_COUNT;
+ }
+
+ @Guard(Idle.class)
+ public boolean areThreadsGone() {
+ int nThreads=appEnv.getWorkingContext().getActiveThreadCount();
+ logger.log(Level.FINE, MessageNames.N_THREADS_LEFT,
+ new Object[]{ appEnv.getServiceName(), nThreads });
+ return nThreads==0;
+ }
+ }
public class Starting {
@Transition(Running.class)
@@ -200,4 +272,26 @@ public class StarterServiceLifeCycleSM {
exceptions.add(ex);
}
}
+
+ ScheduledFuture timer=null;
+
+ public synchronized void setTimer() {
+ Runnable command=new Runnable() {
+ public void run() {
+ eventProxy.timeout();
+ setTimer();
+ }
+ };
+ clearTimer();
+ // We're shutting down the appEnv's working context, so we need the
+ // deployer's work manager.
+ timer=deployer.workManager.schedule(null, command, 2,
TimeUnit.SECONDS);
+ }
+
+ public synchronized void clearTimer() {
+ if (timer != null) {
+ timer.cancel(true);
+ timer=null;
+ }
+ }
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StatusEvents.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StatusEvents.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StatusEvents.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/deployer/StatusEvents.java
Mon May 27 01:21:24 2013
@@ -28,7 +28,9 @@ interface StatusEvents {
public void stopSucceeded();
+ public void stopFailed();
+
public void exception(Exception ex);
- public void tick();
+ public void timeout();
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/PlainStateMachineExecutor.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/PlainStateMachineExecutor.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/PlainStateMachineExecutor.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/PlainStateMachineExecutor.java
Mon May 27 01:21:24 2013
@@ -263,12 +263,17 @@ public class PlainStateMachineExecutor i
}
private void runEventActions(List<MetaState> activeStates, Method
eventInterfaceMethod, Object[] args) {
+ boolean thereWasAnEventMethod=false;
for (MetaState ms : activeStates) {
Operation op = ms.eventMethods.get(eventInterfaceMethod);
if (op != null) {
+ thereWasAnEventMethod=true;
op.eval(this, args);
}
}
+ if(!thereWasAnEventMethod) {
+ exceptions.add(new IllegalStateException());
+ }
}
private void runGuardMethods(List<MetaState> activeStates) {
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/BasicWorkManager.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/work/BasicWorkManager.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/BasicWorkManager.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/BasicWorkManager.java
Mon May 27 01:21:24 2013
@@ -20,7 +20,10 @@ package org.apache.river.container.work;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.river.container.Init;
@@ -39,18 +42,24 @@ public class BasicWorkManager implements
private static final Logger log =
Logger.getLogger(BasicWorkManager.class.getName(), MessageNames.BUNDLE_NAME);
ExecutorService executor = null;
+ ScheduledExecutorService scheduledExecutor=null;
private MyThreadFactory threadFactory = null;
private String name = Strings.UNNAMED;
public BasicWorkManager() {
threadFactory = new MyThreadFactory();
executor = Executors.newCachedThreadPool(threadFactory);
+ scheduledExecutor=
+ Executors.newSingleThreadScheduledExecutor(threadFactory);
+
}
public BasicWorkManager(String name) {
this.name = name;
threadFactory = new MyThreadFactory();
executor = Executors.newCachedThreadPool(threadFactory);
+ scheduledExecutor=
+ Executors.newSingleThreadScheduledExecutor(threadFactory);
}
synchronized int getActiveCount() {
@@ -58,12 +67,19 @@ public class BasicWorkManager implements
}
@Override
- public void queueTask(TaskClass taskClass, ClassLoader contextClassLoader,
Runnable task) {
+ public void queueTask(ClassLoader contextClassLoader, Runnable task) {
ClassLoader classLoaderToUse =
contextClassLoader != null ? contextClassLoader :
Thread.currentThread().getContextClassLoader();
executor.execute(new TaskHolder(task, classLoaderToUse));
}
+ @Override
+ public ScheduledFuture<?> schedule(ClassLoader contextClassLoader,
Runnable command, long delay, TimeUnit unit) {
+ ClassLoader classLoaderToUse =
+ contextClassLoader != null ? contextClassLoader :
Thread.currentThread().getContextClassLoader();
+ return scheduledExecutor.schedule(new TaskHolder(command,
classLoaderToUse), delay, unit);
+ }
+
private class TaskHolder implements Runnable {
Runnable task = null;
@@ -95,8 +111,13 @@ public class BasicWorkManager implements
@Shutdown
public void shutdown() {
executor.shutdownNow();
+ scheduledExecutor.shutdownNow();
}
+ public void interrupt() {
+ threadFactory.threadGroup.interrupt();
+ }
+
private class MyThreadFactory implements ThreadFactory {
private ThreadGroup threadGroup = new ThreadGroup(name);
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/ContextualWorkManager.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/work/ContextualWorkManager.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/ContextualWorkManager.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/ContextualWorkManager.java
Mon May 27 01:21:24 2013
@@ -29,7 +29,7 @@ public class ContextualWorkManager {
List<Context> contexts=new ArrayList<Context>();
- WorkingContext createContext(String name) {
+ public WorkingContext createContext(String name) {
Context context=new Context(name);
contexts.add(context);
return context;
@@ -60,8 +60,13 @@ public class ContextualWorkManager {
}
@Override
+ public void shutdown() {
+ workManager.shutdown();
+ }
+
+ @Override
public void interrupt() {
- throw new UnsupportedOperationException("Not supported yet.");
+ workManager.interrupt();
}
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkManager.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkManager.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkManager.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkManager.java
Mon May 27 01:21:24 2013
@@ -15,35 +15,51 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.river.container.work;
-/**
-
- Interface for the container's workload manager. System objects use an
-instance of this interface to request the container to perform work on their
-behalf. Using a centralized workload manager allows the container to both
-control the scheduling of the workload and provide instrumentation on the
-workload that might be useful for debugging or performance management.
-
-TODO: Need to have some way of grouping tasks, then killing off a task
-and all its subtasks (thread groups etc) for shutdown purposes.
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+/**
+ *
+ * Interface for the container's workload manager. System objects use an
+ * instance of this interface to request the container to perform work on their
+ * behalf. Using a centralized workload manager allows the container to both
+ * control the scheduling of the workload and provide instrumentation on the
+ * workload that might be useful for debugging or performance management.
+ *
+ * TODO: Need to have some way of grouping tasks, then killing off a task and
+ * all its subtasks (thread groups etc) for shutdown purposes.
+ *
* @author trasukg
*/
public interface WorkManager {
-
+
/**
- Queue a task for execution.
- @param taskClass Indicates what type of task this is. The implementation
- may use this information to assign the task to one of several execution
- queues.
-
- @param contextClassLoader The context classloader that should be used when
- running the task.
-
- @param task The task to be run.
- */
- public void queueTask(TaskClass taskClass, ClassLoader contextClassLoader,
+ * Queue a task for execution.
+ *
+ * @param taskClass Indicates what type of task this is. The implementation
+ * may use this information to assign the task to one of several execution
+ * queues.
+ *
+ * @param contextClassLoader The context classloader that should be used
+ * when running the task.
+ *
+ * @param task The task to be run.
+ */
+ public void queueTask(ClassLoader contextClassLoader,
Runnable task);
+
+ /**
+ * Schedule a task for future execution
+ *
+ * @param command
+ * @param delay
+ * @param unit
+ * @return
+ */
+ ScheduledFuture<?> schedule(ClassLoader contextClassLoader,
+ Runnable command,
+ long delay,
+ TimeUnit unit);
}
Modified:
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkingContext.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkingContext.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkingContext.java
(original)
+++
river/jtsk/skunk/surrogate/src/org/apache/river/container/work/WorkingContext.java
Mon May 27 01:21:24 2013
@@ -38,5 +38,10 @@ public interface WorkingContext {
/**
Attempt to stop all threads in the context by interrupting them.
*/
+ void shutdown();
+
+ /**
+ * Interrupt all threads associated with this working context.
+ */
void interrupt();
}
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedMachineTest.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedMachineTest.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedMachineTest.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedMachineTest.java
Mon May 27 01:21:24 2013
@@ -74,6 +74,21 @@ public class InitializedMachineTest {
}
/**
+ * The "Armed" state subclasses Locked, so the unlocking should continue to
+ * work.
+ */
+ @Test
+ public void testArming() {
+ UUTI.arm();
+ assertTrue("lockedState is not instance of Armed", UUT.lockedState
instanceof InitializedTestSM.Armed);
+
+ UUTI.unlock();
+ assertTrue("lockedState is not instance of Unlocked", UUT.lockedState
instanceof InitializedTestSM.Unlocked);
+ UUTI.setValue(20);
+
+ }
+
+ /**
* Test that the methods are executing against the same instance that we
* created.
*/
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSM.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSM.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSM.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSM.java
Mon May 27 01:21:24 2013
@@ -23,37 +23,45 @@ package org.apache.river.container.hsm;
*/
@RootState(InitializedTestSMInterface.class)
public class InitializedTestSM {
-
- private int value=0;
-
- @State({Locked.class, Unlocked.class})
+
+ private int value = 0;
+
+ @State({Locked.class, Unlocked.class, Armed.class})
@Initial(Locked.class)
Object lockedState;
public int getValue() {
return value;
}
-
+
public class Locked {
-
+
@Transition(Unlocked.class)
public void unlock() {
System.out.println("Locked.unlock()");
}
-
+
public void setValue(int v) {
throw new IllegalStateException("Locked!");
}
+
+ @Transition(Armed.class)
+ public void arm() {
+ }
+ }
+
+ public class Armed extends Locked {
}
-
+
public class Unlocked {
+
@Transition(Locked.class)
public void lock() {
System.out.println("Unlocked.lock()");
}
-
+
public void setValue(int v) {
- value=v;
+ value = v;
}
}
}
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSMInterface.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSMInterface.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSMInterface.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/InitializedTestSMInterface.java
Mon May 27 01:21:24 2013
@@ -26,6 +26,8 @@ public interface InitializedTestSMInterf
public void unlock();
+ public void arm();
+
public void setValue(int x);
public int getValue();
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/PlainMachineExecutorTest.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/PlainMachineExecutorTest.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/PlainMachineExecutorTest.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/PlainMachineExecutorTest.java
Mon May 27 01:21:24 2013
@@ -225,4 +225,14 @@ public class PlainMachineExecutorTest {
activeStates.contains(TestSM.A.class));
assertEquals("HelloFromC", UUT.sayHello());
}
+
+
+ /**
+ * Calling an event method that isn't implemented in the current state
+ * should throw an IllegalStateException.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testUnimplementedMethod() {
+ UUT.unimplementedMethod();
+ }
}
\ No newline at end of file
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java
(original)
+++ river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java
Mon May 27 01:21:24 2013
@@ -39,6 +39,10 @@ public class TestSM {
int nullTransitionEntryCount = 0;
int aEntryCount = 0, aExitCount = 0;
+ public Object returnNull() {
+ return null;
+ }
+
public List<Class> getActiveStates() {
try {
return controller.getActiveStates();
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java
Mon May 27 01:21:24 2013
@@ -45,4 +45,6 @@ public interface TestSMInterface {
public void gotoB();
List<Class> getActiveStates();
+
+ public void unimplementedMethod();
}
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/BasicWorkManagerTest.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/work/BasicWorkManagerTest.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/BasicWorkManagerTest.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/BasicWorkManagerTest.java
Mon May 27 01:21:24 2013
@@ -18,6 +18,7 @@
package org.apache.river.container.work;
+import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -39,12 +40,24 @@ public class BasicWorkManagerTest {
@Test
public void testNullContextClassLoader() {
Harness h=new Harness();
- UUT.queueTask(TaskClass.SYSTEM_TASK, null, h);
+ UUT.queueTask(null, h);
waitHarness(4000,h);
assertEquals("Didn't use current context classloader.",
Thread.currentThread().getContextClassLoader(), h.cl);
}
+ @Test
+ public void testScheduledExecution() {
+ Harness h=new Harness();
+ long startTime=System.currentTimeMillis();
+ UUT.schedule(null, h, 2, TimeUnit.SECONDS);
+ waitHarness(4000,h);
+ assertEquals("Didn't use current context classloader.",
+ Thread.currentThread().getContextClassLoader(), h.cl);
+ assertTrue("Delay was only " + (h.runTime - startTime),
+ h.runTime >= startTime+2000);
+ }
+
private void waitHarness(long time, Harness h) {
long start=System.currentTimeMillis();
while ( !h.done && System.currentTimeMillis() - start < time) {
@@ -57,14 +70,16 @@ public class BasicWorkManagerTest {
private class Harness implements Runnable {
ClassLoader cl=null;
- boolean done=false;
+ volatile boolean done=false;
String threadName=null;
+ volatile long runTime=0;
@Override
public void run() {
cl=Thread.currentThread().getContextClassLoader();
threadName=Thread.currentThread().getName();
done=true;
+ runTime=System.currentTimeMillis();
}
}
Modified:
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/ContextualWorkManagerTest.java
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/test/org/apache/river/container/work/ContextualWorkManagerTest.java?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
---
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/ContextualWorkManagerTest.java
(original)
+++
river/jtsk/skunk/surrogate/test/org/apache/river/container/work/ContextualWorkManagerTest.java
Mon May 27 01:21:24 2013
@@ -43,7 +43,7 @@ public class ContextualWorkManagerTest {
@Test
public void testThreadCount() {
WorkerRunnable wt = new WorkerRunnable();
- context.getWorkManager().queueTask(TaskClass.SYSTEM_TASK, null, wt);
+ context.getWorkManager().queueTask(null, wt);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 2000 &
context.getActiveThreadCount() < 1) {
Thread.yield();
@@ -55,7 +55,7 @@ public class ContextualWorkManagerTest {
@Test
public void testChildThreadGroup() throws Exception {
WorkerRunnable wt = new WorkerRunnable();
- context.getWorkManager().queueTask(TaskClass.SYSTEM_TASK, null, wt);
+ context.getWorkManager().queueTask(null, wt);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 2000 &
context.getActiveThreadCount() < 1) {
Thread.yield();
@@ -71,7 +71,7 @@ public class ContextualWorkManagerTest {
@Test
public void testThreadCountWithChildren() throws Exception {
WorkerRunnable wt = new WorkerRunnable(2);
- context.getWorkManager().queueTask(TaskClass.SYSTEM_TASK, null, wt);
+ context.getWorkManager().queueTask(null, wt);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 2000 &
context.getActiveThreadCount() < 1) {
Thread.yield();
Modified:
river/jtsk/skunk/surrogate/testfiles/testroot/profile/default/config.xml
URL:
http://svn.apache.org/viewvc/river/jtsk/skunk/surrogate/testfiles/testroot/profile/default/config.xml?rev=1486497&r1=1486496&r2=1486497&view=diff
==============================================================================
--- river/jtsk/skunk/surrogate/testfiles/testroot/profile/default/config.xml
(original)
+++ river/jtsk/skunk/surrogate/testfiles/testroot/profile/default/config.xml
Mon May 27 01:21:24 2013
@@ -33,6 +33,7 @@
<cfg:property name="deploymentDirectory" value="deploy"/>
<cfg:property name="defaultDiscoveryGroup" value="RiverContainerDefault"/>
+ <cfg:component
class="org.apache.river.container.work.ContextualWorkManager"/>
<cfg:component class="org.apache.river.container.work.BasicWorkManager"/>
<cfg:component class="org.apache.river.container.codebase.ClassServer"/>