You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by gt...@apache.org on 2014/02/18 15:20:34 UTC

[1/8] git commit: There is now an Ideas page in river-container that describes the concepts of the plugin. The river-container-maven-plugin project has a 'listApps' goal that one can install and then print out the configured container home.

Repository: river-container
Updated Branches:
  refs/heads/master 2cbf9f244 -> 496e36fcb
  refs/heads/plugin-work 33855de25 -> 496e36fcb


There is now an Ideas page in river-container that describes the concepts of the plugin.
The river-container-maven-plugin project has a 'listApps' goal that one can install and then print out the configured container home.


Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/3b5a40ff
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/3b5a40ff
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/3b5a40ff

Branch: refs/heads/master
Commit: 3b5a40ff841c6b1b4389e09b18d5371bab267eaa
Parents: 2cbf9f2
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Mon Jan 20 00:50:01 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Mon Jan 20 00:50:01 2014 -0500

----------------------------------------------------------------------
 river-container-maven-plugin/pom.xml            |  2 +-
 .../river/container/mvnplugin/ListAppsMojo.java | 57 +++++++++++++
 .../river/container/mvnplugin/MyMojo.java       | 84 --------------------
 src/site/markdown/Ideas.md                      | 69 ++++++++++++++++
 src/site/markdown/index.md                      |  5 ++
 5 files changed, 132 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/3b5a40ff/river-container-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/river-container-maven-plugin/pom.xml b/river-container-maven-plugin/pom.xml
index 161fe36..9bc4b1c 100644
--- a/river-container-maven-plugin/pom.xml
+++ b/river-container-maven-plugin/pom.xml
@@ -69,7 +69,7 @@
         <artifactId>maven-plugin-plugin</artifactId>
         <version>3.2</version>
         <configuration>
-          <goalPrefix>river-container-maven-plugin</goalPrefix>
+          <goalPrefix>river</goalPrefix>
           <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
         </configuration>
         <executions>

