r1821 - in trunk/main/metro: . appliance appliance/etc appliance/etc/data appliance/etc/main appliance/etc/main/META-INF appliance/etc/main/META-INF/services appliance/etc/xsds appliance/src appliance/src/main appliance/src/main/dpml appliance/src/main/dpml/station appliance/src/main/dpml/station/info appliance/src/main/dpml/station/util appliance/src/main/net appliance/src/main/net/dpml appliance/src/main/net/dpml/station appliance/src/test appliance/src/test/net appliance/src/test/net/dpml appliance/src/test/net/dpml/appliance connector connector/etc connector/src connector/src/main connector/src/main/dpml connector/src/main/dpml/station connector/src/main/dpml/station/connector main main/etc main/etc/bin main/src main/src/main main/src/main/dpml main/src/main/dpml/metro main/src/main/dpml/metro/console station station/etc station/etc/bin station/etc/bin/scm station/etc/bin/scm/conf station/etc/bin/scm/lib station/etc/prefs station/etc/prefs/plans station/etc/pref! s/propertiess station/src station/src/main station/src/main/dpml station/src/main/dpml/station station/src/main/dpml/station/console test test/etc/data test/src test/src/test/net/dpml/test

mcconnell at BerliOS mcconnell at mail.berlios.de
Thu Feb 8 18:33:52 EST 2007


Author: mcconnell
Date: 2007-02-09 00:33:09 +0100 (Fri, 09 Feb 2007)
New Revision: 1821

Added:
   trunk/main/metro/appliance/
   trunk/main/metro/appliance/build.xml
   trunk/main/metro/appliance/etc/
   trunk/main/metro/appliance/etc/data/
   trunk/main/metro/appliance/etc/data/appliance.xml
   trunk/main/metro/appliance/etc/data/bar.xml
   trunk/main/metro/appliance/etc/data/empty.xml
   trunk/main/metro/appliance/etc/data/foo.xml
   trunk/main/metro/appliance/etc/data/logging.properties
   trunk/main/metro/appliance/etc/data/plan.xml
   trunk/main/metro/appliance/etc/data/security.policy
   trunk/main/metro/appliance/etc/main/
   trunk/main/metro/appliance/etc/main/META-INF/
   trunk/main/metro/appliance/etc/main/META-INF/services/
   trunk/main/metro/appliance/etc/main/META-INF/services/net.dpml.transit.ContentHandler
   trunk/main/metro/appliance/etc/main/META-INF/services/org.w3c.dom.ls.LSResourceResolver
   trunk/main/metro/appliance/etc/xsds/
   trunk/main/metro/appliance/etc/xsds/appliance.xsd
   trunk/main/metro/appliance/etc/xsds/plan.xsd
   trunk/main/metro/appliance/project.xml
   trunk/main/metro/appliance/src/
   trunk/main/metro/appliance/src/main/
   trunk/main/metro/appliance/src/main/dpml/
   trunk/main/metro/appliance/src/main/dpml/station/
   trunk/main/metro/appliance/src/main/dpml/station/info/
   trunk/main/metro/appliance/src/main/dpml/station/info/ApplianceDescriptor.java
   trunk/main/metro/appliance/src/main/dpml/station/info/EntryDescriptor.java
   trunk/main/metro/appliance/src/main/dpml/station/info/InfoDescriptor.java
   trunk/main/metro/appliance/src/main/dpml/station/info/PlanDescriptor.java
   trunk/main/metro/appliance/src/main/dpml/station/info/ProcessDescriptor.java
   trunk/main/metro/appliance/src/main/dpml/station/info/package-info.java
   trunk/main/metro/appliance/src/main/dpml/station/util/
   trunk/main/metro/appliance/src/main/dpml/station/util/LoggingServer.java
   trunk/main/metro/appliance/src/main/dpml/station/util/OutputStreamReader.java
   trunk/main/metro/appliance/src/main/dpml/station/util/StreamReader.java
   trunk/main/metro/appliance/src/main/net/
   trunk/main/metro/appliance/src/main/net/dpml/
   trunk/main/metro/appliance/src/main/net/dpml/station/
   trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceContentHandler.java
   trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceNamespaceResolver.java
   trunk/main/metro/appliance/src/main/net/dpml/station/Application.java
   trunk/main/metro/appliance/src/main/net/dpml/station/CompositeAppliance.java
   trunk/main/metro/appliance/src/main/net/dpml/station/PlanContentHandler.java
   trunk/main/metro/appliance/src/main/net/dpml/station/PlanNamespaceResolver.java
   trunk/main/metro/appliance/src/main/net/dpml/station/Station.java
   trunk/main/metro/appliance/src/main/net/dpml/station/StationException.java
   trunk/main/metro/appliance/src/main/net/dpml/station/package-info.java
   trunk/main/metro/appliance/src/test/
   trunk/main/metro/appliance/src/test/net/
   trunk/main/metro/appliance/src/test/net/dpml/
   trunk/main/metro/appliance/src/test/net/dpml/appliance/
   trunk/main/metro/appliance/src/test/net/dpml/appliance/AbstractTestCase.java
   trunk/main/metro/appliance/src/test/net/dpml/appliance/ApplianceDescriptorTestCase.java
   trunk/main/metro/appliance/src/test/net/dpml/appliance/PlanDescriptorTestCase.java
   trunk/main/metro/connector/
   trunk/main/metro/connector/build.xml
   trunk/main/metro/connector/etc/
   trunk/main/metro/connector/etc/component.xml
   trunk/main/metro/connector/etc/local.xml
   trunk/main/metro/connector/project.xml
   trunk/main/metro/connector/src/
   trunk/main/metro/connector/src/main/
   trunk/main/metro/connector/src/main/dpml/
   trunk/main/metro/connector/src/main/dpml/station/
   trunk/main/metro/connector/src/main/dpml/station/connector/
   trunk/main/metro/connector/src/main/dpml/station/connector/LocalConnector.java
   trunk/main/metro/main/
   trunk/main/metro/main/build.xml
   trunk/main/metro/main/etc/
   trunk/main/metro/main/etc/bin/
   trunk/main/metro/main/etc/bin/metro
   trunk/main/metro/main/etc/bin/metro.exe
   trunk/main/metro/main/etc/bin/metro.lap
   trunk/main/metro/main/etc/bin/metro.policy
   trunk/main/metro/main/etc/component.xml
   trunk/main/metro/main/project.xml
   trunk/main/metro/main/src/
   trunk/main/metro/main/src/main/
   trunk/main/metro/main/src/main/dpml/
   trunk/main/metro/main/src/main/dpml/metro/
   trunk/main/metro/main/src/main/dpml/metro/console/
   trunk/main/metro/main/src/main/dpml/metro/console/Main.java
   trunk/main/metro/station/
   trunk/main/metro/station/build.xml
   trunk/main/metro/station/etc/
   trunk/main/metro/station/etc/bin/
   trunk/main/metro/station/etc/bin/scm/
   trunk/main/metro/station/etc/bin/scm/WRAPPER_LICENSE.txt
   trunk/main/metro/station/etc/bin/scm/conf/
   trunk/main/metro/station/etc/bin/scm/conf/wrapper.conf
   trunk/main/metro/station/etc/bin/scm/install-DPML-SCM.bat
   trunk/main/metro/station/etc/bin/scm/lib/
   trunk/main/metro/station/etc/bin/scm/lib/wrapper.dll
   trunk/main/metro/station/etc/bin/scm/lib/wrapper.jar
   trunk/main/metro/station/etc/bin/scm/uninstall-DPML-SCM.bat
   trunk/main/metro/station/etc/bin/scm/wrapper.exe
   trunk/main/metro/station/etc/bin/station
   trunk/main/metro/station/etc/bin/station.exe
   trunk/main/metro/station/etc/bin/station.lap
   trunk/main/metro/station/etc/bin/station.policy
   trunk/main/metro/station/etc/component.xml
   trunk/main/metro/station/etc/prefs/
   trunk/main/metro/station/etc/prefs/plans/
   trunk/main/metro/station/etc/prefs/plans/default.plan
   trunk/main/metro/station/etc/prefs/propertiess/
   trunk/main/metro/station/etc/prefs/propertiess/process.properties
   trunk/main/metro/station/etc/prefs/propertiess/station.properties
   trunk/main/metro/station/project.xml
   trunk/main/metro/station/src/
   trunk/main/metro/station/src/main/
   trunk/main/metro/station/src/main/dpml/
   trunk/main/metro/station/src/main/dpml/station/
   trunk/main/metro/station/src/main/dpml/station/console/
   trunk/main/metro/station/src/main/dpml/station/console/Main.java
   trunk/main/metro/station/src/main/dpml/station/console/StationNotBoundException.java
   trunk/main/metro/test/etc/data/application.xml
   trunk/main/metro/test/etc/data/security.policy
   trunk/main/metro/test/etc/data/test.properties
   trunk/main/metro/test/project.xml
   trunk/main/metro/test/src/test/net/dpml/test/LocalTestCase.java
   trunk/main/metro/test/src/test/net/dpml/test/PlanTestCase.java
Removed:
   trunk/main/metro/build.xml
   trunk/main/metro/component/
   trunk/main/metro/model/
   trunk/main/metro/runtime/
   trunk/main/metro/state/
   trunk/main/metro/test/src/main/
   trunk/main/metro/test/src/test/net/dpml/test/part/
   trunk/main/metro/test/src/test/net/dpml/test/runtime/
   trunk/main/metro/tools/
Modified:
   trunk/main/metro/module.xml
   trunk/main/metro/test/build.xml
   trunk/main/metro/test/etc/data/logging.properties
Log:
SDK 2.X staged commit.

Added: trunk/main/metro/appliance/build.xml
===================================================================
--- trunk/main/metro/appliance/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="dpml-component" default="install" basedir="." 
+    xmlns:x="antlib:dpml.tools">
+
+  <x:import uri="local:template:dpml/tools/standard"/>
+
+  <target name="build" depends="standard.build">
+    <x:rmic>
+      <include name="**/StandardAppliance.class"/>
+      <include name="**/CompositeAppliance.class"/>
+    </x:rmic>
+  </target>
+  
+</project>

Added: trunk/main/metro/appliance/etc/data/appliance.xml
===================================================================
--- trunk/main/metro/appliance/etc/data/appliance.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/appliance.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<appliance xmlns="dpml:appliance">
+
+  <info name="hello"/>
+  
+  <process startup="0" shutdown="0">
+    <environment>
+      <variable name="FOO" value="BAR"/>
+    </environment>
+    <properties>
+      <property name="foo" value="bar"/>
+    </properties>
+  </process>
+  
+  <codebase uri="link:part:dpml/lang/dpml-lang-sample?message=Hello%20World,port=1024"/>
+
+</appliance>

Added: trunk/main/metro/appliance/etc/data/bar.xml
===================================================================
--- trunk/main/metro/appliance/etc/data/bar.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/bar.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<appliance xmlns="dpml:appliance">
+
+  <info name="bar"/>
+  
+  <process startup="0" shutdown="0">
+    <environment>
+      <variable name="FOO" value="BAR"/>
+    </environment>
+    <properties>
+      <property name="foo" value="bar"/>
+    </properties>
+  </process>
+  
+  <codebase uri="link:part:dpml/lang/dpml-lang-sample?message=Bar"/>
+
+</appliance>

Added: trunk/main/metro/appliance/etc/data/empty.xml
===================================================================
--- trunk/main/metro/appliance/etc/data/empty.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/empty.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+
+<plan xmlns="dpml:plan" name="demo" title="Plan Demo">
+
+</plan>

Added: trunk/main/metro/appliance/etc/data/foo.xml
===================================================================
--- trunk/main/metro/appliance/etc/data/foo.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/foo.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<appliance xmlns="dpml:appliance">
+
+  <info name="foo"/>
+  
+  <process startup="0" shutdown="0">
+    <environment>
+      <variable name="FOO" value="BAR"/>
+    </environment>
+    <properties>
+      <property name="foo" value="bar"/>
+    </properties>
+  </process>
+  
+  <codebase uri="link:part:dpml/lang/dpml-lang-sample?message=Foo,port=7"/>
+
+</appliance>

Added: trunk/main/metro/appliance/etc/data/logging.properties
===================================================================
--- trunk/main/metro/appliance/etc/data/logging.properties	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/logging.properties	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,3 @@
+.level=INFO
+sun.rmi.level=INFO
+#dpml.transit.level=INFO

Added: trunk/main/metro/appliance/etc/data/plan.xml
===================================================================
--- trunk/main/metro/appliance/etc/data/plan.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/plan.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+
+<plan xmlns="dpml:plan" name="demo" title="Plan Demo">
+
+  <entry key="foo" uri="link:appliance:dpml/metro/demo-foo"/>
+  <entry key="bar" uri="link:appliance:dpml/metro/demo-bar"/>
+  <entry key="toto" uri="link:part:dpml/lang/dpml-lang-sample?message=Hello%20World,port=1024"/>
+  
+</plan>

Added: trunk/main/metro/appliance/etc/data/security.policy
===================================================================
--- trunk/main/metro/appliance/etc/data/security.policy	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/data/security.policy	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,4 @@
+grant { 
+    permission java.security.AllPermission;
+};
+

Added: trunk/main/metro/appliance/etc/main/META-INF/services/net.dpml.transit.ContentHandler
===================================================================
--- trunk/main/metro/appliance/etc/main/META-INF/services/net.dpml.transit.ContentHandler	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/main/META-INF/services/net.dpml.transit.ContentHandler	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,6 @@
+#
+# List of available Transit content handlers.
+#
+
+net.dpml.station.ApplianceContentHandler
+net.dpml.station.PlanContentHandler
\ No newline at end of file

Added: trunk/main/metro/appliance/etc/main/META-INF/services/org.w3c.dom.ls.LSResourceResolver
===================================================================
--- trunk/main/metro/appliance/etc/main/META-INF/services/org.w3c.dom.ls.LSResourceResolver	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/main/META-INF/services/org.w3c.dom.ls.LSResourceResolver	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,6 @@
+#
+# List of namespace resolvers within the dpml-lang-part artifact.
+#
+
+net.dpml.station.ApplianceNamespaceResolver
+net.dpml.station.PlanNamespaceResolver

Added: trunk/main/metro/appliance/etc/xsds/appliance.xsd
===================================================================
--- trunk/main/metro/appliance/etc/xsds/appliance.xsd	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/xsds/appliance.xsd	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+
+<!--
+Defintion of an application.
+
+Example:
+
+  <application title="Sample Application" policy="automatic">
+    
+    <process startup="60" shutdown="60">
+      <properties>
+        <property name="foo" value="bar"/>
+      </properties>
+    </process>
+    
+    <codebase uri="link:part:acme/widget">
+      <param class="java.awt.Color" method="RED"/>
+    </codebase>
+    
+  </application>
+  
+-->
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+            xmlns:part="dpml:part"
+            xmlns:this="dpml:appliance"
+            targetNamespace="dpml:appliance"
+            elementFormDefault="qualified">
+    
+    <import namespace="dpml:part" schemaLocation="link:xsd:dpml/lang/dpml-lang-part"/>
+
+    <element name="appliance" type="this:ApplianceType"/>
+    <element name="codebase" type="this:CodebaseType"/>
+    
+    <complexType name="ApplianceType">
+      <sequence>
+        <element name="info" type="this:InfoType" minOccurs="0" maxOccurs="1"/>
+        <element name="process" type="this:ProcessType" minOccurs="0" maxOccurs="1"/>
+        <element name="codebase" type="this:CodebaseType" minOccurs="1" maxOccurs="1"/>
+      </sequence>
+    </complexType>
+
+    <complexType name="ProcessType">
+      <sequence>
+        <element name="environment" type="this:EnvironmentType" minOccurs="0" maxOccurs="1"/>
+        <element name="properties" type="this:PropertiesType" minOccurs="0" maxOccurs="1"/>
+        <element name="arguments" type="this:ArgumentsType" minOccurs="0" maxOccurs="1"/>
+      </sequence>
+      <attribute name="startup" type="integer" default="0"/>
+      <attribute name="shutdown" type="integer" default="0"/>
+      <attribute name="path" type="string"/>
+      <attribute name="executable" type="string" default="metro"/>
+    </complexType>
+    
+    <complexType name="PropertiesType">
+      <sequence>
+        <element name="property" type="this:PropertyType" minOccurs="0" maxOccurs="unbounded"/>
+      </sequence>
+    </complexType>
+    
+    <complexType name="EnvironmentType">
+      <sequence>
+        <element name="variable" type="this:PropertyType" minOccurs="0" maxOccurs="unbounded"/>
+      </sequence>
+    </complexType>
+    
+    <complexType name="ArgumentsType">
+      <sequence>
+        <element name="arg" type="this:ArgumentsType" minOccurs="0" maxOccurs="unbounded"/>
+      </sequence>
+    </complexType>
+    
+    <complexType name="ArgumentType">
+      <attribute name="value" type="string"/>
+    </complexType>
+
+    <complexType name="PropertyType">
+      <attribute name="name" type="string"/>
+      <attribute name="value" type="string"/>
+    </complexType>
+
+    <complexType name="CodebaseType">
+      <attribute name="uri" type="anyURI"/>
+    </complexType>
+    
+    <complexType name="InfoType">
+      <sequence>
+        <element name="description" type="string" minOccurs="0" maxOccurs="1"/>
+      </sequence>
+      <attribute name="name" type="string"/>
+      <attribute name="title" type="string"/>
+    </complexType>
+
+</schema>

Added: trunk/main/metro/appliance/etc/xsds/plan.xsd
===================================================================
--- trunk/main/metro/appliance/etc/xsds/plan.xsd	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/etc/xsds/plan.xsd	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+
+<!--
+Defintion of an multi-application deployment plan.
+
+Example:
+
+  <plan title="Scenario Demo">
+    <entry name="foo" uri="link:appliance:dpml/metro/demo"/>
+    <entry name="bar" uri="link:part:dpml/lang/dpml-lang-sample"/>
+    <entry name="toto" uri="link:part:dpml/lang/dpml-lang-sample?message=My%20Scenario,port=999"/>
+  </plan>
+  
+-->
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+            xmlns:this="dpml:plan"
+            targetNamespace="dpml:plan"
+            elementFormDefault="qualified">
+    
+    <element name="plan" type="this:PlanType"/>
+    
+    <complexType name="PlanType">
+      <sequence>
+        <element name="entry" type="this:EntryType" minOccurs="0" maxOccurs="unbounded"/>
+      </sequence>
+      <attribute name="name" type="string" default="root"/>
+      <attribute name="title" type="string"/>
+    </complexType>
+
+    <complexType name="EntryType">
+      <attribute name="uri" type="anyURI" use="required"/>
+      <attribute name="key" type="string" use="required"/>
+    </complexType>
+
+</schema>

Added: trunk/main/metro/appliance/project.xml
===================================================================
--- trunk/main/metro/appliance/project.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/project.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-metro-appliance">
+
+  <info title="DPML Application Content Handler">
+    <description>Content handler for the application datatype.</description>
+  </info>
+  
+  <types>
+    <type id="xsd" alias="true" source="etc/xsds/appliance.xsd">
+      <property name="project.package.include-in-classes" value="true"/>
+    </type>
+    <type id="xsd" name="dpml-metro-plan" alias="true" source="etc/xsds/plan.xsd">
+      <property name="project.package.include-in-classes" value="true"/>
+    </type>
+    <type id="jar"/>
+    <type id="appliance" name="demo" source="etc/data/appliance.xml" alias="true"/>
+    <type id="appliance" name="demo-foo" source="etc/data/foo.xml" alias="true"/>
+    <type id="appliance" name="demo-bar" source="etc/data/bar.xml" alias="true"/>
+    <type id="plan" name="demo" source="etc/data/plan.xml" alias="true"/>
+    <type id="plan" name="empty" source="etc/data/empty.xml" alias="true"/>
+  </types>
+  
+  <dependencies>
+    <build>
+      <include ref="dpml/lang/dpml-lang-sample"/>
+    </build>
+    <runtime>
+      <include ref="dpml/lang/dpml-lang-part"/>
+      <include ref="dpml/metro/dpml-metro-connector"/>
+    </runtime>
+    <test>
+      <include ref="org/apache/ant/ant-junit"/>
+    </test>
+  </dependencies>
+  
+</project>
+