http://git-wip-us.apache.org/repos/asf/river-container/blob/3b5a40ff/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/ListAppsMojo.java
----------------------------------------------------------------------
diff --git a/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/ListAppsMojo.java b/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/ListAppsMojo.java
new file mode 100644
index 0000000..6cdd294
--- /dev/null
+++ b/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/ListAppsMojo.java
@@ -0,0 +1,57 @@
+package org.apache.river.container.mvnplugin;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * Goal which touches a timestamp file.
+ *
+ * 
+ */
+@Mojo( name = "listApps", requiresDirectInvocation=true, requiresProject=false)
+public class ListAppsMojo
+    extends AbstractMojo
+{
+    /**
+     * Location of the file.
+     */
+    @Parameter( property = "river.container.home", required = true )
+    private File containerHome;
+
+    /**
+     * Uses the client admin listApps script to list the applications that are
+     * in the currently running container.
+     * @throws MojoExecutionException 
+     */
+    @Override
+    public void execute()
+        throws MojoExecutionException
+    {
+        System.out.println("Container home is " + containerHome.getAbsolutePath());
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/3b5a40ff/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/MyMojo.java
----------------------------------------------------------------------
diff --git a/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/MyMojo.java b/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/MyMojo.java
deleted file mode 100644
index 6a00263..0000000
--- a/river-container-maven-plugin/src/main/java/org/apache/river/container/mvnplugin/MyMojo.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.apache.river.container.mvnplugin;
-
-/*
- * Copyright 2001-2005 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
-
-import org.apache.maven.plugins.annotations.LifecyclePhase;
-import org.apache.maven.plugins.annotations.Mojo;
-import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.plugins.annotations.ResolutionScope;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * Goal which touches a timestamp file.
- *
- * @deprecated Don't use!
- */
-@Mojo( name = "touch", defaultPhase = LifecyclePhase.PROCESS_SOURCES )
-public class MyMojo
-    extends AbstractMojo
-{
-    /**
-     * Location of the file.
-     */
-    @Parameter( defaultValue = "${project.build.directory}", property = "outputDir", required = true )
-    private File outputDirectory;
-
-    public void execute()
-        throws MojoExecutionException
-    {
-        File f = outputDirectory;
-
-        if ( !f.exists() )
-        {
-            f.mkdirs();
-        }
-
-        File touch = new File( f, "touch.txt" );
-
-        FileWriter w = null;
-        try
-        {
-            w = new FileWriter( touch );
-
-            w.write( "touch.txt" );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( "Error creating file " + touch, e );
-        }
-        finally
-        {
-            if ( w != null )
-            {
-                try
-                {
-                    w.close();
-                }
-                catch ( IOException e )
-                {
-                    // ignore
-                }
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/river-container/blob/3b5a40ff/src/site/markdown/Ideas.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/Ideas.md b/src/site/markdown/Ideas.md
new file mode 100644
index 0000000..3aa89ad
--- /dev/null
+++ b/src/site/markdown/Ideas.md
@@ -0,0 +1,69 @@
+Service Invocation Manager
+--------------------------
+* Somewhat similar to ServiceDiscoveryManager.
+* Purpose is to allow a client to invoke an operation on a service, where there
+may be more than one possible service client.
+    * For instance, if the service interface is to a business process that uses
+corellating data, there might be more than one provider, and every one but the 
+"right" one will throw a "process not found" exception.  
+    We want to keep the "right" one until such time as we're done interacting 
+with it.  
+* Two modes of operation:
+    * Cached mode - somewhat like SDMCache, it keeps a cache of discovered services, and
+runs through the cached services when we try to make a call.
+    * Normal mode - When a "discovery" operation is required, it queries all the 
+lookup services it can find for candidate services.  This would be used for
+a web server installation where SDM can't export a listener.
+
+Business Process
+----------------
+* Inspiration is drawn from how BPEL manages its business processes with a 
+"stateless" interface.  
+    * In other words, there's no need to lookup a particular process instance and 
+then interact with it - you just make operation calls against the stateless
+interface, and the BPEL engine maps the stateless call to the correct instance  
+    *  Mapping is done using a "Corelation set" that is defined in the interface and
+the process variables.  Parameters in the call are used to select the correct 
+instance.  
+    * e.g. confirmOrder(12667) will map to the instance that holds order 12667.  
+    * This gets a little ugly if you allow that there may be more than one service
+that "might" hold a given instance.  
+    * you need to try the invocation against all known services that hold that 
+interface  
+    * Most of these services will return some kind of "no such process" exception,
+but one of them will return successfully.  
+    * (note that in all likelihood this means one or two services, not tens or 
+hundreds).
+
+
+River Container Maven Plugin
+----------------------------
+
+We'd like to have a plugin that makes it easy to deploy and run an application
+created in Maven.  Proposed goals would be something like:
+
+* Goals  
+    * `mvn river:deploy` - Installs the current application to the default river
+    container by copying to the 'deploy' dir in the container's default profile.
+    If the container is running, this will effectively load the new service 
+    * `mvn river:deploy-client` - Installs the current application to the default
+    river container by copying to the 'deploy' dir in the container's client
+    profile.  Note that the plugin doesn't try to figure out whether your app _should_
+    be installed as a client or not - it just takes your word for it.
+    * `mvn river:run` - Contacts the currently running container to deploy the current
+    application (in-place with no copying),
+    undeploying any application with the same name (i.e. the previous version).  
+    * `mvn river:run-client` - Runs the current application using the client profile
+    in-place (i.e. no copying to the deploy directory).  
+    * `mvn river:start-server` - Starts the server in default profile, or other profile
+    if the `river.container.profile` property is set.  
+    * `mvn river:stop-server` - Stops the server's default profile, or other profile if
+    the `river.container.profile` property is set.  
+    * `mvn river:list-apps` - Lists the applications currently running in the container.  
+* Properties
+    * `river.container.home` - The home directory for the container.  
+    * `river.container.profile` - The profile to run as a "server".  
+    * `river.container.clientProfile` - The profile to run as a "client".  
+
+
+

http://git-wip-us.apache.org/repos/asf/river-container/blob/3b5a40ff/src/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
new file mode 100644
index 0000000..25037f2
--- /dev/null
+++ b/src/site/markdown/index.md
@@ -0,0 +1,5 @@
+!River Container
+
+The Apache River Container is an application server that hosts Jini services.
+
+[Ideas](Ideas.html) Ideas for future development.
\ No newline at end of file


[2/8] git commit: Client-profile command line admin app now exists. Files in product/root/bin now have correct file modes on Unix. 'run.sh' is renamed to 'run'. river-container-core 'core-config.xml' is updated to include the river-hsm jar in runtime cla

Posted by gt...@apache.org.
Client-profile command line admin app now exists.
Files in product/root/bin now have correct file modes on Unix.
'run.sh' is renamed to 'run'.
river-container-core 'core-config.xml' is updated to include the river-hsm jar in runtime classpath.




Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/82f44f6b
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/82f44f6b
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/82f44f6b

Branch: refs/heads/master
Commit: 82f44f6b1c1389bd80a2da7c80b91ec3068b1b1d
Parents: 3b5a40f
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Mon Jan 20 02:15:32 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Mon Jan 20 02:15:32 2014 -0500

----------------------------------------------------------------------
 admin-app/pom.xml                               | 42 ++++++++++++
 .../container/admin/app/CommandLineAdmin.java   | 20 ++++++
 .../river/container/admin/app/AppTest.java      | 38 +++++++++++
 admin-module/pom.xml                            | 61 ++++++++++++++++++
 admin-module/src/assemble/module.xml            | 67 ++++++++++++++++++++
 admin-module/src/main/root/admin.config         | 38 +++++++++++
 admin-module/src/main/root/start.properties     | 20 ++++++
 pom.xml                                         |  6 +-
 product/pom.xml                                 |  6 ++
 product/src/assemble/product-container.xml      | 45 ++++++++++++-
 product/src/main/root/bin/run                   | 19 ++++++
 product/src/main/root/bin/run.sh                | 19 ------
 .../org/apache/river/container/core-config.xml  |  3 +-
 13 files changed, 361 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-app/pom.xml
----------------------------------------------------------------------
diff --git a/admin-app/pom.xml b/admin-app/pom.xml
new file mode 100644
index 0000000..8f976dc
--- /dev/null
+++ b/admin-app/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>river-container</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.river.container</groupId>
+  <artifactId>admin-app</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <name>admin-app</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-app/src/main/java/org/apache/river/container/admin/app/CommandLineAdmin.java
----------------------------------------------------------------------
diff --git a/admin-app/src/main/java/org/apache/river/container/admin/app/CommandLineAdmin.java b/admin-app/src/main/java/org/apache/river/container/admin/app/CommandLineAdmin.java
new file mode 100644
index 0000000..ca2304e
--- /dev/null
+++ b/admin-app/src/main/java/org/apache/river/container/admin/app/CommandLineAdmin.java
@@ -0,0 +1,20 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.container.admin.app;
+
+
+
+/**
+ *
+ * @author trasukg
+ */
+public class CommandLineAdmin {
+    public static void main(String[] args) {
+        System.out.println("Command line admin invoked.");
+        System.exit(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-app/src/test/java/org/apache/river/container/admin/app/AppTest.java
----------------------------------------------------------------------
diff --git a/admin-app/src/test/java/org/apache/river/container/admin/app/AppTest.java b/admin-app/src/test/java/org/apache/river/container/admin/app/AppTest.java
new file mode 100644
index 0000000..dcd561b
--- /dev/null
+++ b/admin-app/src/test/java/org/apache/river/container/admin/app/AppTest.java
@@ -0,0 +1,38 @@
+package org.apache.river.container.admin.app;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-module/pom.xml
----------------------------------------------------------------------
diff --git a/admin-module/pom.xml b/admin-module/pom.xml
new file mode 100644
index 0000000..b8b1eb0
--- /dev/null
+++ b/admin-module/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>river-container</artifactId>
+        <groupId>org.apache.river.container</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-module</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>admin-module</name>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.river.container</groupId>
+            <artifactId>admin-app</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptor>src/assemble/module.xml</descriptor>
+                    <appendAssemblyId>false</appendAssemblyId>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>ssar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        
+                    </execution>
+                </executions>
+            </plugin>
+            
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-module/src/assemble/module.xml
----------------------------------------------------------------------
diff --git a/admin-module/src/assemble/module.xml b/admin-module/src/assemble/module.xml
new file mode 100644
index 0000000..d8f36d3
--- /dev/null
+++ b/admin-module/src/assemble/module.xml
@@ -0,0 +1,67 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    
+    <id>ssar</id>
+    
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+  <fileSets>
+
+        <fileSet>
+            <directory>${basedir}/src/main/root</directory>
+            <includes>
+                <include>**/**</include>
+                <include>*</include>
+            </includes>
+            <outputDirectory>/</outputDirectory>
+        </fileSet>
+  
+  </fileSets>    
+  <dependencySets>
+     
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/lib</outputDirectory>
+            <!-- jsk jars are already provided by the container. -->
+            <excludes>
+                <exclude>*:jsk-*</exclude>
+            </excludes>
+        </dependencySet>
+        
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/lib-dl</outputDirectory>
+            <includes>
+                <include>*:*-dl</include>
+                <include>*:*-api</include>
+            </includes>
+            <!-- jsk jars are already provided by the container. -->
+            <excludes>
+                <exclude>*:jsk-*</exclude>
+            </excludes>
+        </dependencySet>
+    </dependencySets>
+
+</assembly>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-module/src/main/root/admin.config
----------------------------------------------------------------------
diff --git a/admin-module/src/main/root/admin.config b/admin-module/src/main/root/admin.config
new file mode 100644
index 0000000..d0dcb87
--- /dev/null
+++ b/admin-module/src/main/root/admin.config
@@ -0,0 +1,38 @@
+import java.security.Permission;
+import net.jini.constraint.BasicMethodConstraints;
+import net.jini.core.constraint.InvocationConstraints;
+import net.jini.core.entry.Entry;
+import net.jini.core.lookup.ServiceID;
+import net.jini.discovery.LookupDiscovery;
+import net.jini.jeri.BasicILFactory;
+import net.jini.jeri.BasicJeriExporter;
+import net.jini.jeri.tcp.TcpServerEndpoint;
+import net.jini.lookup.JoinManager;
+import net.jini.lookup.entry.Name;
+import net.jini.security.BasicProxyPreparer;
+
+org.apache.river.container.examples.greeter {
+	
+    groups = new String[] {$discoveryGroup};
+    
+    exporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
+                                     new BasicILFactory());
+
+    serviceInvocationConstraints=InvocationConstraints.EMPTY;
+        
+    registrarPreparer = 
+        new BasicProxyPreparer(false, new BasicMethodConstraints(serviceInvocationConstraints),
+            new Permission[] { new RuntimePermission("accessClassInPackage.com.sun.proxy") } );
+
+    static discoveryManager = 
+        new LookupDiscovery( groups, this);
+
+    static attributes = new Entry[] { new Name("greeter-service") };
+
+}
+
+net.jini.lookup.JoinManager {
+    registrarPreparer = org.apache.river.container.examples.greeter.registrarPreparer;
+    registrationPreparer = org.apache.river.container.examples.greeter.registrarPreparer;
+    
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/admin-module/src/main/root/start.properties
----------------------------------------------------------------------
diff --git a/admin-module/src/main/root/start.properties b/admin-module/src/main/root/start.properties
new file mode 100644
index 0000000..9e05112
--- /dev/null
+++ b/admin-module/src/main/root/start.properties
@@ -0,0 +1,20 @@
+
+ # Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements.  See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership. The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (the
+ # "License"); you may not use this file except in compliance
+ # with the License. You may obtain a copy of the License at
+ #
+ #      http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ #
+
+startClass=org.apache.river.container.admin.app.CommandLineAdmin
+startParameters=admin.config $*

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e70fd7d..e8ef195 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,8 +36,10 @@
         <module>product</module>
         <module>transient-outrigger-module</module>
         <module>river-container-maven-plugin</module>
-    <module>river-hsm</module>
-  </modules>
+        <module>river-hsm</module>
+        <module>admin-app</module>
+        <module>admin-module</module>
+    </modules>
     <properties>
         <jsk-version>2.2.2</jsk-version>
     </properties>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/product/pom.xml
----------------------------------------------------------------------
diff --git a/product/pom.xml b/product/pom.xml
index 368ffec..992f8d7 100644
--- a/product/pom.xml
+++ b/product/pom.xml
@@ -64,6 +64,12 @@
             <version>1.0-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.river.container</groupId>
+            <artifactId>admin-module</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
   
     <build>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/product/src/assemble/product-container.xml
----------------------------------------------------------------------
diff --git a/product/src/assemble/product-container.xml b/product/src/assemble/product-container.xml
index 47f66ca..c1c1c56 100644
--- a/product/src/assemble/product-container.xml
+++ b/product/src/assemble/product-container.xml
@@ -28,7 +28,32 @@
     <fileSets>
         <fileSet>
             <outputDirectory>/</outputDirectory>
-            <directory>src/main/root</directory> 
+            <directory>src/main/root</directory>
+            <fileMode>0644</fileMode>
+            <excludes>
+                <exclude>bin/*</exclude>
+            </excludes>
+            <filtered>true</filtered>
+        </fileSet>
+        <fileSet>
+            <outputDirectory>/</outputDirectory>
+            <directory>src/main/root</directory>
+            <fileMode>0744</fileMode>
+            <includes>
+                <include>bin/*</include>
+            </includes>
+            <excludes>
+                <exclude>bin/logging.properties</exclude>
+            </excludes>
+            <filtered>true</filtered>
+        </fileSet>
+        <fileSet>
+            <outputDirectory>/</outputDirectory>
+            <directory>src/main/root</directory>
+            <fileMode>0644</fileMode>
+            <includes>
+                <include>bin/logging.properties</include>
+            </includes>
             <filtered>true</filtered>
         </fileSet>
     </fileSets>
@@ -45,6 +70,9 @@
                 <exclude>*:plexus-*</exclude>
             </excludes>
         </dependencySet>
+        
+        <!-- Default profile
+        -->
         <dependencySet>
             <useProjectArtifact>false</useProjectArtifact>
             <outputDirectory>/profile/default/deploy</outputDirectory>
@@ -62,6 +90,21 @@
                 <include>*:browser-module</include>
             </includes>
         </dependencySet>
+        
+        <!-- Client Profile
+        -->
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/profile/client/deploy</outputDirectory>
+            <scope>runtime</scope>
+            <includes>
+                <include>*:browser-module</include>
+                <include>*:admin-module</include>
+            </includes>
+        </dependencySet>
+        
+        <!-- Outrigger profile
+        -->
         <dependencySet>
             <useProjectArtifact>false</useProjectArtifact>
             <outputDirectory>/profile/outrigger/deploy</outputDirectory>

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/product/src/main/root/bin/run
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/run b/product/src/main/root/bin/run
new file mode 100644
index 0000000..a38cc95
--- /dev/null
+++ b/product/src/main/root/bin/run
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+java -classpath lib/river-container-core-*.jar  -Djava.util.logging.config.file=bin/logging.properties -Dcom.sun.management.jmxremote org.apache.river.container.Bootstrap $*
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/product/src/main/root/bin/run.sh
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/run.sh b/product/src/main/root/bin/run.sh
deleted file mode 100644
index a38cc95..0000000
--- a/product/src/main/root/bin/run.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-java -classpath lib/river-container-core-*.jar  -Djava.util.logging.config.file=bin/logging.properties -Dcom.sun.management.jmxremote org.apache.river.container.Bootstrap $*
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/82f44f6b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
index 6ce4ee4..b99cd8f 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
+++ b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
@@ -47,12 +47,13 @@
     -->
     <cfg:classpath id="systemClassLoader">lib/jsk-policy-${jsk-version}.jar</cfg:classpath>
     <cfg:classpath id="containerClassLoader" parent="systemClassLoader">
-        lib/river-container-core-1.0-SNAPSHOT.jar
+        lib/river-container-core-${project.version}.jar
         lib/commons-logging-1.1.1.jar
         lib/commons-vfs2-2.0.jar
         lib/jsk-platform-${jsk-version}.jar
         lib/jsk-resources-${jsk-version}.jar
         lib/regexp-1.3.jar
+        lib/river-hsm-${project.version}.jar
     </cfg:classpath>
 
     <!--cfg:component class="org.apache.river.container.ShowContextToConsole"/-->


[7/8] git commit: Readme.md now contains a "First Fifteen Minutes" guide to building and running the container and a 'hello-world' example.

Posted by gt...@apache.org.
Readme.md now contains a "First Fifteen Minutes" guide to building and running the container and a 'hello-world' example.

Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/496e36fc
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/496e36fc
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/496e36fc

Branch: refs/heads/master
Commit: 496e36fcbf192165a027343af29db09a7572a0e4
Parents: 33855de
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Tue Feb 18 09:14:41 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Tue Feb 18 09:14:41 2014 -0500

----------------------------------------------------------------------
 README.md                                       | 104 ++++++++++++++++++-
 .../src/main/root/profile/default/config.xml    |   5 +
 2 files changed, 105 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/496e36fc/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 23a59d7..7e59b85 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,103 @@
 river-container
 ===============
 
-Initial development on Apache River Container
+This project is the initial development of the Apache River Container.
+It is _not_ yet released as Apache Software.  Use at your own risk, and please
+post comments to dev@river.apache.org.
+
+The First Fifteen Minutes
+=========================
+
+Let's assume you've managed to download the source from git.  In fact, let's assume that
+you're reasonably conversant with git, so you can pull the examples project below.
+
+# Before You Start  
+You'll need Maven 3.x installed, such that you can run 'mvn' from the command
+line.  
+
+# Build From Source 
+
+<i>This step may not be required in the future, since you'll be able to 
+download a convenience binary once the project is released</i>
+
+Go to the root of the river-container download, and type  
+    mvn clean install
+
+# Run the default container profile  
+    cd product/target/product*
+    bin/run 
+
+The steps above will startup a default container that has instances of the 
+service registrar (Reggie) and the transaction manager (Mahalo).  All services
+are registered in a workgroup called 'RiverContainerDefault'.
+
+# Run the service browser  
+Open a new command line window in the root of the river-container download, then
+do the following  
+    cd product/target/product*
+    bin/run client browser
+
+You'll see a service browser window open up.  It should show one registrar.
+Select the registrar.  You should now see the infrastructure services, Reggie and 
+Mahalo.  Leave the service browser running while we start up a "Hello-world" 
+service, below.
+
+# Compile a "Hello-World" Service
+
+<i>Maybe the 'hello-world' example should be included in the container deliverable?
+Please comment on 'dev@river.apache.org'.</i>
+
+<i>Eventually, we should be able to create this example service using a Maven
+archetype.</i>
+
+Using git, pull the examples from https://github.com/trasukg/river-container-examples.
+
+'cd' into your hello-example' directory, and then  
+    mvn clean install
+
+# Deploy and run the "Hello-World" Service
+
+When Maven is done, you should be able to see the finished service archive,
+'hello-module/target/hello-module-1.0-SNAPSHOT.jar'
+
+Copy that 'jar' file into the
+'profiles/default/deploy' folder inside our 'river-container/product/target/product*' folder.
+
+<i>Eventually, we'll have a maven plugin that does this, so you can just do 
+'mvn river:deploy' rather than copying it manually.</i>
+
+If you left the container running, you should see some output indicating that the 
+service is being deployed.  If you didn't leave the container running, start it up now.
+
+You should also see the service in the service browser, with the interface
+'org.apache.river.container.hello.example.api.Greeter'
+
+# Deploy and Run the "Hello-World" Consumer
+
+When Maven finished above, it also created a client archive, 
+'hello-client-module/target/hello-client-module-1.0-SNAPSHOT.jar'
+
+Copy that 'jar' file into the
+'profiles/client/deploy' folder inside our 'river-container/product/target/product*' folder.
+
+Open a new command line window in the root of the river-container download, then
+do the following  
+    cd product/target/product*
+    bin/run client hello-client
+
+The client starts up, and eventually prompts 'Please enter your name'.  Enter
+your name and then press return.
+
+The client sends the greeter service a message, then prints out the reply.
+
+# Use the Network!
+
+If you have another machine on the local area network, and if the network is
+configured to allow multicast, you should be able to run the browser and the
+hello-client on a different machine.
+
+That concludes the 'First Fifteen Minutes' demo.  Below, there is a little more 
+detailed information...
 
 # Building from Source
 
@@ -28,7 +124,7 @@ Initial development on Apache River Container
 # Running Services in the Container
 
     cd product/target/product*
-    sh bin/run.sh [profile] arg*
+    bin/run [profile] arg*
 
 If you don't specify [profile] the 'default' profile will be used.  'arg*' isn't
 really used much in the service container profiles (like 'default').  
@@ -48,7 +144,7 @@ what the archive should look like.  Startup parameters are in 'start.properties'
 # Running Client Applications
 
     cd product/target/product*
-    sh bin/run.sh client AppName arg*
+    bin/run client AppName arg*
 
 Starts up the container using the 'client' profile, which then starts the client
 that is named by 'AppName' (and only that client, no matter if there are multiple
@@ -61,7 +157,7 @@ Client apps are packaged much like the services mentioned above.
 # Service Browser
 
     cd product/target/product*
-    sh bin/run.sh client browser
+    bin/run client browser
 
 Starts up the service browser.
 

http://git-wip-us.apache.org/repos/asf/river-container/blob/496e36fc/product/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/config.xml b/product/src/main/root/profile/default/config.xml
index cd21bc2..22be40b 100644
--- a/product/src/main/root/profile/default/config.xml
+++ b/product/src/main/root/profile/default/config.xml
@@ -32,7 +32,12 @@
    xsi:schemaLocation='http://river.apache.org/xml/ns/container/config/1.0 file:/home/trasukg/development/surrogate/src/schemas/config.xsd'>
     <cfg:property name="deploymentDirectory" value="deploy"/>
 
+    <!-- Change this value to change the discovery group for the container.
+    In the default 'service-starter.cfg', this  value is made available inside 
+    service starter configuration files as '$discoveryGroup'.
+    -->
     <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"/>


[6/8] git commit: Admin Service is able to query all the ApplicationManager objects in the container context for application statuses.

Posted by gt...@apache.org.
Admin Service is able to query all the ApplicationManager objects in the container context for application statuses.

StarterServiceDeployer now creates a working directory for each service and places the File for that directory into the service's configuration as $workingDirectory.

The StartupDeployer has been renamed to FolderBasedAppRunner which is more descriptive of its function.  It scans a folder at startup and runs any application archives that it finds.  Similarly, the ClientAppDeployer has been renamed to CommandLineAppRunner, since it runs the application specified on the command line.

The Context class now supports getting all components that implement a given interface.  This functionality is used to find all the ApplicationManager implementations that can be polled for applications.


Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/33855de2
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/33855de2
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/33855de2

Branch: refs/heads/master
Commit: 33855de2556a78d42329e48b109bd949eb244dad
Parents: e6828db
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Mon Feb 17 22:05:39 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Mon Feb 17 22:05:39 2014 -0500

----------------------------------------------------------------------
 .../container/admin/api/ApplicationInfo.java    |  43 ++-
 .../river/container/admin/impl/AdminImpl.java   |  68 +++-
 .../admin-svc-module/src/assemble/module.xml    |   3 +
 .../src/main/root/admin-svc.config              |   6 +
 product/src/main/root/bin/logging.properties    |   3 +-
 .../main/root/profile/admin-client/config.xml   |   2 +-
 product/src/main/root/profile/client/config.xml |   2 +-
 .../src/main/root/profile/default/config.xml    |   9 +-
 .../src/main/root/profile/outrigger/config.xml  |   2 +-
 river-container-core/pom.xml                    |  10 +-
 .../river/container/ApplicationManager.java     |  30 ++
 .../org/apache/river/container/Context.java     |  12 +
 .../apache/river/container/MessageNames.java    |   1 +
 .../org/apache/river/container/Strings.java     |   3 +-
 .../deployer/ApplicationEnvironment.java        |  22 ++
 .../container/deployer/ClientAppDeployer.java   | 195 ------------
 .../deployer/CommandLineAppRunner.java          | 197 ++++++++++++
 .../deployer/FolderBasedAppRunner.java          | 316 +++++++++++++++++++
 .../deployer/StarterServiceDeployer.java        |  48 ++-
 .../deployer/StarterServiceDeployerMXBean.java  |  26 --
 .../container/deployer/StartupDeployer.java     | 291 -----------------
 .../river/container/deployer/Strings.java       |   3 +
 .../apache/river/container/Messages.properties  |   1 +
 .../org/apache/river/container/core-config.xml  |   1 +
 .../org/apache/river/container/ContextTest.java |  73 +++++
 .../src/main/root/profile/client/config.xml     |   2 +-
 .../src/main/root/profile/default/config.xml    |   2 +-
 27 files changed, 824 insertions(+), 547 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
index df3f73b..74e2945 100644
--- a/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
+++ b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
@@ -1,7 +1,19 @@
 /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package org.apache.river.container.admin.api;
@@ -9,16 +21,35 @@ package org.apache.river.container.admin.api;
 import java.io.Serializable;
 
 /**
- *
- * @author trasukg
+ * Transfer object for information about applications running in the container.
+ * 
  */
 public class ApplicationInfo implements Serializable {
     String name;
     ApplicationStatus status;
+    String deployer;
 
-    public ApplicationInfo(String name, ApplicationStatus status) {
+    public ApplicationInfo(String deployer, String name, ApplicationStatus status) {
+        this.deployer=deployer;
         this.name = name;
         this.status = status;
     }
+
+    public String getName() {
+        return name;
+    }
+
+    public ApplicationStatus getStatus() {
+        return status;
+    }
+
+    /**
+     * The name of the deployer that launched this service.
+     * @return 
+     */
+    public String getDeployer() {
+        return deployer;
+    }
+    
     
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
index b137e94..82e206a 100644
--- a/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
+++ b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
@@ -19,9 +19,14 @@ package org.apache.river.container.admin.impl;
 
 import com.sun.jini.config.Config;
 import com.sun.jini.start.LifeCycle;
+import java.io.File;
 import java.io.IOException;
 import java.rmi.server.ExportException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import net.jini.config.Configuration;
@@ -34,11 +39,12 @@ import net.jini.export.Exporter;
 import net.jini.lookup.JoinManager;
 import net.jini.lookup.ServiceIDListener;
 import net.jini.security.ProxyPreparer;
+import org.apache.river.container.ApplicationManager;
+import org.apache.river.container.Context;
 import org.apache.river.container.MessageNames;
 import org.apache.river.container.Utils;
 import org.apache.river.container.admin.api.Admin;
 import org.apache.river.container.admin.api.ApplicationInfo;
-import org.apache.river.container.admin.api.ApplicationStatus;
 import org.apache.river.container.admin.dl.AdminRemote;
 
 /**
@@ -53,17 +59,28 @@ public class AdminImpl implements ServiceIDListener, AdminRemote {
     private static final String COMPONENT_ID = "basic";
 
     Configuration config = null;
+    Context ctx = null;
+
     Admin myProxy = null;
     Exporter exporter = null;
     ProxyPreparer registrarPreparer = null;
     JoinManager joinManager = null;
     DiscoveryManagement discoveryManager = null;
     Entry[] attributes = null;
-    ScheduledExecutorService executor=null;
+    volatile ScheduledExecutorService executor = null;
+    File workingDirectory=null;
     
     public AdminImpl(String args[], final LifeCycle lc) throws ConfigurationException, ExportException, IOException {
 
         config = ConfigurationProvider.getInstance(args);
+        try {
+            ctx = (Context) config.getEntry(COMPONENT_ID, "context", Context.class);
+        } catch(Throwable t) {
+            t.printStackTrace();
+        }
+
+        workingDirectory=(File) Config.getNonNullEntry(config, COMPONENT_ID, "workingDirectory", File.class);
+        
         // Get the exporter and create our proxy.
         exporter = (Exporter) Config.getNonNullEntry(config, COMPONENT_ID, "exporter", Exporter.class);
         Utils.logGrantsToClass(log, Level.FINE, this.getClass());
@@ -78,16 +95,31 @@ public class AdminImpl implements ServiceIDListener, AdminRemote {
         // Publish it using the join manager.
         // We don't have to do anything with it - just creating it starts the join process.
         joinManager = new JoinManager(myProxy, attributes, this, discoveryManager, null, config);
-        log.info("Started the admin service");
-        
+
         /* For local clients, we don't want to be dependent on the Jini infrastructure being setup
-        correctly.  For this reason, we stash a copy of the proxy's MarshalledObject in the local 
-        file system.
-        */
-        synchronized(this) {
-            executor=(ScheduledExecutorService) Config.getNonNullEntry(config, COMPONENT_ID, "$executor", ScheduledExecutorService.class);
+         correctly.  For this reason, we stash a copy of the proxy's MarshalledObject in the local 
+         file system.
+         */
+        try {
+            synchronized (this) {
+                executor = (ScheduledExecutorService) Config.getNonNullEntry(config, COMPONENT_ID,
+                        "scheduledExecutorService", ScheduledExecutorService.class);
+                executor.schedule(new Runnable() {
+                    public void run() {
+                        System.out.println("Hooray! we're on the executor!");
+                        System.out.println("Applications:");
+                        try {
+                            printApps(listApplications());
+                        } catch(Exception ex) {
+                            ex.printStackTrace();
+                        }
+                    }
+                }, 4, TimeUnit.SECONDS);
+            }
+            log.info("Started the admin service");
+        } catch (Throwable t) {
+            t.printStackTrace();
         }
-        
     }
 
     ServiceID sid = null;
@@ -97,9 +129,19 @@ public class AdminImpl implements ServiceIDListener, AdminRemote {
     }
 
     public ApplicationInfo[] listApplications() throws IOException {
-        return new ApplicationInfo[]{
-            new ApplicationInfo("abc", ApplicationStatus.UNKNOWN)
-        };
+
+        Collection<ApplicationManager> managers = ctx.getAll(ApplicationManager.class);
+        List<ApplicationInfo> info = new ArrayList<ApplicationInfo>();
+        for (ApplicationManager manager : managers) {
+            info.addAll(manager.getApplicationInfo());
+        }
+        return info.toArray(new ApplicationInfo[0]);
     }
 
+    void printApps(ApplicationInfo[] apps) {
+        for (ApplicationInfo app:apps) {
+            System.out.printf("   %s - %s - %s\n", app.getDeployer(), app.getName(), app.getStatus().toString());
+        }
+        System.out.printf("Working directory is %s and writable=%b\n", workingDirectory.getAbsolutePath(), workingDirectory.canWrite());
+    }
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/admin-svc/admin-svc-module/src/assemble/module.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/src/assemble/module.xml b/admin-svc/admin-svc-module/src/assemble/module.xml
index d8f36d3..a051d78 100644
--- a/admin-svc/admin-svc-module/src/assemble/module.xml
+++ b/admin-svc/admin-svc-module/src/assemble/module.xml
@@ -47,6 +47,9 @@
             <!-- jsk jars are already provided by the container. -->
             <excludes>
                 <exclude>*:jsk-*</exclude>
+                <!-- This jar is in the parent, so we can't have it in the 
+                module -->
+                <exclude>org.apache.river.container:admin-svc-api</exclude>
             </excludes>
         </dependencySet>
         

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/admin-svc/admin-svc-module/src/main/root/admin-svc.config
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/src/main/root/admin-svc.config b/admin-svc/admin-svc-module/src/main/root/admin-svc.config
index 7b6854f..0ed2d46 100644
--- a/admin-svc/admin-svc-module/src/main/root/admin-svc.config
+++ b/admin-svc/admin-svc-module/src/main/root/admin-svc.config
@@ -29,6 +29,12 @@ basic {
 
     static attributes = new Entry[] { new Name("admin-service") };
 
+    scheduledExecutorService=$scheduledExecutorService;
+
+    context=$context;
+
+    workingDirectory=$workingDirectory;
+
 }
 
 net.jini.lookup.JoinManager {

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/product/src/main/root/bin/logging.properties
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/logging.properties b/product/src/main/root/bin/logging.properties
index 66e0a0c..4586c3b 100644
--- a/product/src/main/root/bin/logging.properties
+++ b/product/src/main/root/bin/logging.properties
@@ -77,6 +77,7 @@ org.apache.river.container.security.ContainerCodePolicy.level=SEVERE
 org.apache.river.container.admin.level=INFO
 org.apache.river.container.deployer.level=INFO
 org.apache.river.container.deployer.ClasspathFilterBuilder.level=INFO
-org.apache.river.container.deployer.DeployerConfigParser=INFO
+org.apache.river.container.deployer.DeployerConfigParser.level=INFO
+org.apache.river.container.deployer.FolderBasedAppRunner.level=FINE
 org.apache.river.container.hsm.level=SEVERE
 net.jini.config.level=INFO

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/product/src/main/root/profile/admin-client/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/config.xml b/product/src/main/root/profile/admin-client/config.xml
index dc607fe..914ca41 100644
--- a/product/src/main/root/profile/admin-client/config.xml
+++ b/product/src/main/root/profile/admin-client/config.xml
@@ -45,7 +45,7 @@
     <!-- Deployer for 'service-starter'-style applications. 
     This is the 'admin-app' profile, so set the clientAppName to 'admin'
     -->
-    <cfg:component class="org.apache.river.container.deployer.ClientAppDeployer">
+    <cfg:component class="org.apache.river.container.deployer.CommandLineAppRunner">
         <cfg:property name="deployDirectory" value="deploy"/>
         <cfg:property name="clientAppName" value="admin"/>
     </cfg:component>

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/product/src/main/root/profile/client/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/client/config.xml b/product/src/main/root/profile/client/config.xml
index 9b01480..b46200f 100644
--- a/product/src/main/root/profile/client/config.xml
+++ b/product/src/main/root/profile/client/config.xml
@@ -43,7 +43,7 @@
     </cfg:component>
     
     <!-- Deployer for 'service-starter'-style applications. -->
-    <cfg:component class="org.apache.river.container.deployer.ClientAppDeployer">
+    <cfg:component class="org.apache.river.container.deployer.CommandLineAppRunner">
         <cfg:property name="deployDirectory" value="deploy"/>
     </cfg:component>
     

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/product/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/config.xml b/product/src/main/root/profile/default/config.xml
index 69488e2..cd21bc2 100644
--- a/product/src/main/root/profile/default/config.xml
+++ b/product/src/main/root/profile/default/config.xml
@@ -38,13 +38,15 @@
     <cfg:component class="org.apache.river.container.codebase.ClassServer"/>
 
     <!-- Deployer for 'service-starter'-style applications. -->
-    <cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer">
+    <cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer"
+        name="starter-service-deployer">
         <cfg:property name="config" value="service-starter.cfg"/>
     </cfg:component>
     
     <!-- Deployer for applications that are in the 'deploy' directory
     at startup. -->
-    <cfg:component class="org.apache.river.container.deployer.StartupDeployer">
+    <cfg:component class="org.apache.river.container.deployer.FolderBasedAppRunner" name="deploy">
+        <cfg:property name="deployerName" value="starter-service-deployer"/>
         <cfg:property name="deployDirectory" value="deploy"/>
         <cfg:property name="autoDeploy" value="true"/>
     </cfg:component>
@@ -59,7 +61,8 @@
     
     <!-- Deployer for applications that are in the 'deploy' directory
     at startup. -->
-    <cfg:component class="org.apache.river.container.deployer.StartupDeployer">
+    <cfg:component class="org.apache.river.container.deployer.FolderBasedAppRunner"
+        name="deploy-privileged">
         <cfg:property name="deployDirectory" value="deploy-privileged"/>
         <cfg:property name="autoDeploy" value="true"/>
         <cfg:property name="deployerName" value="privileged-deployer"/>

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/product/src/main/root/profile/outrigger/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/outrigger/config.xml b/product/src/main/root/profile/outrigger/config.xml
index 7d81f52..5dcd2e0 100644
--- a/product/src/main/root/profile/outrigger/config.xml
+++ b/product/src/main/root/profile/outrigger/config.xml
@@ -44,7 +44,7 @@
     
     <!-- Deployer for applications that are in the 'deploy' directory
     at startup. -->
-    <cfg:component class="org.apache.river.container.deployer.StartupDeployer">
+    <cfg:component class="org.apache.river.container.deployer.FolderBasedAppRunner">
         <cfg:property name="deployDirectory" value="deploy"/>
         <cfg:property name="autoDeploy" value="true"/>
     </cfg:component>

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/pom.xml
----------------------------------------------------------------------
diff --git a/river-container-core/pom.xml b/river-container-core/pom.xml
index 1bce606..e3c5727 100644
--- a/river-container-core/pom.xml
+++ b/river-container-core/pom.xml
@@ -61,9 +61,17 @@
     
         <dependency>
             <groupId>org.apache.river.container</groupId>
-            <artifactId>reggie-module</artifactId>
+            <artifactId>admin-svc-api</artifactId>
             <version>1.0-SNAPSHOT</version>
             
+            <scope>compile</scope>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.apache.river.container</groupId>
+            <artifactId>reggie-module</artifactId>
+            <version>${project.version}</version>
+            
             <scope>test</scope>
         </dependency>
         

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/ApplicationManager.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/ApplicationManager.java b/river-container-core/src/main/java/org/apache/river/container/ApplicationManager.java
new file mode 100644
index 0000000..346c388
--- /dev/null
+++ b/river-container-core/src/main/java/org/apache/river/container/ApplicationManager.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.container;
+
+import java.util.List;
+import org.apache.river.container.admin.api.ApplicationInfo;
+
+/**
+ *
+ * @author trasukg
+ */
+public interface ApplicationManager {
+    List<ApplicationInfo> getApplicationInfo();
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/Context.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Context.java b/river-container-core/src/main/java/org/apache/river/container/Context.java
index bbf2de6..89047e1 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Context.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Context.java
@@ -19,6 +19,7 @@
 package org.apache.river.container;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -65,6 +66,17 @@ public class Context {
         return contents.get(name);
     }
     
+    public <T extends Object> Collection<T> getAll(Class<T> type) {
+        List<T> list=new ArrayList<T>();
+        for (Object item:contents.values()) {
+            if (type.isAssignableFrom(item.getClass())) {
+                list.add((T) item);
+            }
+        }
+        return list;
+    }
+    
+
     /**
      Called by the bootstrapper to tell us that processing of the initialization
      file is now complete.

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
index 95828e8..7c404b8 100644
--- a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
+++ b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
@@ -78,6 +78,7 @@ public class MessageNames {
             DUPLICATE_CLASSPATH="duplicateClasspath",
             EXCEPTION_THROWN="exceptionThrown",
             EXCEPTION_WHILE_STOPPING="exceptionWhileStopping",
+            EXECUTOR_NAME_IS="executorNameIs",
             FAILED_CLEAN_SHUTDOWN="failedCleanShutdown",
             FAILED_DEPLOY_SERVICE="failedDeployService",
             FAILED_READ_PROPERTIES="failedReadProperties",

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/Strings.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Strings.java b/river-container-core/src/main/java/org/apache/river/container/Strings.java
index 76510b3..48dfa55 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Strings.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Strings.java
@@ -80,6 +80,7 @@ public class Strings {
             UNKNOWN="unknown",
             UNNAMED="unnamed",
             WHITESPACE_SEPARATORS=" \t\n\r",
-            WORK="work";
+            WORK="work",
+            WORKING_DIRECTORY="workingDirectory";
 
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/ApplicationEnvironment.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/ApplicationEnvironment.java b/river-container-core/src/main/java/org/apache/river/container/deployer/ApplicationEnvironment.java
index dc9dab3..47f1c3f 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/ApplicationEnvironment.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/ApplicationEnvironment.java
@@ -18,6 +18,7 @@
 
 package org.apache.river.container.deployer;
 
+import java.io.File;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.river.container.classloading.VirtualFileSystemClassLoader;
 import org.apache.river.container.codebase.CodebaseContext;
@@ -30,6 +31,16 @@ import org.apache.river.container.work.WorkingContext;
 public class ApplicationEnvironment {
     VirtualFileSystemClassLoader classLoader=null;
 
+    String applicationManagerName=null;
+
+    public String getApplicationManagerName() {
+        return applicationManagerName;
+    }
+
+    public void setApplicationManagerName(String applicationManagerName) {
+        this.applicationManagerName = applicationManagerName;
+    }
+    
     String serviceName=null;
 
     public String getServiceName() {
@@ -95,4 +106,15 @@ public class ApplicationEnvironment {
         this.workingContext = workingContext;
     }
     
+    File workingDirectory=null;
+
+    public File getWorkingDirectory() {
+        return workingDirectory;
+    }
+
+    public void setWorkingDirectory(File workingDirectory) {
+        this.workingDirectory = workingDirectory;
+    }
+    
+    
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
deleted file mode 100644
index f3c3638..0000000
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.river.container.deployer;
-
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.ResourceBundle;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.MBeanRegistrationException;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.ObjectName;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileType;
-import org.apache.river.container.ConfigurationException;
-import org.apache.river.container.Context;
-import org.apache.river.container.FileUtility;
-import org.apache.river.container.Init;
-import org.apache.river.container.Injected;
-import org.apache.river.container.InjectionStyle;
-import org.apache.river.container.MBeanRegistrar;
-import org.apache.river.container.MessageNames;
-import org.apache.river.container.Name;
-import org.apache.river.container.Utils;
-
-/**
- *
- * A Deployer task that deploys all the applications in a given directory when
- * the container is started up.
- */
-public class ClientAppDeployer {
-
-    private static final Logger log
-            = Logger.getLogger(ClientAppDeployer.class.getName(), MessageNames.BUNDLE_NAME);
-
-    @Injected
-    ResourceBundle messages;
-
-    @Injected
-    public String[] commandLineArguments = null;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    Context context = null;
-
-    private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private FileUtility fileUtility = null;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private StarterServiceDeployer deployer;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private MBeanRegistrar mbeanRegistrar;
-
-    @Name
-    private String myName = null;
-
-    private List<ApplicationEnvironment> applicationEnvironments
-            = new ArrayList<ApplicationEnvironment>();
-
-    public String getDeployDirectory() {
-        return deployDirectory;
-    }
-
-    public void setDeployDirectory(String deployDirectory) {
-        this.deployDirectory = deployDirectory;
-    }
-
-    FileObject deploymentDirectoryFile = null;
-
-    private String clientAppName = null;
-
-    public String getClientAppName() {
-        return clientAppName;
-    }
-
-    /**
-     * Set the client app that should be loaded. If not provided, client app
-     * name is taken from the first parameter.
-     *
-     * @param clientApp
-     */
-    public void setClientAppName(String clientApp) {
-        this.clientAppName = clientApp;
-    }
-
-    @Init
-    public void init() {
-        try {
-            tryInitialize();
-        } catch (Throwable ex) {
-            log.log(Level.SEVERE, MessageNames.STARTUP_DEPLOYER_FAILED_INIT,
-                    ex);
-            throw new ConfigurationException(ex,
-                    MessageNames.STARTUP_DEPLOYER_FAILED_INIT);
-        }
-    }
-
-    private void tryInitialize() throws IOException, ParseException {
-        log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
-
-        /*
-         Establish the deployment directory.
-         */
-        deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);
-        if (deploymentDirectoryFile == null
-                || deploymentDirectoryFile.getType() != FileType.FOLDER) {
-            log.log(Level.WARNING, MessageNames.NO_DEPLOYMENT_DIRECTORY,
-                    new Object[]{deployDirectory, fileUtility.getProfileDirectory()});
-        }
-        /*
-         * Find the name of the client we need to deploy.  
-         */
-        /* First argument was the profile name.  Second argument is the name of 
-         * the client app to run.  All the rest are parameters to the client
-         * app.
-         */
-        if (clientAppName == null && commandLineArguments.length < 2) {
-            System.out.println(messages.getString(MessageNames.CLIENT_APP_USAGE));
-            System.exit(1);
-        }
-        String[] clientAppArgs;
-        if (clientAppName == null) {
-            clientAppName = commandLineArguments[1];
-            clientAppArgs = new String[commandLineArguments.length - 2];
-            System.arraycopy(commandLineArguments, 2, clientAppArgs, 0,
-                    clientAppArgs.length);
-        } else {
-            clientAppArgs = new String[commandLineArguments.length - 1];
-            System.arraycopy(commandLineArguments, 1, clientAppArgs, 0,
-                    clientAppArgs.length);
-        }
-        // Locate the service archive that has the client's name.
-        // First get all the jar files.
-        List<FileObject> serviceArchives
-                = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
-                        org.apache.river.container.Strings.JAR);
-        //Then find the one that starts with the client name
-        FileObject serviceArchive = null;
-        for (FileObject fo : serviceArchives) {
-            if (fo.getName().getBaseName().startsWith(clientAppName + org.apache.river.container.Strings.DASH)) {
-                serviceArchive = fo;
-                break;
-            }
-
-        }
-
-        if (serviceArchive == null) {
-            System.err.println(MessageFormat.format(messages.getString(MessageNames.NO_SUCH_CLIENT_APP), clientAppName));
-            System.exit(1);
-        }
-        // Deploy the service
-        deployServiceArchive(serviceArchive, clientAppArgs);
-        // Run the main method with the remaining command line parameters.
-    }
-
-    private void deployServiceArchive(FileObject archiveFile, String[] commandLineArgs) {
-        try {
-            /* Try the archive in all the deployers to see if someone can 
-             * handle it. For now there's only one.
-             */
-
-            /*
-             * Create the ApplicationEnvironment for the archive.
-             */
-            ServiceLifeCycle deployedApp = deployer.deployServiceArchive(archiveFile);
-
-            deployedApp.startWithArgs(commandLineArgs);
-        } catch (Throwable t) {
-            log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, archiveFile.toString());
-            log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/CommandLineAppRunner.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/CommandLineAppRunner.java b/river-container-core/src/main/java/org/apache/river/container/deployer/CommandLineAppRunner.java
new file mode 100644
index 0000000..ed2abf6
--- /dev/null
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/CommandLineAppRunner.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.river.container.deployer;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileType;
+import org.apache.river.container.ConfigurationException;
+import org.apache.river.container.Context;
+import org.apache.river.container.FileUtility;
+import org.apache.river.container.Init;
+import org.apache.river.container.Injected;
+import org.apache.river.container.InjectionStyle;
+import org.apache.river.container.MBeanRegistrar;
+import org.apache.river.container.MessageNames;
+import org.apache.river.container.Name;
+import org.apache.river.container.Utils;
+
+/**
+ *
+ * A runner task that looks at the command line to determine the name of an
+ * application to run from a deployment folder.  Generally used to run "client"
+ * apps where the name of the app is supplied on the command line, for instance
+ * the browser app or the admin client app.
+ */
+public class CommandLineAppRunner {
+
+    private static final Logger log
+            = Logger.getLogger(CommandLineAppRunner.class.getName(), MessageNames.BUNDLE_NAME);
+
+    @Injected
+    ResourceBundle messages;
+
+    @Injected
+    public String[] commandLineArguments = null;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    Context context = null;
+
+    private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private FileUtility fileUtility = null;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private StarterServiceDeployer deployer;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private MBeanRegistrar mbeanRegistrar;
+
+    @Name
+    private String myName = null;
+
+    private List<ApplicationEnvironment> applicationEnvironments
+            = new ArrayList<ApplicationEnvironment>();
+
+    public String getDeployDirectory() {
+        return deployDirectory;
+    }
+
+    public void setDeployDirectory(String deployDirectory) {
+        this.deployDirectory = deployDirectory;
+    }
+
+    FileObject deploymentDirectoryFile = null;
+
+    private String clientAppName = null;
+
+    public String getClientAppName() {
+        return clientAppName;
+    }
+
+    /**
+     * Set the client app that should be loaded. If not provided, client app
+     * name is taken from the first parameter.
+     *
+     * @param clientApp
+     */
+    public void setClientAppName(String clientApp) {
+        this.clientAppName = clientApp;
+    }
+
+    @Init
+    public void init() {
+        try {
+            tryInitialize();
+        } catch (Throwable ex) {
+            log.log(Level.SEVERE, MessageNames.STARTUP_DEPLOYER_FAILED_INIT,
+                    ex);
+            throw new ConfigurationException(ex,
+                    MessageNames.STARTUP_DEPLOYER_FAILED_INIT);
+        }
+    }
+
+    private void tryInitialize() throws IOException, ParseException {
+        log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
+
+        /*
+         Establish the deployment directory.
+         */
+        deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);
+        if (deploymentDirectoryFile == null
+                || deploymentDirectoryFile.getType() != FileType.FOLDER) {
+            log.log(Level.WARNING, MessageNames.NO_DEPLOYMENT_DIRECTORY,
+                    new Object[]{deployDirectory, fileUtility.getProfileDirectory()});
+        }
+        /*
+         * Find the name of the client we need to deploy.  
+         */
+        /* First argument was the profile name.  Second argument is the name of 
+         * the client app to run.  All the rest are parameters to the client
+         * app.
+         */
+        if (clientAppName == null && commandLineArguments.length < 2) {
+            System.out.println(messages.getString(MessageNames.CLIENT_APP_USAGE));
+            System.exit(1);
+        }
+        String[] clientAppArgs;
+        if (clientAppName == null) {
+            clientAppName = commandLineArguments[1];
+            clientAppArgs = new String[commandLineArguments.length - 2];
+            System.arraycopy(commandLineArguments, 2, clientAppArgs, 0,
+                    clientAppArgs.length);
+        } else {
+            clientAppArgs = new String[commandLineArguments.length - 1];
+            System.arraycopy(commandLineArguments, 1, clientAppArgs, 0,
+                    clientAppArgs.length);
+        }
+        // Locate the service archive that has the client's name.
+        // First get all the jar files.
+        List<FileObject> serviceArchives
+                = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
+                        org.apache.river.container.Strings.JAR);
+        //Then find the one that starts with the client name
+        FileObject serviceArchive = null;
+        for (FileObject fo : serviceArchives) {
+            if (fo.getName().getBaseName().startsWith(clientAppName + org.apache.river.container.Strings.DASH)) {
+                serviceArchive = fo;
+                break;
+            }
+
+        }
+
+        if (serviceArchive == null) {
+            System.err.println(MessageFormat.format(messages.getString(MessageNames.NO_SUCH_CLIENT_APP), clientAppName));
+            System.exit(1);
+        }
+        // Deploy the service
+        deployServiceArchive(serviceArchive, clientAppArgs);
+        // Run the main method with the remaining command line parameters.
+    }
+
+    private void deployServiceArchive(FileObject archiveFile, String[] commandLineArgs) {
+        try {
+            /* Try the archive in all the deployers to see if someone can 
+             * handle it. For now there's only one.
+             */
+
+            /*
+             * Create the ApplicationEnvironment for the archive.
+             */
+            ServiceLifeCycle deployedApp = deployer.deployServiceArchive(myName, archiveFile);
+
+            deployedApp.startWithArgs(commandLineArgs);
+        } catch (Throwable t) {
+            log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, archiveFile.toString());
+            log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/FolderBasedAppRunner.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/FolderBasedAppRunner.java b/river-container-core/src/main/java/org/apache/river/container/deployer/FolderBasedAppRunner.java
new file mode 100644
index 0000000..1204420
--- /dev/null
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/FolderBasedAppRunner.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.river.container.deployer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileType;
+import org.apache.river.container.ApplicationManager;
+import org.apache.river.container.ConfigurationException;
+import org.apache.river.container.Context;
+import org.apache.river.container.FileUtility;
+import org.apache.river.container.Init;
+import org.apache.river.container.Injected;
+import org.apache.river.container.InjectionStyle;
+import org.apache.river.container.MBeanRegistrar;
+import org.apache.river.container.MessageNames;
+import org.apache.river.container.Name;
+import org.apache.river.container.Utils;
+import org.apache.river.container.admin.api.ApplicationInfo;
+import org.apache.river.container.admin.api.ApplicationStatus;
+
+/**
+ *
+ * A task that deploys and runs all the applications in a given directory when
+ * the container is started up.
+ */
+public class FolderBasedAppRunner implements ApplicationManager  {
+
+    private static final Logger log
+            = Logger.getLogger(FolderBasedAppRunner.class.getName(), MessageNames.BUNDLE_NAME);
+
+    private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private FileUtility fileUtility = null;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private Context context;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private StarterServiceDeployer deployer;
+
+    @Injected(style = InjectionStyle.BY_TYPE)
+    private MBeanRegistrar mbeanRegistrar;
+
+    @Name
+    private String myName = null;
+
+    private Map<String, DeploymentRecord> deployedServices = new HashMap<String, DeploymentRecord>();
+
+    private class DeploymentRecord {
+
+        String name;
+        long updateTime;
+        FileObject fileObject;
+        ServiceLifeCycle serviceLifeCycle;
+    }
+
+    private boolean autoDeploy = false;
+
+    public boolean isAutoDeploy() {
+        return autoDeploy;
+    }
+
+    public void setAutoDeploy(boolean autoDeploy) {
+        this.autoDeploy = autoDeploy;
+    }
+
+    public int getScanInterval() {
+        return scanInterval;
+    }
+
+    public void setScanInterval(int scanInterval) {
+        this.scanInterval = scanInterval;
+    }
+
+    private int scanInterval = 5;
+
+    public String getDeployDirectory() {
+        return deployDirectory;
+    }
+
+    public void setDeployDirectory(String deployDirectory) {
+        this.deployDirectory = deployDirectory;
+    }
+
+    FileObject deploymentDirectoryFile = null;
+
+    private String deployerName=null;
+
+    public String getDeployerName() {
+        return deployerName;
+    }
+
+    public void setDeployerName(String deployerName) {
+        this.deployerName = deployerName;
+    }
+    
+    @Init
+    public void init() {
+        try {
+            tryInitialize();
+        } catch (Throwable ex) {
+            log.log(Level.SEVERE, MessageNames.STARTUP_DEPLOYER_FAILED_INIT,
+                    ex);
+            throw new ConfigurationException(ex,
+                    MessageNames.STARTUP_DEPLOYER_FAILED_INIT);
+        }
+    }
+
+    private void tryInitialize() throws IOException, ParseException {
+        log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
+        /*
+        If the deployerName is supplied, look it up and override the injected deployer.
+        */
+        if(deployerName != null) {
+            deployer=(StarterServiceDeployer) context.get(deployerName);
+        }
+        /*
+         Establish the deployment directory.
+         */
+        deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);
+        if (deploymentDirectoryFile == null
+                || deploymentDirectoryFile.getType() != FileType.FOLDER) {
+            log.log(Level.WARNING, MessageNames.NO_DEPLOYMENT_DIRECTORY,
+                    new Object[]{deployDirectory, fileUtility.getProfileDirectory()});
+        }
+        /*
+         Do the scan task once - this will launch all the services currently in 
+         deploy dir.
+         */
+        new ScanTask().runOnce();
+
+        if (autoDeploy) {
+            /* Now schedule a scan in the required scan time. */
+            deployer.workManager.schedule(null, new ScanTask(), getScanInterval(), TimeUnit.SECONDS);
+        }
+    }
+
+    private void registerApplication(ServiceLifeCycle deployedApp) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+        Hashtable<String, String> props = new Hashtable<String, String>();
+        props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
+        ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
+        mbeanRegistrar.getMbeanServer().registerMBean(
+                deployedApp, oName);
+    }
+
+    private void unregisterApplication(ServiceLifeCycle deployedApp) {
+        try {
+            Hashtable<String, String> props = new Hashtable<String, String>();
+            props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
+            ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
+            mbeanRegistrar.getMbeanServer().unregisterMBean(oName);
+        } catch (Exception e) {
+            log.log(Level.SEVERE, MessageNames.FAILED_TO_REMOVE_MBEAN,
+                    new Object[]{deployedApp.getName()});
+        }
+    }
+
+    private Map<String, DeploymentRecord> scanDeploymentArchives() throws FileSystemException {
+        /*
+         Go through the deployment directory looking for services to deploy.
+         */
+        Map<String, DeploymentRecord> deployDirListing = new HashMap<String, DeploymentRecord>();
+        deploymentDirectoryFile.refresh();
+        List<FileObject> serviceArchives
+                = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
+                        org.apache.river.container.Strings.JAR);
+        if (serviceArchives != null) {
+            log.log(Level.FINER, MessageNames.FOUND_SERVICE_ARCHIVES,
+                    new Object[]{serviceArchives.size(), deployDirectory});
+            for (FileObject serviceArchive : serviceArchives) {
+                DeploymentRecord rec = new DeploymentRecord();
+                rec.fileObject = serviceArchive;
+                rec.name = serviceArchive.getName().getBaseName();
+                rec.updateTime = serviceArchive.getContent().getLastModifiedTime();
+                deployDirListing.put(rec.name, rec);
+            }
+        }
+        return deployDirListing;
+    }
+
+    private class ScanTask implements Runnable {
+
+        public void runOnce() {
+            try {
+                log.log(Level.FINER, MessageNames.SCANNING_DEPLOYMENT_DIRECTORY,
+                        new Object[]{deployDirectory});
+                Map<String, DeploymentRecord> deployDirListing = scanDeploymentArchives();
+                // DeployDirListing will become the deployedServices collection
+                synchDeployedServices(deployedServices, deployDirListing);
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
+        }
+
+        public void run() {
+            runOnce();
+            deployer.workManager.schedule(null, this, scanInterval, TimeUnit.SECONDS);
+        }
+    }
+
+    private synchronized void synchDeployedServices(Map<String, DeploymentRecord> currentList,
+            Map<String, DeploymentRecord> newList) {
+        // For each entry
+        for (DeploymentRecord rec : newList.values()) {
+            // If it isn't already in deployedServices, start it
+            DeploymentRecord current = currentList.get(rec.name);
+            if (current == null) {
+                log.log(Level.FINE, MessageNames.STARTING_SERVICE,
+                        new Object[]{rec.name});
+                currentList.put(rec.name, rec);
+                deployAndStart(rec);
+            } else if (current.updateTime != rec.updateTime) {
+                // If it's in deployedServices but now newer, stop and restart
+                log.log(Level.FINE, MessageNames.UPDATING_SERVICE,
+                        new Object[]{rec.name});
+                currentList.remove(current.name);
+                stopAndRemove(current);
+                currentList.put(rec.name, rec);
+                deployAndStart(rec);
+            }
+        }
+        // If there are any services left in deployedServices, stop them
+        List<DeploymentRecord> removals = new ArrayList<DeploymentRecord>();
+        for (DeploymentRecord current : currentList.values()) {
+            if (!newList.containsKey(current.name)) {
+                removals.add(current);
+            }
+        }
+        for (DeploymentRecord current : removals) {
+            log.log(Level.FINE, MessageNames.STOPPING_SERVICE,
+                    new Object[]{current.name});
+            currentList.remove(current.name);
+            stopAndRemove(current);
+        }
+
+    }
+
+    private void deployAndStart(DeploymentRecord dr) {
+        try {
+            /* Try the archive in all the deployers to see if someone can 
+             * handle it. For now there's only one.
+             */
+
+            /*
+             * Create the ApplicationEnvironment for the archive.
+             */
+            dr.serviceLifeCycle = deployer.deployServiceArchive(myName, dr.fileObject);
+            // Register it as an MBean
+            registerApplication(dr.serviceLifeCycle);
+            dr.serviceLifeCycle.start();
+        } catch (Throwable t) {
+            log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, dr.name);
+            log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
+        }
+
+    }
+
+    private void stopAndRemove(DeploymentRecord dr) {
+        dr.serviceLifeCycle.stop();
+        unregisterApplication(dr.serviceLifeCycle);
+    }
+
+    public synchronized List<ApplicationInfo> getApplicationInfo() {
+        List<ApplicationInfo> info=new ArrayList<ApplicationInfo>(deployedServices.size());
+        for (DeploymentRecord rec: deployedServices.values()) {
+            ApplicationInfo item=new ApplicationInfo(myName, rec.name, toApplicationStatus(rec.serviceLifeCycle));
+            info.add(item);
+        }
+        return info;
+    }
+    
+    ApplicationStatus toApplicationStatus(ServiceLifeCycle lc) {
+        String status=lc.getStatus();
+        if (Strings.RUNNING.equals(status)) {
+            return ApplicationStatus.RUNNING;
+        }
+        if (Strings.IDLE.equals(status)) {
+            return ApplicationStatus.STOPPED;
+        }
+        if (Strings.FAILED.equals(status)) {
+            return ApplicationStatus.FAILED;
+        }
+        return ApplicationStatus.UNKNOWN;
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
index 500bf90..8016c6a 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
@@ -73,7 +73,7 @@ import org.apache.river.container.work.WorkManager;
  * Deployer that instantiates applications or services based on the
  * com.sun.jini.starter API
  */
-public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
+public class StarterServiceDeployer  {
 
     private static final Logger log
             = Logger.getLogger(StarterServiceDeployer.class.getName(), MessageNames.BUNDLE_NAME);
@@ -276,13 +276,18 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
             Thread.currentThread().setContextClassLoader(env.getClassLoader());
             File workingDir = null;
             if (env.getServiceArchive() != null) {
-                /* TODO: Is this right?  Shouldn't the working directory be created
-                by the file manager under the 'work' dir?
+                /* This variable, and the method we're calling on VirtualFileSystemConfiguration,
+                is named in an unfortunate manner for 
+                historical reasons.  What we're really doing here is telling the 
+                VirtualFileSystemConfiguration where to read its configuration 
+                file from.  Iternally to VFSConfig, it's called the "root" directory.
+                It has nothing to do with the "working" directory where the service
+                should be allowed to write its own data.
                 */
                 workingDir = new File(env.getServiceArchive().getURL().toURI());
             } else {
                 workingDir = new File(env.getServiceArchive().getURL().toURI());
-
+            
             }
 
             grantPermissions(env.getClassLoader(),
@@ -311,7 +316,16 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
                             new Object[]{getConfig(), varName, contextVarName});
                 }
             }
+            
+            /* 
+            One extra "special" variable is the File that gives the working directory.
+            */
+            invokeStatic(env.getClassLoader(), configName, Strings.PUT_SPECIAL_ENTRY,
+                    new Class[]{String.class, Object.class},
+                    Strings.DOLLAR + Strings.WORKING_DIRECTORY, env.getWorkingDirectory());
             /* Install the Executor. */
+            log.log(Level.INFO, MessageNames.EXECUTOR_NAME_IS, 
+                    new Object[]{Strings.DOLLAR + Strings.EXECUTOR_NAME});
             invokeStatic(env.getClassLoader(), configName,
                     Strings.PUT_SPECIAL_ENTRY,
                     new Class[]{String.class, Object.class
@@ -341,9 +355,10 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
                 new Object[]{myName});
     }
 
-    public ServiceLifeCycle deployServiceArchive(FileObject serviceArchive) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
+    public ServiceLifeCycle deployServiceArchive(String managerName, FileObject serviceArchive) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
         // Create an application environment
         ApplicationEnvironment env = new ApplicationEnvironment();
+        env.setApplicationManagerName(managerName);
         env.setServiceArchive(serviceArchive);
         env.setServiceRoot(
                 serviceArchive.getFileSystem().getFileSystemManager().createFileSystem(Strings.JAR, serviceArchive));
@@ -398,6 +413,12 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         grantPermissions(cl, perms);
         
         /*
+         Create the service's working directory and grant permissions to it.
+        */
+        createWorkDirectoryFor(env);
+        grantPermissionsToWorkDirectoryFor(env);
+        
+        /*
          * Create a working context (work manager).
          */
         env.setWorkingContext(contextualWorkManager.createContext(env.getServiceName(), env.getClassLoader()));
@@ -580,4 +601,21 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         }
 
     }
+    
+    void createWorkDirectoryFor(ApplicationEnvironment env) throws IOException {
+        FileObject managerDir=fileUtility.getWorkingDirectory(env.getApplicationManagerName());
+        FileObject workingDir=managerDir.resolveFile(env.getServiceName());
+        if (!workingDir.exists()) {
+            workingDir.createFolder();
+        }
+        File workingDirFile=new File(workingDir.getName().getPath());
+        env.setWorkingDirectory(workingDirFile);
+    }
+    
+    void grantPermissionsToWorkDirectoryFor(ApplicationEnvironment env) {
+        Permission[] perms=new Permission[] {
+            new FilePermission(env.getWorkingDirectory().getAbsolutePath()+"/-","read,write,delete")
+        };
+        grantPermissions(env.getClassLoader(), perms);
+    }
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployerMXBean.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployerMXBean.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployerMXBean.java
deleted file mode 100644
index b091746..0000000
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployerMXBean.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.river.container.deployer;
-
-/**
- *
- * @author trasukg
- */
-public interface StarterServiceDeployerMXBean {
-
-}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
deleted file mode 100644
index 92c78ac..0000000
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.river.container.deployer;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanRegistrationException;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.ObjectName;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileType;
-import org.apache.river.container.ConfigurationException;
-import org.apache.river.container.Context;
-import org.apache.river.container.FileUtility;
-import org.apache.river.container.Init;
-import org.apache.river.container.Injected;
-import org.apache.river.container.InjectionStyle;
-import org.apache.river.container.MBeanRegistrar;
-import org.apache.river.container.MessageNames;
-import org.apache.river.container.Name;
-import org.apache.river.container.Utils;
-
-/**
- *
- * A Deployer task that deploys all the applications in a given directory when
- * the container is started up.
- */
-public class StartupDeployer {
-
-    private static final Logger log
-            = Logger.getLogger(StartupDeployer.class.getName(), MessageNames.BUNDLE_NAME);
-
-    private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private FileUtility fileUtility = null;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private Context context;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private StarterServiceDeployer deployer;
-
-    @Injected(style = InjectionStyle.BY_TYPE)
-    private MBeanRegistrar mbeanRegistrar;
-
-    @Name
-    private String myName = null;
-
-    private Map<String, DeploymentRecord> deployedServices = new HashMap<String, DeploymentRecord>();
-
-    private class DeploymentRecord {
-
-        String name;
-        long updateTime;
-        FileObject fileObject;
-        ServiceLifeCycle serviceLifeCycle;
-    }
-
-    private boolean autoDeploy = false;
-
-    public boolean isAutoDeploy() {
-        return autoDeploy;
-    }
-
-    public void setAutoDeploy(boolean autoDeploy) {
-        this.autoDeploy = autoDeploy;
-    }
-
-    public int getScanInterval() {
-        return scanInterval;
-    }
-
-    public void setScanInterval(int scanInterval) {
-        this.scanInterval = scanInterval;
-    }
-
-    private int scanInterval = 5;
-
-    public String getDeployDirectory() {
-        return deployDirectory;
-    }
-
-    public void setDeployDirectory(String deployDirectory) {
-        this.deployDirectory = deployDirectory;
-    }
-
-    FileObject deploymentDirectoryFile = null;
-
-    private String deployerName=null;
-
-    public String getDeployerName() {
-        return deployerName;
-    }
-
-    public void setDeployerName(String deployerName) {
-        this.deployerName = deployerName;
-    }
-    
-    @Init
-    public void init() {
-        try {
-            tryInitialize();
-        } catch (Throwable ex) {
-            log.log(Level.SEVERE, MessageNames.STARTUP_DEPLOYER_FAILED_INIT,
-                    ex);
-            throw new ConfigurationException(ex,
-                    MessageNames.STARTUP_DEPLOYER_FAILED_INIT);
-        }
-    }
-
-    private void tryInitialize() throws IOException, ParseException {
-        log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
-        /*
-        If the deployerName is supplied, look it up and override the injected deployer.
-        */
-        if(deployerName != null) {
-            deployer=(StarterServiceDeployer) context.get(deployerName);
-        }
-        /*
-         Establish the deployment directory.
-         */
-        deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);
-        if (deploymentDirectoryFile == null
-                || deploymentDirectoryFile.getType() != FileType.FOLDER) {
-            log.log(Level.WARNING, MessageNames.NO_DEPLOYMENT_DIRECTORY,
-                    new Object[]{deployDirectory, fileUtility.getProfileDirectory()});
-        }
-        /*
-         Do the scan task once - this will launch all the services currently in 
-         deploy dir.
-         */
-        new ScanTask().runOnce();
-
-        if (autoDeploy) {
-            /* Now schedule a scan in the required scan time. */
-            deployer.workManager.schedule(null, new ScanTask(), getScanInterval(), TimeUnit.SECONDS);
-        }
-    }
-
-    private void registerApplication(ServiceLifeCycle deployedApp) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
-        Hashtable<String, String> props = new Hashtable<String, String>();
-        props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
-        ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
-        mbeanRegistrar.getMbeanServer().registerMBean(
-                deployedApp, oName);
-    }
-
-    private void unregisterApplication(ServiceLifeCycle deployedApp) {
-        try {
-            Hashtable<String, String> props = new Hashtable<String, String>();
-            props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
-            ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
-            mbeanRegistrar.getMbeanServer().unregisterMBean(oName);
-        } catch (Exception e) {
-            log.log(Level.SEVERE, MessageNames.FAILED_TO_REMOVE_MBEAN,
-                    new Object[]{deployedApp.getName()});
-        }
-    }
-
-    private Map<String, DeploymentRecord> scanDeploymentArchives() throws FileSystemException {
-        /*
-         Go through the deployment directory looking for services to deploy.
-         */
-        Map<String, DeploymentRecord> deployDirListing = new HashMap<String, DeploymentRecord>();
-        deploymentDirectoryFile.refresh();
-        List<FileObject> serviceArchives
-                = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
-                        org.apache.river.container.Strings.JAR);
-        if (serviceArchives != null) {
-            log.log(Level.FINER, MessageNames.FOUND_SERVICE_ARCHIVES,
-                    new Object[]{serviceArchives.size(), deployDirectory});
-            for (FileObject serviceArchive : serviceArchives) {
-                DeploymentRecord rec = new DeploymentRecord();
-                rec.fileObject = serviceArchive;
-                rec.name = serviceArchive.getName().getBaseName();
-                rec.updateTime = serviceArchive.getContent().getLastModifiedTime();
-                deployDirListing.put(rec.name, rec);
-            }
-        }
-        return deployDirListing;
-    }
-
-    private class ScanTask implements Runnable {
-
-        public void runOnce() {
-            try {
-                log.log(Level.FINER, MessageNames.SCANNING_DEPLOYMENT_DIRECTORY,
-                        new Object[]{deployDirectory});
-                Map<String, DeploymentRecord> deployDirListing = scanDeploymentArchives();
-                // DeployDirListing will become the deployedServices collection
-                synchDeployedServices(deployedServices, deployDirListing);
-            } catch (Throwable t) {
-                t.printStackTrace();
-            }
-        }
-
-        public void run() {
-            runOnce();
-            deployer.workManager.schedule(null, this, scanInterval, TimeUnit.SECONDS);
-        }
-    }
-
-    private void synchDeployedServices(Map<String, DeploymentRecord> currentList,
-            Map<String, DeploymentRecord> newList) {
-        // For each entry
-        for (DeploymentRecord rec : newList.values()) {
-            // If it isn't already in deployedServices, start it
-            DeploymentRecord current = currentList.get(rec.name);
-            if (current == null) {
-                log.log(Level.FINE, MessageNames.STARTING_SERVICE,
-                        new Object[]{rec.name});
-                currentList.put(rec.name, rec);
-                deployAndStart(rec);
-            } else if (current.updateTime != rec.updateTime) {
-                // If it's in deployedServices but now newer, stop and restart
-                log.log(Level.FINE, MessageNames.UPDATING_SERVICE,
-                        new Object[]{rec.name});
-                currentList.remove(current.name);
-                stopAndRemove(current);
-                currentList.put(rec.name, rec);
-                deployAndStart(rec);
-            }
-        }
-        // If there are any services left in deployedServices, stop them
-        List<DeploymentRecord> removals = new ArrayList<DeploymentRecord>();
-        for (DeploymentRecord current : currentList.values()) {
-            if (!newList.containsKey(current.name)) {
-                removals.add(current);
-            }
-        }
-        for (DeploymentRecord current : removals) {
-            log.log(Level.FINE, MessageNames.STOPPING_SERVICE,
-                    new Object[]{current.name});
-            currentList.remove(current.name);
-            stopAndRemove(current);
-        }
-
-    }
-
-    private void deployAndStart(DeploymentRecord dr) {
-        try {
-            /* Try the archive in all the deployers to see if someone can 
-             * handle it. For now there's only one.
-             */
-
-            /*
-             * Create the ApplicationEnvironment for the archive.
-             */
-            dr.serviceLifeCycle = deployer.deployServiceArchive(dr.fileObject);
-            // Register it as an MBean
-            registerApplication(dr.serviceLifeCycle);
-            dr.serviceLifeCycle.start();
-        } catch (Throwable t) {
-            log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, dr.name);
-            log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
-        }
-
-    }
-
-    private void stopAndRemove(DeploymentRecord dr) {
-        dr.serviceLifeCycle.stop();
-        unregisterApplication(dr.serviceLifeCycle);
-    }
-}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/java/org/apache/river/container/deployer/Strings.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/Strings.java b/river-container-core/src/main/java/org/apache/river/container/deployer/Strings.java
index 3f48d84..b7158f9 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/Strings.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/Strings.java
@@ -25,7 +25,10 @@ package org.apache.river.container.deployer;
 public class Strings {
     public static final String
             EMPTY="",
+            FAILED="Failed",
+            IDLE="Idle",
             LPAREN="(",
             RPAREN=")",
+            RUNNING="Running",
             SPACE=" ";
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
index 2dcf8c2..f700f4a 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
+++ b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
@@ -57,6 +57,7 @@ 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}
+executorNameIs=Executor name is ''{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.

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
index d4bb419..05db56a 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
+++ b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
@@ -55,6 +55,7 @@
         lib/jsk-resources-${jsk-version}.jar
         lib/regexp-1.3.jar
         lib/river-hsm-${project.version}.jar
+        lib/admin-svc-api-${project.version}.jar
     </cfg:classpath>
 
     <!--cfg:component class="org.apache.river.container.ShowContextToConsole"/-->

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/river-container-core/src/test/java/org/apache/river/container/ContextTest.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/test/java/org/apache/river/container/ContextTest.java b/river-container-core/src/test/java/org/apache/river/container/ContextTest.java
new file mode 100644
index 0000000..9d62ee3
--- /dev/null
+++ b/river-container-core/src/test/java/org/apache/river/container/ContextTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.container;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import org.apache.river.container.admin.api.ApplicationInfo;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author trasukg
+ */
+public class ContextTest {
+    
+    Context UUT=new Context();
+    
+    public ContextTest() {
+    }
+    
+    @BeforeClass
+    public static void setUpClass() {
+    }
+    
+    @AfterClass
+    public static void tearDownClass() {
+    }
+    
+    @Before
+    public void setUp() {
+    }
+    
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void testGetByClass() {
+        UUT.put(new Object());
+        UUT.put(new Date());
+        ApplicationManager am=new ApplicationManager() {
+            public List<ApplicationInfo> getApplicationInfo() {
+                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+            }
+        };
+        UUT.put(am);
+        Collection<ApplicationManager> ams=UUT.getAll(ApplicationManager.class);
+        assertEquals("Count of ApplicationManagers",1, ams.size());
+        assertEquals("ApplicationManagerInstance", am, ams.iterator().next());
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/test-container/src/main/root/profile/client/config.xml
----------------------------------------------------------------------
diff --git a/test-container/src/main/root/profile/client/config.xml b/test-container/src/main/root/profile/client/config.xml
index 1c108d1..941d075 100644
--- a/test-container/src/main/root/profile/client/config.xml
+++ b/test-container/src/main/root/profile/client/config.xml
@@ -44,7 +44,7 @@
     </cfg:component>
     
     <!-- Deployer for 'service-starter'-style applications. -->
-    <cfg:component class="org.apache.river.container.deployer.ClientAppDeployer">
+    <cfg:component class="org.apache.river.container.deployer.CommandLineAppRunner">
         <cfg:property name="config" value="client-app.cfg"/>
         <cfg:property name="deployDirectory" value="deploy"/>
     </cfg:component>

http://git-wip-us.apache.org/repos/asf/river-container/blob/33855de2/test-container/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/test-container/src/main/root/profile/default/config.xml b/test-container/src/main/root/profile/default/config.xml
index 06108ed..8525202 100644
--- a/test-container/src/main/root/profile/default/config.xml
+++ b/test-container/src/main/root/profile/default/config.xml
@@ -45,7 +45,7 @@
     
     <!-- Deployer for applications that are in the 'deploy' directory
     at startup. -->
-    <cfg:component class="org.apache.river.container.deployer.StartupDeployer">
+    <cfg:component class="org.apache.river.container.deployer.FolderBasedAppRunner">
         <cfg:property name="config" value="service-starter.cfg"/>
         <cfg:property name="deployDirectory" value="deploy"/>
     </cfg:component>


[8/8] git commit: Readme.md now contains a "First Fifteen Minutes" guide to building and running the container and a 'hello-world' example.

Posted by gt...@apache.org.
Readme.md now contains a "First Fifteen Minutes" guide to building and running the container and a 'hello-world' example.

Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/496e36fc
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/496e36fc
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/496e36fc

Branch: refs/heads/plugin-work
Commit: 496e36fcbf192165a027343af29db09a7572a0e4
Parents: 33855de
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Tue Feb 18 09:14:41 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Tue Feb 18 09:14:41 2014 -0500

----------------------------------------------------------------------
 README.md                                       | 104 ++++++++++++++++++-
 .../src/main/root/profile/default/config.xml    |   5 +
 2 files changed, 105 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/496e36fc/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 23a59d7..7e59b85 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,103 @@
 river-container
 ===============
 
-Initial development on Apache River Container
+This project is the initial development of the Apache River Container.
+It is _not_ yet released as Apache Software.  Use at your own risk, and please
+post comments to dev@river.apache.org.
+
+The First Fifteen Minutes
+=========================
+
+Let's assume you've managed to download the source from git.  In fact, let's assume that
+you're reasonably conversant with git, so you can pull the examples project below.
+
+# Before You Start  
+You'll need Maven 3.x installed, such that you can run 'mvn' from the command
+line.  
+
+# Build From Source 
+
+<i>This step may not be required in the future, since you'll be able to 
+download a convenience binary once the project is released</i>
+
+Go to the root of the river-container download, and type  
+    mvn clean install
+
+# Run the default container profile  
+    cd product/target/product*
+    bin/run 
+
+The steps above will startup a default container that has instances of the 
+service registrar (Reggie) and the transaction manager (Mahalo).  All services
+are registered in a workgroup called 'RiverContainerDefault'.
+
+# Run the service browser  
+Open a new command line window in the root of the river-container download, then
+do the following  
+    cd product/target/product*
+    bin/run client browser
+
+You'll see a service browser window open up.  It should show one registrar.
+Select the registrar.  You should now see the infrastructure services, Reggie and 
+Mahalo.  Leave the service browser running while we start up a "Hello-world" 
+service, below.
+
+# Compile a "Hello-World" Service
+
+<i>Maybe the 'hello-world' example should be included in the container deliverable?
+Please comment on 'dev@river.apache.org'.</i>
+
+<i>Eventually, we should be able to create this example service using a Maven
+archetype.</i>
+
+Using git, pull the examples from https://github.com/trasukg/river-container-examples.
+
+'cd' into your hello-example' directory, and then  
+    mvn clean install
+
+# Deploy and run the "Hello-World" Service
+
+When Maven is done, you should be able to see the finished service archive,
+'hello-module/target/hello-module-1.0-SNAPSHOT.jar'
+
+Copy that 'jar' file into the
+'profiles/default/deploy' folder inside our 'river-container/product/target/product*' folder.
+
+<i>Eventually, we'll have a maven plugin that does this, so you can just do 
+'mvn river:deploy' rather than copying it manually.</i>
+
+If you left the container running, you should see some output indicating that the 
+service is being deployed.  If you didn't leave the container running, start it up now.
+
+You should also see the service in the service browser, with the interface
+'org.apache.river.container.hello.example.api.Greeter'
+
+# Deploy and Run the "Hello-World" Consumer
+
+When Maven finished above, it also created a client archive, 
+'hello-client-module/target/hello-client-module-1.0-SNAPSHOT.jar'
+
+Copy that 'jar' file into the
+'profiles/client/deploy' folder inside our 'river-container/product/target/product*' folder.
+
+Open a new command line window in the root of the river-container download, then
+do the following  
+    cd product/target/product*
+    bin/run client hello-client
+
+The client starts up, and eventually prompts 'Please enter your name'.  Enter
+your name and then press return.
+
+The client sends the greeter service a message, then prints out the reply.
+
+# Use the Network!
+
+If you have another machine on the local area network, and if the network is
+configured to allow multicast, you should be able to run the browser and the
+hello-client on a different machine.
+
+That concludes the 'First Fifteen Minutes' demo.  Below, there is a little more 
+detailed information...
 
 # Building from Source
 
@@ -28,7 +124,7 @@ Initial development on Apache River Container
 # Running Services in the Container
 
     cd product/target/product*
-    sh bin/run.sh [profile] arg*
+    bin/run [profile] arg*
 
 If you don't specify [profile] the 'default' profile will be used.  'arg*' isn't
 really used much in the service container profiles (like 'default').  
@@ -48,7 +144,7 @@ what the archive should look like.  Startup parameters are in 'start.properties'
 # Running Client Applications
 
     cd product/target/product*
-    sh bin/run.sh client AppName arg*
+    bin/run client AppName arg*
 
 Starts up the container using the 'client' profile, which then starts the client
 that is named by 'AppName' (and only that client, no matter if there are multiple
@@ -61,7 +157,7 @@ Client apps are packaged much like the services mentioned above.
 # Service Browser
 
     cd product/target/product*
-    sh bin/run.sh client browser
+    bin/run client browser
 
 Starts up the service browser.
 

http://git-wip-us.apache.org/repos/asf/river-container/blob/496e36fc/product/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/config.xml b/product/src/main/root/profile/default/config.xml
index cd21bc2..22be40b 100644
--- a/product/src/main/root/profile/default/config.xml
+++ b/product/src/main/root/profile/default/config.xml
@@ -32,7 +32,12 @@
    xsi:schemaLocation='http://river.apache.org/xml/ns/container/config/1.0 file:/home/trasukg/development/surrogate/src/schemas/config.xsd'>
     <cfg:property name="deploymentDirectory" value="deploy"/>
 
+    <!-- Change this value to change the discovery group for the container.
+    In the default 'service-starter.cfg', this  value is made available inside 
+    service starter configuration files as '$discoveryGroup'.
+    -->
     <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"/>


[3/8] git commit: Admin client requires extended permissions (i.e. java.security.AllPermission) so it's now in a separate profile that includes AllPermission in the client-deploy.config.

Posted by gt...@apache.org.
Admin client requires extended permissions (i.e. java.security.AllPermission) so it's now in a separate profile that includes AllPermission in the client-deploy.config.

Client app deployer now has the ability to use a preset app name rather than reading the app name from the command line parameters.  Set 'clientAppName' property to invoke this behavior.  

Admin-client profile uses the above functionality to automatically startup the admin module.


Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/f3245a2d
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/f3245a2d
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/f3245a2d

Branch: refs/heads/master
Commit: f3245a2dd9f26571c360e91dfdaea7ba900cb70b
Parents: 82f44f6
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Mon Jan 20 13:22:29 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Mon Jan 20 13:22:29 2014 -0500

----------------------------------------------------------------------
 product/src/assemble/product-container.xml      | 10 +++
 product/src/main/root/bin/logging.properties    |  2 +-
 .../admin-client/class-server.properties        | 17 ++++
 .../root/profile/admin-client/client-app.cfg    | 53 +++++++++++
 .../main/root/profile/admin-client/config.xml   | 57 ++++++++++++
 .../admin-client/deploy-privileged/readme.txt   |  2 +
 .../root/profile/admin-client/deploy/readme.txt |  2 +
 .../container/deployer/ClientAppDeployer.java   | 95 ++++++++++++--------
 8 files changed, 201 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/assemble/product-container.xml
----------------------------------------------------------------------
diff --git a/product/src/assemble/product-container.xml b/product/src/assemble/product-container.xml
index c1c1c56..763d831 100644
--- a/product/src/assemble/product-container.xml
+++ b/product/src/assemble/product-container.xml
@@ -99,6 +99,16 @@
             <scope>runtime</scope>
             <includes>
                 <include>*:browser-module</include>
+            </includes>
+        </dependencySet>
+        
+        <!-- Admin-client Profile
+        -->
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/profile/admin-client/deploy</outputDirectory>
+            <scope>runtime</scope>
+            <includes>
                 <include>*:admin-module</include>
             </includes>
         </dependencySet>

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/bin/logging.properties
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/logging.properties b/product/src/main/root/bin/logging.properties
index 75d0a47..fdbd071 100644
--- a/product/src/main/root/bin/logging.properties
+++ b/product/src/main/root/bin/logging.properties
@@ -68,7 +68,7 @@ java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
 # Provides extra control for each logger.
 ############################################################
 
-org.apache.river.container.level = FINE
+org.apache.river.container.level = INFO
 
 org.apache.river.container.ShowContextToConsole.level=INFO
 

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/profile/admin-client/class-server.properties
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/class-server.properties b/product/src/main/root/profile/admin-client/class-server.properties
new file mode 100644
index 0000000..6957c40
--- /dev/null
+++ b/product/src/main/root/profile/admin-client/class-server.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements.  See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership. The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (the
+ # "License"); you may not use this file except in compliance
+ # with the License. You may obtain a copy of the License at
+ #
+ #      http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ #
+initialPort=8080
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/profile/admin-client/client-app.cfg
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/client-app.cfg b/product/src/main/root/profile/admin-client/client-app.cfg
new file mode 100644
index 0000000..faa9d09
--- /dev/null
+++ b/product/src/main/root/profile/admin-client/client-app.cfg
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Sample file that our policy file parser should be able to process.
+
+// Grants given to all applications.
+grant {
+    java.security.AllPermission;
+}
+
+classloader {
+    // Variables required to set up the application classloader.
+    //For a privileged application deployer, parent=containerClassLoader;
+    parent systemClassLoader;
+
+    jars {
+        commons-vfs2-2.0.jar,
+        commons-logging-1.1.1.jar,
+        jsk-platform-${jsk-version}.jar,
+        jsk-lib-${jsk-version}.jar,
+        jsk-resources-${jsk-version}.jar,
+        river-container-core-1.0-SNAPSHOT.jar(org.apache.river.container.liaison.Strings,
+            org.apache.river.container.liaison.VirtualFileSystemConfiguration, 
+            org.apache.river.container.liaison.VirtualFileSystemConfiguration$MyConfigurationFile, 
+            "META-INF/services/*")
+    }
+
+    codebase {jsk-dl-${jsk-version}.jar}
+}
+
+configuration {
+    // Anything on the left-hand side of '=' is set into the application config
+    // as a "special variable, accessible through '$name'.
+    discoveryGroup=defaultDiscoveryGroup;
+    
+    // For privileged deployer, include 
+    // context=context;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/profile/admin-client/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/config.xml b/product/src/main/root/profile/admin-client/config.xml
new file mode 100644
index 0000000..dc607fe
--- /dev/null
+++ b/product/src/main/root/profile/admin-client/config.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : December 10, 2010, 6:39 PM
+    Author     : trasukg
+    Description:
+        Configuration file in the 'profile' directory selected by the 
+        command line.
+-->
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership. The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+ -->
+
+<cfg:container-config  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+   xmlns:cfg='http://river.apache.org/xml/ns/container/config/1.0'
+   xsi:schemaLocation='http://river.apache.org/xml/ns/container/config/1.0 file:/home/trasukg/development/surrogate/src/schemas/config.xsd'>
+    <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"/>
+
+    <!-- Deployer for 'service-starter'-style applications. -->
+    <cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer">
+        <cfg:property name="config" value="client-app.cfg"/>
+    </cfg:component>
+    
+    <!-- Deployer for 'service-starter'-style applications. 
+    This is the 'admin-app' profile, so set the clientAppName to 'admin'
+    -->
+    <cfg:component class="org.apache.river.container.deployer.ClientAppDeployer">
+        <cfg:property name="deployDirectory" value="deploy"/>
+        <cfg:property name="clientAppName" value="admin"/>
+    </cfg:component>
+    
+
+    <!--
+    <cfg:component class="org.apache.river.container.ShowContextToConsole"/>
+    -->
+</cfg:container-config>

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/profile/admin-client/deploy-privileged/readme.txt
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/deploy-privileged/readme.txt b/product/src/main/root/profile/admin-client/deploy-privileged/readme.txt
new file mode 100644
index 0000000..eb900da
--- /dev/null
+++ b/product/src/main/root/profile/admin-client/deploy-privileged/readme.txt
@@ -0,0 +1,2 @@
+This file is only here to ensure that the parent directory is 
+preserved in version control.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/product/src/main/root/profile/admin-client/deploy/readme.txt
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/admin-client/deploy/readme.txt b/product/src/main/root/profile/admin-client/deploy/readme.txt
new file mode 100644
index 0000000..eb900da
--- /dev/null
+++ b/product/src/main/root/profile/admin-client/deploy/readme.txt
@@ -0,0 +1,2 @@
+This file is only here to ensure that the parent directory is 
+preserved in version control.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/f3245a2d/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
index 31e4c64..f3c3638 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/ClientAppDeployer.java
@@ -50,34 +50,34 @@ import org.apache.river.container.Utils;
  */
 public class ClientAppDeployer {
 
-    private static final Logger log =
-            Logger.getLogger(ClientAppDeployer.class.getName(), MessageNames.BUNDLE_NAME);
-    
-    @Injected 
+    private static final Logger log
+            = Logger.getLogger(ClientAppDeployer.class.getName(), MessageNames.BUNDLE_NAME);
+
+    @Injected
     ResourceBundle messages;
-    
+
     @Injected
-    public String[] commandLineArguments=null;
+    public String[] commandLineArguments = null;
 
-    @Injected(style= InjectionStyle.BY_TYPE)
-    Context context=null;
+    @Injected(style = InjectionStyle.BY_TYPE)
+    Context context = null;
 
     private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
-    
+
     @Injected(style = InjectionStyle.BY_TYPE)
     private FileUtility fileUtility = null;
-        
+
     @Injected(style = InjectionStyle.BY_TYPE)
     private StarterServiceDeployer deployer;
-    
+
     @Injected(style = InjectionStyle.BY_TYPE)
     private MBeanRegistrar mbeanRegistrar;
-    
+
     @Name
     private String myName = null;
 
-    private List<ApplicationEnvironment> applicationEnvironments =
-            new ArrayList<ApplicationEnvironment>();
+    private List<ApplicationEnvironment> applicationEnvironments
+            = new ArrayList<ApplicationEnvironment>();
 
     public String getDeployDirectory() {
         return deployDirectory;
@@ -87,8 +87,24 @@ public class ClientAppDeployer {
         this.deployDirectory = deployDirectory;
     }
 
-    FileObject deploymentDirectoryFile=null;
-    
+    FileObject deploymentDirectoryFile = null;
+
+    private String clientAppName = null;
+
+    public String getClientAppName() {
+        return clientAppName;
+    }
+
+    /**
+     * Set the client app that should be loaded. If not provided, client app
+     * name is taken from the first parameter.
+     *
+     * @param clientApp
+     */
+    public void setClientAppName(String clientApp) {
+        this.clientAppName = clientApp;
+    }
+
     @Init
     public void init() {
         try {
@@ -103,7 +119,7 @@ public class ClientAppDeployer {
 
     private void tryInitialize() throws IOException, ParseException {
         log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
-        
+
         /*
          Establish the deployment directory.
          */
@@ -117,33 +133,40 @@ public class ClientAppDeployer {
          * Find the name of the client we need to deploy.  
          */
         /* First argument was the profile name.  Second argument is the name of 
-         * the client app to run.  All the rest are paramters to the client
+         * the client app to run.  All the rest are parameters to the client
          * app.
          */
-        if (commandLineArguments.length < 2) {
+        if (clientAppName == null && commandLineArguments.length < 2) {
             System.out.println(messages.getString(MessageNames.CLIENT_APP_USAGE));
             System.exit(1);
         }
-        String clientAppName=commandLineArguments[1];
-        String[] clientAppArgs=new String[commandLineArguments.length-2];
-        System.arraycopy(commandLineArguments,2, clientAppArgs, 0,
-                clientAppArgs.length);
+        String[] clientAppArgs;
+        if (clientAppName == null) {
+            clientAppName = commandLineArguments[1];
+            clientAppArgs = new String[commandLineArguments.length - 2];
+            System.arraycopy(commandLineArguments, 2, clientAppArgs, 0,
+                    clientAppArgs.length);
+        } else {
+            clientAppArgs = new String[commandLineArguments.length - 1];
+            System.arraycopy(commandLineArguments, 1, clientAppArgs, 0,
+                    clientAppArgs.length);
+        }
         // Locate the service archive that has the client's name.
         // First get all the jar files.
-        List<FileObject> serviceArchives =
-                Utils.findChildrenWithSuffix(deploymentDirectoryFile,
-                org.apache.river.container.Strings.JAR);
+        List<FileObject> serviceArchives
+                = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
+                        org.apache.river.container.Strings.JAR);
         //Then find the one that starts with the client name
-        FileObject serviceArchive=null;
-        for (FileObject fo:serviceArchives) {
-            if (fo.getName().getBaseName().startsWith(clientAppName+ org.apache.river.container.Strings.DASH)) {
-                serviceArchive=fo;
+        FileObject serviceArchive = null;
+        for (FileObject fo : serviceArchives) {
+            if (fo.getName().getBaseName().startsWith(clientAppName + org.apache.river.container.Strings.DASH)) {
+                serviceArchive = fo;
                 break;
             }
-            
+
         }
-        
-        if (serviceArchive==null) {
+
+        if (serviceArchive == null) {
             System.err.println(MessageFormat.format(messages.getString(MessageNames.NO_SUCH_CLIENT_APP), clientAppName));
             System.exit(1);
         }
@@ -157,12 +180,12 @@ public class ClientAppDeployer {
             /* Try the archive in all the deployers to see if someone can 
              * handle it. For now there's only one.
              */
-            
+
             /*
              * Create the ApplicationEnvironment for the archive.
              */
-            ServiceLifeCycle deployedApp=deployer.deployServiceArchive(archiveFile);
-            
+            ServiceLifeCycle deployedApp = deployer.deployServiceArchive(archiveFile);
+
             deployedApp.startWithArgs(commandLineArgs);
         } catch (Throwable t) {
             log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, archiveFile.toString());


[5/8] git commit: ContextualWorkManager has been changed over to present a ScheduledExecutorService for applications to use, rather than a WorkManager.

Posted by gt...@apache.org.
ContextualWorkManager has been changed over to present a ScheduledExecutorService for applications to use, rather than a WorkManager.

Starting up the Admin service now works.  AdminService is not yet fully implemented.

Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/e6828db5
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/e6828db5
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/e6828db5

Branch: refs/heads/master
Commit: e6828db5b36e56d6eef5c40f1b9cd3e79f2eb93f
Parents: 317dac0
Author: Greg Trasuk <gt...@apache.org>
Authored: Mon Jan 27 01:50:17 2014 -0500
Committer: Greg Trasuk <gt...@apache.org>
Committed: Mon Jan 27 01:50:17 2014 -0500

----------------------------------------------------------------------
 .../river/container/admin/impl/AdminImpl.java   |  19 +-
 .../org/apache/river/container/Bootstrap.java   |   4 +
 .../org/apache/river/container/Strings.java     |   2 +
 .../deployer/StarterServiceDeployer.java        |  42 ++--
 .../river/container/work/BasicExecutor.java     | 242 +++++++++++++++++++
 .../container/work/ContextualWorkManager.java   |  25 +-
 .../river/container/work/WorkingContext.java    |   4 +-
 .../src/site/markdown/WorkManager.md            |  60 +++++
 river-container-core/src/site/markdown/index.md |   5 +-
 .../work/ContextualWorkManagerTest.java         |  16 +-
 10 files changed, 376 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
index ca0de09..b137e94 100644
--- a/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
+++ b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
@@ -20,9 +20,8 @@ package org.apache.river.container.admin.impl;
 import com.sun.jini.config.Config;
 import com.sun.jini.start.LifeCycle;
 import java.io.IOException;
-import java.net.SocketPermission;
 import java.rmi.server.ExportException;
-import java.security.AccessController;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import net.jini.config.Configuration;
@@ -60,16 +59,13 @@ public class AdminImpl implements ServiceIDListener, AdminRemote {
     JoinManager joinManager = null;
     DiscoveryManagement discoveryManager = null;
     Entry[] attributes = null;
-
+    ScheduledExecutorService executor=null;
+    
     public AdminImpl(String args[], final LifeCycle lc) throws ConfigurationException, ExportException, IOException {
 
         config = ConfigurationProvider.getInstance(args);
         // Get the exporter and create our proxy.
         exporter = (Exporter) Config.getNonNullEntry(config, COMPONENT_ID, "exporter", Exporter.class);
-        log.fine("\n");
-        org.apache.river.container.Utils.logClassLoaderHierarchy(log, this.getClass());
-        org.apache.river.container.Utils.logClassLoaderHierarchy(log, config.getClass());
-        log.fine("\n");
         Utils.logGrantsToClass(log, Level.FINE, this.getClass());
         try {
             myProxy = (Admin) exporter.export(this);
@@ -83,6 +79,15 @@ public class AdminImpl implements ServiceIDListener, AdminRemote {
         // We don't have to do anything with it - just creating it starts the join process.
         joinManager = new JoinManager(myProxy, attributes, this, discoveryManager, null, config);
         log.info("Started the admin service");
+        
+        /* For local clients, we don't want to be dependent on the Jini infrastructure being setup
+        correctly.  For this reason, we stash a copy of the proxy's MarshalledObject in the local 
+        file system.
+        */
+        synchronized(this) {
+            executor=(ScheduledExecutorService) Config.getNonNullEntry(config, COMPONENT_ID, "$executor", ScheduledExecutorService.class);
+        }
+        
     }
 
     ServiceID sid = null;

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java b/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
index 0943d4c..a7860a2 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
@@ -173,6 +173,10 @@ public class Bootstrap {
         Method initCompleteMethod = context.getClass().getMethod(Strings.INIT_COMPLETE, new Class[0]);
         Thread.currentThread().setContextClassLoader(containerClassLoader);
         putByNameMethod.invoke(context, Strings.CLASS_LOADERS, (Object) classLoaders);
+        
+        /* Store a link to the context in the context. */
+        putByNameMethod.invoke(context, Strings.CONTEXT, context);
+        
         /*
          Process the core configuration
          */

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/Strings.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Strings.java b/river-container-core/src/main/java/org/apache/river/container/Strings.java
index 4bbc2be..76510b3 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Strings.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Strings.java
@@ -32,6 +32,7 @@ public class Strings {
             CORE_CONFIG_XML="core-config.xml",
             CONTAINER_CLASS_LOADER="containerClassLoader",
             CONTAINER_JMX_DOMAIN="org.apache.river.container",
+            CONTEXT="context",
             CONTEXT_CLASS = "org.apache.river.container.Context",
             DASH = "-",
             DEFAULT = "default",
@@ -45,6 +46,7 @@ public class Strings {
             DOT_PROPERTIES=".properties",
             DOT_SSAR=".ssar",
             EMPTY = "",
+            EXECUTOR_NAME="scheduledExecutorService",
             GET_ADMIN="getAdmin",
             FILE_UTILITY="fileUtility",
             INIT_COMPLETE="initComplete",

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
index 54578dc..500bf90 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
@@ -137,9 +137,9 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         String parentLoaderName = configNode.search(
                 new Class[]{ASTconfig.class, ASTclassloader.class, ASTparent.class}).get(0).jjtGetChild(0).toString();
         log.log(Level.FINE, MessageNames.SERVICE_PARENT_CLASSLOADER_IS, parentLoaderName);
-        boolean isAppPriority=false;
-        if (!configNode.search( new Class[]{ ASTconfig.class, ASTclassloader.class, ASTappPriority.class}).isEmpty()) {
-            isAppPriority=true;
+        boolean isAppPriority = false;
+        if (!configNode.search(new Class[]{ASTconfig.class, ASTclassloader.class, ASTappPriority.class}).isEmpty()) {
+            isAppPriority = true;
         }
         ClassLoader parentLoader = (ClassLoader) context.get(parentLoaderName);
         VirtualFileSystemClassLoader cl
@@ -248,7 +248,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         } else {
             throw new UnsupportedOperationException();
         }
-        env.getWorkingContext().getWorkManager().queueTask(env.getClassLoader(), task);
+        env.getWorkingContext().getScheduledExecutorService().submit(task);
     }
 
     public Properties readStartProperties(FileObject serviceRoot) throws FileSystemException, LocalizedRuntimeException, IOException {
@@ -267,26 +267,29 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         return startProps;
     }
 
-    public void setupLiaisonConfiguration(FileObject serviceArchive, FileObject serviceRoot, VirtualFileSystemClassLoader cl) throws ConfigurationException {
+    public void setupLiaisonConfiguration(ApplicationEnvironment env) throws ConfigurationException {
         /*
          Setup the liaison configuration.
          */
         ClassLoader originalContextCl = Thread.currentThread().getContextClassLoader();
         try {
-            Thread.currentThread().setContextClassLoader(cl);
+            Thread.currentThread().setContextClassLoader(env.getClassLoader());
             File workingDir = null;
-            if (serviceArchive != null) {
-                workingDir = new File(serviceArchive.getURL().toURI());
+            if (env.getServiceArchive() != null) {
+                /* TODO: Is this right?  Shouldn't the working directory be created
+                by the file manager under the 'work' dir?
+                */
+                workingDir = new File(env.getServiceArchive().getURL().toURI());
             } else {
-                workingDir = new File(serviceRoot.getURL().toURI());
+                workingDir = new File(env.getServiceArchive().getURL().toURI());
 
             }
 
-            grantPermissions(cl,
+            grantPermissions(env.getClassLoader(),
                     new Permission[]{new FilePermission(workingDir.getAbsolutePath(), Strings.READ)});
             Utils.logClassLoaderHierarchy(log, Level.FINE, this.getClass());
             String configName = VirtualFileSystemConfiguration.class.getName();
-            invokeStatic(cl, configName,
+            invokeStatic(env.getClassLoader(), configName,
                     Strings.SET_WORKING_DIRECTORY,
                     workingDir);
             /*
@@ -299,7 +302,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
                 String contextVarName = cfgEntryNode.jjtGetChild(1).toString();
                 Object contextValue = context.get(contextVarName);
                 if (contextValue != null) {
-                    invokeStatic(cl, configName,
+                    invokeStatic(env.getClassLoader(), configName,
                             Strings.PUT_SPECIAL_ENTRY,
                             new Class[]{String.class, Object.class},
                             Strings.DOLLAR + varName, contextValue);
@@ -308,6 +311,14 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
                             new Object[]{getConfig(), varName, contextVarName});
                 }
             }
+            /* Install the Executor. */
+            invokeStatic(env.getClassLoader(), configName,
+                    Strings.PUT_SPECIAL_ENTRY,
+                    new Class[]{String.class, Object.class
+                    },
+                    Strings.DOLLAR + Strings.EXECUTOR_NAME, env.getWorkingContext().getScheduledExecutorService()
+            );
+
         } catch (Exception ex) {
             log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(ex));
             throw new ConfigurationException(ex,
@@ -385,12 +396,13 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
          */
         Permission[] perms = createPermissionsInClassloader(cl);
         grantPermissions(cl, perms);
-        setupLiaisonConfiguration(env.getServiceArchive(), env.getServiceRoot(), cl);
-
+        
         /*
          * Create a working context (work manager).
          */
-        env.setWorkingContext(contextualWorkManager.createContext(env.getServiceName()));
+        env.setWorkingContext(contextualWorkManager.createContext(env.getServiceName(), env.getClassLoader()));
+ 
+        setupLiaisonConfiguration(env);
     }
 
     void launchService(ApplicationEnvironment env, String[] serviceArgs) throws FileSystemException, IOException, ClassNotFoundException {

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/work/BasicExecutor.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/work/BasicExecutor.java b/river-container-core/src/main/java/org/apache/river/container/work/BasicExecutor.java
new file mode 100644
index 0000000..c3a996e
--- /dev/null
+++ b/river-container-core/src/main/java/org/apache/river/container/work/BasicExecutor.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ */
+package org.apache.river.container.work;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.river.container.Init;
+import org.apache.river.container.MessageNames;
+import org.apache.river.container.Shutdown;
+import org.apache.river.container.Strings;
+
+/**
+ *
+ * A Basic implementation of WorkManager that runs the work threads through a
+ * ThreadPoolExecutor.
+ *
+ * @author trasukg
+ */
+public class BasicExecutor implements ScheduledExecutorService {
+
+    private static final Logger log = Logger.getLogger(BasicExecutor.class.getName(), MessageNames.BUNDLE_NAME);
+    ExecutorService executor = null;
+    ScheduledExecutorService scheduledExecutor=null;
+    private MyThreadFactory threadFactory = null;
+    private String name = Strings.UNNAMED;
+    private ClassLoader contextLoader;
+    
+    public BasicExecutor(ClassLoader contextLoader) {
+        this(contextLoader, Strings.UNNAMED);
+    }
+
+    public BasicExecutor(ClassLoader contextLoader, String name) {
+        this.contextLoader=contextLoader;
+        this.name = name;
+        threadFactory = new MyThreadFactory();
+        executor = Executors.newCachedThreadPool(threadFactory);
+        scheduledExecutor=
+                Executors.newSingleThreadScheduledExecutor(threadFactory);
+    }
+
+    synchronized int getActiveCount() {
+        return threadFactory.threadGroup.activeCount();
+    }
+
+    @Override
+    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+        return scheduledExecutor.schedule(new TaskRunnable(command, classLoaderToUse()), delay, unit);
+    }
+
+    private class TaskRunnable implements Runnable {
+
+        Runnable task = null;
+        ClassLoader contextClassLoader = null;
+        ClassLoader originalClassLoader = null;
+
+        TaskRunnable(Runnable task, ClassLoader contextClassLoader) {
+            this.task = task;
+            this.contextClassLoader = contextClassLoader;
+        }
+
+        @Override
+        public void run() {
+            originalClassLoader = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+            try {
+                task.run();
+            } finally {
+                Thread.currentThread().setContextClassLoader(originalClassLoader);
+            }
+        }
+    }
+
+    private class TaskCallable<T> implements Callable<T> {
+
+        Callable<T> task = null;
+        ClassLoader contextClassLoader = null;
+        ClassLoader originalClassLoader = null;
+
+        TaskCallable(Callable<T> task, ClassLoader contextClassLoader) {
+            this.task = task;
+            this.contextClassLoader = contextClassLoader;
+        }
+
+        @Override
+        public T call() throws Exception {
+            originalClassLoader = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+            try {
+                return task.call();
+            } finally {
+                Thread.currentThread().setContextClassLoader(originalClassLoader);
+            }
+        }
+    }
+
+    @Init
+    public void init() {
+        log.info(MessageNames.BASIC_WORK_MANAGER_INITIALIZED);
+    }
+
+    @Shutdown
+    public void shutdown() {
+        executor.shutdownNow();
+        scheduledExecutor.shutdownNow();
+    }
+
+    private class MyThreadFactory implements ThreadFactory {
+
+        private ThreadGroup threadGroup = new ThreadGroup(name);
+        private int index = 0;
+
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(threadGroup, r);
+            t.setName(name + Strings.DASH + index++);
+            log.log(Level.FINE, MessageNames.CREATED_THREAD,
+                    new Object[]{t.getName(), t.getThreadGroup().getName()});
+            return t;
+        }
+    }
+
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+        return scheduledExecutor.schedule(new TaskCallable(callable, classLoaderToUse()), delay, unit);
+    }
+
+    private ClassLoader classLoaderToUse() {
+        ClassLoader classLoaderToUse =
+                contextLoader != null ? contextLoader : Thread.currentThread().getContextClassLoader();
+        return classLoaderToUse;
+    }
+
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+        return scheduledExecutor.scheduleAtFixedRate(new TaskRunnable(command, classLoaderToUse()), initialDelay, period, unit);
+    }
+
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+        return scheduledExecutor.scheduleWithFixedDelay(new TaskRunnable(command, classLoaderToUse()), initialDelay, delay, unit);
+    }
+
+    public List<Runnable> shutdownNow() {
+        List<Runnable> neverCommenced=new ArrayList<Runnable>();
+        neverCommenced.addAll(scheduledExecutor.shutdownNow());
+        neverCommenced.addAll(executor.shutdownNow());
+        return neverCommenced;
+    }
+
+    public boolean isShutdown() {
+        return scheduledExecutor.isShutdown() & executor.isShutdown();
+    }
+
+    public boolean isTerminated() {
+        return scheduledExecutor.isTerminated() & executor.isTerminated() & getActiveCount()==0;
+    }
+
+    /**
+     * Await termination.  Note that this implementation doesn't make any guarantees
+     * about accuracy of the termination wait time, but it will be bounded at 2*timeout.
+     * @param timeout
+     * @param unit
+     * @return
+     * @throws InterruptedException 
+     */
+    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+        return executor.awaitTermination(timeout, unit) & scheduledExecutor.awaitTermination(timeout, unit);
+    }
+
+    public <T> Future<T> submit(Callable<T> task) {
+        return executor.submit(new TaskCallable(task, classLoaderToUse()));
+    }
+
+    public <T> Future<T> submit(Runnable task, T result) {
+        return executor.submit(new TaskRunnable(task, classLoaderToUse()), result);
+    }
+
+    public Future<?> submit(Runnable task) {
+        return executor.submit(new TaskRunnable(task, classLoaderToUse()));
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
+        List<Callable<T>> wrappedTasks = constructListOfWrappedTasks(tasks);
+        return executor.invokeAll(wrappedTasks);
+    }
+
+    private <T> List<Callable<T>> constructListOfWrappedTasks(Collection<? extends Callable<T>> tasks) {
+        /* Construct a list of wrapped tasks. */
+        List<Callable<T>> wrappedTasks=new ArrayList<Callable<T>>(tasks.size());
+        for (Callable<T> task: tasks) {
+            wrappedTasks.add(new TaskCallable(task, classLoaderToUse()));
+        }
+        return wrappedTasks;
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
+        List<Callable<T>> wrappedTasks = constructListOfWrappedTasks(tasks);
+        return executor.invokeAll(wrappedTasks, timeout, unit);
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
+        List<Callable<T>> wrappedTasks = constructListOfWrappedTasks(tasks);
+        return executor.invokeAny(wrappedTasks);
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+        List<Callable<T>> wrappedTasks = constructListOfWrappedTasks(tasks);
+        return executor.invokeAny(wrappedTasks, timeout, unit);
+    }
+
+    public void execute(Runnable command) {
+        executor.execute(new TaskRunnable(command, classLoaderToUse()));
+    }
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/work/ContextualWorkManager.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/work/ContextualWorkManager.java b/river-container-core/src/main/java/org/apache/river/container/work/ContextualWorkManager.java
index 8b6e742..e23307b 100644
--- a/river-container-core/src/main/java/org/apache/river/container/work/ContextualWorkManager.java
+++ b/river-container-core/src/main/java/org/apache/river/container/work/ContextualWorkManager.java
@@ -19,6 +19,7 @@ package org.apache.river.container.work;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
 import org.apache.river.container.Strings;
 
 /**
@@ -29,44 +30,46 @@ public class ContextualWorkManager {
 
     List<Context> contexts=new ArrayList<Context>();
     
-    public WorkingContext createContext(String name) {
-        Context context=new Context(name);
+    public WorkingContext createContext(String name, ClassLoader contextLoader) {
+        Context context=new Context(name, contextLoader);
         contexts.add(context);
         return context;
     }
     
     private class Context implements WorkingContext {
         String name=Strings.UNNAMED;
-
+        ClassLoader contextLoader;
+        
         public String getName() {
             return name;
         }
 
-        public Context(String name) {
+        public Context(String name, ClassLoader contextLoader) {
             this.name=name;
-            workManager=new BasicWorkManager(name);
+            this.contextLoader=contextLoader;
+            executor=new BasicExecutor(contextLoader, name);
         }
         
-        BasicWorkManager workManager=null;
+        BasicExecutor executor=null;
         
         @Override
-        public WorkManager getWorkManager() {
-            return workManager;
+        public ScheduledExecutorService getScheduledExecutorService() {
+            return executor;
         }
 
         @Override
         public int getActiveThreadCount() {
-            return workManager.getActiveCount();
+            return executor.getActiveCount();
         }
 
         @Override
         public void shutdown() {
-            workManager.shutdown();
+            executor.shutdownNow();
         }
 
         @Override
         public void interrupt() {
-            workManager.interrupt();
+            executor.shutdownNow();
         }
         
     }

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/main/java/org/apache/river/container/work/WorkingContext.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/work/WorkingContext.java b/river-container-core/src/main/java/org/apache/river/container/work/WorkingContext.java
index 56b2a0a..1f8c6e4 100644
--- a/river-container-core/src/main/java/org/apache/river/container/work/WorkingContext.java
+++ b/river-container-core/src/main/java/org/apache/river/container/work/WorkingContext.java
@@ -17,6 +17,8 @@
  */
 package org.apache.river.container.work;
 
+import java.util.concurrent.ScheduledExecutorService;
+
 /**
 
  @author trasukg
@@ -27,7 +29,7 @@ public interface WorkingContext {
     context.
     @return The WorkManager instance.
     */
-    WorkManager getWorkManager();
+    ScheduledExecutorService getScheduledExecutorService();
     
     /**
     Answer how many threads are currently active in this context.

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/site/markdown/WorkManager.md
----------------------------------------------------------------------
diff --git a/river-container-core/src/site/markdown/WorkManager.md b/river-container-core/src/site/markdown/WorkManager.md
new file mode 100644
index 0000000..5ea2bf5
--- /dev/null
+++ b/river-container-core/src/site/markdown/WorkManager.md
@@ -0,0 +1,60 @@
+Work Manager and Work Management in the Container
+=================================================
+
+- In general, containers should be able to control the thread usage and scheduling of 
+work inside the container.  Otherwise it's possible for an application to hijack
+execution or prevent a different application, or possibly the container itself,
+from executing properly.  
+- So, this desire means that applications should be discouraged or disallowed from 
+creating their own threads.  In turn, that restriction means that the container must
+offer some way to schedule work that should happen on another thread, and possibly at
+some time in the future, or even repeatedly.
+
+How it is on 20140125
+---------------------
+
+- The container includes an attempt at this, embodied in `org.apache.river.container.work`  
+    - There is an interface 'WorkManager' that contains a `queue(...)` method that 
+    drops the task into a task queue.  The queue method also allows the user to 
+    specify a classloader for the task to run in.  The thread pool is expected to set
+    this classloader as the context classloader before executing the task.
+    - There is a 'BasicWorkManager' implementation that uses a ThreadPoolExecutor to
+    implement 'WorkManager'  
+    - There is a 'ContextualWorkManager' implementation that allows jobs to be grouped
+    together and cancelled en-masse, for instance when an application needs to be
+    shut down.
+
+Problems
+--------
+
+- We need to provide a way for well-written applications to schedule multi-threaded
+work.  We probably shouldn't introduce container-specific API, especially since there
+is a perfectly good API for work management in `javax.concurrent`.  
+- As written now, the API doesn't prevent a single thread pool, but that isn't implemented
+yet. The working contexts each have their own thread pool. 
+- There is no facility for an application to have any internal prioritization.
+
+Design Goals
+------------
+
+- Provide an API to applications that allows them to fire off background work, 
+scheduled executions, and repetitive tasks.  
+    - Essentially, one or more ScheduledExecutorService objects should be provided
+    for the application.
+- Ideally, there should be one thread pool that is managed by the container  
+- The executor objects provided to the applications should be isolated from each
+other, cancellable en-masse (for application shutdown) and should preserve the 
+context classloader.
+- The number of threads in the thread pool should be configurable.  
+- Ideally, the thread pool policy should be configurable (i.e. fixed threads,
+max threads, min threads, etc).
+- Current users of WorkManager interface should be migrated to the new API.  
+- Number of threads in use, etc should be visible through a management interface.  
+- Applications should be able to provide prioritization on the tasks  
+    - Perhaps by also implementing Comparable in the task that implements Runnable.  
+    - Runnables that come "first" are run first.  
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/river-container-core/src/site/markdown/index.md b/river-container-core/src/site/markdown/index.md
index ed271e1..d86c88a 100644
--- a/river-container-core/src/site/markdown/index.md
+++ b/river-container-core/src/site/markdown/index.md
@@ -58,6 +58,9 @@ classes.
 - [State Machine](StateMachine.html) Information on the annotation-based state
 machine implementation used in various places in the container.
 - [Surrogate Deployment](SurrogateDeployment.html) Deployer used to host 
-Jini Surrogates.
+Jini Surrogates.  
+- [Work Manager Considerations](WorkManager.html) Design thoughts on work/thread
+management in the
+container.
 - [To Do](Todo.html) To-do list for the development.
 

http://git-wip-us.apache.org/repos/asf/river-container/blob/e6828db5/river-container-core/src/test/java/org/apache/river/container/work/ContextualWorkManagerTest.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/test/java/org/apache/river/container/work/ContextualWorkManagerTest.java b/river-container-core/src/test/java/org/apache/river/container/work/ContextualWorkManagerTest.java
index 3c751d8..5bdab85 100644
--- a/river-container-core/src/test/java/org/apache/river/container/work/ContextualWorkManagerTest.java
+++ b/river-container-core/src/test/java/org/apache/river/container/work/ContextualWorkManagerTest.java
@@ -32,30 +32,30 @@ import org.junit.Test;
 public class ContextualWorkManagerTest {
 
     ContextualWorkManager UUT = new ContextualWorkManager();
-    WorkingContext context = UUT.createContext("Test-ctx");
+    WorkingContext context = UUT.createContext("Test-ctx", Thread.currentThread().getContextClassLoader());
 
     @Test
     public void testContextCreation() {
         assertNotNull("context", context);
-        assertNotNull("context.workManager", context.getWorkManager());
+        assertNotNull("context.scheduledExecutorService", context.getScheduledExecutorService());
     }
 
     @Test
-    public void testThreadCount() {
+    public void testRunAndExit() {
         WorkerRunnable wt = new WorkerRunnable();
-        context.getWorkManager().queueTask(null, wt);
+        context.getScheduledExecutorService().submit(wt);
         long start = System.currentTimeMillis();
         while (System.currentTimeMillis() - start < 2000 & context.getActiveThreadCount() < 1) {
             Thread.yield();
         }
         assertEquals("thread count", 1, context.getActiveThreadCount());
-        wt.proceed = true;
+        
     }
 
     @Test
     public void testChildThreadGroup() throws Exception {
         WorkerRunnable wt = new WorkerRunnable();
-        context.getWorkManager().queueTask(null, wt);
+        context.getScheduledExecutorService().submit(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(null, wt);
+        context.getScheduledExecutorService().submit(wt);
         long start = System.currentTimeMillis();
         while (System.currentTimeMillis() - start < 2000 & context.getActiveThreadCount() < 1) {
             Thread.yield();
@@ -91,7 +91,7 @@ public class ContextualWorkManagerTest {
         String threadGroupName = Strings.UNKNOWN;
         List<WorkerRunnable> children = new ArrayList<WorkerRunnable>();
         String id = "--";
-        boolean proceed = false;
+        volatile boolean proceed = false;
         int nChildren = 0;
 
         public WorkerRunnable() {


[4/8] git commit: AdminSvc now starts up in privileged mode and joins the workgroup. Classloader spec in deployer config now has an option to set "parent priority" or "application priority", in which setting "application priority" causes classes to be lo

Posted by gt...@apache.org.
AdminSvc now starts up in privileged mode and joins the workgroup.
Classloader spec in deployer config now has an option to set "parent priority" or "application priority", in which setting "application priority" causes classes to be loaded from the application in preference to the parent loader.


Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/317dac09
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/317dac09
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/317dac09

Branch: refs/heads/master
Commit: 317dac09de78169564215cef125a936abe99afe1
Parents: f3245a2
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Thu Jan 23 18:00:50 2014 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Thu Jan 23 18:00:50 2014 -0500

----------------------------------------------------------------------
 .gitignore                                      |   7 +-
 admin-svc/admin-svc-api/pom.xml                 |  44 +++++
 .../apache/river/container/admin/api/Admin.java |  34 ++++
 .../container/admin/api/ApplicationInfo.java    |  24 +++
 .../container/admin/api/ApplicationStatus.java  |  29 +++
 .../river/container/admin/api/AppTest.java      |  38 ++++
 .../admin/api/ApplicationStatusTest.java        |  52 ++++++
 admin-svc/admin-svc-dl/pom.xml                  |  49 +++++
 .../river/container/admin/dl/AdminRemote.java   |  18 ++
 .../river/container/admin/dl/AppTest.java       |  38 ++++
 admin-svc/admin-svc-impl/pom.xml                |  65 +++++++
 .../river/container/admin/impl/AdminImpl.java   | 100 ++++++++++
 admin-svc/admin-svc-module/pom.xml              |  61 ++++++
 .../admin-svc-module/src/assemble/module.xml    |  67 +++++++
 .../src/main/root/admin-svc.config              |  38 ++++
 .../src/main/root/start.properties              |  20 ++
 admin-svc/pom.xml                               |  38 ++++
 pom.xml                                         |   3 +-
 product/pom.xml                                 |   5 +
 product/src/assemble/product-container.xml      |   7 +-
 product/src/main/root/bin/logging.properties    |   4 +-
 .../src/main/root/profile/default/config.xml    |  16 ++
 .../default/privileged-service-starter.cfg      | 100 ++++++++++
 .../apache/river/container/MessageNames.java    |   1 +
 .../org/apache/river/container/Strings.java     |   1 +
 .../java/org/apache/river/container/Utils.java  |  49 +++--
 .../VirtualFileSystemClassLoader.java           | 184 ++++++++++++++-----
 .../deployer/StarterServiceDeployer.java        |  42 +++--
 .../container/deployer/StartupDeployer.java     |  16 ++
 .../container/security/ContainerCodePolicy.java |  30 +--
 .../container/security/SecurityInitializer.java |  56 +++---
 .../src/main/jjtree/DeployerConfigParser.jjt    |  30 ++-
 .../apache/river/container/Messages.properties  |   1 +
 .../org/apache/river/container/core-config.xml  |   1 +
 .../deployer/DeployerConfigParserTest.java      |   3 +
 .../river/container/deployer/sample.config      |   2 +
 36 files changed, 1153 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b2ae2aa..03e7b9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,9 @@
 *.jar
 *.war
 *.ear
-/target/
\ No newline at end of file
+/target/
+/admin-svc-api/nbproject/private/
+/admin-svc/admin-svc-api/target/
+/admin-svc/admin-svc-module/target/
+/admin-svc/admin-svc-impl/target/
+/admin-svc/admin-svc-dl/target/
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/pom.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/pom.xml b/admin-svc/admin-svc-api/pom.xml
new file mode 100644
index 0000000..fdd9ac1
--- /dev/null
+++ b/admin-svc/admin-svc-api/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.river.container</groupId>
+        <artifactId>admin-svc</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-svc-api</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>admin-svc-api</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.11</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/Admin.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/Admin.java b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/Admin.java
new file mode 100644
index 0000000..1af7375
--- /dev/null
+++ b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/Admin.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.container.admin.api;
+
+import java.io.IOException;
+
+/**
+ * Administration interface for River Container.
+ */
+public interface Admin {
+    
+    /**
+     * List applications in the container.
+     * @return the applications.
+     * @throws java.io.IOException
+     */
+    public ApplicationInfo[] listApplications() throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
new file mode 100644
index 0000000..df3f73b
--- /dev/null
+++ b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationInfo.java
@@ -0,0 +1,24 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.container.admin.api;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author trasukg
+ */
+public class ApplicationInfo implements Serializable {
+    String name;
+    ApplicationStatus status;
+
+    public ApplicationInfo(String name, ApplicationStatus status) {
+        this.name = name;
+        this.status = status;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationStatus.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationStatus.java b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationStatus.java
new file mode 100644
index 0000000..4bbab7a
--- /dev/null
+++ b/admin-svc/admin-svc-api/src/main/java/org/apache/river/container/admin/api/ApplicationStatus.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.container.admin.api;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author trasukg
+ */
+public enum ApplicationStatus implements Serializable {
+    STOPPED,FAILED,RUNNING,UNKNOWN;
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/AppTest.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/AppTest.java b/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/AppTest.java
new file mode 100644
index 0000000..1780b29
--- /dev/null
+++ b/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/AppTest.java
@@ -0,0 +1,38 @@
+package org.apache.river.container.admin.api;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/ApplicationStatusTest.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/ApplicationStatusTest.java b/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/ApplicationStatusTest.java
new file mode 100644
index 0000000..fbd19a7
--- /dev/null
+++ b/admin-svc/admin-svc-api/src/test/java/org/apache/river/container/admin/api/ApplicationStatusTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.container.admin.api;
+
+
+import junit.framework.TestCase;
+import static junit.framework.Assert.*;
+
+import org.apache.river.container.admin.api.ApplicationStatus;
+import org.junit.Test;
+
+/**
+ *
+ * @author trasukg
+ */
+public class ApplicationStatusTest extends TestCase {
+    
+    public ApplicationStatusTest(String testName) {
+        super(testName);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+    
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    @Test
+    public void testEnumString() {
+        assertEquals("String value of ApplicationStatus.RUNNING", "RUNNING", ApplicationStatus.RUNNING.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-dl/pom.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-dl/pom.xml b/admin-svc/admin-svc-dl/pom.xml
new file mode 100644
index 0000000..9bdceff
--- /dev/null
+++ b/admin-svc/admin-svc-dl/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.river.container</groupId>
+        <artifactId>admin-svc</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-svc-dl</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>admin-svc-dl</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>admin-svc-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-dl/src/main/java/org/apache/river/container/admin/dl/AdminRemote.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-dl/src/main/java/org/apache/river/container/admin/dl/AdminRemote.java b/admin-svc/admin-svc-dl/src/main/java/org/apache/river/container/admin/dl/AdminRemote.java
new file mode 100644
index 0000000..338f9cb
--- /dev/null
+++ b/admin-svc/admin-svc-dl/src/main/java/org/apache/river/container/admin/dl/AdminRemote.java
@@ -0,0 +1,18 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.river.container.admin.dl;
+
+import java.rmi.Remote;
+import org.apache.river.container.admin.api.Admin;
+
+/**
+ *
+ * @author trasukg
+ */
+public interface AdminRemote extends Admin, Remote {
+    
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-dl/src/test/java/org/apache/river/container/admin/dl/AppTest.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-dl/src/test/java/org/apache/river/container/admin/dl/AppTest.java b/admin-svc/admin-svc-dl/src/test/java/org/apache/river/container/admin/dl/AppTest.java
new file mode 100644
index 0000000..1579e76
--- /dev/null
+++ b/admin-svc/admin-svc-dl/src/test/java/org/apache/river/container/admin/dl/AppTest.java
@@ -0,0 +1,38 @@
+package org.apache.river.container.admin.dl;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest 
+    extends TestCase
+{
+    /**
+     * Create the test case
+     *
+     * @param testName name of the test case
+     */
+    public AppTest( String testName )
+    {
+        super( testName );
+    }
+
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite( AppTest.class );
+    }
+
+    /**
+     * Rigourous Test :-)
+     */
+    public void testApp()
+    {
+        assertTrue( true );
+    }
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-impl/pom.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-impl/pom.xml b/admin-svc/admin-svc-impl/pom.xml
new file mode 100644
index 0000000..ee174b0
--- /dev/null
+++ b/admin-svc/admin-svc-impl/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.river.container</groupId>
+        <artifactId>admin-svc</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-svc-impl</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <name>admin-svc-impl</name>
+    <url>http://maven.apache.org</url>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.jini</groupId>
+            <artifactId>jsk-lib</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>admin-svc-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>admin-svc-dl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>river-container-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
new file mode 100644
index 0000000..ca0de09
--- /dev/null
+++ b/admin-svc/admin-svc-impl/src/main/java/org/apache/river/container/admin/impl/AdminImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.river.container.admin.impl;
+
+import com.sun.jini.config.Config;
+import com.sun.jini.start.LifeCycle;
+import java.io.IOException;
+import java.net.SocketPermission;
+import java.rmi.server.ExportException;
+import java.security.AccessController;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.jini.config.Configuration;
+import net.jini.config.ConfigurationException;
+import net.jini.config.ConfigurationProvider;
+import net.jini.core.entry.Entry;
+import net.jini.core.lookup.ServiceID;
+import net.jini.discovery.DiscoveryManagement;
+import net.jini.export.Exporter;
+import net.jini.lookup.JoinManager;
+import net.jini.lookup.ServiceIDListener;
+import net.jini.security.ProxyPreparer;
+import org.apache.river.container.MessageNames;
+import org.apache.river.container.Utils;
+import org.apache.river.container.admin.api.Admin;
+import org.apache.river.container.admin.api.ApplicationInfo;
+import org.apache.river.container.admin.api.ApplicationStatus;
+import org.apache.river.container.admin.dl.AdminRemote;
+
+/**
+ *
+ * @author trasukg
+ */
+public class AdminImpl implements ServiceIDListener, AdminRemote {
+
+    private static final Logger log
+            = Logger.getLogger(AdminImpl.class.getName(), MessageNames.BUNDLE_NAME);
+
+    private static final String COMPONENT_ID = "basic";
+
+    Configuration config = null;
+    Admin myProxy = null;
+    Exporter exporter = null;
+    ProxyPreparer registrarPreparer = null;
+    JoinManager joinManager = null;
+    DiscoveryManagement discoveryManager = null;
+    Entry[] attributes = null;
+
+    public AdminImpl(String args[], final LifeCycle lc) throws ConfigurationException, ExportException, IOException {
+
+        config = ConfigurationProvider.getInstance(args);
+        // Get the exporter and create our proxy.
+        exporter = (Exporter) Config.getNonNullEntry(config, COMPONENT_ID, "exporter", Exporter.class);
+        log.fine("\n");
+        org.apache.river.container.Utils.logClassLoaderHierarchy(log, this.getClass());
+        org.apache.river.container.Utils.logClassLoaderHierarchy(log, config.getClass());
+        log.fine("\n");
+        Utils.logGrantsToClass(log, Level.FINE, this.getClass());
+        try {
+            myProxy = (Admin) exporter.export(this);
+        } catch (SecurityException se) {
+            log.log(Level.SEVERE, "Caught security exception:", se);
+        }
+        discoveryManager = (DiscoveryManagement) config.getEntry(COMPONENT_ID, "discoveryManager", DiscoveryManagement.class);
+        attributes = (Entry[]) config.getEntry(COMPONENT_ID, "attributes", Entry[].class);
+
+        // Publish it using the join manager.
+        // We don't have to do anything with it - just creating it starts the join process.
+        joinManager = new JoinManager(myProxy, attributes, this, discoveryManager, null, config);
+        log.info("Started the admin service");
+    }
+
+    ServiceID sid = null;
+
+    public void serviceIDNotify(ServiceID sid) {
+        this.sid = sid;
+    }
+
+    public ApplicationInfo[] listApplications() throws IOException {
+        return new ApplicationInfo[]{
+            new ApplicationInfo("abc", ApplicationStatus.UNKNOWN)
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-module/pom.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/pom.xml b/admin-svc/admin-svc-module/pom.xml
new file mode 100644
index 0000000..6cf4789
--- /dev/null
+++ b/admin-svc/admin-svc-module/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>admin-svc</artifactId>
+        <groupId>org.apache.river.container</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-svc-module</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>admin-svc-module</name>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptor>src/assemble/module.xml</descriptor>
+                    <appendAssemblyId>false</appendAssemblyId>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>ssar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        
+                    </execution>
+                </executions>
+            </plugin>
+            
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>admin-svc-impl</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-module/src/assemble/module.xml
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/src/assemble/module.xml b/admin-svc/admin-svc-module/src/assemble/module.xml
new file mode 100644
index 0000000..d8f36d3
--- /dev/null
+++ b/admin-svc/admin-svc-module/src/assemble/module.xml
@@ -0,0 +1,67 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    
+    <id>ssar</id>
+    
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+  <fileSets>
+
+        <fileSet>
+            <directory>${basedir}/src/main/root</directory>
+            <includes>
+                <include>**/**</include>
+                <include>*</include>
+            </includes>
+            <outputDirectory>/</outputDirectory>
+        </fileSet>
+  
+  </fileSets>    
+  <dependencySets>
+     
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/lib</outputDirectory>
+            <!-- jsk jars are already provided by the container. -->
+            <excludes>
+                <exclude>*:jsk-*</exclude>
+            </excludes>
+        </dependencySet>
+        
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/lib-dl</outputDirectory>
+            <includes>
+                <include>*:*-dl</include>
+                <include>*:*-api</include>
+            </includes>
+            <!-- jsk jars are already provided by the container. -->
+            <excludes>
+                <exclude>*:jsk-*</exclude>
+            </excludes>
+        </dependencySet>
+    </dependencySets>
+
+</assembly>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-module/src/main/root/admin-svc.config
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/src/main/root/admin-svc.config b/admin-svc/admin-svc-module/src/main/root/admin-svc.config
new file mode 100644
index 0000000..7b6854f
--- /dev/null
+++ b/admin-svc/admin-svc-module/src/main/root/admin-svc.config
@@ -0,0 +1,38 @@
+import java.security.Permission;
+import net.jini.constraint.BasicMethodConstraints;
+import net.jini.core.constraint.InvocationConstraints;
+import net.jini.core.entry.Entry;
+import net.jini.core.lookup.ServiceID;
+import net.jini.discovery.LookupDiscovery;
+import net.jini.jeri.BasicILFactory;
+import net.jini.jeri.BasicJeriExporter;
+import net.jini.jeri.tcp.TcpServerEndpoint;
+import net.jini.lookup.JoinManager;
+import net.jini.lookup.entry.Name;
+import net.jini.security.BasicProxyPreparer;
+
+basic {
+	
+    groups = new String[] {$discoveryGroup};
+    
+    exporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0),
+                                     new BasicILFactory());
+
+    serviceInvocationConstraints=InvocationConstraints.EMPTY;
+        
+    registrarPreparer = 
+        new BasicProxyPreparer(false, new BasicMethodConstraints(serviceInvocationConstraints),
+            new Permission[] { new RuntimePermission("accessClassInPackage.com.sun.proxy") } );
+
+    static discoveryManager = 
+        new LookupDiscovery( groups, this);
+
+    static attributes = new Entry[] { new Name("admin-service") };
+
+}
+
+net.jini.lookup.JoinManager {
+    registrarPreparer = basic.registrarPreparer;
+    registrationPreparer = basic.registrarPreparer;
+    
+}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/admin-svc-module/src/main/root/start.properties
----------------------------------------------------------------------
diff --git a/admin-svc/admin-svc-module/src/main/root/start.properties b/admin-svc/admin-svc-module/src/main/root/start.properties
new file mode 100644
index 0000000..6ac1420
--- /dev/null
+++ b/admin-svc/admin-svc-module/src/main/root/start.properties
@@ -0,0 +1,20 @@
+
+ # Licensed to the Apache Software Foundation (ASF) under one
+ # or more contributor license agreements.  See the NOTICE file
+ # distributed with this work for additional information
+ # regarding copyright ownership. The ASF licenses this file
+ # to you under the Apache License, Version 2.0 (the
+ # "License"); you may not use this file except in compliance
+ # with the License. You may obtain a copy of the License at
+ #
+ #      http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ #
+
+startClass=org.apache.river.container.admin.impl.AdminImpl
+startParameters=admin-svc.config

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/admin-svc/pom.xml
----------------------------------------------------------------------
diff --git a/admin-svc/pom.xml b/admin-svc/pom.xml
new file mode 100644
index 0000000..5ad8f60
--- /dev/null
+++ b/admin-svc/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>river-container</artifactId>
+        <groupId>org.apache.river.container</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <groupId>org.apache.river.container</groupId>
+    <artifactId>admin-svc</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>admin-svc</name>
+    <modules>
+        <module>admin-svc-api</module>
+        <module>admin-svc-dl</module>
+        <module>admin-svc-impl</module>
+        <module>admin-svc-module</module>
+    </modules>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e8ef195..e624b0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,7 +39,8 @@
         <module>river-hsm</module>
         <module>admin-app</module>
         <module>admin-module</module>
-    </modules>
+    <module>admin-svc</module>
+  </modules>
     <properties>
         <jsk-version>2.2.2</jsk-version>
     </properties>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/product/pom.xml
----------------------------------------------------------------------
diff --git a/product/pom.xml b/product/pom.xml
index 992f8d7..07bfdf5 100644
--- a/product/pom.xml
+++ b/product/pom.xml
@@ -70,6 +70,11 @@
             <version>1.0-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>admin-svc-module</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
   
     <build>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/product/src/assemble/product-container.xml
----------------------------------------------------------------------
diff --git a/product/src/assemble/product-container.xml b/product/src/assemble/product-container.xml
index 763d831..8a9898b 100644
--- a/product/src/assemble/product-container.xml
+++ b/product/src/assemble/product-container.xml
@@ -73,6 +73,7 @@
         
         <!-- Default profile
         -->
+        
         <dependencySet>
             <useProjectArtifact>false</useProjectArtifact>
             <outputDirectory>/profile/default/deploy</outputDirectory>
@@ -84,13 +85,13 @@
         </dependencySet>
         <dependencySet>
             <useProjectArtifact>false</useProjectArtifact>
-            <outputDirectory>/profile/client/deploy</outputDirectory>
+            <outputDirectory>/profile/default/deploy-privileged</outputDirectory>
             <scope>runtime</scope>
             <includes>
-                <include>*:browser-module</include>
+                <include>*:admin-svc-module</include>
             </includes>
         </dependencySet>
-        
+
         <!-- Client Profile
         -->
         <dependencySet>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/product/src/main/root/bin/logging.properties
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/logging.properties b/product/src/main/root/bin/logging.properties
index fdbd071..66e0a0c 100644
--- a/product/src/main/root/bin/logging.properties
+++ b/product/src/main/root/bin/logging.properties
@@ -73,7 +73,9 @@ org.apache.river.container.level = INFO
 org.apache.river.container.ShowContextToConsole.level=INFO
 
 net.jini.config.level=INFO
-org.apache.river.container.security.ContainerCodePolicy.level=INFO
+org.apache.river.container.security.ContainerCodePolicy.level=SEVERE
+org.apache.river.container.admin.level=INFO
+org.apache.river.container.deployer.level=INFO
 org.apache.river.container.deployer.ClasspathFilterBuilder.level=INFO
 org.apache.river.container.deployer.DeployerConfigParser=INFO
 org.apache.river.container.hsm.level=SEVERE

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/product/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/config.xml b/product/src/main/root/profile/default/config.xml
index 7d81f52..69488e2 100644
--- a/product/src/main/root/profile/default/config.xml
+++ b/product/src/main/root/profile/default/config.xml
@@ -49,6 +49,22 @@
         <cfg:property name="autoDeploy" value="true"/>
     </cfg:component>
     
+    <!-- Deployer for privileged 'service-starter'-style applications. 
+        i.e. the Admin service.
+    -->
+    <cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer"
+        name="privileged-deployer">
+        <cfg:property name="config" value="privileged-service-starter.cfg"/>
+    </cfg:component>
+    
+    <!-- Deployer for applications that are in the 'deploy' directory
+    at startup. -->
+    <cfg:component class="org.apache.river.container.deployer.StartupDeployer">
+        <cfg:property name="deployDirectory" value="deploy-privileged"/>
+        <cfg:property name="autoDeploy" value="true"/>
+        <cfg:property name="deployerName" value="privileged-deployer"/>
+    </cfg:component>
+    
     <!-- Deployer for 'system apps' like the remote deployment service 
     <cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer">
         <cfg:property name="config" value="privileged-services.cfg"/>

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/product/src/main/root/profile/default/privileged-service-starter.cfg
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/privileged-service-starter.cfg b/product/src/main/root/profile/default/privileged-service-starter.cfg
new file mode 100644
index 0000000..91c48c5
--- /dev/null
+++ b/product/src/main/root/profile/default/privileged-service-starter.cfg
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Sample file that our policy file parser should be able to process.
+
+// Grants given to all applications.
+grant {
+    java.security.AllPermission;
+    //java.io.FilePermission "${serviceArchive}" "read";
+    java.io.FilePermission "-" "read";
+    java.net.SocketPermission "*" "connect,listen,accept,resolve";
+
+    // Required for VFSFileManager
+    java.util.PropertyPermission "java.io.tmpdir" "read";
+    java.util.PropertyPermission "os.*" "read";
+    java.util.PropertyPermission "path.*" "read";
+    java.lang.RuntimePermission "getClassLoader";
+    java.lang.RuntimePermission "setContextClassLoader";
+    /* net.jini.security.Security requires createSecurityManager, but we
+    don't grant 'setSecurityManager'. */
+    java.lang.RuntimePermission "createSecurityManager";
+    java.lang.RuntimePermission "getProtectionDomain";
+    java.lang.RuntimePermission "setFactory";
+    java.lang.RuntimePermission "modifyThread";
+    java.lang.RuntimePermission "modifyThreadGroup";
+    java.security.SecurityPermission "getDomainCombiner";
+    java.security.SecurityPermission "createAccessControlContext";
+    java.security.SecurityPermission "getPolicy";
+
+    // BasicProxyPreparer requirements:
+    javax.security.auth.AuthPermission "getSubject";
+    // Should not be required once UmbrellaGrantPolicy is implemented.
+    // TODO: Config file parser doesn't recognize \"
+    // net.jini.security.GrantPermission "delim=| java.lang.RuntimePermission |accessClassInPackage.com.sun.proxy|";
+
+    net.jini.security.policy.UmbrellaGrantPermission;
+    com.sun.jini.thread.ThreadPoolPermission "getSystemThreadPool";
+    com.sun.jini.thread.ThreadPoolPermission "getUserThreadPool";
+    com.sun.jini.discovery.internal.EndpointInternalsPermission "set";
+    com.sun.jini.discovery.internal.EndpointInternalsPermission "get";
+    java.lang.reflect.ReflectPermission "suppressAccessChecks";
+    net.jini.export.ExportPermission "exportRemoteInterface.*";
+    net.jini.discovery.DiscoveryPermission "*";
+    java.lang.RuntimePermission "shutdownHooks";
+    java.util.PropertyPermission "*" "read";
+
+    java.lang.RuntimePermission "accessClassInPackage.com.sun.proxy";
+
+    // Only in client configuration - apps can call System.exit()
+    java.lang.RuntimePermission "exitVM.*";
+}
+
+classloader {
+    // Variables required to set up the application classloader.
+    //For a privileged application deployer, parent=containerClassLoader;
+    //parent systemClassLoader;
+    parent containerClassLoader;
+
+    // Indicates that for this loader, classes are to be loaded from the 
+    // application loader first, rather than the parent.
+    // Default is priority parent.
+    priority application;
+
+    jars {
+        //commons-vfs2-2.0.jar,
+        //commons-logging-1.1.1.jar,
+        //jsk-platform-${jsk-version}.jar,
+        //jsk-lib-${jsk-version}.jar,
+        //jsk-resources-${jsk-version}.jar,
+        river-container-core-1.0-SNAPSHOT.jar(org.apache.river.container.liaison.Strings,
+            org.apache.river.container.liaison.VirtualFileSystemConfiguration, 
+            org.apache.river.container.liaison.VirtualFileSystemConfiguration$MyConfigurationFile, 
+            "META-INF/services/*")
+    }
+
+    codebase {jsk-dl-${jsk-version}.jar}
+}
+configuration {
+    // Anything on the left-hand side of '=' is set into the application config
+    // as a "special variable, accessible through '$name'.
+    discoveryGroup=defaultDiscoveryGroup;
+    
+    // For privileged deployer, include 
+    context=context;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
index a566d03..95828e8 100644
--- a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
+++ b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
@@ -85,6 +85,7 @@ public class MessageNames {
             FAILED_TO_SET_PROPERTY="failedToSetProperty",
             FOUND_NO_SERVICE_ARCHIVES="foundNoServiceArchives",
             FOUND_SERVICE_ARCHIVES="foundServiceArchives",
+            GRANTS_TO_CLASS_ARE="grantsToClassAre",
             ILLEGAL_ARGUMENT_EXCEPTION="illegalArgumentException",
             ILLEGAL_ACCESS_EXCEPTION="illegalAccessException",
             INITIALIZATION_EXCEPTION="initializationException",

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/Strings.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Strings.java b/river-container-core/src/main/java/org/apache/river/container/Strings.java
index 8528ab9..4bbc2be 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Strings.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Strings.java
@@ -55,6 +55,7 @@ public class Strings {
             MAIN="main",
             MESSAGES="messages",
             NAME="name",
+            NEWLINE="\n",
             PLATFORM_JARS="platformJars",
             PLATFORM_CODEBASE="platformCodebase",
             PROFILE = "profile",

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/Utils.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Utils.java b/river-container-core/src/main/java/org/apache/river/container/Utils.java
index 7da2d6f..ccce2a1 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Utils.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Utils.java
@@ -19,6 +19,10 @@ package org.apache.river.container;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.Policy;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -26,13 +30,14 @@ import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import net.jini.security.policy.DynamicPolicyProvider;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.commons.vfs2.FileSystemException;
 import org.apache.commons.vfs2.FileType;
 
 /**
-
- @author trasukg
+ *
+ * @author trasukg
  */
 public class Utils {
 
@@ -107,12 +112,17 @@ public class Utils {
             Class cls) {
         log.log(level, MessageNames.CLASSLOADER_IS,
                 new Object[]{cls.getName(), cls.getClassLoader()});
-        ClassLoader parent = cls.getClassLoader().getParent();
-        while (parent != null) {
-            log.log(level, MessageNames.PARENT_CLASS_LOADER_IS,
-                    new Object[]{parent});
-            parent = parent.getParent();
+        try {
+            ClassLoader parent = cls.getClassLoader().getParent();
+            while (parent != null) {
+                log.log(level, MessageNames.PARENT_CLASS_LOADER_IS,
+                        new Object[]{parent});
+                parent = parent.getParent();
+            }
+        } catch (Throwable t) {
+            log.log(level, Strings.NEWLINE);
         }
+
     }
 
     public static void logClassLoaderHierarchy(Logger log,
@@ -124,14 +134,31 @@ public class Utils {
         while (parent != null) {
             log.log(level, MessageNames.PARENT_CLASS_LOADER_IS,
                     new Object[]{parent});
-            parent = parent.getParent();
+            try {
+                parent = parent.getParent();
+            } catch (Throwable t) {
+                parent = null;
+            }
         }
     }
-    
+
     public static String stackTrace(Throwable t) {
-        StringWriter s=new StringWriter();
-        PrintWriter pw=new PrintWriter(s);
+        StringWriter s = new StringWriter();
+        PrintWriter pw = new PrintWriter(s);
         t.printStackTrace(pw);
         return s.toString();
     }
+
+    public static void logGrantsToClass(final Logger log, final Level level, final Class c) {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            public Object run() {
+                ClassLoader cl = c.getClassLoader();
+                DynamicPolicyProvider dpp = (DynamicPolicyProvider) Policy.getPolicy();
+                Permission[] perms = dpp.getGrants(c, null);
+                log.log(level, MessageNames.GRANTS_TO_CLASS_ARE,
+                        new Object[]{c.getName(), Utils.format(perms)});
+                return null;
+            }
+        });
+    }
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/classloading/VirtualFileSystemClassLoader.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/classloading/VirtualFileSystemClassLoader.java b/river-container-core/src/main/java/org/apache/river/container/classloading/VirtualFileSystemClassLoader.java
index 19a6c63..a3c8b9f 100644
--- a/river-container-core/src/main/java/org/apache/river/container/classloading/VirtualFileSystemClassLoader.java
+++ b/river-container-core/src/main/java/org/apache/river/container/classloading/VirtualFileSystemClassLoader.java
@@ -38,17 +38,23 @@ import org.apache.river.container.LocalizedRuntimeException;
 import org.apache.river.container.MessageNames;
 
 /**
-
- @author trasukg
+ *
+ * @author trasukg
  */
 public class VirtualFileSystemClassLoader extends URLClassLoader {
 
     private FileObject fileSystemRoot = null;
     private List<ClasspathEntry> classpathEntries = new ArrayList<ClasspathEntry>();
     private CodeSource codeSource = null;
+    private boolean isAppPriority = false;
 
     public VirtualFileSystemClassLoader(FileObject fileSystemRoot, ClassLoader parent, CodeSource codeSource) {
+        this(fileSystemRoot, parent, codeSource, false);
+    }
+
+    public VirtualFileSystemClassLoader(FileObject fileSystemRoot, ClassLoader parent, CodeSource codeSource, boolean isAppPriority) {
         super(new URL[0], parent);
+        this.isAppPriority = isAppPriority;
         this.fileSystemRoot = fileSystemRoot;
         this.codeSource = codeSource;
     }
@@ -59,10 +65,10 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Add the given classpath to this classloader, based on the default root
-     supplied at construction time.
-
-     @param classPath
+     * Add the given classpath to this classloader, based on the default root
+     * supplied at construction time.
+     *
+     * @param classPath
      */
     public void addClassPathEntry(String classPath) {
 
@@ -70,14 +76,14 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Add the given classpath to this classloader, based on the given fileRoot.
-     The classpath can contain multiple entries, separated by colons, e.g.
-     'jsk-platform.jar:jsk-lib.jar'.<br> Each entry can either be a jar file or
-     a jar file with a list of classes that the jar file can be used to provide.
-     For instance, 'surrogate.jar(org.apache.ABC, org.apache.DEF)'.
-
-     @param fileRoot
-     @param classPath
+     * Add the given classpath to this classloader, based on the given fileRoot.
+     * The classpath can contain multiple entries, separated by colons, e.g.
+     * 'jsk-platform.jar:jsk-lib.jar'.<br> Each entry can either be a jar file
+     * or a jar file with a list of classes that the jar file can be used to
+     * provide. For instance, 'surrogate.jar(org.apache.ABC, org.apache.DEF)'.
+     *
+     * @param fileRoot
+     * @param classPath
      */
     public void addClassPathEntry(FileObject fileRoot, String classPath) {
 
@@ -100,18 +106,18 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
         for (ClasspathFilter filter : filters) {
             FileObject entryObject = fileRoot.resolveFile(filter.getJarName());
 
-            FileObject entryFileSystem =
-                    fileRoot.getFileSystem().getFileSystemManager().createFileSystem(entryObject);
+            FileObject entryFileSystem
+                    = fileRoot.getFileSystem().getFileSystemManager().createFileSystem(entryObject);
             classpathEntries.add(new ClasspathEntry(filter, entryFileSystem));
         }
     }
 
     /**
-     Find a resource by searching through all the classpath entries that have
-     been set up.
-
-     @param name
-     @return
+     * Find a resource by searching through all the classpath entries that have
+     * been set up.
+     *
+     * @param name
+     * @return
      */
     @Override
     public URL findResource(final String name) {
@@ -134,8 +140,7 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     @Override
     public Enumeration<URL> findResources(final String name) throws IOException {
 
-        Enumeration result = (Enumeration)
-                Security.doPrivileged(new PrivilegedAction<Enumeration>() {
+        Enumeration result = (Enumeration) Security.doPrivileged(new PrivilegedAction<Enumeration>() {
 
             public Enumeration run() {
                 List<URL> urlList = new ArrayList<URL>();
@@ -155,11 +160,11 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Find the file object for a resource by searching through all the classpath
-     entries that have been set up.
-
-     @param name
-     @return
+     * Find the file object for a resource by searching through all the
+     * classpath entries that have been set up.
+     *
+     * @param name
+     * @return
      */
     public FileObject findResourceFileObject(String name) {
         for (ClasspathEntry cpEntry : classpathEntries) {
@@ -176,11 +181,11 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Find the all the file objects for a resource by searching through all the
-     classpath entries that have been set up.
-
-     @param name
-     @return
+     * Find the all the file objects for a resource by searching through all the
+     * classpath entries that have been set up.
+     *
+     * @param name
+     * @return
      */
     public List<FileObject> findResourceFileObjects(String name) {
         List<FileObject> foList = new ArrayList<FileObject>();
@@ -223,12 +228,12 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Set the codebase URLs to an arbitrary list of URLs. These URLs form the
-     codebase annotation for classes loaded through this classloader. For the
-     sake of general paranoia, sets the codebase to a copy of the provided
-     array.
-
-     @param codebase
+     * Set the codebase URLs to an arbitrary list of URLs. These URLs form the
+     * codebase annotation for classes loaded through this classloader. For the
+     * sake of general paranoia, sets the codebase to a copy of the provided
+     * array.
+     *
+     * @param codebase
      */
     public void setCodebase(URL[] codebase) {
         if (codebase == null || codebase.length == 0) {
@@ -242,20 +247,20 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
     }
 
     /**
-     Get the list of URLs that are used for the codebase annotation. Note that
-     this list is not the actual classpath (that is in the superclass). The
-     codebase URLs are imposed to match whatever the Jini service wants to
-     expose as its codebase annotation.
-
-     @return
+     * Get the list of URLs that are used for the codebase annotation. Note that
+     * this list is not the actual classpath (that is in the superclass). The
+     * codebase URLs are imposed to match whatever the Jini service wants to
+     * expose as its codebase annotation.
+     *
+     * @return
      */
     @Override
     public URL[] getURLs() {
         return codebaseURLs;
     }
     /**
-     Stores the codebase that will be returned as the codebase annotation.
-
+     * Stores the codebase that will be returned as the codebase annotation.
+     *
      */
     private URL codebaseURLs[] = new URL[0];
 
@@ -295,4 +300,89 @@ public class VirtualFileSystemClassLoader extends URLClassLoader {
 
         return sb.toString();
     }
+
+    /**
+     * Loads a class with the specified name.
+     *
+     * <p>
+     * <code>VirtualFileSystemClassLoader</code> implements this method as
+     * follows:
+     *
+     * <li>If <code>isAppPriority</code> is <code>true</code>, then this method
+     * invokes {@link #findClass
+     * findClass} with <code>name</code>. If <code>findClass</code> throws an
+     * exception, then this method throws that exception. Otherwise, this method
+     * returns the <code>Class</code> returned by <code>findClass</code>, and if
+     * <code>resolve</code> is <code>true</code>,
+     * {@link #resolveClass resolveClass} is invoked with the <code>Class</code>
+     * before returning.
+     *
+     * <li>If <code>isAppPriority</code> is <code>false</code>, then this method
+     * invokes the superclass implementation of {@link ClassLoader#loadClass(String,boolean)
+     * loadClass} with <code>name</code> and <code>resolve</code> and returns
+     * the result. If the superclass's <code>loadClass</code> throws an
+     * exception, then this method throws that exception.
+     *
+     * </ul>
+     *
+     * @param name the binary name of the class to load
+     *
+     * @param resolve if <code>true</code>, then {@link #resolveClass
+     * resolveClass} will be invoked with the loaded class before returning
+     *
+     * @return the loaded class
+     *
+     * @throws ClassNotFoundException if the class could not be found
+     *
+     */
+    protected synchronized Class loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+        // First, check if the class has already been loaded
+	Class c = findLoadedClass(name);
+        if (c!=null) return c;
+        
+        if (isAppPriority) {
+            try {
+                c = findClass(name);
+            } catch (ClassNotFoundException e) {
+                return super.loadClass(name, resolve);
+            }
+            if (resolve) {
+                resolveClass(c);
+            }
+            return c;
+        } else {
+            return super.loadClass(name, resolve);
+        }
+    }
+
+    /**
+     * Gets a resource with the specified name.
+     *
+     * <p>
+     * <code>VirtualFileSystemClassLoader</code> implements this method as
+     * follows:
+     * <li>If <code>isAppPriority</code> is <code>true</code>, then this method
+     * invokes {@link
+     * #findResource findResource} with <code>name</code> and returns the
+     * result.
+     *
+     * <li>If <code>isAppPriority</code> is <code>false</code>, then this method
+     * invokes the superclass implementation of
+     * {@link ClassLoader#getResource getResource} with <code>name</code> and
+     * returns the result.
+     *
+     * </ul>
+     *
+     * @param name the name of the resource to get
+     *
+     * @return a <code>URL</code> for the resource, or <code>null</code> if the
+     * resource could not be found
+     *
+     */
+    public URL getResource(String name) {
+        return isAppPriority
+                ? findResource(name) : super.getResource(name);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
index 3f33689..54578dc 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
@@ -137,17 +137,23 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         String parentLoaderName = configNode.search(
                 new Class[]{ASTconfig.class, ASTclassloader.class, ASTparent.class}).get(0).jjtGetChild(0).toString();
         log.log(Level.FINE, MessageNames.SERVICE_PARENT_CLASSLOADER_IS, parentLoaderName);
+        boolean isAppPriority=false;
+        if (!configNode.search( new Class[]{ ASTconfig.class, ASTclassloader.class, ASTappPriority.class}).isEmpty()) {
+            isAppPriority=true;
+        }
         ClassLoader parentLoader = (ClassLoader) context.get(parentLoaderName);
         VirtualFileSystemClassLoader cl
-                = createChildOfGivenClassloader(parentLoader, codeSource);
+                = createChildOfGivenClassloader(parentLoader, codeSource, isAppPriority);
         /*
          Include platform jars from the container's lib directory.
          */
-        ASTclasspath platformJarSpec = (ASTclasspath) configNode.search(new Class[]{ASTconfig.class,
-            ASTclassloader.class, ASTjars.class, ASTclasspath.class}).get(0);
-        addPlatformJarsToClassloader(platformJarSpec, cl);
+        List classpathNodes = configNode.search(new Class[]{ASTconfig.class,
+            ASTclassloader.class, ASTjars.class, ASTclasspath.class});
+        if (classpathNodes.size() > 0) {
+            ASTclasspath platformJarSpec = (ASTclasspath) classpathNodes.get(0);
+            addPlatformJarsToClassloader(platformJarSpec, cl);
+        }
         addLibDirectoryJarsToClasspath(serviceRoot, cl);
-
         return cl;
 
     }
@@ -171,12 +177,12 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         cl.addClasspathFilters(filters, fileUtility.getLibDirectory());
     }
 
-    protected VirtualFileSystemClassLoader createChildOfGivenClassloader(ClassLoader parent, CodeSource codeSource) {
+    protected VirtualFileSystemClassLoader createChildOfGivenClassloader(ClassLoader parent, CodeSource codeSource, boolean isAppPriority) {
         /*
          Create the service classloader.
          */
         VirtualFileSystemClassLoader cl
-                = new VirtualFileSystemClassLoader(null, parent, codeSource);
+                = new VirtualFileSystemClassLoader(null, parent, codeSource, isAppPriority);
         return cl;
     }
 
@@ -215,7 +221,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         log.log(Level.FINE, MessageNames.CALLING_MAIN, new Object[]{
             startClassName, Utils.format(args)
         });
-        Runnable task=null;
+        Runnable task = null;
         if (hasServiceStarterConstructor(env.getClassLoader(), startClassName)) {
             task = new Runnable() {
                 @Override
@@ -238,7 +244,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
                     }
                 }
             };
-            
+
         } else {
             throw new UnsupportedOperationException();
         }
@@ -484,11 +490,11 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
         try {
             Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String[].class, lifeCycleClass});
             return true;
-        } catch(NoSuchMethodException nsme) {
+        } catch (NoSuchMethodException nsme) {
             return false;
         }
     }
-    
+
     private boolean hasMain(ClassLoader cl, String className) throws ClassNotFoundException {
         Class clazz = Class.forName(className, true, cl);
         log.log(Level.FINE, MessageNames.CLASSLOADER_IS,
@@ -496,15 +502,14 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
 
         // Get this through dynamic lookup becuase it won't be in the parent
         // classloader!
-        
         try {
             Method main = clazz.getMethod(Strings.MAIN, new Class[]{String[].class});
             return true;
-        } catch(NoSuchMethodException nsme) {
+        } catch (NoSuchMethodException nsme) {
             return false;
         }
     }
-    
+
     private void callMain(ClassLoader cl, String className, String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
         Class clazz = Class.forName(className, true, cl);
         log.log(Level.FINE, MessageNames.CLASSLOADER_IS,
@@ -512,16 +517,15 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
 
         // Get this through dynamic lookup becuase it won't be in the parent
         // classloader!
-        
         try {
             Method main = clazz.getMethod(Strings.MAIN, new Class[]{String[].class});
-            main.invoke(null, new Object[] {args});
-        } catch(NoSuchMethodException nsme) {
+            main.invoke(null, new Object[]{args});
+        } catch (NoSuchMethodException nsme) {
             throw new RuntimeException(nsme);
         }
-        
+
     }
-    
+
     private Object instantiateService(ClassLoader cl, String className, String[] parms)
             throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, InstantiationException {
         Class clazz = Class.forName(className, true, cl);

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
index 26e5598..92c78ac 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
@@ -113,6 +113,16 @@ public class StartupDeployer {
 
     FileObject deploymentDirectoryFile = null;
 
+    private String deployerName=null;
+
+    public String getDeployerName() {
+        return deployerName;
+    }
+
+    public void setDeployerName(String deployerName) {
+        this.deployerName = deployerName;
+    }
+    
     @Init
     public void init() {
         try {
@@ -128,6 +138,12 @@ public class StartupDeployer {
     private void tryInitialize() throws IOException, ParseException {
         log.log(Level.FINE, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
         /*
+        If the deployerName is supplied, look it up and override the injected deployer.
+        */
+        if(deployerName != null) {
+            deployer=(StarterServiceDeployer) context.get(deployerName);
+        }
+        /*
          Establish the deployment directory.
          */
         deploymentDirectoryFile = fileUtility.getProfileDirectory().resolveFile(deployDirectory);

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/security/ContainerCodePolicy.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/security/ContainerCodePolicy.java b/river-container-core/src/main/java/org/apache/river/container/security/ContainerCodePolicy.java
index e927e0d..fb26969 100644
--- a/river-container-core/src/main/java/org/apache/river/container/security/ContainerCodePolicy.java
+++ b/river-container-core/src/main/java/org/apache/river/container/security/ContainerCodePolicy.java
@@ -35,17 +35,18 @@ import org.apache.river.container.MessageNames;
  */
 public class ContainerCodePolicy extends Policy {
 
-    private static final Logger log =
-            Logger.getLogger(ContainerCodePolicy.class.getName(),
-            MessageNames.BUNDLE_NAME);
+    private static final Logger log
+            = Logger.getLogger(ContainerCodePolicy.class.getName(),
+                    MessageNames.BUNDLE_NAME);
     List<ClassLoader> privilegedClassLoaders = new ArrayList<ClassLoader>();
 
-    public ContainerCodePolicy(ClassLoader bootstrapClassLoader) {
-        privilegedClassLoaders.add(bootstrapClassLoader);
-        ClassLoader cl = this.getClass().getClassLoader();
-        while (cl != null) {
-            privilegedClassLoaders.add(cl);
-            cl = cl.getParent();
+    public ContainerCodePolicy(ClassLoader... classLoaders) {
+
+        for (ClassLoader cl : classLoaders) {
+            while (cl != null) {
+                privilegedClassLoaders.add(cl);
+                cl = cl.getParent();
+            }
         }
         allPermissions.add(new AllPermission());
         allPermissions.setReadOnly();
@@ -67,12 +68,13 @@ public class ContainerCodePolicy extends Policy {
 
     /**
      * This seems to be necessary to allow the com.sun.rmi.server.LoaderHandler
-     * class to read the marshalled object.  LoaderHandler will call 
-     * this method to get the permissions that are granted to all classes, which
-     * in the case of the container, is none.  But the permissions collection
-     * must be writable.
+     * class to read the marshalled object. LoaderHandler will call this method
+     * to get the permissions that are granted to all classes, which in the case
+     * of the container, is none. But the permissions collection must be
+     * writable.
+     *
      * @param codesource
-     * @return 
+     * @return
      */
     @Override
     public PermissionCollection getPermissions(CodeSource codesource) {

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/java/org/apache/river/container/security/SecurityInitializer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/security/SecurityInitializer.java b/river-container-core/src/main/java/org/apache/river/container/security/SecurityInitializer.java
index d200975..95b8364 100644
--- a/river-container-core/src/main/java/org/apache/river/container/security/SecurityInitializer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/security/SecurityInitializer.java
@@ -18,8 +18,10 @@
 package org.apache.river.container.security;
 
 import java.security.Policy;
+import java.security.PrivilegedAction;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import net.jini.security.Security;
 import net.jini.security.policy.DynamicPolicyProvider;
 import org.apache.river.container.ConfigurationException;
 import org.apache.river.container.Context;
@@ -27,40 +29,52 @@ import org.apache.river.container.Init;
 import org.apache.river.container.Injected;
 import org.apache.river.container.InjectionStyle;
 import org.apache.river.container.MessageNames;
+import org.apache.river.container.Utils;
 
 /**
- This class is the container component that sets up the security manager and
- dynamic policy provider.
-
- @author trasukg
+ * This class is the container component that sets up the security manager and
+ * dynamic policy provider.
+ *
+ * @author trasukg
  */
 public class SecurityInitializer {
 
-    private static Logger log =
-            Logger.getLogger(SecurityInitializer.class.getName(),
-            MessageNames.BUNDLE_NAME);
+    private static Logger log
+            = Logger.getLogger(SecurityInitializer.class.getName(),
+                    MessageNames.BUNDLE_NAME);
     @Injected(style = InjectionStyle.BY_TYPE)
     private Context context;
 
     @Injected
+    private ClassLoader containerClassLoader;
+
+    @Injected 
     private ClassLoader bootstrapClassLoader;
     
     @Init
     public void initialize() {
-        Policy basePolicy = new ContainerCodePolicy(bootstrapClassLoader);
-        DynamicPolicyProvider policy = new DynamicPolicyProvider(basePolicy);
-        Policy.setPolicy(policy);
-        
-        context.put(org.apache.river.container.Strings.SECURITY_POLICY, policy);
-        
-        System.setSecurityManager(new SecurityManager());
-        
-        Policy installedPolicy = Policy.getPolicy();
-        if (installedPolicy != policy) {
-            throw new ConfigurationException(MessageNames.SECURITY_INIT_WRONG_POLICY,
-                    installedPolicy);
-        }
-        
+        Security.doPrivileged(new PrivilegedAction() {
+
+            public Object run() {
+                log.info("Container classloader is...");
+                Utils.logClassLoaderHierarchy(log, Level.INFO, containerClassLoader);
+                Policy basePolicy = new ContainerCodePolicy(containerClassLoader, bootstrapClassLoader);
+                DynamicPolicyProvider policy = new DynamicPolicyProvider(basePolicy);
+                Policy.setPolicy(policy);
+
+                context.put(org.apache.river.container.Strings.SECURITY_POLICY, policy);
+
+                System.setSecurityManager(new SecurityManager());
+
+                Policy installedPolicy = Policy.getPolicy();
+                if (installedPolicy != policy) {
+                    throw new ConfigurationException(MessageNames.SECURITY_INIT_WRONG_POLICY,
+                            installedPolicy);
+                }
+                return null;
+            }
+        });
+
         log.log(Level.INFO, MessageNames.SECURITY_INIT_SUCCEEDED);
 
     }

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/jjtree/DeployerConfigParser.jjt
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/jjtree/DeployerConfigParser.jjt b/river-container-core/src/main/jjtree/DeployerConfigParser.jjt
index dabc18d..1df99fd 100644
--- a/river-container-core/src/main/jjtree/DeployerConfigParser.jjt
+++ b/river-container-core/src/main/jjtree/DeployerConfigParser.jjt
@@ -99,11 +99,13 @@ TOKEN :
 |       < CONFIGURATION: "configuration">
 |       < JARS: "jars">
 |       < PARENT: "parent">
+|       < APPLICATION: "application">
 | 	< AND: "and" >
 | 	< OR: "or" >
 | 	< NOT: "not" >
 | 	< TRUE: "true" >
 | 	< FALSE: "false" >
+|       < PRIORITY: "priority" >
 |  	< SYMBOL:
 		["A"-"Z", "a"-"z", "_"] 
                     (["0"-"9", "A"-"Z", "a"-"z", ".", "_", "-", "$"])*>
@@ -184,7 +186,31 @@ void classloader() #classloader:
     log.fine("classloader()");
 }
 {
-    <CLASSLOADER> <LBRACE> parent() [jars()] [codebase()] <RBRACE>
+    <CLASSLOADER> <LBRACE> parent() [loaderPriority()] [jars()] [codebase()] <RBRACE>
+}
+
+void loaderPriority():
+{
+    log.fine("loaderPriority");
+}
+{
+    <PRIORITY> (appPriority() | parentPriority()) <SEMICOLON>
+}
+
+void appPriority() #appPriority:
+{
+    log.fine("appPriority");
+}
+{
+    <APPLICATION>
+}
+
+void parentPriority() #parentPriority:
+{
+    log.fine("parentPriority()");
+}
+{   
+    <PARENT>
 }
 
 void jars() #jars:
@@ -192,7 +218,7 @@ void jars() #jars:
     log.fine("jars()");
 }
 {
-    <JARS> <LBRACE> classpath() <RBRACE>
+    <JARS> <LBRACE> [classpath()] <RBRACE>
 }
 
 void parent() #parent:

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
index 7a93455..2dcf8c2 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
+++ b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
@@ -64,6 +64,7 @@ failedToRemoveMBean=Failed to remove MBean for application ''{0}''.
 failedToSetProperty=Failed to set property ''{0}'' on component class ''{1}'' to ''{2}''.
 foundNoServiceArchives=Found no service archives for deployment dir ''{0}''.
 foundServiceArchives=Found {0} service archives in deployment dir ''{1}''.
+grantsToClassAre=Permissions granted to class ''{0}'' are {1}.
 illegalArgumentException=An operation threw an IllegalArgumentException.
 illegalAccessException=An operation threw an IllegalAccessException.
 invalidClasspathEntry=Invalid classpath entry: {0}

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
index b99cd8f..d4bb419 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
+++ b/river-container-core/src/main/resources/org/apache/river/container/core-config.xml
@@ -51,6 +51,7 @@
         lib/commons-logging-1.1.1.jar
         lib/commons-vfs2-2.0.jar
         lib/jsk-platform-${jsk-version}.jar
+        lib/jsk-lib-${jsk-version}.jar
         lib/jsk-resources-${jsk-version}.jar
         lib/regexp-1.3.jar
         lib/river-hsm-${project.version}.jar

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/test/java/org/apache/river/container/deployer/DeployerConfigParserTest.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/test/java/org/apache/river/container/deployer/DeployerConfigParserTest.java b/river-container-core/src/test/java/org/apache/river/container/deployer/DeployerConfigParserTest.java
index d017b26..4c658f5 100644
--- a/river-container-core/src/test/java/org/apache/river/container/deployer/DeployerConfigParserTest.java
+++ b/river-container-core/src/test/java/org/apache/river/container/deployer/DeployerConfigParserTest.java
@@ -20,6 +20,7 @@ package org.apache.river.container.deployer;
 import java.util.List;
 import java.util.logging.Logger;
 import java.io.InputStream;
+import java.util.logging.Level;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
@@ -60,11 +61,13 @@ public class DeployerConfigParserTest {
      it through the parser without errors.
      */
     public void testBasicParsing() throws ParseException {
+        log.setLevel(Level.FINE);
         ASTconfig config = parseTestConfig();
         log.fine("grants string is:" + config.toString());
         String expected = "config (grant (permission java.io.FilePermission \"${serviceArchive}\" \"read\") "
                 + "(permission java.net.SocketPermission \"*\" \"connect\")) "
                 + "(classloader (parent systemClassLoader) "
+                + "appPriority "
                 + "(jars (classpath (cpEntry commons-vfs-1.0.jar) "
                 + "(cpEntry commons-logging-1.1.1.jar) (cpEntry jsk-platform.jar) "
                 + "(cpEntry jsk-lib.jar) (cpEntry jsk-resources.jar) "

http://git-wip-us.apache.org/repos/asf/river-container/blob/317dac09/river-container-core/src/test/resources/org/apache/river/container/deployer/sample.config
----------------------------------------------------------------------
diff --git a/river-container-core/src/test/resources/org/apache/river/container/deployer/sample.config b/river-container-core/src/test/resources/org/apache/river/container/deployer/sample.config
index d7116d5..157ce66 100644
--- a/river-container-core/src/test/resources/org/apache/river/container/deployer/sample.config
+++ b/river-container-core/src/test/resources/org/apache/river/container/deployer/sample.config
@@ -29,6 +29,8 @@ classloader {
     //For a privileged application deployer, parent=containerClassLoader;
     parent systemClassLoader;
 
+    priority application;
+
     jars {
         commons-vfs-1.0.jar,
         commons-logging-1.1.1.jar,