Added: trunk/main/metro/appliance/src/main/dpml/station/info/ApplianceDescriptor.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/ApplianceDescriptor.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/ApplianceDescriptor.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.info;
+
+import dpml.util.ElementHelper;
+
+import java.util.Map;
+import java.util.Properties;
+import java.net.URI;
+
+import net.dpml.util.Resolver;
+import net.dpml.lang.DecodingException;
+
+import org.w3c.dom.Element;
+
+/**
+ * The ApplianceDescriptor is immutable datastructure used to 
+ * describe an application.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ApplianceDescriptor
+{
+    private final Element m_element;
+    private final InfoDescriptor m_info;
+    private final ProcessDescriptor m_profile;
+    private final URI m_codebase;
+    private final URI m_uri;
+    
+    public ApplianceDescriptor( Element element, Resolver resolver, URI uri ) throws DecodingException
+    {
+        m_uri = uri;
+        m_element = element;
+        
+        Element codebase = ElementHelper.getChild( element, "codebase" );
+        m_codebase = getCodebase( codebase, resolver );
+        
+        Element info = ElementHelper.getChild( element, "info" );
+        m_info = new InfoDescriptor( info, resolver );
+        
+        Element process = ElementHelper.getChild( element, "process" );
+        m_profile = new ProcessDescriptor( process, resolver );
+    }
+    
+    /*
+    public ApplianceDescriptor( InfoDescriptor info, ProcessDescriptor profile, URI codebase )
+    {
+        m_info = info;
+        m_profile = profile;
+        m_codebase = codebase;
+        m_element = null;
+    }
+    */
+    
+   /**
+    * Return the element defining the scenario descriptor.
+    * @return the defining element
+    */
+    public Element getElement()
+    {
+        return m_element;
+    }
+    
+   /**
+    * Get the application name.
+    *
+    * @return the name
+    */
+    public String getName()
+    {
+        return m_info.getName();
+    }
+    
+   /**
+    * Get the application title.
+    *
+    * @return the title
+    */
+    public String getTitle()
+    {
+        return m_info.getTitle();
+    }
+    
+   /**
+    * Get the application description.
+    *
+    * @return the description
+    */
+    public String getDescription()
+    {
+        return m_info.getDescription();
+    }
+    
+   /**
+    * Returns the executable name.
+    * 
+    * @return the name of the target executable
+    */
+    public String getExecutable()
+    {
+        return m_profile.getExecutable();
+    }
+
+   /**
+    * Returns the relative path for establishment of the working directory.
+    * 
+    * @return the working directory path
+    */
+    public String getPath()
+    {
+        return m_profile.getPath();
+    }
+
+   /**
+    * Get the duration in seconds to wait for startup
+    * of the application before considering deployment as a timeout failure.
+    * 
+    * @return the startup timeout value
+    */    
+    public int getStartupTimeout()
+    {
+        return m_profile.getStartupTimeout();
+    }
+
+   /**
+    * Get the duration in seconds to wait for the shutdown
+    * of the application before considering the process as non-responsive.
+    * 
+    * @return the shutdown timeout value
+    */
+    public int getShutdownTimeout()
+    {
+        return m_profile.getStartupTimeout();
+    }
+    
+   /**
+    * Get the environment variable declarations.
+    * 
+    * @return the environment variable map
+    */
+    public Map<String,String> getEnvironmentMap()
+    {
+        return m_profile.getEnvironmentMap();
+    }
+    
+   /**
+    * Get the system properties.
+    * 
+    * @return the system properties
+    */
+    public Properties getSystemProperties()
+    {
+        return m_profile.getSystemProperties();
+    }
+    
+   /**
+    * Get the target uri.
+    * 
+    * @return the target uri
+    */
+    public URI getTargetURI()
+    {
+        return m_codebase;
+    }
+    
+    
+   /**
+    * Get the codebase uri.
+    * 
+    * @return the codebase uri
+    */
+    public URI getCodebaseURI()
+    {
+        return m_uri;
+    }
+    
+    /**
+     * Compare this object with another for equality.
+     * @param other the object to compare this object with
+     * @return TRUE if the supplied object equivalent
+     */
+    public boolean equals( Object other )
+    {
+        if( null == other )
+        {
+            return false;
+        }
+        else if( getClass() != other.getClass() )
+        {
+            return false;
+        }
+        else
+        {
+            ApplianceDescriptor application = (ApplianceDescriptor) other;
+            if( !m_info.equals( application.m_info ) )
+            {
+                return false;
+            }
+            if( !m_profile.equals( application.m_profile ) )
+            {
+                return false;
+            }
+            if( !m_codebase.equals( application.m_codebase ) )
+            {
+                return false;
+            }
+            return true;
+        }
+    }
+    
+   /**
+    * Return the hashcode for the object.
+    * @return the hashcode value
+    */
+    public int hashCode()
+    {
+        int hash = getClass().hashCode();
+        hash ^= m_info.hashCode();
+        hash ^= m_profile.hashCode();
+        hash ^= m_codebase.hashCode();
+        return hash;
+    }
+    
+    private static URI getCodebase( Element element, Resolver resolver ) throws DecodingException
+    {
+        String spec = ElementHelper.getAttribute( element, "uri", null, resolver );
+        if( null == spec )
+        {
+            final String error = 
+              "Mising uri attribute.";
+            throw new DecodingException( error, element );
+        }
+        else
+        {
+            return URI.create( spec );
+        }
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/info/EntryDescriptor.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/EntryDescriptor.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/EntryDescriptor.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+ 
+package dpml.station.info;
+
+import dpml.util.ElementHelper;
+
+import java.net.URI;
+
+import net.dpml.lang.DecodingException;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * Immutable datastructure used to describe an deployment scenario.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class EntryDescriptor
+{
+    private final Element m_element;
+    private final String m_key;
+    private final URI m_uri;
+    
+    public EntryDescriptor( Element element, Resolver resolver ) throws DecodingException
+    {
+        m_element = element;
+        m_key = ElementHelper.getAttribute( element, "key", null, resolver );
+        if( null == m_key )
+        {
+            final String error = 
+              "Missing 'key' attribute in entry descriptor.";
+            throw new DecodingException( error, element );
+        }
+        String spec = ElementHelper.getAttribute( element, "uri", null, resolver );
+        m_uri = URI.create( spec );
+        if( null == m_uri )
+        {
+            final String error = 
+              "Missing 'uri' attribute in entry descriptor.";
+            throw new DecodingException( error, element );
+        }
+    }
+    
+   /**
+    * Return the element defining the entry descriptor.
+    * @return the defining element
+    */
+    public Element getElement()
+    {
+        return m_element;
+    }
+    
+   /**
+    * Get the uri.
+    * 
+    * @return the uri
+    */
+    public URI getURI()
+    {
+        return m_uri;
+    }
+    
+   /**
+    * Get the entry key.
+    * 
+    * @return the key
+    */
+    public String getKey()
+    {
+        return m_key;
+    }
+    
+    /**
+     * Compare this object with another for equality.
+     * @param other the object to compare this object with
+     * @return TRUE if the supplied object is equivalent
+     */
+    public boolean equals( Object other )
+    {
+        if( null == other )
+        {
+            return false;
+        }
+        else if( getClass() != other.getClass() )
+        {
+            return false;
+        }
+        else
+        {
+            EntryDescriptor entry = (EntryDescriptor) other;
+            if( !m_key.equals( entry.m_key ) )
+            {
+                return false;
+            }
+            else if( !m_uri.equals( entry.m_uri ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+    
+   /**
+    * Return the hashcode for the object.
+    * @return the hashcode value
+    */
+    public int hashCode()
+    {
+        int hash = getClass().hashCode();
+        hash ^= m_uri.hashCode();
+        hash ^= m_key.hashCode();
+        return hash;
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/info/InfoDescriptor.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/InfoDescriptor.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/InfoDescriptor.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.info;
+
+import dpml.util.ElementHelper;
+import dpml.util.ObjectUtils;
+
+import net.dpml.util.Resolver;
+import net.dpml.lang.DecodingException;
+
+import org.w3c.dom.Element;
+
+/**
+ * Application info description.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class InfoDescriptor
+{
+    private final Element m_element;
+    private final String m_title;
+    private final String m_description;
+    private final String m_name;
+    
+   /**
+    * Creation of a new application info descriptor.
+    * @param name the application name
+    * @param title the title of the application
+    * @param description the application description
+    */
+    public InfoDescriptor( Element element, Resolver resolver ) throws DecodingException
+    {
+        m_element = element;
+        if( null == element )
+        {
+            m_name = null;
+            m_description = null;
+            m_title = null;
+        }
+        else
+        {
+            m_name = ElementHelper.getAttribute( element, "name", null, resolver );
+            m_title = ElementHelper.getAttribute( element, "title", null, resolver );
+            Element elem = ElementHelper.getChild( element, "description" );
+            if( null != elem )
+            {
+                m_description = ElementHelper.getValue( elem );
+            }
+            else
+            {
+                m_description = null;
+            }
+        }
+    }
+    
+    public InfoDescriptor( String name, String title, String description )
+    {
+        m_name = name;
+        m_title = title;
+        m_description = description;
+        m_element = null;
+    }
+    
+   /**
+    * Return the element defining the scenario descriptor.
+    * @return the defining element
+    */
+    public Element getElement()
+    {
+        return m_element;
+    }
+    
+   /**
+    * Get the application name.
+    *
+    * @return the name
+    */
+    public String getName()
+    {
+        return m_name;
+    }
+    
+   /**
+    * Get the application title.
+    *
+    * @return the title
+    */
+    public String getTitle()
+    {
+        return m_title;
+    }
+    
+   /**
+    * Get the application description.
+    *
+    * @return the description
+    */
+    public String getDescription()
+    {
+        return m_description;
+    }
+    
+   /**
+    * Test if this instance is equal to the supplied instance.
+    * @param other the other instance
+    * @return the equality status
+    */
+    public boolean equals( Object other )
+    {
+        if( null == other )
+        {
+            return false;
+        }
+        if( getClass() != other.getClass() )
+        {
+            return false;
+        }
+        InfoDescriptor info = (InfoDescriptor) other;
+        if( !ObjectUtils.equals( m_name, info.m_name ) )
+        {
+            return false;
+        }
+        else if( !ObjectUtils.equals( m_title, info.m_title ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ObjectUtils.equals( m_description, info.m_description );
+        }
+    }
+    
+   /**
+    * Get the hashcode for this instance.
+    * @return the hash value
+    */
+    public int hashCode()
+    {
+        int hash = getClass().hashCode();
+        hash ^= ObjectUtils.hashValue( m_name );
+        hash ^= ObjectUtils.hashValue( m_title );
+        hash ^= ObjectUtils.hashValue( m_description );
+        return hash;
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/info/PlanDescriptor.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/PlanDescriptor.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/PlanDescriptor.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+ 
+package dpml.station.info;
+
+import dpml.util.ElementHelper;
+
+import java.io.IOException;
+import java.net.URI;
+
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * Immutable datastructure used to describe an deployment scenario.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class PlanDescriptor
+{
+    private final Element m_element;
+    private final String m_name;
+    private final String m_title;
+    private final EntryDescriptor[] m_entries;
+    private final URI m_codebase;
+    
+    public PlanDescriptor( Element element, Resolver resolver, URI codebase ) throws IOException
+    {
+        m_element = element;
+        m_codebase = codebase;
+        m_name = ElementHelper.getAttribute( element, "name", null, resolver );
+        m_title = ElementHelper.getAttribute( element, "title", null, resolver );
+        Element[] elements = ElementHelper.getChildren( element, "entry" );
+        m_entries = new EntryDescriptor[ elements.length ];
+        for( int i=0; i<elements.length; i++ )
+        {
+            Element elem = elements[i];
+            m_entries[i] = new EntryDescriptor( elem, resolver );
+        }
+    }
+    
+   /**
+    * Return the element defining the scenario descriptor.
+    * @return the defining element
+    */
+    public Element getElement()
+    {
+        return m_element;
+    }
+    
+   /**
+    * Get the codebase uri.
+    * 
+    * @return the uri
+    */
+    public URI getCodebaseURI()
+    {
+        return m_codebase;
+    }
+    
+   /**
+    * Get the scenario name.
+    * 
+    * @return the name
+    */
+    public String getName()
+    {
+        return m_name;
+    }
+    
+   /**
+    * Get the scenario title.
+    * 
+    * @return the title
+    */
+    public String getTitle()
+    {
+        return m_title;
+    }
+    
+   /**
+    * Get the deployment uris.
+    * 
+    * @return the deployment uris
+    */
+    public EntryDescriptor[] getEntryDescriptors()
+    {
+        return m_entries;
+    }
+    
+    /**
+     * Compare this object with another for equality.
+     * @param other the object to compare this object with
+     * @return TRUE if the supplied object is equivalent
+     */
+    public boolean equals( Object other )
+    {
+        if( null == other )
+        {
+            return false;
+        }
+        else if( getClass() != other.getClass() )
+        {
+            return false;
+        }
+        else
+        {
+            PlanDescriptor scenario = (PlanDescriptor) other;
+            int n = m_entries.length;
+            int m = scenario.m_entries.length;
+            if( n != m )
+            {
+                return false;
+            }
+            for( int i=0; i<m_entries.length; i++ )
+            {
+                EntryDescriptor local = m_entries[i];
+                EntryDescriptor external = scenario.m_entries[i];
+                if( !local.equals( external ) )
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+    
+   /**
+    * Return the hashcode for the object.
+    * @return the hashcode value
+    */
+    public int hashCode()
+    {
+        int hash = getClass().hashCode();
+        for( EntryDescriptor entry : m_entries )
+        {
+            hash ^= entry.hashCode();
+        }
+        return hash;
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/info/ProcessDescriptor.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/ProcessDescriptor.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/ProcessDescriptor.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.info;
+
+import dpml.util.ElementHelper;
+import dpml.util.ObjectUtils;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.ArrayList;
+
+import net.dpml.lang.DecodingException;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * Application info description.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ProcessDescriptor
+{
+    private final Element m_element;
+    private final String m_executable;
+    private final Map<String,String> m_environment = new Hashtable<String,String>();
+    private final Properties m_properties = new Properties();
+    private final List<String> m_arguments = new ArrayList<String>();
+    private final String m_path;
+    private final int m_startup;
+    private final int m_shutdown;
+    
+   /**
+    * Creation of a new process descriptor.
+    * @param executable the java executable name (optional)
+    * @param environment a map of overriding environment variables
+    * @param properties supplimentary system properties 
+    * @param path the deployment base directory path
+    * @param startup startup timeout in seconds
+    * @param shutdown startup timeout in seconds
+    */
+    public ProcessDescriptor( Element element, Resolver resolver ) throws DecodingException
+    {
+        m_element = element;
+        if( null == element )
+        {
+            m_executable = "metro";
+            m_path = null;
+            m_startup = 0;
+            m_shutdown = 0;
+        }
+        else
+        {
+            m_executable = ElementHelper.getAttribute( element, "executable", null, resolver );
+            m_path = ElementHelper.getAttribute( element, "path", null, resolver );
+            Element environment = ElementHelper.getChild( element, "environment" );
+            if( null != environment )
+            {
+                Element[] variables = ElementHelper.getChildren( environment, "variable" );
+                for( Element variable : variables )
+                {
+                    String name = ElementHelper.getAttribute( variable, "name", null, resolver );
+                    String value = ElementHelper.getAttribute( variable, "value", null, resolver );
+                    m_environment.put( name, value );
+                }
+            }
+            
+            Element properties = ElementHelper.getChild( element, "properties" );
+            if( null != properties )
+            {
+                Element[] props = ElementHelper.getChildren( properties, "property" );
+                for( Element elem : props )
+                {
+                    String name = ElementHelper.getAttribute( elem, "name", null, resolver );
+                    String value = ElementHelper.getAttribute( elem, "value", null, resolver );
+                    m_properties.setProperty( name, value );
+                }
+            }
+            
+            Element arguments = ElementHelper.getChild( element, "arguments" );
+            if( null != arguments )
+            {
+                Element[] args = ElementHelper.getChildren( properties, "arg" );
+                for( Element arg : args )
+                {
+                    String value = ElementHelper.getAttribute( arg, "value", null, resolver );
+                    m_arguments.add( value );
+                }
+            }
+            
+            String start = ElementHelper.getAttribute( element, "startup", "0", resolver );
+            m_startup = Integer.parseInt( start );
+            String stop = ElementHelper.getAttribute( element, "shutdown", "0", resolver );
+            m_shutdown = Integer.parseInt( stop );
+        }
+    }
+    
+    public ProcessDescriptor( 
+      String executable, Map<String,String> environment, Properties properties, 
+      List<String> arguments, String path, int startup, int shutdown )
+    {
+        m_element = null;
+        m_executable = executable;
+        if( null != environment )
+        {
+            m_environment.putAll( environment );
+        }
+        if( null != properties )
+        {
+            m_properties.putAll( properties );
+        }
+        if( null != arguments )
+        {
+            m_arguments.addAll( arguments );
+        }
+        m_path = path;
+        m_startup = startup;
+        m_shutdown = shutdown;
+    }
+    
+   /**
+    * Return the element defining the scenario descriptor.
+    * @return the defining element
+    */
+    public Element getElement()
+    {
+        return m_element;
+    }
+    
+   /**
+    * Return the executable name (defaults to metro).
+    *
+    * @return the executable name
+    */
+    public String getExecutable()
+    {
+        return m_executable;
+    }
+    
+   /**
+    * Return the executable arguments.
+    *
+    * @return the executable arguments
+    */
+    public String[] getArguments()
+    {
+        return m_arguments.toArray( new String[0] );
+    }
+    
+   /**
+    * Get the relative deployment path.
+    *
+    * @return the path
+    */
+    public String getPath()
+    {
+        return m_path;
+    }
+    
+   /**
+    * Get the duration in seconds to wait for startup
+    * of the application before considering deployment as a timeout failure.
+    * 
+    * @return the startup timeout value
+    */    
+    public int getStartupTimeout()
+    {
+        return m_startup;
+    }
+    
+   /**
+    * Get the duration in seconds to wait for the shutdown
+    * of the application before considering the process as non-responsive.
+    * 
+    * @return the shutdown timeout value
+    */
+    public int getShutdownTimeout()
+    {
+        return m_shutdown;
+    }
+    
+   /**
+    * Get the system properties.
+    * 
+    * @return the system properties
+    */
+    public Properties getSystemProperties()
+    {
+        return m_properties;
+    }
+    
+   /**
+    * Get the environment variable declarations.
+    * 
+    * @return the environment variable map
+    */
+    public Map<String,String> getEnvironmentMap()
+    {
+        return m_environment;
+    }
+    
+   /**
+    * Test if this instance is equal to the supplied instance.
+    * @param other the other instance
+    * @return the equality status
+    */
+    public boolean equals( Object other )
+    {
+        if( null == other )
+        {
+            return false;
+        }
+        if( getClass() != other.getClass() )
+        {
+            return false;
+        }
+        ProcessDescriptor profile = (ProcessDescriptor) other;
+        if( !ObjectUtils.equals( m_path, profile.m_path )  )
+        {
+            return false;
+        }
+        if( !ObjectUtils.equals( m_executable, profile.m_executable )  )
+        {
+            return false;
+        }
+        if( !ObjectUtils.equals( m_properties, profile.m_properties ) )
+        {
+            return false;
+        }
+        if( m_startup != profile.m_startup )
+        {
+            return false;
+        }
+        if( m_shutdown != profile.m_shutdown )
+        {
+            return false;
+        }
+        return true;
+    }
+    
+   /**
+    * Get the hashcode for this instance.
+    * @return the hash value
+    */
+    public int hashCode()
+    {
+        int hash = getClass().hashCode();
+        hash ^= ObjectUtils.hashValue( m_executable );
+        hash ^= ObjectUtils.hashValue( m_path );
+        hash ^= ObjectUtils.hashValue( m_properties );
+        hash ^= m_startup;
+        hash ^= m_shutdown;
+        return hash;
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/info/package-info.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/info/package-info.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/info/package-info.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * <p>Internal datastructures describing an appliance.</p>
+ * 
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package dpml.station.info;

Added: trunk/main/metro/appliance/src/main/dpml/station/util/LoggingServer.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/util/LoggingServer.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/util/LoggingServer.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,230 @@
+/* 
+ * Copyright 2005-2007 Stephen McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.BufferedInputStream;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.SocketException;
+import java.util.logging.Logger;
+import java.util.logging.LogRecord;
+
+import dpml.util.LogStatement;
+
+import dpml.util.PID;
+
+/**
+ * The LoggingServer is a remote service that handles the aggregation of 
+ * log records from multiple jvm processes.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class LoggingServer extends Thread
+{
+    private static final PID PROCESS = new PID();
+    private static final String LOG_SERVER_PORT_KEY = "dpml.station.logging.port";
+    private static final int DEFAULT_LOG_SERVER_PORT = 2020;
+    
+    //public static final Thread SERVER = createLoggingServerThread();
+    
+    /*
+    private static Thread createLoggingServerThread()
+    {
+        System.out.println( "## CREATING LOG SERVER THREAD IN " + PROCESS );
+        int port = getLogServerPort();
+        try
+        {
+            LoggingServer server = new LoggingServer( port );
+            Thread thread = new Thread( server, "DPML Station Aggregator" );
+            thread.setDaemon( true );
+            thread.start();
+            return thread;
+        }
+        catch( Throwable e )
+        {
+            final String error =
+             "Unexpected error while attempting to start the logging server on port [" + port + "].";
+            throw new Error( error, e );
+        }
+    }
+    */
+    
+    private static LoggingServer SERVER;
+    
+    public static void init()
+    {
+        if( null == SERVER )
+        {
+            try
+            {
+                SERVER = new LoggingServer();
+                SERVER.setDaemon( true );
+                SERVER.setName( "DPML Logging Server" );
+                SERVER.start();
+            }
+            catch( Throwable e )
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    private static int getLogServerPort()
+    {
+        String port = System.getProperty( LOG_SERVER_PORT_KEY, null );
+        if( null == port )
+        {
+            return DEFAULT_LOG_SERVER_PORT;
+        }
+        else
+        {
+            return Integer.parseInt( port );
+        }
+    }
+    
+    private final ServerSocket m_server;
+    
+    private int m_count = 0;
+    
+   /**
+    * Creation of a new logging service instance.
+    * @param port the log server port
+    * @exception IOException if an IO exception occurs
+    */
+    public LoggingServer() throws IOException
+    {
+        this( getLogServerPort() );
+    }
+    
+   /**
+    * Creation of a new logging service instance.
+    * @param port the log server port
+    * @exception IOException if an IO exception occurs
+    */
+    public LoggingServer( int port ) throws IOException
+    {
+        m_server = new ServerSocket( port );
+    }
+    
+   /**
+    * Runnable implementation.
+    */ 
+    public void run()
+    {
+        while( true )
+        {
+            try
+            {
+                Socket socket = m_server.accept();
+                RequestHandler handler = new RequestHandler( socket );
+                Thread thread = new Thread( handler );
+                thread.start();
+            }
+            catch( Throwable e )
+            {
+                e.printStackTrace();
+                m_count++;
+            }
+        }
+    }
+    
+    int getErrorCount()
+    {
+        return m_count;
+    }
+    
+   /**
+    * Internal utility class to handle a client connection.
+    */
+    final class RequestHandler implements Runnable
+    {
+        private final Socket m_socket;
+        
+       /**
+        * Creation of a new request handler.
+        * @param socket the socket
+        */
+        private RequestHandler( Socket socket )
+        {
+            m_socket = socket;
+        }
+        
+       /**
+        * Run the process.
+        */
+        public void run()
+        {
+            try
+            {
+                InputStream input = m_socket.getInputStream();
+                BufferedInputStream buffer = new BufferedInputStream( input );
+                ObjectInputStream ois = new ObjectInputStream( buffer );
+                while( true )
+                {
+                    Object object = ois.readObject();
+                    if( object instanceof LogStatement )
+                    {
+                        LogStatement statement = (LogStatement) object;
+                        PID pid = statement.getPID();
+                        if( !PROCESS.equals( pid ) )
+                        {
+                            int id = pid.getValue();
+                            LogRecord record = statement.getLogRecord();
+                            String raw = record.getMessage();
+                            String message = "$[" + id + "] " + raw;
+                            record.setMessage( message );
+                            Logger logger = getNamedLogger( record );
+                            logger.log( record );
+                        }
+                    }
+                }
+            }
+            catch( ClassNotFoundException e )
+            {
+                e.printStackTrace();
+            }
+            catch( SocketException ioe )
+            {
+                // ignore
+            }
+            catch( IOException ioe )
+            {
+                //ioe.printStackTrace();
+            }
+        }
+
+        private Logger getNamedLogger( LogRecord record )
+        {
+            String name = record.getLoggerName();
+            if( null != name )
+            {
+                return Logger.getLogger( name );
+            }
+            else
+            {
+                return Logger.getAnonymousLogger();
+            }
+        }
+    }
+}
+

Added: trunk/main/metro/appliance/src/main/dpml/station/util/OutputStreamReader.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/util/OutputStreamReader.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/util/OutputStreamReader.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2005-2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.util;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import net.dpml.util.Logger;
+
+/**
+ * Stream reader utility class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class OutputStreamReader extends StreamReader
+{
+   /**
+    * Creation of a process output reader.
+    * @param logger the assigned logging channel
+    * @param input the subprocess input stream
+    */
+    public OutputStreamReader( Logger logger, InputStream input )
+    {
+        super( logger, input );
+    }
+
+   /**
+    * Start the stream reader.
+    */
+    public void run()
+    {
+        try
+        {
+            InputStreamReader isr = new InputStreamReader( getInputStream() );
+            BufferedReader reader = new BufferedReader( isr );
+            String line = null;
+            while( ( line = reader.readLine() ) != null )
+            {
+                System.out.println( line );
+                getLogger().debug( "$ " + line );
+            }
+        }
+        catch( IOException e )
+        {
+            getLogger().error( "Process read error.", e );
+        }
+    }
+}

Added: trunk/main/metro/appliance/src/main/dpml/station/util/StreamReader.java
===================================================================
--- trunk/main/metro/appliance/src/main/dpml/station/util/StreamReader.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/dpml/station/util/StreamReader.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2005 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.util;
+
+import java.io.InputStream;
+
+import net.dpml.util.Logger;
+
+/**
+ * Stream reader utility class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class StreamReader extends Thread
+{
+    private final Logger m_logger;
+    private final InputStream m_input;
+    
+   /**
+    * Creation of a new reader.
+    * @param logger the assigned logging channel
+    * @param input the subprocess input stream
+    */
+    public StreamReader( Logger logger, InputStream input )
+    {
+        m_input = input;
+        m_logger = logger;
+    }
+
+   /**
+    * Return the input stream.
+    * @return the subprocess input stream
+    */
+    protected InputStream getInputStream()
+    {
+        return m_input;
+    }
+    
+   /**
+    * Return the assigned logging channel.
+    * @return the logging channel
+    */
+    protected Logger getLogger()
+    {
+        return m_logger;
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceContentHandler.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceContentHandler.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceContentHandler.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2006 Stephen McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.lang.DOM3DocumentBuilder;
+import dpml.util.SimpleResolver;
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+import dpml.station.util.LoggingServer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.rmi.Remote;
+import java.util.Properties;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.ContentHandler;
+import net.dpml.transit.ContentManager;
+import net.dpml.lang.DecodingException;
+import net.dpml.util.Logger;
+import net.dpml.util.Resolver;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceManager;
+import net.dpml.appliance.ApplianceContentManager;
+import net.dpml.appliance.ApplianceFactory;
+import dpml.station.info.ApplianceDescriptor;
+import dpml.station.info.InfoDescriptor;
+import dpml.station.info.ProcessDescriptor;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Content handler for the <tt>appliance</tt> artifact type.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceContentHandler extends ContentHandler implements ApplianceContentManager, ApplianceFactory
+{
+    static final String NAMESPACE = "dpml:appliance";
+    static final String TYPE = "appliance";
+    
+    private static final Logger LOGGER = new DefaultLogger( "dpml.metro.appliance" );
+    private static final DOM3DocumentBuilder DOCUMENT_BUILDER = 
+      new DOM3DocumentBuilder();
+      
+    private static final List<ApplianceManager> MANAGERS = 
+      new ArrayList<ApplianceManager>();
+      
+    private static final ApplianceContentHandler SINGLETON = newApplianceContentHandler();
+    
+    private static ApplianceContentHandler newApplianceContentHandler()
+    {
+        ApplianceContentHandler handler = new ApplianceContentHandler();
+        String flag = System.getProperty( "dpml.jmx.enabled", "false" );
+        if( "true".equals( flag ) )
+        {
+            try
+            {
+                MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+                Hashtable<String,String> table = new Hashtable<String,String>();
+                table.put( "type", "Appliances" );
+                ObjectName name =
+                  ObjectName.getInstance( "net.dpml.transit", table );
+                server.registerMBean( handler, name );
+            }
+            catch( Exception e )
+            {
+                e.printStackTrace();
+            }
+        }
+        return handler;
+    }
+    
+    public ApplianceContentHandler()
+    {
+        this( LOGGER );
+    }
+    
+    protected ApplianceContentHandler( Logger logger )
+    {
+        logger.debug( "instantiating" );
+    }
+    
+    /*
+    protected MBeanServerConnection getMBeanServerConnection() throws MalformedURLException, IOException
+    {
+        String spec = System.getProperty( Station.STATION_JMX_URI_KEY );
+        if( null != spec )
+        {
+            JMXServiceURL url = new JMXServiceURL( spec );
+            JMXConnector connector = JMXConnectorFactory.connect( url, null ); 
+            return connector.getMBeanServerConnection();
+        }
+        else
+        {
+            return ManagementFactory.getPlatformMBeanServer();
+        }
+    }
+    */
+    
+    public ApplianceManager[] getApplianceManagers()
+    {
+        return MANAGERS.toArray( new ApplianceManager[0] );
+    }
+    
+   /**
+    * Returns the type thar the content handler supports.
+    * @return the content type name
+    */
+    public String getType()
+    {
+        return TYPE;
+    }
+    
+   /**
+    * Returns the content in the form of a {@link net.dpml.appliance.Appliance}.
+    * @param connection the url connection
+    * @return the application handler
+    * @exception IOException if an IO error occurs
+    */
+    public Object getContent( URLConnection connection ) throws IOException
+    {
+        return newAppliance( connection, null );
+    }
+    
+   /**
+    * Returns the content assignable to the first recognized class in the list
+    * of suppied classes.  If the class array is empty the application handler is returned.
+    * If none of the classes are recognized, null is returned.
+    * @param connection the url connection
+    * @param classes the selection class array
+    * @return the resolved instance
+    * @exception IOException if an IO error occurs
+    */
+    public Object getContent( URLConnection connection, Class[] classes ) throws IOException
+    {
+        ApplianceDescriptor descriptor = getApplianceDescriptor( connection );
+        return getContentForClasses( descriptor, classes );
+    }
+    
+   /**
+    * Create a new appliance using the supplied connection object.
+    * @param connection the URL connection
+    * @param partition an optional partition name
+    * @return the appliance
+    * @exception IOException if an IO error occurs
+    */
+    public Appliance newAppliance( URLConnection connection, String partition ) throws IOException
+    {
+        ApplianceDescriptor descriptor = getApplianceDescriptor( connection );
+        return newAppliance( partition, descriptor );
+    }
+
+    static <T>T getContentForClass( URLConnection connection, Class<T> type ) throws IOException
+    {
+        ApplianceDescriptor descriptor = getApplianceDescriptor( connection );
+        return getContentForClass( descriptor, type );
+    }
+    
+    private static Object getContentForClasses( ApplianceDescriptor descriptor, Class<?>[] classes ) throws IOException
+    {
+        for( Class<?> c : classes )
+        {
+            Object value = getContentForClass( descriptor, c );
+            if( null != value )
+            {
+                return value;
+            }
+        }
+        return null;
+    }
+    
+    private static <T>T getContentForClass( ApplianceDescriptor descriptor, Class<T> type ) throws IOException
+    {
+        if( ApplianceDescriptor.class == type )
+        {
+            return type.cast( descriptor );
+        }
+        else if( Appliance.class == type )
+        {
+            String key = "" + System.identityHashCode( descriptor );
+            Appliance appliance = newAppliance( key, descriptor );
+            return type.cast( appliance );
+        }
+        else
+        {
+            return null;
+        }
+    }
+    
+    private static final Appliance newAppliance( String key, ApplianceDescriptor descriptor ) throws IOException
+    {
+        if( null == key )
+        {
+            throw new NullPointerException( "key" );
+        }
+        Logger logger = getLogger();
+        Application application = new Application( logger, key, descriptor );
+        Appliance appliance = application.getAppliance();
+        register( key, appliance );
+        return appliance;
+    }
+    
+    static void register( String id, Appliance appliance )
+    {
+        if( appliance instanceof ApplianceManager )
+        {
+            if( null == id )
+            {
+                throw new NullPointerException( "id" );
+            }
+            ApplianceManager manager = (ApplianceManager) appliance;
+            if( !MANAGERS.contains( manager ) )
+            {
+                try
+                {
+                    MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+                    Hashtable<String, String> table = new Hashtable<String, String>();
+                    table.put( "type", "Appliances" );
+                    table.put( "name", id );
+                    ObjectName name =
+                      ObjectName.getInstance( "net.dpml.transit", table );
+                    server.registerMBean( manager, name );
+                    MANAGERS.add( manager );
+                }
+                catch( Exception e )
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    
+    static void deregister( Appliance appliance )
+    {
+        if( appliance instanceof ApplianceManager )
+        {
+            ApplianceManager manager = (ApplianceManager) appliance;
+            if( MANAGERS.contains( manager ) )
+            {
+                MANAGERS.remove( manager );
+            }
+        }
+    }
+    
+    static Appliance newAppliance( String key, URI uri ) throws IOException
+    {
+        URL url = Artifact.toURL( uri );
+        URLConnection connection = url.openConnection();
+        ApplianceDescriptor descriptor = getApplianceDescriptor( connection );
+        return newAppliance( key, descriptor );
+    }
+    
+    //static final Appliance newLocalAppliance( String partition, URI codebase ) throws IOException
+    //{
+    //    return new StandardAppliance( LOGGER, partition, codebase );
+    //}
+    
+    private static ApplianceDescriptor getApplianceDescriptor( URLConnection connection ) throws IOException
+    {
+        URL url = connection.getURL();
+        try
+        {
+            Document document = DOCUMENT_BUILDER.parse( url );
+            final Element element = document.getDocumentElement();
+            TypeInfo type = element.getSchemaTypeInfo();
+            String namespace = type.getTypeNamespace();
+            if( NAMESPACE.equals( namespace ) )
+            {
+                URI uri = URI.create( url.toExternalForm() );
+                Resolver resolver = new SimpleResolver();
+                return new ApplianceDescriptor( element, resolver, uri );
+            }
+            else
+            {
+                final String error = 
+                  "ApplianceDescriptor namespace not recognized."
+                  + "\nFound: " + namespace
+                  + "\nExpecting: " + NAMESPACE;
+                throw new DecodingException( error, element );
+            }
+        }
+        catch( IOException e )
+        {
+            throw e;
+        }
+        catch( Exception e )
+        {
+            final String error = "Unexpected error while constructing application profile: " + url;
+            IOException ioe = new IOException();
+            ioe.initCause( e );
+            throw ioe;
+        }
+    }
+    
+    private static Logger getLogger()
+    {
+        return LOGGER;
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceNamespaceResolver.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceNamespaceResolver.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/ApplianceNamespaceResolver.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.lang.DOMInput;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+import net.dpml.lang.NamespaceError;
+
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSResourceResolver;
+
+/**
+ * LSInput resolver service.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ApplianceNamespaceResolver implements LSResourceResolver
+{
+   /**
+    * Return the schema definition for a <tt>dpml:appliance</tt> namespace.
+    *
+    * @param type the node type
+    * @param namespace the node namespace
+    * @param publicId the public id
+    * @param systemId the system id
+    * @param base the base value
+    * @return the LS input instance or null if not recognized
+    */
+    public LSInput resolveResource( 
+      String type, String namespace, String publicId, String systemId, String base )
+    {
+        URL url = getNamespaceURL( namespace );
+        if( null == url )
+        {
+            return null;
+        }
+        try
+        {
+            DOMInput input = new DOMInput();
+            input.setPublicId( publicId );
+            input.setSystemId( systemId );
+            input.setBaseURI( base );
+            InputStream stream = url.openStream();
+            InputStreamReader reader = new InputStreamReader( stream );
+            input.setCharacterStream( reader );
+            return input;
+        }
+        catch( Exception e )
+        {
+            final String error = 
+              "Internal error while resolving the resource for the namespace ["
+              + namespace 
+              + "].";
+              
+            throw new NamespaceError( error, e );
+        }
+    }
+    
+    private URL getNamespaceURL( String namespace )
+    {
+        ClassLoader classloader = getClass().getClassLoader();
+        if( ApplianceContentHandler.NAMESPACE.equals( namespace ) )
+        {
+            return classloader.getResource( "dpml/metro/dpml-metro-appliance.xsd" );
+        }
+        else
+        {
+            return null;
+        }
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/Application.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/Application.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/Application.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.util.PID;
+
+import dpml.station.connector.LocalConnector;
+import dpml.station.info.ApplianceDescriptor;
+import dpml.station.util.OutputStreamReader;
+import dpml.station.util.StreamReader;
+import dpml.station.util.LoggingServer;
+
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.net.URL;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Date;
+import java.util.Set;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+import java.rmi.ConnectException;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.server.UnicastRemoteObject;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.management.InstanceAlreadyExistsException;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+
+import net.dpml.util.Logger;
+
+import net.dpml.lang.DuplicateKeyException;
+import net.dpml.lang.Strategy;
+import net.dpml.runtime.Status;
+
+/**
+ * Process configuration and management support class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class Application
+{
+    static
+    {
+        LoggingServer.init();
+    }
+    
+    private static final PID PROCESS_ID = new PID();
+    
+    private final ApplianceDescriptor m_descriptor;
+    private final Logger m_logger;
+    private final ProcessBuilder m_builder;
+    private final LocalConnector m_connector;
+    private final String m_address;
+    private final String m_key;
+    
+    Application( Logger logger, String key, ApplianceDescriptor descriptor ) throws IOException
+    {
+        m_logger = logger;
+        m_descriptor = descriptor;
+        m_key = key;
+        
+        int port = getConnectorPort();
+        try
+        {
+            m_connector = new LocalConnector();
+            Registry registry = resolveRegistry( port );
+            m_address = 
+              "dpml/station/" 
+              + PROCESS_ID.getValue() 
+              + "/"
+              + System.identityHashCode( this );
+            registry.bind( m_address, m_connector );
+        }
+        catch( ApplianceException e )
+        {
+            throw e;
+        }
+        catch( Throwable e )
+        {
+            final String error = 
+              "Unable to bind local station callback to RMI registry.";
+            throw new ApplianceException( error, e );
+        }
+        
+        m_builder = newProcessBuilder();
+    }
+    
+    private Registry resolveRegistry( int port )throws ApplianceException
+    {
+        try
+        {
+            Registry registry = LocateRegistry.createRegistry( port );
+            getLogger().debug( "created local registry on port " + port );
+            return registry;
+        }
+        catch( RemoteException re )
+        {
+            try
+            {
+                Registry registry = LocateRegistry.getRegistry( port );
+                getLogger().debug( "using local registry on port " + port );
+                return registry;
+            }
+            catch( RemoteException e )
+            {
+                final String error = 
+                  "Unable to locate or create RMI registry to due a remote exeception.";
+                throw new ApplianceException( error, e );
+            }
+        }
+    }
+    
+    private int getConnectorPort()
+    {
+        String port = System.getProperty( "dpml.appliance.connector.port", null );
+        if( null == port )
+        {
+            return Registry.REGISTRY_PORT;
+        }
+        else
+        {
+            return Integer.parseInt( port );
+        }
+    }
+    
+   /**
+    * Returns the part URI as a string.
+    * @return the codebase uri
+    */
+    //public String getCodebaseURI()
+    //{
+    //    return m_descriptor.getURI().toASCIIString();
+    //}
+    
+   /**
+    * Returns the part title.
+    * @return the title
+    */
+    public String getTitle()
+    {
+        return m_descriptor.getTitle();
+    }
+    
+   /**
+    * Returns the part description.
+    * @return the description
+    */
+    public String getDescription()
+    {
+        return m_descriptor.getDescription();
+    }
+    
+    public Appliance getAppliance() throws IOException
+    {
+        int timeout = m_descriptor.getStartupTimeout();
+        if( 0 == timeout )
+        {
+            return getAppliance( TimeUnit.SECONDS, 60 );
+        }
+        else
+        {
+            return getAppliance( TimeUnit.SECONDS, timeout );
+        }
+    }
+
+    public Appliance getAppliance( TimeUnit unit, int timeout ) throws IOException
+    {
+        final Process process = newProcess();
+        long now = new Date().getTime();
+        Appliance appliance = m_connector.getAppliance( unit, timeout );
+        long then = new Date().getTime();
+        long diff = then - now;
+        getLogger().info( "process established in " + diff + " ms" );
+        return appliance;
+    }
+    
+    Logger getLogger()
+    {
+        return m_logger;
+    }
+    
+    ApplianceDescriptor getApplianceDescriptor()
+    {
+        return m_descriptor;
+    }
+    
+    Process newProcess() throws IOException
+    {
+        Process process = m_builder.start();
+        setShutdownHook( process );
+        OutputStreamReader output = 
+          new OutputStreamReader( m_logger, process.getInputStream() );
+        output.setDaemon( true );
+        output.start();
+        return process;
+    }
+    
+    private ProcessBuilder newProcessBuilder() throws IOException
+    {
+        List<String> commands = getProcessCommands();
+        ProcessBuilder builder = new ProcessBuilder( commands );
+        builder.redirectErrorStream( true );
+        File dir = getValidatedProcessDirectory();
+        builder.directory( dir );
+        Map<String,String> environment = builder.environment();
+        Map<String,String> env = m_descriptor.getEnvironmentMap();
+        environment.putAll( env );
+        return builder;
+    }
+    
+    private File getValidatedProcessDirectory() throws IOException
+    {
+        File file = getProcessDirectory();
+        if( null == file )
+        {
+            return file;
+        }
+        if( !file.exists() )
+        {
+            final String error = 
+              "Process basedir not found: " 
+              + file.getCanonicalPath();
+            throw new ApplianceException( error, null, m_descriptor.getElement() );  
+            //throw new FileNotFoundException( error );
+        }
+        if( !file.isDirectory() )
+        {
+            final String error = 
+              "Process basedir is not a directory: " 
+              + file.getCanonicalPath();
+            throw new ApplianceException( error, null, m_descriptor.getElement() );  
+            //throw new IllegalArgumentException( error );
+        }
+        return file;
+    }
+    
+    private File getProcessDirectory()
+    {
+        String path = m_descriptor.getPath();
+        if( null == path )
+        {
+            return null;
+        }
+        else
+        {
+            File file = new File( path );
+            if( file.isAbsolute() )
+            {
+                return file;
+            }
+            else
+            {
+                File base = new File( System.getProperty( "user.dir" ) );
+                return new File( base, path );
+            }
+        }
+    }
+    
+    private List<String> getProcessCommands() throws IOException
+    {
+        List<String> list = new ArrayList<String>();
+        
+        //
+        // add the metro command
+        //
+        
+        String executable = m_descriptor.getExecutable();
+        list.add( executable );
+        
+        //
+        // add partition
+        //
+        
+        if( null != m_key )
+        {
+            list.add( "-Ddpml.station.partition=" + m_key );
+        }
+        
+        //
+        // add connection key
+        //
+        
+        list.add( "-Ddpml.appliance.connector.key=" + m_address );
+        
+        //
+        // add codebase uri
+        //
+        
+        URI codebase = m_descriptor.getCodebaseURI();
+        if( null != codebase )
+        {
+            String spec = codebase.toASCIIString();
+            list.add( "-Ddpml.appliance.codebase.uri=" + spec );
+        }
+        
+        //
+        // add decommissioning timeout
+        //
+        
+        list.add( "-Ddpml.decommmission.timeout=" + m_descriptor.getShutdownTimeout() );
+        
+        //
+        // add default system properties
+        //
+        
+        list.add( "-Djava.util.logging.config.class=dpml.util.DepotLoggingConfiguration" );
+        //list.add( "-Ddpml.logging.config=local:properties:dpml/station/application" );
+
+        //
+        // add declared system properties
+        //
+        
+        Properties properties = m_descriptor.getSystemProperties();
+        Set<String> names = properties.stringPropertyNames();
+        for( String name : names )
+        {
+            String value = properties.getProperty( name ); // expand symbols?
+            list.add( "-D" + name + "=" + value );
+        }
+        
+        //
+        // add the codebase uri
+        //
+        
+        URI uri = m_descriptor.getTargetURI();
+        String spec = uri.toASCIIString();
+        list.add( spec );
+        
+        return list;
+    }
+    
+    private static void setShutdownHook( final ApplianceListener listener )
+    {
+        Runtime.getRuntime().addShutdownHook(
+          new Thread()
+          {
+            public void run()
+            {
+                try
+                {
+                    UnicastRemoteObject.unexportObject( listener, false );
+                }
+                catch( RemoteException e )
+                {
+                }
+            }
+          }
+        );
+    }
+    
+    private static void setShutdownHook( final Process process )
+    {
+        Runtime.getRuntime().addShutdownHook(
+          new Thread()
+          {
+            public void run()
+            {
+                try
+                {
+                    process.destroy();
+                }
+                catch( Throwable e )
+                {
+                    e.printStackTrace();
+                }
+            }
+          }
+        );
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/CompositeAppliance.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/CompositeAppliance.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/CompositeAppliance.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.station.info.PlanDescriptor;
+import dpml.station.info.EntryDescriptor;
+
+import dpml.appliance.ApplianceHelper;
+import dpml.appliance.AbstractAppliance;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+import net.dpml.appliance.ApplianceManager;
+
+import net.dpml.runtime.Status;
+
+import net.dpml.transit.Artifact;
+import net.dpml.util.Logger;
+
+/**
+ * Appliance implementation that aggregates a collection of ordered appliance instances.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class CompositeAppliance extends AbstractAppliance implements Appliance, ApplianceManager
+{
+    private PlanDescriptor m_descriptor;
+    private ArrayList<Appliance> m_list = new ArrayList<Appliance>();
+    
+    CompositeAppliance( final Logger logger, final PlanDescriptor descriptor ) throws IOException
+    {
+        this( logger, null, descriptor );
+    }
+    
+    CompositeAppliance( final Logger logger, final String partition, final PlanDescriptor descriptor ) throws IOException
+    {
+        super( logger, descriptor.getCodebaseURI() );
+        
+        m_descriptor = descriptor;
+        
+        for( EntryDescriptor entry : m_descriptor.getEntryDescriptors() )
+        {
+            URI codebase = descriptor.getCodebaseURI();
+            String name = getQualifiedName( partition, entry.getKey() );
+            logger.info( "loading " + name );
+            Appliance appliance = getApplianceForType( partition, entry );
+            if( null == appliance )
+            {
+                final String error =
+                  "Failed to resolve an appliance for the uri [ " 
+                  + codebase 
+                  + "]."
+                throw new ApplianceException( error );
+            }
+            else
+            {
+                m_list.add( appliance );
+                ApplianceContentHandler.register( name, appliance );
+            }
+        }
+        
+        ApplianceEvent ae = new ApplianceEvent( this, Status.CREATION );
+        processEvent( ae );
+    }
+    
+   /**
+    * Returns the plan URI as a string.
+    * @return the codebase uri
+    */
+    public String getCodebaseURI()
+    {
+        return m_descriptor.getCodebaseURI().toASCIIString();
+    }
+    
+    private String getQualifiedName( String partition, String key )
+    {
+        if( null == partition )
+        {
+            return key;
+        }
+        else
+        {
+            return partition + "." + key;
+        }
+    }
+    
+    private Appliance getApplianceForType( String partition, EntryDescriptor entry ) throws IOException
+    {
+        String key = entry.getKey();
+        String address = getQualifiedName( partition, key );
+        URI uri = entry.getURI();
+        return ApplianceHelper.newAppliance( address, uri );
+    }
+    
+    public void commission() throws IOException
+    {
+        getLogger().info( "commissioning plan" );
+        synchronized( this )
+        {
+            ApplianceEvent ae = new ApplianceEvent( this, Status.INCARNATION );
+            processEvent( ae );
+            super.commission();
+            for( Appliance appliance : m_list )
+            {
+                appliance.commission();
+            }
+        }
+        getLogger().info( "plan commissioning complete" );
+    }
+    
+    protected void decommission( long timeout, TimeUnit units ) throws RemoteException
+    {
+        getLogger().info( "decommissioning plan" );
+        synchronized( this )
+        {
+            ApplianceEvent ee = new ApplianceEvent( this, Status.ETHERIALIZATION );
+            processEvent( ee );
+            Appliance[] appliances = m_list.toArray( new Appliance[0] );
+            for( int i = appliances.length; i>0; i-- )
+            {
+                Appliance appliance = appliances[i-1];
+                appliance.decommission();
+            }
+            ApplianceEvent te = new ApplianceEvent( this, Status.TERMINATION );
+            processEvent( te );
+            super.decommission( timeout, units );
+        }
+        getLogger().info( "plan decommissioning complete" );
+    }
+    
+   /**
+    * Return a value assignable to the supplied remote type or null if the type
+    * cannot be resolved from the underlying component.
+    * @param type the service type
+    * @return an instance of the type or null
+    * @exception IOException if an IO error occurs
+    */
+    public <T>T getContentForClass( Class<T> type ) throws IOException
+    {
+        return null;
+    }
+}
+

Added: trunk/main/metro/appliance/src/main/net/dpml/station/PlanContentHandler.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/PlanContentHandler.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/PlanContentHandler.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2007 Stephen McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.lang.DOM3DocumentBuilder;
+import dpml.util.SimpleResolver;
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+
+import dpml.station.info.EntryDescriptor;
+import dpml.station.info.PlanDescriptor;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.lang.management.ManagementFactory;
+import java.util.Hashtable;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.management.InstanceAlreadyExistsException;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceFactory;
+
+import net.dpml.lang.DecodingException;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.ContentHandler;
+
+import net.dpml.util.Resolver;
+import net.dpml.util.Logger;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Content handler for the <tt>plan</tt> artifact type.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PlanContentHandler extends ApplianceContentHandler //implements ApplianceFactory
+{
+    private static final Logger LOGGER = new DefaultLogger( "dpml.station.plan" );
+    static final String NAMESPACE = "dpml:plan";
+    static final String TYPE = "plan";
+    
+    private static final DOM3DocumentBuilder DOCUMENT_BUILDER = 
+      new DOM3DocumentBuilder();
+    
+    public PlanContentHandler()
+    {
+        super( LOGGER );
+    }
+    
+   /**
+    * Returns the type thar the content handler supports.
+    * @return the content type name
+    */
+    public String getType()
+    {
+        return TYPE;
+    }
+    
+   /**
+    * Returns the content in the form of a {@link net.dpml.appliance.Appliance}.
+    * @param connection the url connection
+    * @return the application handler
+    * @exception IOException if an IO error occurs
+    */
+    public Object getContent( URLConnection connection ) throws IOException
+    {
+        return getContentForClass( connection, Appliance.class );
+    }
+    
+   /**
+    * Returns the content assignable to the first recognized class in the list
+    * of suppied classes.  If the class array is empty the application handler is returned.
+    * If none of the classes are recognized, null is returned.
+    * @param connection the url connection
+    * @param classes the selection class array
+    * @return the resolved instance
+    * @exception IOException if an IO error occurs
+    */
+    public Object getContent( URLConnection connection, Class[] classes ) throws IOException
+    {
+        PlanDescriptor descriptor = getPlanDescriptor( connection );
+        return getContentForClasses( descriptor, classes );
+    }
+    
+   /**
+    * Create a new appliance using the supplied connection object.
+    * @param connection the URL connection
+    * @param partition an optional partition name
+    * @return the appliance
+    * @exception IOException if an IO error occurs
+    */
+    public Appliance newAppliance( URLConnection connection, String partition ) throws IOException
+    {
+        PlanDescriptor descriptor = getPlanDescriptor( connection );
+        String name = descriptor.getName();
+        String path = getQualifiedName( partition, name );
+        Appliance appliance = new CompositeAppliance( LOGGER, path, descriptor );
+        register( path, appliance );
+        return appliance;
+    }
+    
+    private static String getQualifiedName( String partition, String name )
+    {
+        if( null == partition )
+        {
+            return name;
+        }
+        else
+        {
+            return partition + "." + name;
+        }
+    }
+    
+    static <T>T getContentForClass( URLConnection connection, Class<T> type ) throws IOException
+    {
+        PlanDescriptor descriptor = getPlanDescriptor( connection );
+        return getContentForClass( descriptor, type );
+    }
+    
+    private static Object getContentForClasses( 
+      PlanDescriptor descriptor, Class<?>[] classes ) throws IOException
+    {
+        for( Class<?> c : classes )
+        {
+            Object value = getContentForClass( descriptor, c );
+            if( null != value )
+            {
+                return value;
+            }
+        }
+        return null;
+    }
+    
+    private static <T>T getContentForClass( 
+      PlanDescriptor descriptor, Class<T> type ) throws IOException
+    {
+        if( PlanDescriptor.class == type )
+        {
+            return type.cast( descriptor );
+        }
+        else if( Appliance.class == type )
+        {
+            String name = descriptor.getName();
+            CompositeAppliance appliance = new CompositeAppliance( LOGGER, name, descriptor );
+            register( name, appliance );
+            return type.cast( appliance );
+        }
+        else
+        {
+            return null;
+        }
+    }
+    
+    public static Appliance newAppliance( String key, URI uri ) throws IOException
+    {
+        URL url = Artifact.toURL( uri );
+        URLConnection connection = url.openConnection();
+        PlanDescriptor descriptor = getPlanDescriptor( connection );
+        Appliance appliance = new CompositeAppliance( LOGGER, key, descriptor );
+        register( key, appliance );
+        return appliance;
+    }
+    
+    private static PlanDescriptor getPlanDescriptor( URLConnection connection ) throws IOException
+    {
+        URL url = connection.getURL();
+        try
+        {
+            Document document = DOCUMENT_BUILDER.parse( url );
+            final Element element = document.getDocumentElement();
+            TypeInfo type = element.getSchemaTypeInfo();
+            String namespace = type.getTypeNamespace();
+            if( NAMESPACE.equals( namespace ) )
+            {
+                URI codebase = url.toURI();
+                Resolver resolver = new SimpleResolver();
+                return new PlanDescriptor( element, resolver, codebase );
+            }
+            else
+            {
+                final String error = 
+                  "Document namespace not recognized."
+                  + "\nFound: " + namespace
+                  + "\nExpecting: " + NAMESPACE;
+                throw new DecodingException( error, element );
+            }
+        }
+        catch( IOException e )
+        {
+            throw e;
+        }
+        catch( Exception e )
+        {
+            final String error = "Unexpected error while constructing scenario: " + url;
+            IOException ioe = new IOException();
+            ioe.initCause( e );
+            throw ioe;
+        }
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/PlanNamespaceResolver.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/PlanNamespaceResolver.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/PlanNamespaceResolver.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import dpml.lang.DOMInput;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+
+import net.dpml.lang.NamespaceError;
+
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSResourceResolver;
+
+/**
+ * LSInput resolver service for the <tt>dpml:plan</tt> namespace.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class PlanNamespaceResolver implements LSResourceResolver
+{
+   /**
+    * Return the schema definition for a <tt>dpml:plan</tt> namespace.
+    *
+    * @param type the node type
+    * @param namespace the node namespace
+    * @param publicId the public id
+    * @param systemId the system id
+    * @param base the base value
+    * @return the LS input instance or null if not recognized
+    */
+    public LSInput resolveResource( 
+      String type, String namespace, String publicId, String systemId, String base )
+    {
+        URL url = getNamespaceURL( namespace );
+        if( null == url )
+        {
+            return null;
+        }
+        try
+        {
+            DOMInput input = new DOMInput();
+            input.setPublicId( publicId );
+            input.setSystemId( systemId );
+            input.setBaseURI( base );
+            InputStream stream = url.openStream();
+            InputStreamReader reader = new InputStreamReader( stream );
+            input.setCharacterStream( reader );
+            return input;
+        }
+        catch( Exception e )
+        {
+            final String error = 
+              "Internal error while resolving the resource for the namespace ["
+              + namespace 
+              + "].";
+              
+            throw new NamespaceError( error, e );
+        }
+    }
+    
+    private URL getNamespaceURL( String namespace )
+    {
+        ClassLoader classloader = getClass().getClassLoader();
+        if( PlanContentHandler.NAMESPACE.equals( namespace ) )
+        {
+            return classloader.getResource( "dpml/metro/dpml-metro-plan.xsd" );
+        }
+        else
+        {
+            return null;
+        }
+    }
+}

Added: trunk/main/metro/appliance/src/main/net/dpml/station/Station.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/Station.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/Station.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Station interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Station extends Remote
+{
+    static final String STATION_CONNECTOR_KEY = "dpml.station.key";
+    static final String STATION_JMX_URI_KEY = "dpml.station.jmx.uri";
+    //static final String STATION_RMI_PORT = "dpml.station.rmi.port";
+    
+    void shutdown() throws RemoteException;
+}
+

Added: trunk/main/metro/appliance/src/main/net/dpml/station/StationException.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/StationException.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/StationException.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.station;
+
+import net.dpml.appliance.ApplianceException;
+
+import org.w3c.dom.Element;
+
+
+/**
+ * Station related exception.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StationException extends ApplianceException
+{
+   /**
+    * Serial version identifier.
+    */
+    static final long serialVersionUID = 1L;
+
+   /**
+    * Construct a new <code>StationException</code>.
+    *
+    * @param message the error message
+    */
+    public StationException( final String message )
+    {
+        super( message, null, null );
+    }
+    
+   /**
+    * Construct a new <code>StationException</code>.
+    *
+    * @param message the error message
+    * @param cause the causal exception
+    */
+    public StationException( final String message, Throwable cause )
+    {
+        super( message, cause, null );
+    }
+    
+   /**
+    * Construct a new <code>ApplianceException</code>.
+    *
+    * @param message the error message
+    * @param cause the causal exception
+    * @param element the element definition
+    */
+    public StationException( final String message, Throwable cause, Element element )
+    {
+        super( message, cause, element );
+    }
+    
+}
+

Added: trunk/main/metro/appliance/src/main/net/dpml/station/package-info.java
===================================================================
--- trunk/main/metro/appliance/src/main/net/dpml/station/package-info.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/main/net/dpml/station/package-info.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+/**
+ * <p>Application profile and process execution support.</p>
+ * 
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.station;

Added: trunk/main/metro/appliance/src/test/net/dpml/appliance/AbstractTestCase.java
===================================================================
--- trunk/main/metro/appliance/src/test/net/dpml/appliance/AbstractTestCase.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/test/net/dpml/appliance/AbstractTestCase.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.appliance;
+
+import dpml.station.info.ApplianceDescriptor;
+import dpml.station.info.PlanDescriptor;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLConnection;
+
+import junit.framework.TestCase;
+
+import net.dpml.lang.Strategy;
+import net.dpml.lang.TypeCastException;
+
+import net.dpml.station.ApplianceContentHandler;
+import net.dpml.station.PlanContentHandler;
+
+/**
+ * Test dealing with the appliance descriptor.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class AbstractTestCase extends TestCase
+{
+    static final ApplianceContentHandler HANDLER = new ApplianceContentHandler();
+      
+    ApplianceDescriptor loadApplianceDescriptor( String path ) throws Exception
+    {
+        ClassLoader classloader = getClass().getClassLoader();
+        File dir = new File( System.getProperty( "project.test.dir" ) );
+        File file = new File( dir, path );
+        URL url = file.toURI().toURL();
+        URLConnection connection = url.openConnection();
+        ApplianceContentHandler handler = new ApplianceContentHandler();
+        return (ApplianceDescriptor) handler.getContent( connection, new Class[]{ ApplianceDescriptor.class } );
+    }
+
+    PlanDescriptor loadPlanDescriptor( String path ) throws Exception
+    {
+        ClassLoader classloader = getClass().getClassLoader();
+        File dir = new File( System.getProperty( "project.test.dir" ) );
+        File file = new File( dir, path );
+        URL url = file.toURI().toURL();
+        URLConnection connection = url.openConnection();
+        PlanContentHandler handler = new PlanContentHandler();
+        return (PlanDescriptor) handler.getContent( connection, new Class[]{ PlanDescriptor.class } );
+    }
+}

Added: trunk/main/metro/appliance/src/test/net/dpml/appliance/ApplianceDescriptorTestCase.java
===================================================================
--- trunk/main/metro/appliance/src/test/net/dpml/appliance/ApplianceDescriptorTestCase.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/test/net/dpml/appliance/ApplianceDescriptorTestCase.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.appliance;
+
+import java.net.URI;
+import java.util.Properties;
+import java.util.Map;
+
+import dpml.station.info.ApplianceDescriptor;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceDescriptorTestCase extends AbstractTestCase
+{
+    public void testApplianceDescriptor() throws Exception
+    {
+        ApplianceDescriptor application = loadApplianceDescriptor( "appliance.xml" );
+        String path = application.getPath();
+        int startup = application.getStartupTimeout();
+        int shutdown = application.getShutdownTimeout();
+        Properties properties = application.getSystemProperties();
+        Map environment = application.getEnvironmentMap();
+        assertEquals( "startup", 0, startup );
+        assertEquals( "shutdown", 0, shutdown );
+        assertEquals( "path", null, path );
+        assertEquals( "system", "bar", properties.getProperty( "foo" ) );
+        assertEquals( "environment", "BAR", environment.get( "FOO" ) );
+        URI uri = new URI( "link:part:dpml/lang/dpml-lang-sample?message=Hello%20World,port=1024" );
+        URI target = application.getTargetURI();
+        assertEquals( "uri", uri, target );
+    }
+}

Added: trunk/main/metro/appliance/src/test/net/dpml/appliance/PlanDescriptorTestCase.java
===================================================================
--- trunk/main/metro/appliance/src/test/net/dpml/appliance/PlanDescriptorTestCase.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/appliance/src/test/net/dpml/appliance/PlanDescriptorTestCase.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.appliance;
+
+import dpml.station.info.PlanDescriptor;
+import dpml.station.info.EntryDescriptor;
+
+import java.net.URI;
+import java.util.Properties;
+import java.util.Map;
+
+/**
+ * Scenario descriptor testcase.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PlanDescriptorTestCase extends AbstractTestCase
+{
+    public void testScenarioTitle() throws Exception
+    {
+        PlanDescriptor scenario = loadPlanDescriptor( "plan.xml" );
+        String title = scenario.getTitle();
+        assertEquals( "title", "Plan Demo", title );
+    }
+    
+    public void testPlanURIs() throws Exception
+    {
+        PlanDescriptor scenario = loadPlanDescriptor( "plan.xml" );
+        EntryDescriptor[] entries = scenario.getEntryDescriptors();
+        assertEquals( "uri", 3, entries.length );
+    }
+}

Deleted: trunk/main/metro/build.xml
===================================================================
--- trunk/main/metro/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!-- 
-  Copyright 2004 Stephen J McConnell
-  
-  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.
--->
-
-<project name="dpml-metro" default="install" basedir="." 
-    xmlns:transit="antlib:net.dpml.transit" >
-
-  <transit:import uri="local:template:dpml/tools/standard"/>
-
-</project>

Added: trunk/main/metro/connector/build.xml
===================================================================
--- trunk/main/metro/connector/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/connector/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="dpml-lang-remote" default="install" basedir="." 
+    xmlns:x="antlib:dpml.tools">
+
+  <x:import uri="local:template:dpml/tools/standard"/>
+
+  <target name="build" depends="standard.build">
+    <x:rmic>
+      <include name="**/LocalConnector.class"/>
+    </x:rmic>
+  </target>
+
+</project>

Added: trunk/main/metro/connector/etc/component.xml
===================================================================
--- trunk/main/metro/connector/etc/component.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/connector/etc/component.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<component xmlns="dpml:metro" name="station" type="dpml.station.DefaultStation"/>

Added: trunk/main/metro/connector/etc/local.xml
===================================================================
--- trunk/main/metro/connector/etc/local.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/connector/etc/local.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<component xmlns="dpml:metro" name="local" type="dpml.station.LocalStation"/>

Added: trunk/main/metro/connector/project.xml
===================================================================
--- trunk/main/metro/connector/project.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/connector/project.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-metro-connector">
+
+  <info title="DPML Metro Station"/>
+  
+  <types>
+    <type id="jar"/>
+    <!--
+    <type id="part" source="etc/component.xml" alias="true"/>
+    <type id="part" source="etc/local.xml" alias="true" name="dpml-metro-local"/>
+    -->
+  </types>
+  
+  <dependencies>
+    <runtime>
+      <include ref="dpml/lang/dpml-lang-part"/>
+    </runtime>
+  </dependencies>
+  
+</project>
+

Added: trunk/main/metro/connector/src/main/dpml/station/connector/LocalConnector.java
===================================================================
--- trunk/main/metro/connector/src/main/dpml/station/connector/LocalConnector.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/connector/src/main/dpml/station/connector/LocalConnector.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.connector;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceConnector;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Utility class used to handler the establishment of a connection between 
+ * a spawned sub-process and a parent process.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class LocalConnector extends UnicastRemoteObject implements ApplianceConnector
+{
+    private final Object m_lock = new Object();
+    private Appliance m_appliance;
+    private Monitor m_monitor;
+    
+    public LocalConnector() throws RemoteException
+    {
+        super();
+    }
+    
+   /**
+    * Connect an appliance to the station.
+    * @param appliance the appliance
+    * @exception RemoteException if a remote error occurs
+    */
+    public void connect( Appliance appliance ) throws RemoteException
+    {
+        synchronized( m_lock )
+        {
+            m_appliance = appliance;
+            if( null != m_monitor )
+            {
+                m_monitor.interrupt();
+            }
+        }
+    }
+    
+    public Appliance getAppliance( TimeUnit units, int timeout ) throws IOException
+    {
+        synchronized( m_lock )
+        {
+            if( null != m_appliance )
+            {
+                return m_appliance;
+            }
+            else
+            {
+                m_monitor = new Monitor( units, timeout );
+                m_monitor.setName( "DPML Connection Monitor " 
+                  + System.identityHashCode( this ) );
+                m_monitor.start();
+            }
+        }
+        
+        try
+        {
+            m_monitor.join();
+        }
+        catch( InterruptedException e )
+        {
+        }
+        
+        synchronized( m_lock )
+        {
+            m_monitor = null;
+            if( null != m_appliance )
+            {
+                return m_appliance;
+            }
+            else
+            {
+                throw new IOException( "Appliance connection timeout (" + timeout + ")." );
+            }
+        }
+    }
+    
+    private class Monitor extends Thread
+    {
+        private int m_timeout;
+        private TimeUnit m_units;
+        
+        public Monitor( TimeUnit units, int timeout )
+        {
+            m_timeout = timeout;
+            m_units = units;
+        }
+        
+        public void run()
+        {
+            try
+            {
+                m_units.sleep( m_timeout );
+                //Thread.currentThread().sleep( m_timeout );
+            }
+            catch( InterruptedException e )
+            {
+            }
+        }
+    }
+}

Added: trunk/main/metro/main/build.xml
===================================================================
--- trunk/main/metro/main/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="dpml-metro-main" default="install" basedir="." 
+    xmlns:x="antlib:dpml.tools">
+
+  <x:import uri="local:template:dpml/tools/standard"/>
+
+  <available property="metro.exe.available" file="${dpml.system}/bin/metro.exe"/>
+
+  <target name="build" depends="standard.build">
+    <!--
+    <x:rmic>
+      <include name="**/StandardAppliance.class"/>
+    </x:rmic>
+    -->
+  </target>
+
+  <target name="install" depends="bin,standard.install">
+    <copy todir="${dpml.system}" preservelastmodified="true" overwrite="true">
+      <fileset dir="target">
+        <include name="bin/metro.lap"/>
+        <include name="bin/metro.policy"/>
+        <include name="bin/metro"/>
+      </fileset>
+    </copy>
+    <chmod perm="755">
+      <fileset dir="${dpml.system}/bin">
+        <include name="metro"/>
+      </fileset>
+    </chmod>
+  </target>
+
+  <target name="bin" depends="standard.install" unless="metro.exe.available">
+    <mkdir dir="${dpml.system}/bin"/>
+    <copy todir="${dpml.system}" preservelastmodified="true">
+      <fileset dir="target">
+        <include name="bin/metro.exe"/>
+      </fileset>
+    </copy>
+  </target>
+
+</project>

Added: trunk/main/metro/main/etc/bin/metro
===================================================================
--- trunk/main/metro/main/etc/bin/metro	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/etc/bin/metro	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+
+METRO_JVM_OPTS="-Ddpml.depot.application=link:part:dpml/metro/dpml-metro-main"
+
+if [ "$DEPOT_JVM_OPTS" = "" ] ; then
+    DEPOT_JVM_OPTS=$METRO_JVM_OPTS
+else
+    DEPOT_JVM_OPTS="$METRO_JVM_OPTS $DEPOT_JVM_OPTS"
+fi
+export DEPOT_JVM_OPTS
+
+depot $*

Added: trunk/main/metro/main/etc/bin/metro.exe
===================================================================
(Binary files differ)


Property changes on: trunk/main/metro/main/etc/bin/metro.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/main/metro/main/etc/bin/metro.lap
===================================================================
--- trunk/main/metro/main/etc/bin/metro.lap	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/etc/bin/metro.lap	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,17 @@
+# 
+# This file contains the runtime configuration of the Janel java launcher application.
+#
+
+-Djava.ext.dirs=${env.DPML_HOME}\share\lib\ext
+-Djava.endorsed.dirs=${env.DPML_HOME}\share\lib\endorsed
+-Djava.system.class.loader=dpml.util.SystemClassLoader
+-Djava.security.policy=${env.DPML_HOME}\share\bin\metro.policy
+-Djava.protocol.handler.pkgs=dpml.transit
+-Djava.rmi.server.RMIClassLoaderSpi=dpml.util.FederatingClassLoader
+-Dcom.sun.management.jmxremote
+-Ddpml.class.path=link:jar:dpml/lang/dpml-lang-part
+-Ddpml.depot.application=link:part:dpml/metro/dpml-metro-main
+-Ddpml.jmx.enabled=true
+janel.main.class=dpml.util.Main
+janel.min.java.version=1.4.0
+janel.sysprop.process.id=true

Added: trunk/main/metro/main/etc/bin/metro.policy
===================================================================
--- trunk/main/metro/main/etc/bin/metro.policy	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/etc/bin/metro.policy	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,4 @@
+grant { 
+    permission java.security.AllPermission;
+};
+

Added: trunk/main/metro/main/etc/component.xml
===================================================================
--- trunk/main/metro/main/etc/component.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/etc/component.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<component xmlns="dpml:metro" name="dpml.metro" type="dpml.metro.console.Main"/>

Added: trunk/main/metro/main/project.xml
===================================================================
--- trunk/main/metro/main/project.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/project.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-metro-main">
+
+  <info title="DPML Metro Commandline handler"/>
+  
+  <types>
+    <type id="jar"/>
+    <type id="part" source="etc/component.xml" alias="true"/>
+  </types>
+  
+  <dependencies>
+    <runtime>
+      <include ref="dpml/lang/dpml-lang-part"/>
+      <include ref="dpml/metro/dpml-metro-connector"/>
+      <include ref="dpml/metro/dpml-metro-appliance"/>
+      <include ref="dpml/util/dpml-util-cli"/>
+    </runtime>
+    <test>
+      <include ref="org/apache/ant/ant-junit"/>
+    </test>
+  </dependencies>
+  
+</project>
+

Added: trunk/main/metro/main/src/main/dpml/metro/console/Main.java
===================================================================
--- trunk/main/metro/main/src/main/dpml/metro/console/Main.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/main/src/main/dpml/metro/console/Main.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2005-2007 Stephen McConnell
+ *
+ * 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.
+ */
+
+package dpml.metro.console;
+
+import dpml.appliance.ApplianceHelper;
+
+import dpml.cli.Option;
+import dpml.cli.Group;
+import dpml.cli.CommandLine;
+import dpml.cli.OptionException;
+import dpml.cli.TooManyArgumentsException;
+import dpml.cli.commandline.Parser;
+import dpml.cli.util.HelpFormatter;
+import dpml.cli.DisplaySetting;
+import dpml.cli.builder.ArgumentBuilder;
+import dpml.cli.builder.GroupBuilder;
+import dpml.cli.builder.DefaultOptionBuilder;
+import dpml.cli.builder.CommandBuilder;
+import dpml.cli.option.PropertyOption;
+import dpml.cli.validation.URIValidator;
+import dpml.cli.validation.NumberValidator;
+
+import dpml.util.PropertyResolver;
+import dpml.util.DefaultLogger;
+import dpml.util.PID;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.NotBoundException;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import javax.tools.Tool;
+import javax.lang.model.SourceVersion;
+
+import net.dpml.annotation.Context;
+import net.dpml.annotation.Component;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceError;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+import net.dpml.appliance.ApplianceConnector;
+
+import net.dpml.lang.Strategy;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.SimpleServiceRegistry;
+import net.dpml.lang.DuplicateKeyException;
+
+import net.dpml.runtime.ComponentListener;
+import net.dpml.runtime.ComponentEvent;
+import net.dpml.runtime.ProviderEvent;
+import net.dpml.runtime.Status;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.InvalidArtifactException;
+import net.dpml.transit.ContentHandler;
+import net.dpml.transit.Transit;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.annotation.LifestylePolicy.SINGLETON;
+
+/**
+ * Generic application handler that establishes a dedicated handler based 
+ * on the type of resource exposed by a codebase uri.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ at Component( lifestyle=SINGLETON )
+public class Main implements Tool
+{
+    //------------------------------------------------------------------------------
+    // static
+    //------------------------------------------------------------------------------
+
+    private static final PID PROCESS_ID = new PID();
+    
+    //------------------------------------------------------------------------------
+    // state
+    //------------------------------------------------------------------------------
+    
+    private final Logger m_logger;
+    
+   /**
+    * The application handler class is a generic component handler that delegates
+    * application deployment processes to dedicated handlers based on the codebase 
+    * type of the target application.  Normally this plugin is activated as a 
+    * consequence of invoking the <tt>metro</tt> commandline handler (which is 
+    * the default haviour of the <tt>station</tt> when deployment local processes).
+    * The following command list help about the <tt>metro</tt> commandline handler:
+    * <pre>$ metro help
+Usage:
+metro <uri> [-server] | -help
+options
+  <uri>                    Application codebase part uri.
+  -command                 Enables command mode.
+  -help                    Prints command help and exits.
+  -version                 Prints version info and exits.
+    * </pre>
+    * An example commandline and resulting log of an application launch 
+    * using <tt>metro</tt> is show below:
+    * <pre>
+$ metro -command link:part:dpml/lang/dpml-lang-sample
+
+[2756 ] [INFO   ] (dpml.metro): commissioning hello
+[2756 ] [INFO   ] (hello): pid: [2756]
+[2756 ] [INFO   ] (hello): message: Hello
+[2756 ] [INFO   ] (hello): port: 0
+[2756 ] [INFO   ] (hello): target: artifact:jar:dpml/lang/dpml-lang-sample#SNAPSHOT
+[2756 ] [INFO   ] (hello): starting
+[2756 ] [INFO   ] (hello): started
+[2756 ] [INFO   ] (dpml.metro): decommissioning hello
+[2756 ] [INFO   ] (hello): stopping
+[2756 ] [INFO   ] (hello): stopped
+    * </pre>
+    *
+    * @param logger the assigned logging channel
+    * @exception Exception if an error occurs
+    */
+    public Main( Logger logger ) throws Exception
+    {
+        m_logger = logger;
+        Thread.currentThread().setContextClassLoader( 
+          Appliance.class.getClassLoader() );
+    }
+    
+    public Set<SourceVersion> getSourceVersions()
+    {
+        return Collections.unmodifiableSet(
+          EnumSet.range(
+            SourceVersion.RELEASE_4,
+            SourceVersion.latest() ) );
+    }
+    
+   /**
+    * Run the Metro tool.
+    */
+    public int run( InputStream in, OutputStream out, OutputStream err, String... arguments )
+    {
+        for( int i=0; i<arguments.length; i++ )
+        {
+            String arg = arguments[i];
+            if( m_logger.isTraceEnabled() )
+            {
+                m_logger.trace( "  arg: " + ( i + 1 ) + ": " + arg );
+            }
+            if( "-help".equals( arg ) )
+            {
+                printHelpMessage();
+                return 0;
+            }
+            if( "-version".equals( arg ) )
+            {
+                printVersionMessage();
+                return 0;
+            }
+        }
+        
+        try
+        {
+            return execute( arguments );
+        }
+        catch( Throwable e )
+        {
+            m_logger.error( "Execution error.", e );
+            return -1;
+        }
+    }
+    
+    private int execute( String... args ) throws Exception
+    {
+        CommandLine line = getCommandLine( args );
+        if( ( null == line ) || !line.hasOption( CODEBASE ) )
+        {
+            printHelpMessage();
+            return -1;
+        }
+        
+        URI uri = getURI( line );
+        ClassLoader current = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
+        try
+        {
+            Appliance appliance = ApplianceHelper.newAppliance( uri );
+            boolean flag = line.hasOption( COMMAND_EXECUTION_OPTION );
+            return execute( appliance, flag );
+        }
+        catch( InvalidArtifactException e )
+        {
+            String error = 
+              "Invalid artifact: " 
+              + uri
+              + "\n" + e.getMessage()
+              + " (expected format: 'scheme:type:[group[/group[/...]]/name[#<version>]).";
+            m_logger.error( error );
+            return -1;
+        }
+        catch( MalformedURLException e )
+        {
+            String error = 
+              "Invalid uri: [" 
+              + uri
+              + "] (" + e.getMessage() + 
+              "), expected format: 'scheme:type:[group[/group[/...]]/name[#<version>].";
+            m_logger.error( error );
+            return -1;
+        }
+        catch( TooManyArgumentsException e )
+        {
+            m_logger.error( "Error: " + e.getMessage() );
+            return -1;
+        }
+        finally
+        {
+            Thread.currentThread().setContextClassLoader( current );
+        }
+    }
+    
+    private String getType( URI uri )
+    {
+        if( Artifact.isRecognized( uri ) )
+        {
+            Artifact artifact = Artifact.createArtifact( uri );
+            return artifact.getType();
+        }
+        return null; 
+    }
+    
+   /**
+    * Execute the appliance.
+    * @param appliance the appliance
+    * @param flag if true we are executing in command mode
+    */
+    private int execute( Appliance appliance, boolean flag ) throws Exception
+    {
+        if( flag )
+        {
+            return executeAsCommand( appliance );
+        }
+        else
+        {
+            // 
+            // we are running in server mode - just need to check if we are
+            // running as a top-level server, or if we are running as a 
+            // child of a parent process
+            //
+            
+            String key = System.getProperty( "dpml.appliance.connector.key", null );
+            if( null == key )
+            {
+                //
+                // just go ahead and commission (decommissioning will be handled
+                // by the shutdown hook)
+                //
+                
+                try
+                {
+                    appliance.commission();
+                    return 1;
+                }
+                catch( Exception e )
+                {
+                    getLogger().error( "error commissioning appliance", e );
+                    return -1;
+                }
+            }
+            else
+            {
+                //
+                // we need to bind the appliance to a connector so that the 
+                // parent process can get a handle to the appliance - any
+                // commissioning/decommissioning activity is the responsibity 
+                // of the application that established the callback connector
+                //
+                
+                appliance.addApplianceListener( new LocalApplianceListener() );
+                ApplianceConnector connector = getApplianceConnector( key );
+                connector.connect( appliance );
+                return 1;
+            }
+        }
+    }
+    
+   /**
+    * Execute the appliance.
+    * @param appliance the appliance
+    * @param flag if true we are executing in command mode
+    */
+    private int executeAsCommand( Appliance appliance ) throws Exception
+    {
+        try
+        {
+            appliance.commission();
+        }
+        catch( Exception e )
+        {
+            getLogger().error( "error commissioning appliance", e );
+            return -1;
+        }
+        finally
+        {
+            try
+            {
+                appliance.decommission();
+                return 0;
+            }
+            catch( Exception re )
+            {
+                getLogger().error( "error decommissioning appliance", re );
+                return -1;
+            }
+        }
+    }
+    
+    private static int getStationPort()
+    {
+        String port = System.getProperty( "dpml.appliance.connector.port", null );
+        if( null == port )
+        {
+            return Registry.REGISTRY_PORT;
+        }
+        else
+        {
+            return Integer.parseInt( port );
+        }
+    }
+    
+    private static long getDecommissionTimeout()
+    {
+        String value = System.getProperty( "dpml.decommmission.timeout", null );
+        if( null == value )
+        {
+            return 10;
+        }
+        else
+        {
+            try
+            {
+                return Long.parseLong( value );
+            }
+            catch( Throwable e )
+            {
+                return 10;
+            }
+        }
+    }
+    
+    private URI getURI( CommandLine line )
+    {
+        URI uri = (URI) line.getValue( CODEBASE, null );
+        if( null == uri )
+        {
+            throw new NullPointerException( "uri" ); // will not happen
+        }
+        return uri;
+    }
+    
+    private CommandLine getCommandLine( String[] args ) throws Exception
+    {
+        try
+        {
+            Parser parser = new Parser();
+            parser.setGroup( COMMAND_GROUP );
+            return parser.parse( args );
+        }
+        catch( TooManyArgumentsException e )
+        {
+            String message = e.getMessage();
+            m_logger.error( message );
+            return null;
+        }
+        catch( OptionException oe )
+        {
+            String message = oe.getMessage();
+            m_logger.error( message );
+            return null;
+        }
+    }
+    
+   /**
+    * Return a properties instance composed of the <tt>-C&lt;key&gt;=&lt;value&gt;</tt>
+    * commandline arguments.
+    * @param line the commandline
+    * @return the resolved properties
+    */
+    private Properties getCommandLineProperties( CommandLine line )
+    {
+        Properties properties = new Properties();
+        Set propertyValue = line.getProperties();
+        Iterator iterator = propertyValue.iterator();
+        while( iterator.hasNext() )
+        {
+            String name = (String) iterator.next();
+            String value = line.getProperty( name );
+            properties.setProperty( name, value );
+        }
+        return properties;
+    }
+
+    private class InternalComponentMonitor implements ComponentListener
+    {
+       /**
+        * Notify the listener of a state change.
+        *
+        * @param event the state change event
+        * @exception RemoteException if a remote transport error occurs
+        */
+        public void componentChanged( final ComponentEvent event )
+        {
+            if( event instanceof ProviderEvent )
+            {
+                ProviderEvent e = (ProviderEvent) event;
+                String action = e.getStatus().name().toLowerCase();
+                if( m_logger.isDebugEnabled() )
+                {
+                    m_logger.debug( action );
+                }
+            }
+            else
+            {
+                m_logger.warn( 
+                  "Event not recognized: " 
+                  + event.toString() );
+            }
+        }
+    }
+    
+    private void printVersionMessage()
+    {
+        StringBuffer buffer = new StringBuffer( "version" );
+        buffer.append( "\n" );
+        buffer.append( "\n  DPML Metro" );
+        buffer.append( "\n  Version @PROJECT-VERSION@" );
+        buffer.append( "\n  Copyright 2005-2007 Stephen J. McConnell" );
+        buffer.append( "\n  Digital Product Management Laboratory" );
+        String message = buffer.toString();
+        m_logger.info( message );
+    }
+    
+    private void printHelpMessage()
+    {
+        StringBuffer buffer = new StringBuffer( "help" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Description:" );
+        buffer.append( "\n" );
+        buffer.append( "\n    Deploys a component referenced by a part uri." );
+        buffer.append( "\n" );
+        buffer.append( "\n  Usage: metro [-command] <uri> | -help | -version" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Arguments:" );
+        buffer.append( "\n    <uri>              uri referencing a part datatype" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Options:" );
+        buffer.append( "\n    -command           enables command execution mode" );
+        buffer.append( "\n    -help              list command help and exit" );
+        buffer.append( "\n    -version           list version info and exit" );
+        buffer.append( "\n" );
+        String message = buffer.toString();
+        m_logger.info( message );
+    }
+    
+    //------------------------------------------------------------------------------
+    // internals
+    //------------------------------------------------------------------------------
+    
+    private Logger getLogger()
+    {
+        return m_logger;
+    }
+
+    private ApplianceConnector getApplianceConnector( String key ) throws Exception
+    {
+        if( null == key )
+        {
+            throw new NullPointerException( "key " );
+        }
+        else
+        {
+            int port = getStationPort();
+            Registry registry = LocateRegistry.getRegistry( port );
+            try
+            {
+                return (ApplianceConnector) registry.lookup( key );
+            }
+            catch( NotBoundException e )
+            {
+                final String error = 
+                  "Connector key [" + key + "] is not bound in registry ["
+                  + registry
+                  + "].";
+                throw new ApplianceError( error, e );
+            }
+        }
+    }
+    
+    private class LocalApplianceListener implements ApplianceListener
+    {
+        public void applianceChanged( final ApplianceEvent event )
+        {
+            Status status = event.getStatus();
+            String name = status.name().toLowerCase();
+            getLogger().getChildLogger( "event" ).info( name );
+            if( Status.TERMINATION.equals( status ) )
+            {
+                try
+                {
+                    event.getAppliance().removeApplianceListener( this );
+                }
+                catch( IOException ioe )
+                {
+                    final String warning = 
+                      "Ignoring error on listener removal.";
+                    getLogger().warn( warning, ioe );
+                }
+            }
+        }
+    }
+    
+    //-----------------------------------------------------------------------------
+    // CLI
+    //-----------------------------------------------------------------------------
+
+   /**
+    * List general command help to the console.
+    * @exception IOException if an I/O error occurs
+    */
+    @SuppressWarnings( "unchecked" )
+    private void processHelp() throws IOException
+    {
+        HelpFormatter formatter = new HelpFormatter( 
+          HelpFormatter.DEFAULT_GUTTER_LEFT, 
+          HelpFormatter.DEFAULT_GUTTER_CENTER, 
+          HelpFormatter.DEFAULT_GUTTER_RIGHT, 
+          100 );
+        
+        formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
+        formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
+        formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
+        
+        formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
+        formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
+        formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
+        formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
+        formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
+        formatter.getFullUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
+        
+        formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
+        formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
+        formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
+        formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_GROUP_EXPANDED );
+        
+        formatter.setGroup( CODEBASE_GROUP );
+        formatter.setShellCommand( "metro" );
+        formatter.print();
+    }
+    
+    private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder();
+    private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder();
+    private static final GroupBuilder GROUP_BUILDER = new GroupBuilder();
+    private static final CommandBuilder COMMAND_BUILDER = new CommandBuilder();
+
+    private static final PropertyOption CONTEXT_OPTION = 
+      new PropertyOption( "-C", "Set a context entry value.", 'C' );
+    private static final NumberValidator PORT_VALIDATOR = NumberValidator.getIntegerInstance();
+    private static final URIValidator URI_VALIDATOR = new URIValidator();
+    
+    private static final Option HELP_COMMAND =
+      OPTION_BUILDER
+        .withShortName( "help" )
+        .withShortName( "h" )
+        .withDescription( "Prints command help." )
+        .create();
+
+    private static final Option COMMAND_EXECUTION_OPTION =
+      OPTION_BUILDER
+        .withShortName( "command" )
+        .withShortName( "c" )
+        .withDescription( "Enables command execution mode." )
+        .create();
+
+    private static final Option CODEBASE = 
+        ARGUMENT_BUILDER
+          .withName( "codebase" )
+          .withDescription( "URI referencing a part datastructure." )
+          .withValidator( new URIValidator() )
+          .create();
+
+    private static final Group CODEBASE_GROUP =
+      GROUP_BUILDER
+        .withOption( CODEBASE )
+        .withOption( CONTEXT_OPTION )
+        .create();
+        
+    private static final Group COMMAND_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 1 )
+        .withOption( CODEBASE )
+        .withOption( CONTEXT_OPTION )
+        .withOption( COMMAND_EXECUTION_OPTION )
+        .create();
+}

Modified: trunk/main/metro/module.xml
===================================================================
--- trunk/main/metro/module.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/module.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -1,179 +1,19 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <module name="metro"
-    xmlns="link:xsd:dpml/lang/dpml-module#1.0" 
+    xmlns="dpml:library" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:part="link:xsd:dpml/lang/dpml-part#1.0">
+    xmlns:part="dpml:part">
     
-  <properties>
-    <property name="project.minor.version" value="2"/>
-    <property name="project.micro.version" value="0"/>
-  </properties>
+  <dependencies>
+    <build>
+      <include ref="dpml/depot"/>
+    </build>
+  </dependencies>
 
-  <project name="dpml-metro-state" basedir="state">
-    <info title="DPML State Management Model">
-      <description>State/transition model for lifecycle manaement.</description>
-    </info>
-    <types>
-      <type id="jar"/>
-    </types>
-    <dependencies>
-      <build>
-        <include ref="dpml/lang/dpml-state"/>
-      </build>
-      <runtime>
-        <include ref="dpml/transit/dpml-transit-main"/>
-      </runtime>
-      <test>
-        <include ref="ant/ant-junit"/>
-      </test>
-    </dependencies>
-    <filters>
-      <feature token="STATE-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-state" alias="true"/>
-    </filters>
-  </project>
-  
-  <project name="dpml-metro-component" basedir="component">
-    <info title="DPML Metro Component API">
-      <description>Interfaces defining the Metro component model.</description>
-    </info>
-    <types>
-      <type id="jar"/>
-    </types>
-    <dependencies>
-      <build>
-        <include ref="dpml/lang/dpml-part"/>
-      </build>
-      <runtime>
-        <include key="dpml-metro-state" tag="public"/>
-        <include ref="dpml/transit/dpml-transit-main" tag="private"/>
-      </runtime>
-      <test>
-        <include ref="ant/ant-junit"/>
-      </test>
-    </dependencies>
-    <filters>
-      <feature token="NAME" id="name"/>
-      <feature token="VERSION" id="version"/>
-      <feature token="GROUP" id="group"/>
-      <feature token="PART-HANDLER-URI" id="uri" type="part" ref="dpml/metro/dpml-metro-runtime"/>
-    </filters>
-  </project>
-  
-  <project name="dpml-metro-model" basedir="model">
-    <info title="DPML Metro Component SPI">
-      <description>Interfaces defining the Metro datastructures.</description>
-    </info>
-    <types>
-      <type id="jar"/>
-    </types>
-    <dependencies>
-      <build>
-        <include ref="dpml/lang/dpml-part"/>
-        <include ref="dpml/lang/dpml-state"/>
-        <include ref="dpml/lang/dpml-type"/>
-        <include ref="dpml/lang/dpml-component"/>
-      </build>
-      <runtime>
-        <include key="dpml-metro-state"/>
-        <include key="dpml-metro-component"/>
-      </runtime>
-      <test>
-        <include ref="ant/ant-junit"/>
-      </test>
-    </dependencies>
-    <filters>
-      <feature token="NAME" id="name"/>
-      <feature token="VERSION" id="version"/>
-      <feature token="GROUP" id="group"/>
-      <feature token="PART-HANDLER-URI" id="uri" ref="dpml/metro/dpml-metro-runtime" type="part"/>
-      <feature token="STATE-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-state" alias="true"/>
-      <feature token="PART-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-part" alias="true"/>
-      <feature token="TYPE-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-type" alias="true"/>
-      <feature token="COMPONENT-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-component" alias="true"/>
-    </filters>
-  </project>
-   
-  <project name="dpml-metro-runtime" basedir="runtime">
-    <info title="DPML Metro Runtime">
-      <description>
-      Metro component management platform runtime container.
-      </description>
-    </info>
-    <types>
-      <type id="jar"/>
-      <part:plugin alias="true" class="net.dpml.metro.runtime.CompositionController">
-        <part:param class="net.dpml.component.InitialContext"/>
-      </part:plugin>
-    </types>
-    <dependencies>
-      <build>
-        <include ref="dpml/lang/dpml-part"/>
-        <include ref="dpml/lang/dpml-state"/>
-        <include ref="dpml/lang/dpml-type"/>
-        <include ref="dpml/lang/dpml-component"/>
-      </build>
-      <runtime>
-        <include ref="dpml/util/dpml-logging-api" tag="public"/>
-        <include ref="dpml/metro/dpml-metro-component" tag="protected"/>
-        <include ref="dpml/metro/dpml-metro-model" tag="protected"/>
-      </runtime>
-      <test>
-        <include ref="ant/ant-junit"/>
-      </test>
-    </dependencies>
-    <filters>
-      <feature token="PART-HANDLER-URI" id="uri" type="part"/>
-      <feature token="STATE-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-state" alias="true"/>
-      <feature token="PART-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-part" alias="true"/>
-      <feature token="TYPE-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-type" alias="true"/>
-      <feature token="COMPONENT-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-component" alias="true"/>
-    </filters>
-  </project>
-  
-  <project name="dpml-metro-tools" basedir="tools">
-    <info title="DPML Metro Tools">
-      <description>
-      DPML extensions supporting the Ant build system for component 
-      type and deployment data management.
-      </description>
-    </info>
-    <types>
-      <type id="jar"/>
-      <part:resource alias="true" urn="dpml:metro"
-        path="net/dpml/metro/tools/antlib.xml"/>
-    </types>
-    <dependencies>
-      <build>
-        <include ref="dpml/lang/dpml-component"/>
-      </build>
-      <runtime>
-        <include ref="dpml/depot/dpml-tools-builder"/>
-        <include ref="dpml/transit/dpml-transit-tools"/>
-        <include ref="dpml/metro/dpml-metro-runtime"/>
-      </runtime>
-    </dependencies>
-    <filters>
-      <feature token="PART-BUILDER-URI" id="uri" type="part"/>
-      <feature token="PART-HANDLER-URI" id="uri" type="part" ref="dpml/metro/dpml-metro-runtime"/>
-      <feature token="COMPONENT-XSD-URI" id="uri" type="xsd" ref="dpml/lang/dpml-component" alias="true"/>
-      <feature token="STRATEGY-BUILDER-URI" id="uri" type="part" ref="dpml/metro/dpml-metro-runtime"/>
-    </filters>
-  </project>
+  <project file="appliance/project.xml"/>
+  <project file="main/project.xml"/>
+  <project file="connector/project.xml"/>
+  <project file="test/project.xml"/>
+  <project file="station/project.xml"/>
 
-  <project name="dpml-metro-test" basedir="test">
-    <info title="Internal Test Package"/>
-    <types>
-      <type id="jar"/>
-    </types>
-    <dependencies>
-      <runtime>
-        <include ref="dpml/util/dpml-logging-api"/>
-        <include ref="dpml/metro/dpml-metro-model"/>
-      </runtime>
-      <test>
-        <include key="dpml-metro-tools"/>
-      </test>
-    </dependencies>
-  </project>
-  
 </module>

Added: trunk/main/metro/station/build.xml
===================================================================
--- trunk/main/metro/station/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<project name="dpml-metro-station" default="install" basedir="." 
+    xmlns:x="antlib:dpml.tools">
+
+  <x:import uri="local:template:dpml/tools/standard"/>
+
+  <available property="station.exe.available" file="${dpml.system}/bin/station.exe"/>
+
+  <target name="install" depends="bin,standard.install">
+    <mkdir dir="${dpml.prefs}/${project.group}"/>
+    <copy toDir="${dpml.prefs}/${project.group}">
+      <fileset dir="etc/prefs">
+        <include name="**/*"/>
+      </fileset>
+    </copy>
+    
+    <!--
+    <mkdir dir="${dpml.prefs}/${project.group}/plans"/>
+    <copy file="${basedir}/target/prefs/default.xml" toFile="${dpml.prefs}/${project.group}/plans/default.plan"
+        preservelastmodified="true" overwrite="true"/>
+    -->
+    
+    <copy todir="${dpml.system}" preservelastmodified="true" overwrite="true">
+      <fileset dir="target">
+        <include name="bin/station.lap"/>
+        <include name="bin/station.policy"/>
+        <include name="bin/station"/>
+        <include name="bin/scm/**"/>
+      </fileset>
+    </copy>
+    <chmod perm="755">
+      <fileset dir="${dpml.system}/bin">
+        <include name="station"/>
+      </fileset>
+    </chmod>
+  </target>
+
+  <target name="bin" depends="standard.install" unless="station.exe.available">
+    <mkdir dir="${dpml.system}/bin"/>
+    <copy todir="${dpml.system}" preservelastmodified="true">
+      <fileset dir="target">
+        <include name="bin/station.exe"/>
+      </fileset>
+    </copy>
+  </target>
+
+</project>

Added: trunk/main/metro/station/etc/bin/scm/WRAPPER_LICENSE.txt
===================================================================
--- trunk/main/metro/station/etc/bin/scm/WRAPPER_LICENSE.txt	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/scm/WRAPPER_LICENSE.txt	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,41 @@
+Copyright (c) 1999, 2004 Tanuki Software
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of the Java Service Wrapper and associated
+documentation files (the "Software"), to deal in the Software
+without  restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sub-license,
+and/or sell copies of the Software, and to permit persons to
+whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
+NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+
+Portions of the Software have been derived from source code
+developed by Silver Egg Technology under the following license:
+
+Copyright (c) 2001 Silver Egg Technology
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without 
+restriction, including without limitation the rights to use, 
+copy, modify, merge, publish, distribute, sub-license, and/or 
+sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following 
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+

Added: trunk/main/metro/station/etc/bin/scm/conf/wrapper.conf
===================================================================
--- trunk/main/metro/station/etc/bin/scm/conf/wrapper.conf	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/scm/conf/wrapper.conf	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,115 @@
+#********************************************************************
+# TestWrapper Properties
+#
+# NOTE - Please use src/conf/wrapper.conf.in as a template for your
+#        own application rather than the values used for the
+#        TestWrapper sample.
+#********************************************************************
+# Java Application
+wrapper.java.command=java
+
+# Working directory.
+wrapper.working.dir=../../../data/work
+
+# Java Main class.  This class must implement the WrapperListener interface
+#  or guarantee that the WrapperManager class is initialized.  Helper
+#  classes are provided to do this for you.  See the Integration section
+#  of the documentation for details.
+#wrapper.java.mainclass=net.dpml.depot.Main
+wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
+
+
+# Java Classpath (include wrapper.jar)  Add class path elements as
+#  needed starting from 1
+wrapper.java.classpath.1=../../share/bin/scm/lib/wrapper.jar
+wrapper.java.classpath.2=../../share/lib/dpml-transit-main.jar
+
+# Java Library Path (location of Wrapper.DLL or libwrapper.so)
+wrapper.java.library.path.1=../../share/bin/scm/lib
+
+# Java Additional Parameters
+wrapper.java.additional.1=-Djava.ext.dirs=..\..\share\lib\ext
+wrapper.java.additional.2=-Djava.endorsed.dirs=..\..\share\lib\endorsed
+wrapper.java.additional.3=-Djava.system.class.loader=dpml.util.SystemClassLoader
+wrapper.java.additional.4=-Djava.security.policy=..\..\share\bin\station.policy
+wrapper.java.additional.5=-Djava.protocol.handler.pkgs=dpml.transit
+wrapper.java.additional.6=-Djava.rmi.server.RMIClassLoaderSpi=dpml.util.FederatingClassLoader
+wrapper.java.additional.7=-Dcom.sun.management.jmxremote
+wrapper.java.additional.8=-Ddpml.class.path=link:jar:dpml/lang/dpml-lang-part
+wrapper.java.additional.9=-Ddpml.depot.application=link:part:dpml/metro/dpml-metro-station
+wrapper.java.additional.10=-Ddpml.jmx.enabled=true
+wrapper.java.additional.11=-Ddpml.logging.config=local:properties:dpml/metro/station
+
+# Initial Java Heap Size (in MB)
+#wrapper.java.initmemory=3
+
+# Maximum Java Heap Size (in MB)
+#wrapper.java.maxmemory=64
+
+# Application parameters.  Add parameters as needed starting from 1
+wrapper.app.parameter.1=dpml.util.Main
+wrapper.app.parameter.2=server
+
+#********************************************************************
+# Wrapper Logging Properties
+#********************************************************************
+# Format of output for the console.  (See docs for formats)
+wrapper.console.format=PM
+
+# Log Level for console output.  (See docs for log levels)
+wrapper.console.loglevel=INFO
+
+# Log file to use for wrapper output logging.
+wrapper.logfile=../../data/logs/service.log
+
+# Format of output for the log file.  (See docs for formats)
+wrapper.logfile.format=LPTM
+
+# Log Level for log file output.  (See docs for log levels)
+wrapper.logfile.loglevel=INFO
+
+# Maximum size that the log file will be allowed to grow to before
+#  the log is rolled. Size is specified in bytes.  The default value
+#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
+#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
+wrapper.logfile.maxsize=0
+
+# Maximum number of rolled log files which will be allowed before old
+#  files are deleted.  The default value of 0 implies no limit.
+wrapper.logfile.maxfiles=0
+
+# Log Level for sys/event log output.  (See docs for log levels)
+wrapper.syslog.loglevel=NONE
+
+#********************************************************************
+# Wrapper Windows Properties
+#********************************************************************
+# Title to use when running as a console
+wrapper.console.title=DPML Station Server
+
+#********************************************************************
+# Wrapper Windows NT/2000/XP Service Properties
+#********************************************************************
+# WARNING - Do not modify any of these properties when an application
+#  using this configuration file has been installed as a service.
+#  Please uninstall the service before modifying this section.  The
+#  service can then be reinstalled.
+
+# Name of the service
+wrapper.ntservice.name=DPML
+
+# Display name of the service
+wrapper.ntservice.displayname=DPML Station Server
+
+# Description of the service
+wrapper.ntservice.description=Multi-application management station.
+
+# Service dependencies.  Add dependencies as needed starting from 1
+wrapper.ntservice.dependency.1=
+
+# Mode in which the service is installed.  AUTO_START or DEMAND_START
+wrapper.ntservice.starttype=DEMAND_START
+
+# Allow the service to interact with the desktop.
+wrapper.ntservice.interactive=false
+

Added: trunk/main/metro/station/etc/bin/scm/install-DPML-SCM.bat
===================================================================
--- trunk/main/metro/station/etc/bin/scm/install-DPML-SCM.bat	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/scm/install-DPML-SCM.bat	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,35 @@
+ at echo off
+setlocal
+
+rem
+rem Java Service Wrapper general NT service install script
+rem
+
+if "%OS%"=="Windows_NT" goto nt
+echo This script only works with NT-based versions of Windows.
+goto :eof
+
+:nt
+rem
+rem Find the application home.
+rem
+rem %~dp0 is location of current script under NT
+set _REALPATH=%~dp0
+set _WRAPPER_EXE=%_REALPATH%Wrapper.exe
+
+rem
+rem Find the wrapper.conf
+rem
+:conf
+set _WRAPPER_CONF="%~f1"
+if not %_WRAPPER_CONF%=="" goto startup
+set _WRAPPER_CONF="%_REALPATH%conf\wrapper.conf"
+
+rem
+rem Install the Wrapper as an NT service.
+rem
+:startup
+"%_WRAPPER_EXE%" -i %_WRAPPER_CONF%
+if not errorlevel 1 goto :eof
+pause
+

Added: trunk/main/metro/station/etc/bin/scm/lib/wrapper.dll
===================================================================
(Binary files differ)


Property changes on: trunk/main/metro/station/etc/bin/scm/lib/wrapper.dll
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/main/metro/station/etc/bin/scm/lib/wrapper.jar
===================================================================
(Binary files differ)


Property changes on: trunk/main/metro/station/etc/bin/scm/lib/wrapper.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/main/metro/station/etc/bin/scm/uninstall-DPML-SCM.bat
===================================================================
--- trunk/main/metro/station/etc/bin/scm/uninstall-DPML-SCM.bat	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/scm/uninstall-DPML-SCM.bat	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,35 @@
+ at echo off
+setlocal
+
+rem
+rem Java Service Wrapper general NT service uninstall script
+rem
+
+if "%OS%"=="Windows_NT" goto nt
+echo This script only works with NT-based versions of Windows.
+goto :eof
+
+:nt
+rem
+rem Find the application home.
+rem
+rem %~dp0 is location of current script under NT
+set _REALPATH=%~dp0
+set _WRAPPER_EXE=%_REALPATH%Wrapper.exe
+
+rem
+rem Find the wrapper.conf
+rem
+:conf
+set _WRAPPER_CONF="%~f1"
+if not %_WRAPPER_CONF%=="" goto startup
+set _WRAPPER_CONF="%_REALPATH%conf\wrapper.conf"
+
+rem
+rem Uninstall the Wrapper as an NT service.
+rem
+:startup
+"%_WRAPPER_EXE%" -r %_WRAPPER_CONF%
+if not errorlevel 1 goto :eof
+pause
+

Added: trunk/main/metro/station/etc/bin/scm/wrapper.exe
===================================================================
(Binary files differ)


Property changes on: trunk/main/metro/station/etc/bin/scm/wrapper.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/main/metro/station/etc/bin/station
===================================================================
--- trunk/main/metro/station/etc/bin/station	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/station	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+
+STATION_JVM_OPTS="-Ddpml.depot.application=link:part:dpml/metro/dpml-metro-station"
+
+if [ "$DEPOT_JVM_OPTS" = "" ] ; then
+    DEPOT_JVM_OPTS=$STATION_JVM_OPTS
+else
+    DEPOT_JVM_OPTS="$STATION_JVM_OPTS $DEPOT_JVM_OPTS"
+fi
+export DEPOT_JVM_OPTS
+
+depot $*

Added: trunk/main/metro/station/etc/bin/station.exe
===================================================================
(Binary files differ)


Property changes on: trunk/main/metro/station/etc/bin/station.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/main/metro/station/etc/bin/station.lap
===================================================================
--- trunk/main/metro/station/etc/bin/station.lap	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/station.lap	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,17 @@
+# 
+# This file contains the runtime configuration of the Janel java launcher application.
+#
+
+-Djava.ext.dirs=${env.DPML_HOME}\share\lib\ext
+-Djava.endorsed.dirs=${env.DPML_HOME}\share\lib\endorsed
+-Djava.system.class.loader=dpml.util.SystemClassLoader
+-Djava.security.policy=${env.DPML_HOME}\share\bin\station.policy
+-Djava.protocol.handler.pkgs=dpml.transit
+-Djava.rmi.server.RMIClassLoaderSpi=dpml.util.FederatingClassLoader
+-Dcom.sun.management.jmxremote
+-Ddpml.class.path=link:jar:dpml/lang/dpml-lang-part
+-Ddpml.depot.application=link:part:dpml/metro/dpml-metro-station
+-Ddpml.jmx.enabled=true
+janel.main.class=dpml.util.Main
+janel.min.java.version=1.6.0
+janel.sysprop.process.id=true

Added: trunk/main/metro/station/etc/bin/station.policy
===================================================================
--- trunk/main/metro/station/etc/bin/station.policy	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/bin/station.policy	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,4 @@
+grant { 
+    permission java.security.AllPermission;
+};
+

Added: trunk/main/metro/station/etc/component.xml
===================================================================
--- trunk/main/metro/station/etc/component.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/component.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<component xmlns="dpml:metro" name="dpml.station" type="dpml.station.console.Main"/>

Added: trunk/main/metro/station/etc/prefs/plans/default.plan
===================================================================
--- trunk/main/metro/station/etc/prefs/plans/default.plan	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/prefs/plans/default.plan	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+
+<plan xmlns="dpml:plan" name="station" title="DPML Station Default Deployment Plan">
+
+</plan>

Added: trunk/main/metro/station/etc/prefs/propertiess/process.properties
===================================================================
--- trunk/main/metro/station/etc/prefs/propertiess/process.properties	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/prefs/propertiess/process.properties	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,13 @@
+#
+# Logging configuration template for an application (jvm) established
+# by the Station server. The template assumes that a system property 
+# 'dpml.station.key' and ${dpml.station.logging.dir} are declared.
+# 
+
+handlers=java.util.logging.FileHandler
+java.util.logging.FileHandler.count=10
+java.util.logging.FileHandler.limit=100000
+java.util.logging.FileHandler.pattern=${dpml.station.logging.dir}/${dpml.station.key}/${dpml.station.key}-%g.log
+java.util.logging.FileHandler.formatter=dpml.util.StandardFormatter
+sun.rmi.level=INFO
+

Added: trunk/main/metro/station/etc/prefs/propertiess/station.properties
===================================================================
--- trunk/main/metro/station/etc/prefs/propertiess/station.properties	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/etc/prefs/propertiess/station.properties	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,11 @@
+#
+# Logging configuration for the Station server.
+# 
+
+handlers=java.util.logging.FileHandler
+java.util.logging.FileHandler.pattern=${dpml.data}/logs/station/dpml-station-server-%u.log
+java.util.logging.FileHandler.limit=50000
+java.util.logging.FileHandler.count=1
+java.util.logging.FileHandler.formatter=dpml.util.StandardFormatter
+sun.rmi.level=INFO
+

Added: trunk/main/metro/station/project.xml
===================================================================
--- trunk/main/metro/station/project.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/project.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-metro-station">
+
+  <info title="DPML Station Commandline handler"/>
+  
+  <types>
+    <type id="jar"/>
+    <type id="part" source="etc/component.xml" alias="true"/>
+  </types>
+  
+  <dependencies>
+    <runtime>
+      <include ref="dpml/lang/dpml-lang-part"/>
+      <include ref="dpml/metro/dpml-metro-connector"/>
+      <include ref="dpml/metro/dpml-metro-appliance"/>
+      <include ref="dpml/util/dpml-util-cli"/>
+    </runtime>
+    <test>
+      <include ref="org/apache/ant/ant-junit"/>
+    </test>
+  </dependencies>
+  
+</project>
+

Added: trunk/main/metro/station/src/main/dpml/station/console/Main.java
===================================================================
--- trunk/main/metro/station/src/main/dpml/station/console/Main.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/src/main/dpml/station/console/Main.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,872 @@
+/*
+ * Copyright 2005-2007 Stephen McConnell
+ *
+ * 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.
+ */
+
+package dpml.station.console;
+
+import dpml.appliance.ApplianceHelper;
+import dpml.station.connector.LocalConnector;
+import dpml.station.info.InfoDescriptor;
+import dpml.station.info.ProcessDescriptor;
+import dpml.station.info.ApplianceDescriptor;
+import dpml.station.util.OutputStreamReader;
+import dpml.station.util.StreamReader;
+import dpml.station.util.LoggingServer;
+
+import dpml.cli.Option;
+import dpml.cli.Group;
+import dpml.cli.CommandLine;
+import dpml.cli.OptionException;
+import dpml.cli.TooManyArgumentsException;
+import dpml.cli.commandline.Parser;
+import dpml.cli.util.HelpFormatter;
+import dpml.cli.DisplaySetting;
+import dpml.cli.builder.ArgumentBuilder;
+import dpml.cli.builder.GroupBuilder;
+import dpml.cli.builder.DefaultOptionBuilder;
+import dpml.cli.builder.CommandBuilder;
+import dpml.cli.option.PropertyOption;
+import dpml.cli.validation.URIValidator;
+import dpml.cli.validation.NumberValidator;
+
+import dpml.util.PropertyResolver;
+import dpml.util.DefaultLogger;
+import dpml.util.PID;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.NotBoundException;
+import java.rmi.ConnectException;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.util.Properties;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.tools.Tool;
+import javax.lang.model.SourceVersion;
+
+import javax.management.MBeanServer;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+    
+import net.dpml.annotation.Context;
+import net.dpml.annotation.Component;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceError;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+import net.dpml.appliance.ApplianceConnector;
+
+import net.dpml.lang.Strategy;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.SimpleServiceRegistry;
+import net.dpml.lang.DuplicateKeyException;
+
+import net.dpml.runtime.ComponentListener;
+import net.dpml.runtime.ComponentEvent;
+import net.dpml.runtime.ProviderEvent;
+import net.dpml.runtime.Status;
+
+import net.dpml.station.Station;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.InvalidArtifactException;
+import net.dpml.transit.ContentHandler;
+import net.dpml.transit.Transit;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.annotation.LifestylePolicy.SINGLETON;
+
+/**
+ * Generic application handler that establishes a dedicated handler based 
+ * on the type of resource exposed by a codebase uri.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ at Component( lifestyle=SINGLETON )
+public class Main extends UnicastRemoteObject implements Tool, Station
+{
+    //------------------------------------------------------------------------------
+    // static
+    //------------------------------------------------------------------------------
+    
+    private static final String DEFAULT_PLAN_URI_VALUE = "local:plan:dpml/metro/default";
+    private static final String STATION_CONNECTOR_VALUE = "dpml/station";
+    
+    //------------------------------------------------------------------------------
+    // state
+    //------------------------------------------------------------------------------
+    
+    private final Logger m_logger;
+    private Appliance m_plan;
+    private Thread m_thread;
+    //private JMXServiceURL m_jmx;
+    //private JMXConnectorServer m_server;
+    
+   /**
+    * The application handler class is a generic component handler that delegates
+    * application deployment processes to dedicated handlers based on the codebase 
+    * type of the target application.  Normally this plugin is activated as a 
+    * consequence of invoking the <tt>metro</tt> commandline handler (which is 
+    * the default haviour of the <tt>station</tt> when deployment local processes).
+    * The following command list help about the <tt>metro</tt> commandline handler:
+    * <pre>$ metro help
+Usage:
+metro <uri> [-server] | -help
+options
+  <uri>                    Application codebase part uri.
+  -command                 Enables command mode.
+  -help                    Prints command help and exits.
+  -version                 Prints version info and exits.
+    * </pre>
+    * An example commandline and resulting log of an application launch 
+    * using <tt>metro</tt> is show below:
+    * <pre>
+$ metro -command link:part:dpml/lang/dpml-lang-sample
+
+[2756 ] [INFO   ] (dpml.metro): commissioning hello
+[2756 ] [INFO   ] (hello): pid: [2756]
+[2756 ] [INFO   ] (hello): message: Hello
+[2756 ] [INFO   ] (hello): port: 0
+[2756 ] [INFO   ] (hello): target: artifact:jar:dpml/lang/dpml-lang-sample#SNAPSHOT
+[2756 ] [INFO   ] (hello): starting
+[2756 ] [INFO   ] (hello): started
+[2756 ] [INFO   ] (dpml.metro): decommissioning hello
+[2756 ] [INFO   ] (hello): stopping
+[2756 ] [INFO   ] (hello): stopped
+    * </pre>
+    *
+    * @param logger the assigned logging channel
+    * @exception Exception if an error occurs
+    */
+    public Main( Logger logger ) throws Exception
+    {
+        super();
+        
+        m_logger = logger;
+    }
+    
+    public Set<SourceVersion> getSourceVersions()
+    {
+        return Collections.unmodifiableSet(
+          EnumSet.range(
+            SourceVersion.RELEASE_4,
+            SourceVersion.latest() ) );
+    }
+    
+   /**
+    * Run the Metro tool.
+    */
+    public int run( InputStream in, OutputStream out, OutputStream err, String... arguments )
+    {
+        Thread.currentThread().setContextClassLoader( 
+          getClass().getClassLoader() );
+          
+        for( int i=0; i<arguments.length; i++ )
+        {
+            String arg = arguments[i];
+            if( m_logger.isTraceEnabled() )
+            {
+                m_logger.trace( "  arg: " + ( i + 1 ) + ": " + arg );
+            }
+            if( "-help".equals( arg ) )
+            {
+                printHelpMessage();
+                return 0;
+            }
+            if( "-version".equals( arg ) )
+            {
+                printVersionMessage();
+                return 0;
+            }
+        }
+        
+        try
+        {
+            return execute( arguments );
+        }
+        catch( Throwable e )
+        {
+            m_logger.error( "Execution error.", e );
+            return -1;
+        }
+    }
+    
+    private int execute( String... args ) throws Exception
+    {
+        String name = System.getProperty( STATION_CONNECTOR_KEY, STATION_CONNECTOR_VALUE );
+        CommandLine line = getCommandLine( args );
+        if( null == line )
+        {
+            return -1;
+        }
+        
+        int port = getPortValue( line, Registry.REGISTRY_PORT );
+        if( line.hasOption( SERVER_COMMAND ) )
+        {
+            Registry registry = resolveRegistry( port );
+            
+            LoggingServer.init();
+            
+            //m_jmx = getJMXServiceURL( port );
+            //m_server = getJMXConnectorServer( m_jmx );
+            //m_server.start();
+            
+            URI uri = getURI( line );
+            m_thread = Thread.currentThread();
+            
+            URL url = Artifact.toURL( uri );
+            ClassLoader current = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "resolving plan [" + url + "]" );
+            }
+            try
+            {
+                m_plan = (Appliance) url.getContent( new Class[]{ Appliance.class } );
+            }
+            finally
+            {
+                Thread.currentThread().setContextClassLoader( current );
+            }
+            if( null == m_plan )
+            {
+                if( getLogger().isErrorEnabled() )
+                {
+                    final String error =
+                      "Unable to resolve ["
+                      + url
+                      + "] to an appliance.";
+                    getLogger().error( error );
+                }
+                return -1;
+            }
+            
+            registry.bind( name, this );
+            
+            try
+            {
+                if( getLogger().isTraceEnabled() )
+                {
+                    getLogger().trace( "commissioning plan" );
+                }
+                m_plan.commission();
+                if( getLogger().isTraceEnabled() )
+                {
+                    getLogger().trace( "plan commissioning complete" );
+                }
+                return 1;
+            }
+            catch( Exception e )
+            {
+                final String error = 
+                  "Plan deployment error.";
+                if( getLogger().isErrorEnabled() )
+                {
+                    getLogger().error( error, e );
+                }
+                m_plan.decommission();
+                return -1;
+            }
+        }
+        else if( line.hasOption( STARTUP_COMMAND ) )
+        {
+            URI uri = getURI( line );
+            if( getLogger().isInfoEnabled() )
+            {
+                getLogger().info( "station startup" );
+            }
+            
+            //
+            // otherwise we are creating a sub-process with a sticky connector
+            // and we locate the appliance from the connector, initiate appliance 
+            // commissioning, and given a successfull startup we exit without 
+            // disrupting the launched sub-process
+            //
+            
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "creating station subprocess" );
+            }
+            List<String> commands = new ArrayList<String>();
+            commands.add( "station" );
+            commands.add( 
+              "-D" 
+              + STATION_CONNECTOR_KEY 
+              + "=" 
+              + STATION_CONNECTOR_VALUE );
+            //commands.add( 
+            //  "-D" 
+            //  + STATION_JMX_URI_KEY 
+            //  + "=" 
+            //  + m_jmx.toString() );
+            commands.add( "server" );
+            commands.add( "-port" );
+            commands.add( "" + port );
+            commands.add( uri.toASCIIString() );
+            
+            ProcessBuilder builder = new ProcessBuilder( commands );
+            builder.redirectErrorStream( true );
+            
+            if( getLogger().isTraceEnabled() )
+            {
+                StringBuffer buffer = new StringBuffer( "station command: " );
+                for( String command : commands )
+                {
+                    buffer.append( command );
+                    buffer.append( " " );
+                }
+                getLogger().trace( buffer.toString() );
+            }
+            
+            // execute the process
+            
+            Process process = builder.start();
+            //setShutdownHook( process ); // <-- need to enable this, but add removeShutdownHook before we return
+            OutputStreamReader output = 
+              new OutputStreamReader( m_logger, process.getInputStream() );
+            output.setDaemon( true );
+            output.start();
+            
+            waitForThis( port, name );
+            
+            if( getLogger().isInfoEnabled() )
+            {
+                getLogger().info( "startup complete" );
+            }
+            
+            return 0;
+        }
+        else if( line.hasOption( SHUTDOWN_COMMAND ) )
+        {
+            try
+            {
+                Station station = getStation( port );
+                if( getLogger().isInfoEnabled() )
+                {
+                    getLogger().info( "initiating remote shutdown" );
+                }
+                station.shutdown();
+                if( getLogger().isInfoEnabled() )
+                {
+                    getLogger().info( "remote shutdown request completed" );
+                }
+                return 0;
+            }
+            catch( ConnectException e )
+            {
+                if( getLogger().isWarnEnabled() )
+                {
+                    getLogger().warn( "Station not running" );
+                }
+                return -1;
+            }
+            catch( Exception e )
+            {
+                final String error = "Shutdown error.";
+                if( getLogger().isErrorEnabled() )
+                {
+                    getLogger().error( error, e );
+                }
+                return -1;
+            }
+        }
+        else if( line.hasOption( INFO_COMMAND ) )
+        {
+            try
+            {
+                Station station = getStation( port );
+                if( getLogger().isInfoEnabled() )
+                {
+                    getLogger().info( "Station running on port [" + port + "]" );
+                }
+            }
+            catch( StationNotBoundException e )
+            {
+                if( getLogger().isInfoEnabled() )
+                {
+                    getLogger().info( "Station not bound on port [" + port + "]"  );
+                }
+            }
+            catch( ConnectException e )
+            {
+                if( getLogger().isInfoEnabled() )
+                {
+                    getLogger().info( "Station not running" );
+                }
+            }
+            return 0;
+        }
+        else
+        {
+            final String error = 
+              "Invalid command state.";
+            if( getLogger().isErrorEnabled() )
+            {
+                getLogger().error( error );
+            }
+            return -1;
+        }
+    }
+    
+    private JMXServiceURL getJMXServiceURL( int port ) throws MalformedURLException
+    {
+        return new JMXServiceURL( 
+            "service:jmx:rmi:///jndi/rmi://localhost:" 
+            + port 
+            + "/dpml-station-jmx");
+    }
+    
+    private JMXConnectorServer getJMXConnectorServer( JMXServiceURL url ) throws IOException
+    {
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+        return JMXConnectorServerFactory.newJMXConnectorServer( url, null, server ); 
+    }
+
+    private void waitForThis( int port, String name ) // TODO: add timeout support
+    {
+        Station station = null;
+        while( null == station )
+        {
+            try
+            {
+                Registry registry = LocateRegistry.getRegistry( port );
+                station = (Station) registry.lookup( name );
+            }
+            catch( Exception ie )
+            {
+                try
+                {
+                    Thread.currentThread().sleep( 100 );
+                }
+                catch( InterruptedException e )
+                {
+                }
+            }
+        }
+    }
+    
+    public void shutdown() throws RemoteException
+    {
+        if( null != m_plan )
+        {
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "initiating station process shutdown" );
+            }
+            m_plan.decommission();
+            Terminator terminator = new Terminator( m_thread, this );
+            terminator.setName( "DPML Station Terminator" );
+            terminator.start();
+            /*
+            if( null != m_server )
+            {
+                try
+                {
+                    m_server.stop();
+                }
+                catch( IOException e )
+                {
+                    if( getLogger().isWarnEnabled() )
+                    {
+                        getLogger().warn( "JMX connector server shutdown error.", e );
+                    }
+                }
+            }
+            */
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "station process shutdown complete" );
+            }
+        }
+    }
+    
+    private class Terminator extends Thread
+    {
+        private Thread m_thread;
+        private Station m_station;
+        
+        Terminator( Thread thread, Station station )
+        {
+            m_thread = thread;
+            m_station = station;
+        }
+        
+        public void run()
+        {
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "executing terminator" );
+            }
+            try
+            {
+                UnicastRemoteObject.unexportObject( m_station, false );
+            }
+            catch( Throwable e )
+            {
+                if( getLogger().isWarnEnabled() )
+                {
+                    final String error = 
+                      "Ignoring unexpected error while unexporting the station.";
+                    getLogger().warn( error, e );
+                }
+            }
+            try
+            {
+                UnicastRemoteObject.unexportObject( m_plan, false );
+            }
+            catch( Throwable e )
+            {
+                if( getLogger().isWarnEnabled() )
+                {
+                    final String error = 
+                      "Ignoring unexpected error while unexporting the plan.";
+                    getLogger().warn( error, e );
+                }
+            }
+            try
+            {
+                if( getLogger().isTraceEnabled() )
+                {
+                    getLogger().trace( "interrupting " + m_thread );
+                }
+                m_thread.interrupt();
+            }
+            catch( Throwable e )
+            {
+                if( getLogger().isWarnEnabled() )
+                {
+                    final String error = "interupted";
+                    getLogger().warn( error, e );
+                }
+            }
+            if( getLogger().isTraceEnabled() )
+            {
+                getLogger().trace( "termination completed" );
+            }
+        }
+    }
+    
+    private Station getStation( int port ) throws Exception
+    {
+        Registry registry = LocateRegistry.getRegistry( port );
+        try
+        {
+            return (Station) registry.lookup( STATION_CONNECTOR_VALUE );
+        }
+        catch( NotBoundException nbe )
+        {
+            final String error = 
+              "Station not bound on ["
+              + port
+              + "] under ["
+              + STATION_CONNECTOR_VALUE
+              + "] on registry ["
+              + registry 
+              + "]";
+            throw new StationNotBoundException( error );
+        }
+    }
+
+    private Registry resolveRegistry( int port )throws ApplianceException
+    {
+        try
+        {
+            Registry registry = LocateRegistry.createRegistry( port );
+            getLogger().info( "created local registry on port " + port );
+            return registry;
+        }
+        catch( RemoteException re )
+        {
+            try
+            {
+                Registry registry = LocateRegistry.getRegistry( port );
+                getLogger().info( "using local registry on port " + port );
+                return registry;
+            }
+            catch( RemoteException e )
+            {
+                final String error = 
+                  "Unable to locate or create RMI registry to due a remote exeception.";
+                throw new ApplianceException( error, e );
+            }
+        }
+    }
+    
+    private URI getURI( CommandLine line )
+    {
+        URI uri = (URI) line.getValue( CODEBASE, null );
+        if( null == uri )
+        {
+            return URI.create( DEFAULT_PLAN_URI_VALUE );
+        }
+        else
+        {
+            return uri;
+        }
+    }
+    
+    private int getPortValue( CommandLine line, int defaultPort )
+    {
+        if( line.hasOption( PORT_OPTION ) )
+        {
+            Number number = (Number) line.getValue( PORT_OPTION, null );
+            if( null != number )
+            {
+                return number.intValue();
+            }
+        }
+        return defaultPort;
+    }
+    
+    private CommandLine getCommandLine( String[] args ) throws Exception
+    {
+        try
+        {
+            Parser parser = new Parser();
+            parser.setGroup( COMMAND_GROUP );
+            return parser.parse( args );
+        }
+        catch( TooManyArgumentsException e )
+        {
+            String message = e.getMessage();
+            m_logger.error( message );
+            return null;
+        }
+        catch( OptionException oe )
+        {
+            String message = oe.getMessage();
+            m_logger.error( message );
+            return null;
+        }
+    }
+    
+    private void printVersionMessage()
+    {
+        StringBuffer buffer = new StringBuffer( "version" );
+        buffer.append( "\n" );
+        buffer.append( "\n  DPML Station" );
+        buffer.append( "\n  Version @PROJECT-VERSION@" );
+        buffer.append( "\n  Copyright 2005-2007 Stephen J. McConnell" );
+        buffer.append( "\n  Digital Product Management Laboratory" );
+        String message = buffer.toString();
+        m_logger.info( message );
+    }
+    
+    private void printHelpMessage()
+    {
+        StringBuffer buffer = new StringBuffer( "help" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Description:" );
+        buffer.append( "\n" );
+        buffer.append( "\n    Process management controller." );
+        buffer.append( "\n" );
+        buffer.append( "\n  Usage: $ station startup [<uri>] | info | shutdown | -help | -version" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Common Options:" );
+        buffer.append( "\n" );
+        buffer.append( "\n    -help              list command help and exit" );
+        buffer.append( "\n    -version           list version info and exit" );
+        buffer.append( "\n    -port              override the RMI Registry port value" );
+        buffer.append( "\n" );
+        buffer.append( "\n  Commands:" );
+        buffer.append( "\n" );
+        buffer.append( "\n    startup [<uri>]    startup the station" );
+        buffer.append( "\n" );
+        buffer.append( "\n        <uri>          uri referencing a plan datatype" );
+        buffer.append( "\n                       if not supplied the default station deployment" );
+        buffer.append( "\n                       plan (local:plan:dpml/station/default) will" );
+        buffer.append( "\n                       be selected" );
+        buffer.append( "\n" );
+        buffer.append( "\n        -server        enables server execution mode" );
+        buffer.append( "\n" );
+        buffer.append( "\n    info               list station operational status and exit" );
+        buffer.append( "\n" );
+        buffer.append( "\n    shutdown           shutdown the station" );
+        buffer.append( "\n" );
+        buffer.append( "\n" );
+        String message = buffer.toString();
+        m_logger.info( message );
+    }
+    
+    //------------------------------------------------------------------------------
+    // internals
+    //------------------------------------------------------------------------------
+    
+    private Logger getLogger()
+    {
+        return m_logger;
+    }
+
+    //-----------------------------------------------------------------------------
+    // CLI
+    //-----------------------------------------------------------------------------
+
+    private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder();
+    private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder();
+    private static final GroupBuilder GROUP_BUILDER = new GroupBuilder();
+    private static final CommandBuilder COMMAND_BUILDER = new CommandBuilder();
+
+    private static final NumberValidator PORT_VALIDATOR = NumberValidator.getIntegerInstance();
+    private static final URIValidator URI_VALIDATOR = new URIValidator();
+    
+    private static final Option PORT_OPTION = 
+      OPTION_BUILDER
+        .withShortName( "port" )
+        .withDescription( "RMI Registry port." )
+        .withRequired( false )
+        .withArgument(
+          ARGUMENT_BUILDER 
+            .withDescription( "Registry port." )
+            .withName( "port" )
+            .withMinimum( 0 )
+            .withMaximum( 1 )
+            .withValidator( PORT_VALIDATOR )
+            .create() )
+        .create();
+    
+    private static final Option SERVER_OPTION =
+      OPTION_BUILDER
+        .withShortName( "server" )
+        .withDescription( "Enables server execution mode." )
+        .create();
+    
+    private static final Option SHUTDOWN_OPTION =
+      OPTION_BUILDER
+        .withShortName( "shutdown" )
+        .withShortName( "s" )
+        .withDescription( "Shutdown the station." )
+        .create();
+    
+    private static final Option CODEBASE = 
+        ARGUMENT_BUILDER
+          .withName( "codebase" )
+          .withDescription( "URI referencing a plan datastructure." )
+          .withValidator( new URIValidator() )
+          .create();
+
+    private static final Group SERVER_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 2 )
+        .withOption( PORT_OPTION )
+        .withOption( CODEBASE )
+        .create();
+    
+    private static final Option SERVER_COMMAND =
+      COMMAND_BUILDER
+        .withName( "server" )
+        .withDescription( "Server mode." )
+        .withChildren( SERVER_GROUP )
+        .create();
+    
+    private static final Group INFO_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 1 )
+        .withOption( PORT_OPTION )
+        .create();
+    
+    private static final Option INFO_COMMAND =
+      COMMAND_BUILDER
+        .withName( "info" )
+        .withDescription( "Station status report." )
+        .withChildren( INFO_GROUP )
+        .create();
+    
+    private static final Group STARTUP_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 2 )
+        .withOption( PORT_OPTION )
+        //.withOption( SERVER_OPTION )
+        .withOption( CODEBASE )
+        .create();
+    
+    private static final Option STARTUP_COMMAND =
+      COMMAND_BUILDER
+        .withName( "startup" )
+        .withDescription( "Startup the station." )
+        .withChildren( STARTUP_GROUP )
+        .create();
+    
+    private static final Group SHUTDOWN_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 1 )
+        .withOption( PORT_OPTION )
+        .create();
+
+    private static final Option SHUTDOWN_COMMAND =
+      COMMAND_BUILDER
+        .withName( "shutdown" )
+        .withDescription( "Shutdown the station." )
+        .withChildren( SHUTDOWN_GROUP )
+        .create();
+    
+    private static final Group COMMAND_GROUP =
+      GROUP_BUILDER
+        .withMinimum( 0 )
+        .withMaximum( 1 )
+        .withOption( INFO_COMMAND )
+        .withOption( STARTUP_COMMAND )
+        .withOption( SHUTDOWN_COMMAND )
+        .withOption( SERVER_COMMAND )
+        .create();
+
+    private static void setShutdownHook( final Process process )
+    {
+        Runtime.getRuntime().addShutdownHook(
+          new Thread()
+          {
+            public void run()
+            {
+                try
+                {
+                    process.destroy();
+                }
+                catch( Throwable e )
+                {
+                    e.printStackTrace();
+                }
+            }
+          }
+        );
+    }
+}

Added: trunk/main/metro/station/src/main/dpml/station/console/StationNotBoundException.java
===================================================================
--- trunk/main/metro/station/src/main/dpml/station/console/StationNotBoundException.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/station/src/main/dpml/station/console/StationNotBoundException.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004-2007 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package dpml.station.console;
+
+import net.dpml.station.StationException;
+
+import org.w3c.dom.Element;
+
+
+/**
+ * Exception thrown when an attempt is made to reference an unbound station.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StationNotBoundException extends StationException
+{
+   /**
+    * Serial version identifier.
+    */
+    static final long serialVersionUID = 1L;
+
+   /**
+    * Construct a new <code>StationException</code>.
+    *
+    * @param message the error message
+    */
+    public StationNotBoundException( final String message )
+    {
+        super( message, null, null );
+    }
+    
+}
+

Modified: trunk/main/metro/test/build.xml
===================================================================
--- trunk/main/metro/test/build.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/build.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -17,244 +17,12 @@
   limitations under the License.
 -->
 
-<project name="dpml-metro-test" default="install"
-    xmlns:transit="antlib:net.dpml.transit" 
-    xmlns:x="dpml:depot" 
-    xmlns:c="dpml:metro" >
+<project default="install" xmlns:x="antlib:dpml.tools" >
 
-  <transit:import uri="local:template:dpml/tools/standard"/>
+  <x:import uri="local:template:dpml/tools/standard"/>
 
-  <target name="build" depends="standard.build">
-
-    <rmic base="${project.target.classes.main.dir}" 
-        classpathref="project.compile.path">
-      <include name="**/ManagedComponent#DefaultMonitor.class"/>
-    </rmic>
-
-    <x:plugin uri="link:part:dpml/metro/dpml-metro-tools"/>
-
-    <!-- create the test component types -->
-
-    <c:type class="net.dpml.test.ExampleComponent" name="example">
-      <state>
-        <trigger event="initialization">
-          <transition name="init" target="available"/>
-        </trigger>
-        <state name="available">
-          <trigger event="termination">
-            <transition name="terminate" target="../terminated"/>
-          </trigger>
-        </state>
-        <state name="terminated" terminal="true"/>
-      </state>
-    </c:type>
-    <c:type class="net.dpml.test.SingletonComponent" name="example" threadsafe="true"/>
-    <c:type class="net.dpml.test.ContextTestComponent" name="context" threadsafe="true"/>
-
-    <!-- create test components -->
-
-    <c:component dest="target/test/example.part" test="true"
-        type="net.dpml.test.ExampleComponent" name="example">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-    </c:component>
-
-    <c:component dest="target/test/example-2.part" test="true"
-        type="net.dpml.test.ExampleComponent" name="transient" collection="SOFT" lifestyle="transient">
-      <context>
-        <entry key="color">
-          <value class="int" value="100"/>
-          <value class="int" value="200"/>
-          <value class="int" value="0"/>
-        </entry>
-      </context>
-    </c:component>
-
-    <c:component dest="target/test/example-3.part" test="true" name="weak"
-        type="net.dpml.test.SingletonComponent" lifestyle="SINGLETON" collection="WEAK">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-    </c:component>
-
-    <c:component dest="target/test/example-4.part" test="true"
-        type="net.dpml.test.SingletonComponent" name="singleton" collection="HARD">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-    </c:component>
-
-    <c:component dest="target/test/context.part" test="true"
-        type="net.dpml.test.ContextTestComponent" name="context" collection="SOFT">
-      <context>
-        <entry key="color" method="RED"/>
-        <entry key="integer" value="0"/>
-        <entry key="short" value="0"/>
-        <entry key="long" value="0"/>
-        <entry key="byte" value="0"/>
-        <entry key="double" value="0"/>
-        <entry key="float" value="0.5"/>
-        <entry key="char" value="x"/>
-        <entry key="boolean" value="true"/>
-        <entry key="file" value="$${work}"/>
-        <entry key="tempFile" value="$${temp}"/>
-        <entry key="URI" value="$${uri}"/>
-        <entry key="name" value="$${name}"/>
-        <entry key="path" value="$${path}"/>
-      </context>
-    </c:component>
-
-    <!-- create the composite component -->
-
-    <types xmlns="dpml:metro">
-      <type class="net.dpml.test.composite.ChildComponent" name="child"/>
-      <type class="net.dpml.test.composite.CompositeComponent" name="parent"/>
-      <type class="net.dpml.test.composite.PartsComponent" name="parent"/>
-    </types>
-
-    <c:component dest="target/test/composite.part" test="true" 
-        type="net.dpml.test.composite.CompositeComponent" collection="HARD">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-      <parts>
-        <component type="net.dpml.test.composite.ChildComponent" key="child">
-          <context>
-            <entry key="color" method="BLUE"/>
-          </context>
-        </component>
-      </parts>
-    </c:component>
-
-    <c:component dest="target/test/parts.part" test="true" 
-        type="net.dpml.test.composite.PartsComponent" collection="HARD">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-      <parts>
-        <component type="net.dpml.test.composite.ChildComponent" key="child">
-          <context>
-            <entry key="color" method="BLUE"/>
-          </context>
-        </component>
-      </parts>
-    </c:component>
-
-    <!-- create the lifecycle managed component -->
-
-    <c:type class="net.dpml.test.lifecycle.StartableComponent" name="lifecycle">
-      <state>
-        <trigger event="initialization">
-          <transition name="init" target="started">
-            <operation name="startup" method="start"/>
-          </transition>
-        </trigger>
-        <state name="started">
-          <transition name="stop" target="../stopped">
-            <operation name="stop" method="stop"/>
-          </transition>
-          <trigger event="termination">
-            <apply id="stop"/>
-          </trigger>
-        </state>
-        <state name="stopped">
-          <transition name="start" target="../started">
-            <operation name="start" method="start"/>
-          </transition>
-        </state>
-      </state>
-    </c:type>
-
-    <c:component dest="target/test/lifecycle.part" test="true" 
-        type="net.dpml.test.lifecycle.StartableComponent" collection="HARD"/>
-
-    <!-- categories component -->
-
-    <c:type class="net.dpml.test.categories.CategoriesComponent" name="categories" lifestyle="thread">
-      <categories>
-        <category name="alpha"/>
-        <category name="beta"/>
-      </categories>
-    </c:type>
-
-    <c:component dest="target/test/categories.part" test="true" activation="STARTUP"
-        type="net.dpml.test.categories.CategoriesComponent" collection="hard">
-      <categories>
-        <category name="alpha" priority="warn"/>
-        <category name="beta" priority="error"/>
-      </categories>
-    </c:component>
-
-    <!-- part test component -->
-
-    <c:type class="net.dpml.test.part.ExampleComponent" name="test"/>
-    <c:component dest="target/test/test.part" test="true"
-        type="net.dpml.test.part.ExampleComponent">
-      <context>
-        <entry key="color" method="RED"/>
-      </context>
-    </c:component>
-
-    <!-- composite app-->
-
-    <c:types>
-      <type name="server" class="net.dpml.test.app.DefaultServer" lifestyle="singleton"/>
-      <type name="listener" class="net.dpml.test.app.DefaultListener" lifestyle="singleton"/>
-      <type name="demo" class="net.dpml.test.app.Demo" lifestyle="singleton"/>
-    </c:types>
-
-    <c:component type="net.dpml.test.app.Demo" 
-      dest="target/test/application.part" test="true" collection="hard">
-      <parts>
-        <component key="server" type="net.dpml.test.app.DefaultServer" >
-          <context>
-            <entry key="port" value="1010"/>
-          </context>
-        </component>
-        <component key="listener" type="net.dpml.test.app.DefaultListener" >
-          <context>
-            <entry key="server" lookup="net.dpml.test.app.Server"/>
-          </context>
-        </component>
-      </parts>
-    </c:component>
-
-    <!-- operations test -->
-
-    <c:type class="net.dpml.test.state.ManagedComponent" name="demo" lifestyle="thread">
-      <state>
-        <operation name="ping" method="ping"/>
-        <operation name="monitor"/>
-      </state>
-    </c:type>
-
-    <c:component dest="target/test/state.part" test="true" activation="STARTUP"
-        type="net.dpml.test.state.ManagedComponent" collection="hard"/>
-
-    <!-- array test -->
-
-    <c:type class="net.dpml.test.array.ArrayTestComponent" name="array"/>
-    <c:component dest="target/test/array.part" test="true"
-        type="net.dpml.test.array.ArrayTestComponent">
-      <context>
-        <entry key="values">
-          <value value="Hello"/>
-          <value value="World"/>
-        </entry>
-      </context>
-    </c:component>
-
-  </target>
-
-  <target name="install" depends="standard.install">
-    <c:catalog title="Test Catalog">
-      <fileset dir="${basedir}">
-        <include name="**/target/classes/main/**/*.type"/>
-      </fileset>
-    </c:catalog>
-  </target>
-
+  <target name="javadoc"/>
+  
 </project>
 
 

Added: trunk/main/metro/test/etc/data/application.xml
===================================================================
--- trunk/main/metro/test/etc/data/application.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/etc/data/application.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+
+<application xmlns="dpml:application">
+
+  <info name="hello"/>
+  
+  <process startup="0" shutdown="0" path="target/test">
+    <environment>
+      <variable name="FOO" value="BAR"/>
+    </environment>
+    <properties>
+      <property name="foo" value="bar"/>
+    </properties>
+  </process>
+  
+  <codebase uri="link:part:dpml/lang/dpml-lang-sample?message=Hello%20World,port=1024"/>
+
+</application>

Modified: trunk/main/metro/test/etc/data/logging.properties
===================================================================
--- trunk/main/metro/test/etc/data/logging.properties	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/etc/data/logging.properties	2007-02-08 23:33:09 UTC (rev 1821)
@@ -1,4 +1,7 @@
 .level=INFO
 sun.rmi.level=INFO
 sun.rmi.transport.tcp.level=INFO
-weak.level=FINE
\ No newline at end of file
+weak.level=FINE
+dpml.transit.level=WARNING
+dpml.lang.level=WARNING
+dpml.part.level=WARNING

Added: trunk/main/metro/test/etc/data/security.policy
===================================================================
--- trunk/main/metro/test/etc/data/security.policy	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/etc/data/security.policy	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,4 @@
+grant { 
+    permission java.security.AllPermission;
+};
+

Added: trunk/main/metro/test/etc/data/test.properties
===================================================================
--- trunk/main/metro/test/etc/data/test.properties	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/etc/data/test.properties	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,6 @@
+java.ext.dirs=${env.DPML_HOME}\share\lib\ext
+java.endorsed.dirs=${env.DPML_HOME}\share\lib\endorsed
+java.system.class.loader=dpml.util.SystemClassLoader
+java.protocol.handler.pkgs=dpml.transit
+java.rmi.server.RMIClassLoaderSpi=dpml.util.FederatingClassLoader
+dpml.class.path=link:jar:dpml/lang/dpml-lang-part

Added: trunk/main/metro/test/project.xml
===================================================================
--- trunk/main/metro/test/project.xml	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/project.xml	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-metro-test">
+
+  <info title="DPML Metro Test Suite"/>
+  
+  <dependencies>
+    <runtime>
+      <include ref="dpml/metro/dpml-metro-appliance"/>
+    </runtime>
+    <test>
+      <include ref="org/apache/ant/ant-junit"/>
+    </test>
+  </dependencies>
+  
+</project>
+

Added: trunk/main/metro/test/src/test/net/dpml/test/LocalTestCase.java
===================================================================
--- trunk/main/metro/test/src/test/net/dpml/test/LocalTestCase.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/src/test/net/dpml/test/LocalTestCase.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.test;
+
+import dpml.util.DefaultLogger;
+import dpml.util.ExceptionHelper;
+
+import java.net.URI;
+import java.net.URL;
+import java.rmi.RMISecurityManager;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import net.dpml.appliance.Appliance;
+
+import net.dpml.transit.Artifact;
+
+import net.dpml.util.Logger;
+
+/**
+ * Appliance testcase.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class LocalTestCase extends TestCase
+{
+    private Logger m_logger = new DefaultLogger( "test" );
+    
+    public void testClassicAppliance() throws Exception
+    {
+        URI uri = URI.create( "link:appliance:dpml/metro/demo" );
+        URL url = Artifact.toURL( uri );
+        Appliance appliance = (Appliance) url.getContent( new Class[]{ Appliance.class } );
+        try
+        {
+            appliance.commission();
+        }
+        finally
+        {
+            appliance.decommission();
+        }
+    }
+
+    static
+    {
+        System.setSecurityManager( new RMISecurityManager() );
+    }
+}

Added: trunk/main/metro/test/src/test/net/dpml/test/PlanTestCase.java
===================================================================
--- trunk/main/metro/test/src/test/net/dpml/test/PlanTestCase.java	2007-02-08 23:32:32 UTC (rev 1820)
+++ trunk/main/metro/test/src/test/net/dpml/test/PlanTestCase.java	2007-02-08 23:33:09 UTC (rev 1821)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2006 Stephen J. McConnell.
+ *
+ * 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.
+ */
+
+package net.dpml.test;
+
+import dpml.util.DefaultLogger;
+import dpml.util.ExceptionHelper;
+
+import java.net.URI;
+import java.net.URL;
+import java.rmi.RMISecurityManager;
+
+import junit.framework.TestCase;
+
+import net.dpml.appliance.Appliance;
+
+import net.dpml.transit.Artifact;
+
+import net.dpml.util.Logger;
+
+/**
+ * Plan testcase.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PlanTestCase extends TestCase
+{
+    private Logger m_logger = new DefaultLogger( "test" );
+    
+    public void testPlanDeployment() throws Exception
+    {
+        URI uri = URI.create( "link:plan:dpml/metro/demo" );
+        URL url = Artifact.toURL( uri );
+        Appliance appliance = (Appliance) url.getContent( new Class[]{ Appliance.class } );
+        try
+        {
+            appliance.commission();
+        }
+        finally
+        {
+            appliance.decommission();
+        }
+    }
+    
+    static
+    {
+        System.setSecurityManager( new RMISecurityManager() );
+    }
+}




More information about the notify-dpml mailing list