Skip to Content.
Sympa Menu

notify-dpml - r1859 - in trunk/main/lang: . part part/src part/src/main part/src/main/dpml part/src/main/dpml/appliance part/src/main/dpml/lang part/src/main/dpml/state part/src/main/net part/src/main/net/dpml part/src/main/net/dpml/annotation part/src/main/net/dpml/appliance part/src/main/net/dpml/lang part/src/main/net/dpml/runtime part/src/main/net/dpml/state part/src/test part/src/test/META-INF part/src/test/META-INF/services part/src/test/dpml part/src/test/dpml/lang part/src/test/net part/src/test/net/dpml part/src/test/net/dpml/runtime part/src/test/net/dpml/runtime/composition part/src/test/net/dpml/runtime/context part/src/test/net/dpml/runtime/isolation part/src/test/net/dpml/runtime/lifecycle part/src/test/net/dpml/runtime/lifestyle part/src/test/net/dpml/runtime/profile part/src/test/net/dpml/runtime/service part/src/test/org part/src/test/org/acme sample sample/etc sample/src sample/src/main sample/src/main/org sample/src/main/org/acme

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: mcconnell at BerliOS <mcconnell AT mail.berlios.de>
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: r1859 - in trunk/main/lang: . part part/src part/src/main part/src/main/dpml part/src/main/dpml/appliance part/src/main/dpml/lang part/src/main/dpml/state part/src/main/net part/src/main/net/dpml part/src/main/net/dpml/annotation part/src/main/net/dpml/appliance part/src/main/net/dpml/lang part/src/main/net/dpml/runtime part/src/main/net/dpml/state part/src/test part/src/test/META-INF part/src/test/META-INF/services part/src/test/dpml part/src/test/dpml/lang part/src/test/net part/src/test/net/dpml part/src/test/net/dpml/runtime part/src/test/net/dpml/runtime/composition part/src/test/net/dpml/runtime/context part/src/test/net/dpml/runtime/isolation part/src/test/net/dpml/runtime/lifecycle part/src/test/net/dpml/runtime/lifestyle part/src/test/net/dpml/runtime/profile part/src/test/net/dpml/runtime/service part/src/test/org part/src/test/org/acme sample sample/etc sample/src sample/src/main sample/src/main/org sample/src/main/org/acme
  • Date: Fri, 9 Feb 2007 02:30:10 +0100

Author: mcconnell
Date: 2007-02-09 02:29:45 +0100 (Fri, 09 Feb 2007)
New Revision: 1859

Added:
trunk/main/lang/part/project.xml
trunk/main/lang/part/src/
trunk/main/lang/part/src/main/
trunk/main/lang/part/src/main/dpml/
trunk/main/lang/part/src/main/dpml/appliance/
trunk/main/lang/part/src/main/dpml/appliance/AbstractAppliance.java
trunk/main/lang/part/src/main/dpml/appliance/ApplianceHelper.java
trunk/main/lang/part/src/main/dpml/appliance/StandardAppliance.java
trunk/main/lang/part/src/main/dpml/lang/
trunk/main/lang/part/src/main/dpml/lang/Classpath.java
trunk/main/lang/part/src/main/dpml/lang/Construct.java
trunk/main/lang/part/src/main/dpml/lang/ContextInvocationHandler.java
trunk/main/lang/part/src/main/dpml/lang/DOM3DocumentBuilder.java
trunk/main/lang/part/src/main/dpml/lang/DOMInput.java
trunk/main/lang/part/src/main/dpml/lang/DefaultPartManager.java
trunk/main/lang/part/src/main/dpml/lang/Disposable.java
trunk/main/lang/part/src/main/dpml/lang/DocumentRuntimeException.java
trunk/main/lang/part/src/main/dpml/lang/Info.java
trunk/main/lang/part/src/main/dpml/lang/LoggingInvocationHandler.java
trunk/main/lang/part/src/main/dpml/lang/Part.java
trunk/main/lang/part/src/main/dpml/lang/StandardNamespaceResolver.java
trunk/main/lang/part/src/main/dpml/lang/Value.java
trunk/main/lang/part/src/main/dpml/lang/ValueDecoder.java
trunk/main/lang/part/src/main/dpml/lang/ValueException.java
trunk/main/lang/part/src/main/dpml/lang/ValueRuntimeException.java
trunk/main/lang/part/src/main/dpml/state/
trunk/main/lang/part/src/main/dpml/state/DefaultInterface.java
trunk/main/lang/part/src/main/dpml/state/DefaultOperation.java
trunk/main/lang/part/src/main/dpml/state/DefaultState.java
trunk/main/lang/part/src/main/dpml/state/DefaultTransition.java
trunk/main/lang/part/src/main/dpml/state/DefaultTrigger.java
trunk/main/lang/part/src/main/dpml/state/NullState.java
trunk/main/lang/part/src/main/dpml/state/StateBuilderRuntimeException.java
trunk/main/lang/part/src/main/dpml/state/StateDecoder.java
trunk/main/lang/part/src/main/dpml/state/StateEncoder.java
trunk/main/lang/part/src/main/net/
trunk/main/lang/part/src/main/net/dpml/
trunk/main/lang/part/src/main/net/dpml/annotation/
trunk/main/lang/part/src/main/net/dpml/annotation/Activation.java
trunk/main/lang/part/src/main/net/dpml/annotation/ActivationPolicy.java
trunk/main/lang/part/src/main/net/dpml/annotation/CollectionPolicy.java
trunk/main/lang/part/src/main/net/dpml/annotation/Component.java
trunk/main/lang/part/src/main/net/dpml/annotation/Context.java
trunk/main/lang/part/src/main/net/dpml/annotation/LifestylePolicy.java
trunk/main/lang/part/src/main/net/dpml/annotation/Parts.java
trunk/main/lang/part/src/main/net/dpml/annotation/Services.java
trunk/main/lang/part/src/main/net/dpml/annotation/package-info.java
trunk/main/lang/part/src/main/net/dpml/appliance/
trunk/main/lang/part/src/main/net/dpml/appliance/Appliance.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceConnector.java

trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceContentManager.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceError.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceEvent.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceException.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceFactory.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceListener.java
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceManager.java
trunk/main/lang/part/src/main/net/dpml/appliance/PlanManager.java
trunk/main/lang/part/src/main/net/dpml/appliance/package-info.java
trunk/main/lang/part/src/main/net/dpml/lang/
trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategy.java
trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategyHandler.java
trunk/main/lang/part/src/main/net/dpml/lang/Buffer.java
trunk/main/lang/part/src/main/net/dpml/lang/ClassLoaderHelper.java
trunk/main/lang/part/src/main/net/dpml/lang/DecodingException.java
trunk/main/lang/part/src/main/net/dpml/lang/DuplicateKeyException.java
trunk/main/lang/part/src/main/net/dpml/lang/NamespaceError.java
trunk/main/lang/part/src/main/net/dpml/lang/PartContentHandler.java
trunk/main/lang/part/src/main/net/dpml/lang/PartContentManager.java
trunk/main/lang/part/src/main/net/dpml/lang/PartError.java
trunk/main/lang/part/src/main/net/dpml/lang/PartException.java
trunk/main/lang/part/src/main/net/dpml/lang/PartManager.java
trunk/main/lang/part/src/main/net/dpml/lang/ServiceError.java
trunk/main/lang/part/src/main/net/dpml/lang/ServiceRegistry.java
trunk/main/lang/part/src/main/net/dpml/lang/SimpleServiceRegistry.java
trunk/main/lang/part/src/main/net/dpml/lang/StandardServiceRegistry.java
trunk/main/lang/part/src/main/net/dpml/lang/Strategy.java
trunk/main/lang/part/src/main/net/dpml/lang/StrategyHandler.java
trunk/main/lang/part/src/main/net/dpml/lang/TypeCastException.java
trunk/main/lang/part/src/main/net/dpml/lang/UnknownKeyException.java
trunk/main/lang/part/src/main/net/dpml/lang/UnknownServiceException.java
trunk/main/lang/part/src/main/net/dpml/lang/Version.java
trunk/main/lang/part/src/main/net/dpml/lang/package-info.java
trunk/main/lang/part/src/main/net/dpml/runtime/
trunk/main/lang/part/src/main/net/dpml/runtime/Component.java
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentError.java
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentEvent.java
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentException.java

trunk/main/lang/part/src/main/net/dpml/runtime/ComponentInvocationHandler.java
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentListener.java
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategy.java

trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategyHandler.java
trunk/main/lang/part/src/main/net/dpml/runtime/ContextDirective.java

trunk/main/lang/part/src/main/net/dpml/runtime/ContextInvocationHandler.java
trunk/main/lang/part/src/main/net/dpml/runtime/ContextModel.java
trunk/main/lang/part/src/main/net/dpml/runtime/DefaultStateMachine.java
trunk/main/lang/part/src/main/net/dpml/runtime/Directive.java
trunk/main/lang/part/src/main/net/dpml/runtime/EventQueue.java
trunk/main/lang/part/src/main/net/dpml/runtime/LifestyleHandler.java
trunk/main/lang/part/src/main/net/dpml/runtime/PartsDirective.java
trunk/main/lang/part/src/main/net/dpml/runtime/PartsInvocationHandler.java
trunk/main/lang/part/src/main/net/dpml/runtime/Profile.java
trunk/main/lang/part/src/main/net/dpml/runtime/Provider.java
trunk/main/lang/part/src/main/net/dpml/runtime/ProviderEvent.java
trunk/main/lang/part/src/main/net/dpml/runtime/Query.java
trunk/main/lang/part/src/main/net/dpml/runtime/StandardProvider.java
trunk/main/lang/part/src/main/net/dpml/runtime/Status.java
trunk/main/lang/part/src/main/net/dpml/runtime/package-info.java
trunk/main/lang/part/src/main/net/dpml/state/
trunk/main/lang/part/src/main/net/dpml/state/Action.java
trunk/main/lang/part/src/main/net/dpml/state/ApplyAction.java
trunk/main/lang/part/src/main/net/dpml/state/ExecAction.java
trunk/main/lang/part/src/main/net/dpml/state/IntegrityRuntimeException.java
trunk/main/lang/part/src/main/net/dpml/state/Interface.java
trunk/main/lang/part/src/main/net/dpml/state/Operation.java
trunk/main/lang/part/src/main/net/dpml/state/State.java
trunk/main/lang/part/src/main/net/dpml/state/StateEvent.java
trunk/main/lang/part/src/main/net/dpml/state/StateListener.java
trunk/main/lang/part/src/main/net/dpml/state/StateMachine.java
trunk/main/lang/part/src/main/net/dpml/state/Transition.java
trunk/main/lang/part/src/main/net/dpml/state/Trigger.java
trunk/main/lang/part/src/main/net/dpml/state/TriggerPolicy.java
trunk/main/lang/part/src/main/net/dpml/state/UnknownOperationException.java

trunk/main/lang/part/src/main/net/dpml/state/UnknownTransitionException.java
trunk/main/lang/part/src/main/net/dpml/state/package-info.java
trunk/main/lang/part/src/test/
trunk/main/lang/part/src/test/META-INF/
trunk/main/lang/part/src/test/META-INF/services/
trunk/main/lang/part/src/test/META-INF/services/org.acme.Gizmo
trunk/main/lang/part/src/test/META-INF/services/org.acme.Widget
trunk/main/lang/part/src/test/Widget.java
trunk/main/lang/part/src/test/dpml/
trunk/main/lang/part/src/test/dpml/lang/
trunk/main/lang/part/src/test/dpml/lang/AbstractTestCase.java
trunk/main/lang/part/src/test/dpml/lang/ConstructTestCase.java
trunk/main/lang/part/src/test/dpml/lang/ContextTestCase.java
trunk/main/lang/part/src/test/net/
trunk/main/lang/part/src/test/net/dpml/
trunk/main/lang/part/src/test/net/dpml/runtime/
trunk/main/lang/part/src/test/net/dpml/runtime/AbstractTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/composition/

trunk/main/lang/part/src/test/net/dpml/runtime/composition/CompositeTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/composition/ControllerTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/composition/GenericTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/composition/LookupTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/composition/SelectTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/context/
trunk/main/lang/part/src/test/net/dpml/runtime/context/ArrayTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/context/ContextualTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/isolation/

trunk/main/lang/part/src/test/net/dpml/runtime/isolation/SampleTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/lifecycle/
trunk/main/lang/part/src/test/net/dpml/runtime/lifecycle/StateTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/

trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/SingletonTestCase.java

trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/TransientTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/profile/
trunk/main/lang/part/src/test/net/dpml/runtime/profile/ProfileTestCase.java
trunk/main/lang/part/src/test/net/dpml/runtime/service/
trunk/main/lang/part/src/test/net/dpml/runtime/service/ForeignTestCase.java
trunk/main/lang/part/src/test/org/
trunk/main/lang/part/src/test/org/acme/
trunk/main/lang/part/src/test/org/acme/ArrayWidget.java
trunk/main/lang/part/src/test/org/acme/CompositeComponent.java
trunk/main/lang/part/src/test/org/acme/ContextualWidget.java
trunk/main/lang/part/src/test/org/acme/ControllerComponent.java
trunk/main/lang/part/src/test/org/acme/DefaultGizmo.java
trunk/main/lang/part/src/test/org/acme/DefaultWidget.java
trunk/main/lang/part/src/test/org/acme/ForeignWidget.java
trunk/main/lang/part/src/test/org/acme/GenericComponent.java
trunk/main/lang/part/src/test/org/acme/Gizmo.java
trunk/main/lang/part/src/test/org/acme/GizmoAdapter.java
trunk/main/lang/part/src/test/org/acme/Parameterizable.java
trunk/main/lang/part/src/test/org/acme/Sample.java
trunk/main/lang/part/src/test/org/acme/SelectComponent.java
trunk/main/lang/part/src/test/org/acme/SingletonWidget.java
trunk/main/lang/part/src/test/org/acme/StandaloneWidget.java
trunk/main/lang/part/src/test/org/acme/StandaloneWidget.xprofile
trunk/main/lang/part/src/test/org/acme/StandaloneWidgetAdapter.java
trunk/main/lang/part/src/test/org/acme/StateWidget.java
trunk/main/lang/part/src/test/org/acme/StateWidget.xgraph
trunk/main/lang/part/src/test/org/acme/TransientWidget.java
trunk/main/lang/part/src/test/org/acme/Widget.java
trunk/main/lang/part/src/test/org/acme/WidgetUsingGizmo.java
trunk/main/lang/sample/
trunk/main/lang/sample/etc/
trunk/main/lang/sample/etc/component.xml
trunk/main/lang/sample/project.xml
trunk/main/lang/sample/src/
trunk/main/lang/sample/src/main/
trunk/main/lang/sample/src/main/org/
trunk/main/lang/sample/src/main/org/acme/
trunk/main/lang/sample/src/main/org/acme/AnotherContext.java
trunk/main/lang/sample/src/main/org/acme/Hello.java
trunk/main/lang/sample/src/main/org/acme/HelloComponent.java
trunk/main/lang/sample/src/main/org/acme/HelloComponent.xgraph
trunk/main/lang/sample/src/main/org/acme/HelloConfiguration.java
Modified:
trunk/main/lang/module.xml
trunk/main/lang/part/bootstrap.properties
trunk/main/lang/part/bootstrap.xml
trunk/main/lang/part/build.xml
Log:
SDK 2.X staged commit.

Modified: trunk/main/lang/module.xml
===================================================================
--- trunk/main/lang/module.xml 2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/module.xml 2007-02-09 01:29:45 UTC (rev 1859)
@@ -1,92 +1,12 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
-<module name="lang" xmlns="link:xsd:dpml/lang/dpml-module#1.0">
+<module name="lang" xmlns="dpml:library">

<properties>
- <property name="project.micro.version" value="0"/>
+ <property name="project.javac.lint" value="unchecked"/>
</properties>

- <project name="dpml-module" basedir="module">
- <info title="DPML Library XSD Schema">
- <description>Formal XML specification of the index, module, project
and resource elements.</description>
- </info>
- <types>
- <type id="xsd" version="1.0"/>
- </types>
- <filters>
- <feature token="PROJECT-XSD-URI" id="uri" type="xsd"/>
- <feature token="PROJECT-XSD-SPEC-URI" id="uri" type="xsd"
alias="true"/>
- </filters>
- </project>
+ <project file="part/project.xml"/>
+ <!--<project file="library/project.xml"/>-->
+ <project file="sample/project.xml"/>

- <project name="dpml-part" basedir="part">
- <info title="DPML Part XSD Schema">
- <description>Formal XML specification of a part deployment
unit.</description>
- </info>
- <types>
- <type id="xsd" version="1.0"/>
- </types>
- <dependencies>
- <build>
- <include key="dpml-module"/>
- </build>
- </dependencies>
- <filters>
- <feature token="MODULE-XSD-SPEC-URI" id="uri" type="xsd"
ref="dpml/lang/dpml-module" alias="true"/>
- <feature token="PROJECT-XSD-SPEC-URI" id="uri" type="xsd"
alias="true"/>
- </filters>
- </project>
-
- <project name="dpml-state" basedir="state">
- <info title="DPML State XSD Schema">
- <description>Formal XML specification of a state transition
model.</description>
- </info>
- <types>
- <type id="xsd" version="1.0"/>
- </types>
- <filters>
- <feature token="PROJECT-XSD-URI" id="uri" type="xsd" alias="true"/>
- </filters>
- </project>
-
- <project name="dpml-component" basedir="component">
- <info title="DPML State XSD Schema">
- <description>Formal XML specification of the Metro component
descriptors and deployment directives.</description>
- </info>
- <types>
- <type id="xsd" version="1.0"/>
- </types>
- <dependencies>
- <build>
- <include key="dpml-part"/>
- <include key="dpml-type"/>
- </build>
- </dependencies>
- <filters>
- <feature token="PROJECT-XSD-LINK-URI" id="uri" type="xsd"
alias="true"/>
- <feature token="PART-XSD-LINK-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="MODULE-XSD-SPEC-URI" id="uri" type="xsd"
ref="dpml/lang/dpml-module" alias="true"/>
- </filters>
- </project>
-
- <project name="dpml-type" basedir="type">
- <info title="DPML Type XSD Schema">
- <description>Formal XML specification of the Metro component type
descriptors.</description>
- </info>
- <types>
- <type id="xsd" version="1.0"/>
- </types>
- <dependencies>
- <build>
- <include key="dpml-state"/>
- <include key="dpml-part"/>
- </build>
- </dependencies>
- <filters>
- <feature token="PROJECT-XSD-URI" id="uri" type="xsd" alias="true"/>
- <feature token="PART-XSD-URI" id="uri" type="xsd"
ref="dpml/lang/dpml-part" alias="true"/>
- <feature token="STATE-XSD-URI" id="uri" type="xsd"
ref="dpml/lang/dpml-state" alias="true"/>
- </filters>
- </project>
-
</module>

Modified: trunk/main/lang/part/bootstrap.properties
===================================================================
--- trunk/main/lang/part/bootstrap.properties 2007-02-09 01:28:27 UTC (rev
1858)
+++ trunk/main/lang/part/bootstrap.properties 2007-02-09 01:29:45 UTC (rev
1859)
@@ -1,2 +1,5 @@

+home = ../..
+project.test.fork = true
+
specification.version = 1.0

Modified: trunk/main/lang/part/bootstrap.xml
===================================================================
--- trunk/main/lang/part/bootstrap.xml 2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/bootstrap.xml 2007-02-09 01:29:45 UTC (rev 1859)
@@ -18,30 +18,180 @@
limitations under the License.
-->

-<project name="dpml-part" default="install" basedir=".">
+<project name="dpml-lang-part" default="install" basedir=".">

<property name="project.group" value="dpml/lang"/>
- <property name="project.name" value="dpml-part"/>
-
+ <property name="project.name" value="dpml-lang-part"/>
+
<property file="${basedir}/bootstrap.properties"/>
- <property name="home" value="../.."/>
+ <property file="${home}/bootstrap.properties"/>
<import file="${home}/bootstrap.xml"/>
+
+ <target name="setup-path" depends="init">
+ <property name="transit.jar.path"
+
location="${dpml.local.cache}/dpml/transit/jars/dpml-transit-main-${project.version}.jar"/>
+ <path id="project.main.path">
+ <pathelement location="${transit.jar.path}"/>
+ <pathelement location="${target.classes.dir}"/>
+ </path>
+ <path id="project.test.path">
+ <pathelement location="${transit.jar.path}"/>
+ <pathelement location="${ENV.ANT_HOME}/lib/ant.jar"/>
+ <pathelement location="${ENV.ANT_HOME}/lib/ant-junit.jar"/>
+ <pathelement
location="${target.deliverables.jars.dir}/${project.filename}"/>
+ <pathelement
location="${dpml.local.cache}/junit/jars/${junit.filename}"/>
+ </path>
+ </target>

<target name="init" depends="bootstrap.init">
- <property name="xsd.spec.uri"
value="link:xsd:${project.group}/${project.name}#${specification.version}"/>
- <filter token="MODULE-XSD-SPEC-URI"
value="link:xsd:dpml/lang/dpml-module#${specification.version}"/>
- <filter token="PROJECT-XSD-SPEC-URI" value="${xsd.spec.uri}"/>
+ <filter token="PROJECT-NAME" value="${project.name}"/>
+ <filter token="PROJECT-GROUP" value="${project.group}"/>
+ <filter token="PROJECT-VERSION" value="${project.version}"/>
+ <filter token="PART-XSD-SPEC-URI"
value="link:xsd:${project.group}/dpml-lang-part"/>
+ <filter token="COMPONENT-XSD-SPEC-URI"
value="link:xsd:${project.group}/dpml-lang-component"/>
+ <filter token="RESOURCE-NAMESPACE"
value="link:xsd:${project.group}/dpml-lang-resource"/>
+ <filter token="DEPOT-CLASSLOADER-CLASS"
value="dpml.util.SystemClassLoader"/>
+ <filter token="DEPOT-MAIN-CLASS" value="dpml.util.Main"/>
</target>

<target name="package" depends="bootstrap.package">
<property name="xsds" location="${target.deliverables.dir}/xsds"/>
<mkdir dir="${xsds}"/>
+ <!--
+ Copy part XSD to deliverables and classes.
+ -->
<property name="filename"
value="${project.name}-${project.version}.xsd"/>
- <copy toFile="${xsds}/${filename}" preservelastmodified="true"
overwrite="true"
- file="${target.dir}/part.xsd"/>
+ <copy file="${target.dir}/xsds/part.xsd"
+ toFile="${xsds}/${filename}" preservelastmodified="true"
overwrite="true"/>
+ <mkdir dir="${target.dir}/classes/main/${project.group}"/>
+ <copy file="${target.dir}/xsds/part.xsd"
+
toFile="${target.dir}/classes/main/${project.group}/${project.name}.xsd"
+ preservelastmodified="true" overwrite="true"/>
<checksum fileext=".md5" file="${xsds}/${filename}"/>
- <echo file="${xsds}/${project.name}-${specification.version}.xsd.link"
+ <echo file="${xsds}/${project.name}.xsd.link"

message="artifact:xsd:${project.group}/${project.name}#${project.version}"/>
+ <mkdir dir="${target.deliverables.jars.dir}"/>
+ <!--
+ Copy state XSD to deliverables and classes.
+ -->
+ <property name="state.filename"
value="dpml-lang-state-${project.version}.xsd"/>
+ <copy file="${target.dir}/xsds/state.xsd"
+ toFile="${xsds}/${state.filename}" preservelastmodified="true"
overwrite="true"/>
+ <mkdir dir="${target.dir}/classes/main/${project.group}"/>
+ <copy file="${target.dir}/xsds/state.xsd"
+
toFile="${target.dir}/classes/main/${project.group}/dpml-lang-state.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5" file="${xsds}/${state.filename}"/>
+ <echo file="${xsds}/dpml-lang-state.xsd.link"
+
message="artifact:xsd:${project.group}/dpml-lang-state#${project.version}"/>
+ <!--
+ Copy component XSD to deliverables and classes.
+ -->
+ <property name="component.filename"
value="dpml-lang-component-${project.version}.xsd"/>
+ <copy file="${target.dir}/xsds/component.xsd"
+ toFile="${xsds}/${component.filename}" preservelastmodified="true"
overwrite="true"/>
+ <mkdir dir="${target.dir}/classes/main/${project.group}"/>
+ <copy file="${target.dir}/xsds/component.xsd"
+
toFile="${target.dir}/classes/main/${project.group}/dpml-lang-component.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5" file="${xsds}/${component.filename}"/>
+ <echo file="${xsds}/dpml-lang-component.xsd.link"
+
message="artifact:xsd:${project.group}/dpml-lang-component#${project.version}"/>
+ <!--
+ Copy resource XSD to deliverables and classes.
+ -->
+ <property name="resource.filename"
value="dpml-lang-resource-${project.version}.xsd"/>
+ <copy file="${target.dir}/xsds/resource.xsd"
+ toFile="${xsds}/${resource.filename}" preservelastmodified="true"
overwrite="true"/>
+ <mkdir dir="${target.dir}/classes/main/${project.group}"/>
+ <copy file="${target.dir}/xsds/resource.xsd"
+
toFile="${target.dir}/classes/main/${project.group}/dpml-lang-resource.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5" file="${xsds}/${resource.filename}"/>
+ <echo file="${xsds}/dpml-lang-resource.xsd.link"
+
message="artifact:xsd:${project.group}/dpml-lang-resource#${project.version}"/>
+ <!--
+ Copy library XSD to deliverables and classes.
+ -->
+ <property name="library.filename"
value="dpml-lang-library-${project.version}.xsd"/>
+ <copy file="${target.dir}/xsds/library.xsd"
+ toFile="${xsds}/${library.filename}" preservelastmodified="true"
overwrite="true"/>
+ <mkdir dir="${target.dir}/classes/main/${project.group}"/>
+ <copy file="${target.dir}/xsds/library.xsd"
+
toFile="${target.dir}/classes/main/${project.group}/dpml-lang-library.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5" file="${xsds}/${library.filename}"/>
+ <echo file="${xsds}/dpml-lang-library.xsd.link"
+
message="artifact:xsd:${project.group}/dpml-lang-library#${project.version}"/>
+ <!--
+ Create and publish the jar file.
+ -->
+ <mkdir dir="${target.deliverables.jars.dir}"/>
+ <jar destfile="${target.deliverables.jars.dir}/${project.filename}"
+ basedir="${target.classes.dir}"
+ includes="**/*.*" excludes="**/*.html,**/*.png"
+ index="true">
+ <manifest>
+ <attribute name="Created-By" value="The Digital Product Management
Laboratory."/>
+ <attribute name="Built-By" value="${user.name}"/>
+ <attribute name="Extension-Name" value="${project.name}"/>
+ <attribute name="Specification-Vendor" value="DPML"/>
+ <attribute name="Specification-Version"
value="${project.specification.version}"/>
+ <attribute name="Implementation-Vendor" value="DPML"/>
+ <attribute name="Implementation-Vendor-Id" value="net.dpml"/>
+ <attribute name="Implementation-Version"
value="${project.version}"/>
+ <attribute name="Main-Class" value="dpml.util.Main"/>
+ </manifest>
+ </jar>
+ <echo file="${target.deliverables.jars.dir}/${project.name}.jar.link"
+
message="artifact:jar:${project.group}/${project.name}#${project.version}"/>
+ <checksum fileext=".md5"
file="${target.deliverables.jars.dir}/${project.filename}"/>
+ <delete file="${target.deliverables.jars.dir}/${project.filename}.asc"/>
+ <antcall target="execute.jar.asc"/>
</target>

+ <target name="install" depends="bootstrap.install">
+ <echo>
+#----------------------------------------------------------------------------------
+# Updating Ant. ${user.home}/.ant/lib
+#----------------------------------------------------------------------------------
+ </echo>
+ <!--
+ <copy tofile="${user.home}/.ant/lib/dpml-lang-part.jar"
+
file="${target.deliverables.jars.dir}/${project.name}-${project.version}.jar"/>
+ -->
+ <property name="lib" location="${dpml.system}/lib"/>
+ <property name="short.filename" value="${project.name}.jar"/>
+ <property name="long.filename"
value="${project.name}-${project.version}.jar"/>
+ <mkdir dir="${lib}/ext"/>
+ <echo>
+#----------------------------------------------------------------------------------
+# Updating DPML Lib ${lib}/ext
+#----------------------------------------------------------------------------------
+ </echo>
+ <!--
+ <copy toFile="${lib}/ext/${short.filename}" preservelastmodified="true"
overwrite="true"
+ file="${target.deliverables.jars.dir}/${long.filename}"/>
+ -->
+ <echo>
+#----------------------------------------------------------------------------------
+# Updating ${dpml.system}/bin
+#----------------------------------------------------------------------------------
+ </echo>
+ <mkdir dir="${dpml.system}/bin"/>
+ <copy todir="${dpml.system}" preservelastmodified="true"
overwrite="true">
+ <fileset dir="target">
+ <include name="bin/**"/>
+ </fileset>
+ </copy>
+ <chmod perm="755">
+ <fileset dir="${dpml.system}/bin">
+ <include name="**/*.sh"/>
+ <include name="**/depot"/>
+ </fileset>
+ </chmod>
+ <property name="work" location="${dpml.data}/work"/>
+ <mkdir dir="${work}"/>
+ </target>
+
</project>

Modified: trunk/main/lang/part/build.xml
===================================================================
--- trunk/main/lang/part/build.xml 2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/build.xml 2007-02-09 01:29:45 UTC (rev 1859)
@@ -1,19 +1,101 @@
<?xml version="1.0" encoding="UTF-8" ?>

<project name="dpml-part" default="install" basedir="."
- xmlns:transit="antlib:net.dpml.transit"
+ xmlns:transit="antlib:dpml.tools.transit"
xmlns:x="dpml:depot" >

<transit:import uri="local:template:dpml/tools/standard"/>
-
- <target name="package" depends="standard.package">
- <property name="target.file" location="${project.target.dir}/part.xsd"/>
- <property name="xsds.dir" location="${project.deliverable.xsd.dir}"/>
- <mkdir dir="${xsds.dir}"/>
- <property name="filename"
value="${project.name}-${project.version}.xsd"/>
- <copy file="${target.file}" toFile="${project.deliverable.xsd.path}"
+
+ <target name="build" depends="standard.build">
+
+ <!-- part.xsd -->
+ <!--
+ <property name="part.file"
location="${project.target.dir}/xsds/part.xsd"/>
+ <mkdir dir="${project.deliverable.xsd.dir}"/>
+ <copy file="${part.file}" toFile="${project.deliverable.xsd.path}"
preservelastmodified="true" overwrite="true"/>
<checksum fileext=".md5" file="${project.deliverable.xsd.path}"/>
+ <property name="packaged.dir"
location="${project.target.classes.main.dir}/dpml/lang"/>
+ <mkdir dir="${packaged.dir}"/>
+ <copy file="${part.file}" toFile="${packaged.dir}/${project.name}.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ -->
+ <!-- state.xsd -->
+
+ <!--
+ <property name="state.file"
location="${project.target.dir}/xsds/state.xsd"/>
+ <mkdir dir="${project.deliverable.xsd.dir}"/>
+ <copy file="${state.file}"
toFile="${project.deliverable.xsd#dpml-lang-state.path}"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5"
file="${project.deliverable.xsd#dpml-lang-state.path}"/>
+ <property name="packaged.dir"
location="${project.target.classes.main.dir}/dpml/lang"/>
+ <mkdir dir="${packaged.dir}"/>
+ <copy file="${state.file}" toFile="${packaged.dir}/dpml-lang-state.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ -->
+
+ <!-- component.xsd -->
+
+ <!--
+ <property name="component.file"
location="${project.target.dir}/xsds/component.xsd"/>
+ <mkdir dir="${project.deliverable.xsd.dir}"/>
+ <copy file="${component.file}"
toFile="${project.deliverable.xsd#dpml-lang-component.path}"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5"
file="${project.deliverable.xsd#dpml-lang-component.path}"/>
+ <property name="packaged.dir"
location="${project.target.classes.main.dir}/dpml/lang"/>
+ <mkdir dir="${packaged.dir}"/>
+ <copy file="${component.file}"
toFile="${packaged.dir}/dpml-lang-component.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ -->
+
+ <!-- resource.xsd -->
+
+ <!--
+ <property name="resource.file"
location="${project.target.dir}/xsds/resource.xsd"/>
+ <mkdir dir="${project.deliverable.xsd.dir}"/>
+ <copy file="${resource.file}"
toFile="${project.deliverable.xsd#dpml-lang-resource.path}"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5"
file="${project.deliverable.xsd#dpml-lang-resource.path}"/>
+ <property name="packaged.dir"
location="${project.target.classes.main.dir}/dpml/lang"/>
+ <mkdir dir="${packaged.dir}"/>
+ <copy file="${resource.file}"
toFile="${packaged.dir}/dpml-lang-resource.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ -->
+
+ <!-- library.xsd -->
+
+ <!--
+ <property name="library.file"
location="${project.target.dir}/xsds/library.xsd"/>
+ <mkdir dir="${project.deliverable.xsd.dir}"/>
+ <copy file="${library.file}"
toFile="${project.deliverable.xsd#dpml-lang-library.path}"
+ preservelastmodified="true" overwrite="true"/>
+ <checksum fileext=".md5"
file="${project.deliverable.xsd#dpml-lang-library.path}"/>
+ <property name="packaged.dir"
location="${project.target.classes.main.dir}/dpml/lang"/>
+ <mkdir dir="${packaged.dir}"/>
+ <copy file="${library.file}"
toFile="${packaged.dir}/dpml-lang-library.xsd"
+ preservelastmodified="true" overwrite="true"/>
+ -->
+
</target>

+ <target name="update">
+ <echo>
+#----------------------------------------------------------------------------------
+# Updating ${dpml.share}/bin
+#----------------------------------------------------------------------------------
+ </echo>
+ <mkdir dir="${dpml.share}/bin"/>
+ <copy todir="${dpml.share}" preservelastmodified="true" overwrite="true">
+ <fileset dir="target">
+ <include name="bin/**"/>
+ </fileset>
+ </copy>
+ <chmod perm="755">
+ <fileset dir="${dpml.share}/bin">
+ <include name="**/*.sh"/>
+ <include name="**/depot"/>
+ </fileset>
+ </chmod>
+ </target>
+
</project>

Added: trunk/main/lang/part/project.xml
===================================================================
--- trunk/main/lang/part/project.xml 2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/project.xml 2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-lang-part">
+
+ <info title="DPML Part Content Handler">
+ <description>Part content handler for the Transit system.</description>
+ </info>
+
+ <properties>
+ <property name="project.package.include-in-classes" value="true"/>
+ </properties>
+
+ <types>
+ <type id="xsd" alias="true" source="etc/xsds/part.xsd"/>
+ <type id="xsd" alias="true" name="dpml-lang-state"
source="etc/xsds/state.xsd"/>
+ <type id="xsd" alias="true" name="dpml-lang-component"
source="etc/xsds/component.xsd"/>
+ <type id="xsd" alias="true" name="dpml-lang-resource"
source="etc/xsds/resource.xsd"/>
+ <type id="xsd" alias="true" name="dpml-lang-library"
source="etc/xsds/library.xsd"/>
+ <type id="jar" alias="true"/>
+ </types>
+
+ <dependencies>
+ <runtime>
+ <include ref="dpml/transit/dpml-transit-main"/>
+ </runtime>
+ <test>
+ <include ref="org/apache/ant/ant-junit"/>
+ </test>
+ </dependencies>
+
+ <filters>
+ <feature token="COMPONENT-XSD-SPEC-URI" id="uri"
type="xsd#dpml-lang-component" alias="true"/>
+ </filters>
+
+</project>
+

Added: trunk/main/lang/part/src/main/dpml/appliance/AbstractAppliance.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/appliance/AbstractAppliance.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/appliance/AbstractAppliance.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2006-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.appliance;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+
+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.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceManager;
+
+import net.dpml.lang.Strategy;
+
+import net.dpml.runtime.Component;
+import net.dpml.runtime.ComponentEvent;
+import net.dpml.runtime.ComponentListener;
+import net.dpml.runtime.Provider;
+import net.dpml.runtime.ProviderEvent;
+import net.dpml.runtime.Status;
+
+import net.dpml.state.State;
+import net.dpml.state.StateEvent;
+import net.dpml.state.StateListener;
+
+import net.dpml.util.Logger;
+
+/**
+ * Remote adapter to a component.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class AbstractAppliance extends UnicastRemoteObject
+{
+ protected void setShutdownHook( final Appliance appliance )
+ {
+ Runtime.getRuntime().addShutdownHook(
+ new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ appliance.decommission();
+ UnicastRemoteObject.unexportObject( appliance, false );
+ }
+ catch( Throwable e )
+ {
+ }
+ }
+ }
+ );
+ }
+
+ private final Logger m_logger;
+ private final URI m_codebase;
+ private final Set<ApplianceListener> m_listeners = new
CopyOnWriteArraySet<ApplianceListener>();
+ private final ExecutorService m_queue =
Executors.newSingleThreadExecutor();
+
+ private boolean m_commissioned = false;
+
+ public AbstractAppliance( final Logger logger, final URI uri ) throws
IOException
+ {
+ super();
+
+ if( null == uri )
+ {
+ String spec = System.getProperty( "dpml.appliance.codebase.uri",
null );
+ if( null != spec )
+ {
+ m_codebase = URI.create( spec );
+ }
+ else
+ {
+ m_codebase = null;
+ }
+ }
+ else
+ {
+ m_codebase = uri;
+ }
+ m_logger = logger;
+ }
+
+ public String getCodebaseURI()
+ {
+ return m_codebase.toASCIIString();
+ }
+
+ /**
+ * Add a listener to the component.
+ * @param listener the component listener
+ */
+ public void addApplianceListener( ApplianceListener listener )
+ {
+ m_listeners.add( listener );
+ }
+
+ /**
+ * Remove a listener from the component.
+ * @param listener the component listener
+ */
+ public void removeApplianceListener( ApplianceListener listener )
+ {
+ m_listeners.remove( listener );
+ }
+
+ public boolean isCommissioned()
+ {
+ synchronized( this )
+ {
+ return m_commissioned;
+ }
+ }
+
+ public void commission() throws IOException
+ {
+ synchronized( this )
+ {
+ m_commissioned = true;
+ }
+ }
+
+ public void decommission() throws RemoteException
+ {
+ decommission( 10, TimeUnit.SECONDS );
+ }
+
+ protected void decommission( long timeout, TimeUnit units ) throws
RemoteException
+ {
+ synchronized( this )
+ {
+ if( !m_commissioned )
+ {
+ return;
+ }
+ try
+ {
+ m_queue.shutdown();
+ boolean ok = m_queue.awaitTermination( timeout, units );
+ if( !ok )
+ {
+ final String message =
+ "A decommissioning timout (some events from may not
have been processed).";
+ getLogger().warn( message );
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ m_commissioned = false;
+ }
+ }
+ }
+
+ protected Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ protected void processEvent( ApplianceEvent event )
+ {
+ Logger logger= getLogger();
+ for( ApplianceListener listener : m_listeners )
+ {
+ m_queue.execute( new ApplianceEventDistatcher( logger, listener,
event ) );
+ }
+ }
+
+ private static class ApplianceEventDistatcher implements Runnable
+ {
+ private Logger m_logger;
+ private ApplianceListener m_listener;
+ private ApplianceEvent m_event;
+
+ ApplianceEventDistatcher( Logger logger, ApplianceListener listener,
ApplianceEvent event )
+ {
+ m_logger = logger;
+ m_listener = listener;
+ m_event = event;
+ }
+
+ public void run()
+ {
+ try
+ {
+ m_listener.applianceChanged( m_event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Event distatch error.";
+ m_logger.error( error, e );
+ }
+ }
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/appliance/ApplianceHelper.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/appliance/ApplianceHelper.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/appliance/ApplianceHelper.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2006-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.appliance;
+
+import dpml.util.PropertyResolver;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Properties;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceFactory;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Transit;
+import net.dpml.transit.ContentHandler;
+
+
+/**
+ * Remote adapter to a component.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceHelper
+{
+ public static Appliance newAppliance( URI uri ) throws IOException
+ {
+ String partition = getPartition();
+ return newAppliance( partition, uri );
+ }
+
+ public static Appliance newAppliance( String partition, URI uri ) throws
IOException
+ {
+ Artifact artifact = Artifact.createArtifact( uri );
+ String type = artifact.getType();
+ ContentHandler handler = Transit.getInstance().getContentHandler(
type );
+ if( null == handler )
+ {
+ final String error =
+ "No content handler found for the type ["
+ + type
+ + "] referenced by the uri ["
+ + uri
+ + "]";
+ throw new ApplianceException( error, null );
+ }
+ if( handler instanceof ApplianceFactory )
+ {
+ URL url = artifact.toURL();
+ URLConnection connection = url.openConnection();
+ ApplianceFactory factory = (ApplianceFactory) handler;
+ return factory.newAppliance( connection, partition );
+ }
+ else
+ {
+ final String error =
+ "Content type ["
+ + type
+ + "] referenced by the uri ["
+ + uri
+ + "] does not support appliance production.";
+ throw new ApplianceException( error, null );
+ }
+ }
+
+ private static String getPartition()
+ {
+ String partition = System.getProperty( "dpml.station.partition",
null );
+ Properties system = System.getProperties();
+ return PropertyResolver.resolve( system, partition );
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/appliance/StandardAppliance.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/appliance/StandardAppliance.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/appliance/StandardAppliance.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2006-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.appliance;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+
+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.ApplianceListener;
+import net.dpml.appliance.ApplianceEvent;
+import net.dpml.appliance.ApplianceException;
+import net.dpml.appliance.ApplianceManager;
+
+import net.dpml.lang.Strategy;
+
+import net.dpml.runtime.Component;
+import net.dpml.runtime.ComponentEvent;
+import net.dpml.runtime.ComponentListener;
+import net.dpml.runtime.Provider;
+import net.dpml.runtime.ProviderEvent;
+import net.dpml.runtime.Status;
+
+import net.dpml.state.State;
+import net.dpml.state.StateEvent;
+import net.dpml.state.StateListener;
+
+import net.dpml.util.Logger;
+
+/**
+ * Remote adapter to a component.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandardAppliance extends AbstractAppliance implements
Appliance, ApplianceManager
+{
+ private final Component m_component;
+ private final ComponentListener m_listener;
+
+ private Provider m_provider;
+ private Object m_instance;
+
+ public StandardAppliance(
+ final Logger logger, final Component component ) throws IOException
+ {
+ super( logger, null );
+
+ m_component = component;
+ m_listener = new InternalComponentListener( this );
+ m_component.addComponentListener( m_listener );
+ setShutdownHook( this );
+ }
+
+ /**
+ * Return a value assignable to the supplied remote type or null if the
type
+ * cannot be resolved from this strategy.
+ * @param c the target class
+ * @return an instance of the class or null
+ * @exception IOException if an IO error occurs
+ */
+ public <T>T getContentForClass( Class<T> c ) throws IOException
+ {
+ if( null == m_instance )
+ {
+ throw new IllegalStateException( "Appliance has not been
commissioned." );
+ }
+ else
+ {
+ if( c.isAssignableFrom( m_instance.getClass() ) )
+ {
+ return c.cast( m_instance );
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+
+ public void commission() throws IOException
+ {
+ synchronized( m_component )
+ {
+ super.commission();
+ if( getLogger().isInfoEnabled() )
+ {
+ getLogger().info( "commissioning " + m_component.getName() );
+ }
+ m_provider = m_component.getProvider();
+ m_instance = m_provider.getInstance( Object.class );
+ }
+ }
+
+ protected void decommission( long timeout, TimeUnit units ) throws
RemoteException
+ {
+ synchronized( m_component )
+ {
+ if( !isCommissioned() )
+ {
+ return;
+ }
+ if( getLogger().isInfoEnabled() )
+ {
+ getLogger().info( "decommissioning " + m_component.getName()
);
+ }
+ if( null != m_provider )
+ {
+ m_component.release( m_provider );
+ }
+ m_provider = null;
+ m_instance = null;
+ m_component.terminate();
+ m_component.removeComponentListener( m_listener );
+ super.decommission( timeout, units );
+ }
+ }
+
+ /*
+ public void stateChanged( final StateEvent event ) throws RemoteException
+ {
+ State from = event.getFromState();
+ State to = event.getToState();
+ if( getLogger().isDebugEnabled() )
+ {
+ String name = m_component.getName();
+ getLogger().debug(
+ "transitioning ["
+ + name
+ + "] from ["
+ + from.getName()
+ + "] to ["
+ + to.getName()
+ + "]" );
+ }
+ }
+ */
+
+ private class InternalComponentListener implements ComponentListener
+ {
+ private Appliance m_appliance;
+
+ InternalComponentListener( Appliance appliance )
+ {
+ m_appliance = appliance;
+ }
+
+ /**
+ * Event within the component.
+ *
+ * @param event the component event
+ */
+ public void componentChanged( final ComponentEvent event )
+ {
+ if( event instanceof ProviderEvent )
+ {
+ ProviderEvent e = (ProviderEvent) event;
+ Status status = e.getStatus();
+ ApplianceEvent ae = new ApplianceEvent( m_appliance, status
);
+ processEvent( ae );
+ }
+ }
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/lang/Classpath.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Classpath.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Classpath.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,241 @@
+/*
+ * 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 dpml.lang;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Arrays;
+
+import javax.xml.XMLConstants;
+
+import dpml.util.Category;
+import net.dpml.lang.Strategy;
+import net.dpml.lang.Buffer;
+
+import net.dpml.util.Logger;
+
+import dpml.util.ObjectUtils;
+
+/**
+ * Immutable datastructure defining a classloader stack.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Classpath
+{
+ private final URI[] m_system;
+ private final URI[] m_public;
+ private final URI[] m_protected;
+ private final URI[] m_private;
+ private final Classpath m_base;
+
+ /**
+ * Creation of a empty classpath definition.
+ */
+ public Classpath()
+ {
+ this( new URI[0], new URI[0], new URI[0], new URI[0] );
+ }
+
+ /**
+ * Creation of a new classpath definition.
+ * @param base the base classpath from which this classpath is derived
+ * @param extension the extended classpath definition
+ */
+ public Classpath( final Classpath base, final Classpath extension )
+ {
+ if( null == extension )
+ {
+ throw new NullPointerException( "extension" );
+ }
+ m_base = base;
+ m_system = extension.m_system;
+ m_public = extension.m_public;
+ m_protected = extension.m_protected;
+ m_private = extension.m_private;
+ }
+
+ /**
+ * Creation of a new classpath definition.
+ * @param systemUris an array of uris representing the system classpath
extensions
+ * @param publicUris an array of uris representing the public classpath
entries
+ * @param protectedUris an array of uris representing protected classpath
entries
+ * @param privateUris an array of uris representing private classpath
entries
+ */
+ public Classpath(
+ URI[] systemUris, URI[] publicUris, URI[] protectedUris, URI[]
privateUris )
+ {
+ this( null, systemUris, publicUris, protectedUris, privateUris );
+ }
+
+ /**
+ * Creation of a new classpath definition.
+ * @param base super classpath (may be null)
+ * @param systemUris an array of uris representing the system classpath
extensions
+ * @param publicUris an array of uris representing the public classpath
entries
+ * @param protectedUris an array of uris representing protected classpath
entries
+ * @param privateUris an array of uris representing private classpath
entries
+ */
+ public Classpath(
+ Classpath base, URI[] systemUris, URI[] publicUris, URI[]
protectedUris, URI[] privateUris )
+ {
+ m_base = base;
+ if( null == systemUris )
+ {
+ m_system = new URI[0];
+ }
+ else
+ {
+ m_system = systemUris;
+ }
+
+ if( null == publicUris )
+ {
+ m_public = new URI[0];
+ }
+ else
+ {
+ m_public = publicUris;
+ }
+
+ if( null == protectedUris )
+ {
+ m_protected = new URI[0];
+ }
+ else
+ {
+ m_protected = protectedUris;
+ }
+
+ if( null == privateUris )
+ {
+ m_private = new URI[0];
+ }
+ else
+ {
+ m_private = privateUris;
+ }
+ }
+
+ /**
+ * Return the base classpath.
+ * @return the base classpath that this classpath extends (possibly null)
+ */
+ public Classpath getBaseClasspath()
+ {
+ return m_base;
+ }
+
+ /**
+ * Return the classloader dependencies relative to a supplied classloader
category.
+ *
+ * @param category the classloader category
+ * @return an array of uris defining the classloader classpath for the
supplied category
+ */
+ public URI[] getDependencies( final Category category )
+ {
+ if( Category.SYSTEM.equals( category ) )
+ {
+ return m_system;
+ }
+ else if( Category.PUBLIC.equals( category ) )
+ {
+ return m_public;
+ }
+ else if( Category.PROTECTED.equals( category ) )
+ {
+ return m_protected;
+ }
+ else if( Category.PRIVATE.equals( category ) )
+ {
+ return m_private;
+ }
+ else
+ {
+ final String error =
+ "Category not recognized."
+ + "\nCategory: " + category;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ /**
+ * Compare this object with another for equality.
+ * @param other the other object
+ * @return TRUE if equal else FALSE
+ */
+ public boolean equals( Object other )
+ {
+ if( other instanceof Classpath )
+ {
+ Classpath classpath = (Classpath) other;
+ if( !Arrays.equals( m_system, classpath.getDependencies(
Category.SYSTEM ) ) )
+ {
+ return false;
+ }
+ if( !Arrays.equals( m_public, classpath.getDependencies(
Category.PUBLIC ) ) )
+ {
+ return false;
+ }
+ if( !Arrays.equals( m_protected, classpath.getDependencies(
Category.PROTECTED ) ) )
+ {
+ return false;
+ }
+ else
+ {
+ return Arrays.equals( m_private, classpath.getDependencies(
Category.PRIVATE ) );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return the hashcode for the plugin definition.
+ * @return the hash code
+ */
+ public int hashCode()
+ {
+ int hash = ObjectUtils.hashArray( m_system );
+ hash ^= ObjectUtils.hashArray( m_public );
+ hash ^= ObjectUtils.hashArray( m_protected );
+ hash ^= ObjectUtils.hashArray( m_private );
+ return hash;
+ }
+
+ /**
+ * Return the classpath as a string.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "classpath: ["
+ + m_system.length
+ + ", " + m_public.length
+ + ", " + m_protected.length
+ + ", " + m_private.length
+ + "]";
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/Construct.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Construct.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Construct.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,1086 @@
+/*
+ * 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.lang;
+
+import dpml.util.PropertyResolver;
+
+import java.beans.Expression;
+import java.io.Serializable;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Properties;
+
+import net.dpml.lang.Buffer;
+
+/**
+ * A object resolvable from primitive arguments.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class Construct implements Value, Serializable
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Utility operation that consolidates an array of values and
supplimentary
+ * arguments to an array of objects.
+ *
+ * @param map a map of keys and values used in symbolic target resolution
+ * @param params the value array
+ * @param args supplimentary arguments
+ * @return the consolidated argument array
+ * @exception Exception if an error occurs in argument resolution
+ */
+ public static Object[] getArgs( Map<String,Object> map, Value[] params,
Object[] args ) throws Exception
+ {
+ ArrayList<Object> list = new ArrayList<Object>();
+ if( null != params )
+ {
+ for( int i=0; i < params.length; i++ )
+ {
+ Value value = params[i];
+ Object object = value.resolve( map );
+ if( null != object )
+ {
+ list.add( object );
+ }
+ }
+ }
+ if( null != args )
+ {
+ for( int i=0; i < args.length; i++ )
+ {
+ Object value = args[i];
+ if( null != value )
+ {
+ list.add( value );
+ }
+ }
+ }
+ return list.toArray();
+ }
+
+ private final String m_method;
+ private final String m_target;
+ private final String m_value;
+ private final Value[] m_args;
+ private final boolean m_compound;
+
+ /**
+ * Create a new construct using the default java.lang.String class as the
base type.
+ * @param value the construct value
+ */
+ public Construct( String value )
+ {
+ this( null, null, value );
+ }
+
+ /**
+ * Create a new construct using a supplied target defintion. The target
argument
+ * may be either a classname or a symbolic reference in the form
${[key]}. If the
+ * argument is symbolic it resolved relative to a context map supplied by
the
+ * application resolving construct values.
+ *
+ * @param target a classname or symbolic reference
+ * @param value the construct value
+ */
+ public Construct( String target, String value )
+ {
+ this( target, null, value );
+ }
+
+ /**
+ * Create a new construct using a supplied target defintion. The target
argument
+ * may be either a classname or a symbolic reference in the form
${[key]}. If the
+ * argument is symbolic it is resolved relative to a context map supplied
by the
+ * application resolving construct values. If the construct value is
symbolic
+ * the implementation will attempt to expand the reference relative to a
context
+ * map (if supplied) otherwise the implementation will attempt to expand
the value
+ * using system properties.
+ *
+ * @param target a classname or symbolic reference
+ * @param method the method to invoke on the target
+ * @param value the construct value
+ */
+ public Construct( String target, String method, String value )
+ {
+ m_target = target;
+ m_method = method;
+ m_value = value;
+ m_args = new Value[0];
+ m_compound = false;
+ }
+
+ /**
+ * Create a new construct using a supplied target defintion. The target
argument
+ * may be either a classname or a symbolic reference in the form
${[key]}. If the
+ * argument is symbolic it is resolved relative to a context map supplied
by the
+ * application resolving construct values. Instance values resolved from
the
+ * supplied Value[] will be used as constructor arguments when resolving
the target.
+ *
+ * @param target the construct classname
+ * @param args an array of unresolved parameter values
+ */
+ public Construct( String target, Value[] args )
+ {
+ this( target, null, args );
+ }
+
+ /**
+ * Create a new construct using a supplied target definition. The target
argument
+ * may be either a classname or a symbolic reference in the form
${[key]}. If the
+ * argument is symbolic it is resolved relative to a context map supplied
by the
+ * application resolving construct values. Instance values resolved from
the
+ * supplied Value[] will be used as method arguments when resolving the
target.
+ *
+ * @param target the construct classname
+ * @param method the method to invoke on the target
+ * @param args an array of unresolved parameter values
+ */
+ public Construct( String target, String method, Value[] args )
+ {
+ if( null == args )
+ {
+ m_args = new Value[0];
+ }
+ else
+ {
+ m_args = args;
+ }
+ m_value = null;
+ m_target = target;
+ m_method = method;
+ m_compound = true;
+ }
+
+ public void encode( Buffer buffer ) throws IOException
+ {
+ encode( buffer, "param", null );
+ }
+
+ public void encode( Buffer buffer, String label, String key ) throws
IOException
+ {
+ buffer.nl( "<" + label );
+ if( null != key )
+ {
+ buffer.write( " key=\"" + key + "\"" );
+ }
+ if( null != getTargetExpression() )
+ {
+ buffer.write( " class=\"" + getTargetExpression() + "\"" );
+ }
+ if( null != getMethodName() )
+ {
+ buffer.write( " method=\"" + getMethodName() + "\"" );
+ }
+ if( isCompound() )
+ {
+ buffer.write( ">" );
+ Value[] values = getValues();
+ Buffer b2 = buffer.indent();
+ for( Value v : values )
+ {
+ v.encode( b2 );
+ }
+ buffer.nl( "</" + label + ">" );
+ }
+ else
+ {
+ String v = getBaseValue();
+ if( null != v )
+ {
+ buffer.write( " value=\"" + v + "\"" );
+ }
+ buffer.write( "/>" );
+ }
+ }
+
+ /**
+ * Return TRUE if this construct is a compound construct else FALSE.
+ * @return TRUE if this ia a compound construct
+ */
+ public boolean isCompound()
+ {
+ return m_compound;
+ }
+
+ /**
+ * Return the method name to be applied to the target object.
+ * @return the method name
+ */
+ public String getMethodName()
+ {
+ return m_method;
+ }
+
+ /**
+ * Return the set of nested values within this value.
+ * @return the nested values array
+ */
+ public Value[] getValues()
+ {
+ return m_args;
+ }
+
+ /**
+ * Return the classname of the resolved value.
+ * @return the classname
+ */
+ public String getBaseValue()
+ {
+ return m_value;
+ }
+
+ /**
+ * Return the classname of the resolved value.
+ * @return the classname
+ */
+ public String getTargetExpression()
+ {
+ return m_target;
+ }
+
+ /**
+ * Resolve an instance from the value using the context classloader.
+ * @return the resolved instance
+ * @exception Exception if an error occurs during value resolution
+ */
+ public Object resolve() throws Exception
+ {
+ return resolve( null );
+ }
+
+ /**
+ * Resolve an instance from the value using a supplied map.
+ * @param map the context map
+ * @return the resolved instance
+ * @exception Exception if an error occurs during value resolution
+ */
+ public Object resolve( Map<String,Object> map ) throws Exception
+ {
+ return resolve( null, map );
+ }
+
+ /**
+ * Resolve an instance from the value using a supplied context map. If
any
+ * target expressions in immediate or nested values contain a symbolic
+ * expression the value will be resolved using the supplied map.
+ *
+ * @param type the implicit target class
+ * @param map the context map
+ * @return the resolved instance
+ * @exception Exception if an error occurs during value resolution
+ */
+ public Object resolve( Class<?> type, Map<String,Object> map ) throws
Exception
+ {
+ return resolve( type, map, null );
+ }
+
+ /**
+ * Resolve an instance from the value.
+ * @param type the implicit target class
+ * @param map the context map
+ * @param classloader the classloader
+ * @return the resolved instance
+ * @exception Exception if an error occurs during value resolution
+ */
+ private Object resolve(
+ Class type, Map<String,Object> map, ClassLoader classloader ) throws
Exception
+ {
+ ClassLoader loader = resolveClassLoader( classloader );
+ Class t = getTargetClass( loader, type );
+ if( isCompound() )
+ {
+ return resolveCompoundExpression( t, map, loader );
+ }
+ else
+ {
+ return resolveSimpleExpression( t, map, loader );
+ }
+ }
+
+ private Object resolveSimpleExpression(
+ Class type, Map map, ClassLoader classloader ) throws Exception
+ {
+ Properties properties = System.getProperties();
+ String value = PropertyResolver.resolve( properties, m_value );
+
+ if( ( null != value ) && ( null != map ) )
+ {
+ if( value.startsWith( "${" ) && m_value.endsWith( "}" ) )
+ {
+ String pre = m_value.substring( 2 );
+ String key = pre.substring( 0, pre.length() -1 );
+ if( map.containsKey( key ) )
+ {
+ return map.get( key );
+ }
+ }
+ }
+
+ String method = getMethodName();
+ if( null == method )
+ {
+ method = "new";
+ }
+ else
+ {
+ if( null == value ) // check if the method name is a static field
+ {
+ try
+ {
+ Field field = type.getField( method );
+ return field.get( type );
+ }
+ catch( NoSuchFieldException e )
+ {
+ // assume its a method
+ }
+ }
+ }
+
+ if( null == value )
+ {
+ Expression expression = new Expression( type, method, new
Object[0] );
+ try
+ {
+ return expression.getValue();
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Internal error while evalating simple expression using:"
+ + "\n target: "
+ + m_target
+ + " ("
+ + type.getName()
+ + ")"
+ + "\n method: "
+ + m_method
+ + " ("
+ + method
+ + ")";
+ throw new ValueException( error, e );
+ }
+ }
+ else
+ {
+ Expression expression = new Expression( type, method, new
Object[]{value} );
+ try
+ {
+ return expression.getValue();
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Internal error while evaluating expression using:"
+ + "\n target: " + m_target + " (" + type.getName() + ")"
+ + "\n method: " + m_method + " (" + method + ")"
+ + "\n value: " + m_value + " (" +
value.getClass().getName() + ")";
+ throw new ValueException( error, e );
+ }
+ }
+ }
+
+ private Object resolveCompoundExpression(
+ Class<?> type, Map<String,Object> map, ClassLoader classloader )
throws Exception
+ {
+ Value[] args = getValues();
+ Object[] instances = getInstanceValues( type, map, classloader, args
);
+ String method = getMethodName();
+
+ //
+ // check if we are dealing with an array class and if so return an
+ // array created from the array of nested values
+ //
+
+ if( type.isArray() )
+ {
+ Class<?> t = type.getComponentType();
+ if( t.isPrimitive() )
+ {
+ return buildPrimitiveArray( t, instances );
+ }
+ else
+ {
+ Object[] result =
+ (Object[]) Array.newInstance( t, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ Class<?> clazz = instance.getClass();
+ if( t.isAssignableFrom( clazz ) )
+ {
+ result[i] = instances[i];
+ }
+ else
+ {
+ final String error =
+ "Array ["
+ + t.getName()
+ + "] contains an invalid element ["
+ + instance.getClass().getName()
+ + "].";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+ }
+
+ // otherwise its a regular expression
+
+ if( null == method )
+ {
+ method = "new";
+ }
+ else
+ {
+ if( instances.length == 0 )
+ {
+ // check if the method name is a static field
+ try
+ {
+ Field field = type.getField( method );
+ return field.get( type );
+ }
+ catch( NoSuchFieldException e )
+ {
+ // assume its a method
+ }
+ }
+ }
+
+ Expression expression = new Expression( type, method, instances );
+ try
+ {
+ return expression.getValue();
+ }
+ catch( Throwable e )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "Internal error while evaluating compound
expression." );
+ buffer.append( "\n target: " + m_target + " (" + type.getName()
+ ")" );
+ buffer.append( "\n method: " + m_method + " (" + method + ")" );
+ for( int i=0; i<instances.length; i++ )
+ {
+ buffer.append(
+ "\n param "
+ + ( i+1 )
+ + ": "
+ + instances[i].getClass().getName()
+ );
+ }
+ String error = buffer.toString();
+ throw new ValueException( error, e );
+ }
+ }
+
+ private Object buildPrimitiveArray( Class type, Object[] instances )
throws ValueException
+ {
+ Object result = Array.newInstance( type, instances.length );
+ if( Integer.TYPE == type )
+ {
+ return buildIntArray( instances );
+ }
+ else if( Short.TYPE == type )
+ {
+ return buildShortArray( instances );
+ }
+ else if( Long.TYPE == type )
+ {
+ return buildLongArray( instances );
+ }
+ else if( Byte.TYPE == type )
+ {
+ return buildByteArray( instances );
+ }
+ else if( Double.TYPE == type )
+ {
+ return buildDoubleArray( instances );
+ }
+ else if( Float.TYPE == type )
+ {
+ return buildFloatArray( instances );
+ }
+ else if( Character.TYPE == type )
+ {
+ return buildCharacterArray( instances );
+ }
+ else if( Boolean.TYPE == type )
+ {
+ return buildBooleanArray( instances );
+ }
+ else
+ {
+ final String error =
+ "Primitive array class ["
+ + type.getName()
+ + "] is not recognized.";
+ throw new UnsupportedOperationException( error );
+ }
+ }
+
+ private Object buildIntArray( Object[] instances ) throws ValueException
+ {
+ Object result = Array.newInstance( Integer.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Integer )
+ {
+ Integer integer = (Integer) instance;
+ int v = integer.intValue();
+ Array.setInt( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied int array argument class ["
+ + instance.getClass().getName()
+ + "] is not an Integer.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildShortArray( Object[] instances ) throws
ValueException
+ {
+ Object result = Array.newInstance( Short.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Short )
+ {
+ Short primitive = (Short) instance;
+ short v = primitive.shortValue();
+ Array.setShort( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied short array argument class ["
+ + instance.getClass().getName()
+ + "] is not an Short.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildLongArray( Object[] instances ) throws ValueException
+ {
+ Object result = Array.newInstance( Long.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Long )
+ {
+ Long primitive = (Long) instance;
+ long v = primitive.longValue();
+ Array.setLong( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied long array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Long.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildByteArray( Object[] instances ) throws ValueException
+ {
+ Object result = Array.newInstance( Byte.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Byte )
+ {
+ Byte primitive = (Byte) instance;
+ byte v = primitive.byteValue();
+ Array.setByte( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied byte array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Byte.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildDoubleArray( Object[] instances ) throws
ValueException
+ {
+ Object result = Array.newInstance( Double.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Double )
+ {
+ Double primitive = (Double) instance;
+ double v = primitive.doubleValue();
+ Array.setDouble( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied double array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Double.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildFloatArray( Object[] instances ) throws
ValueException
+ {
+ Object result = Array.newInstance( Float.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Float )
+ {
+ Float primitive = (Float) instance;
+ float v = primitive.floatValue();
+ Array.setFloat( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied float array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Float.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildCharacterArray( Object[] instances ) throws
ValueException
+ {
+ Object result = Array.newInstance( Character.TYPE, instances.length
);
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Character )
+ {
+ Character primitive = (Character) instance;
+ char v = primitive.charValue();
+ Array.setChar( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied char array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Character.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object buildBooleanArray( Object[] instances ) throws
ValueException
+ {
+ Object result = Array.newInstance( Boolean.TYPE, instances.length );
+ for( int i=0; i<instances.length; i++ )
+ {
+ Object instance = instances[i];
+ if( instance instanceof Boolean )
+ {
+ Boolean primitive = (Boolean) instance;
+ boolean v = primitive.booleanValue();
+ Array.setBoolean( result, i, v );
+ }
+ else
+ {
+ final String error =
+ "Supplied boolean array argument class ["
+ + instance.getClass().getName()
+ + "] is not an instance of Boolean.";
+ throw new ValueException( error );
+ }
+ }
+ return result;
+ }
+
+ private Object[] getInstanceValues(
+ Class type, Map<String,Object> map, ClassLoader classloader, Value[]
args ) throws Exception
+ {
+ Object[] instances = new Object[ args.length ];
+ for( int i=0; i < args.length; i++ )
+ {
+ Value value = args[i];
+ if( value instanceof Construct )
+ {
+ Construct construct = (Construct) value;
+ if( type.isArray() )
+ {
+ Class<?> t = type.getComponentType();
+ instances[i] = construct.resolve( t, map, classloader );
+ }
+ else
+ {
+ instances[i] = construct.resolve( null, map, classloader
);
+ }
+ }
+ else
+ {
+ if( type.isArray() )
+ {
+ Class<?> t = type.getComponentType();
+ instances[i] = value.resolve( t, map );
+ }
+ else
+ {
+ instances[i] = value.resolve( null, map );
+ }
+ }
+ }
+ return instances;
+ }
+
+ private Class getTargetClass( ClassLoader loader, Class type )
+ throws ValueException
+ {
+ if( null == m_target )
+ {
+ if( null == type )
+ {
+ return String.class;
+ }
+ else
+ {
+ if( type.isPrimitive() )
+ {
+ if( type == Integer.TYPE )
+ {
+ return Integer.class;
+ }
+ else if( type == Short.TYPE )
+ {
+ return Short.class;
+ }
+ else if( type == Long.TYPE )
+ {
+ return Long.class;
+ }
+ else if( type == Byte.TYPE )
+ {
+ return Byte.class;
+ }
+ else if( type == Double.TYPE )
+ {
+ return Double.class;
+ }
+ else if( type == Float.TYPE )
+ {
+ return Float.class;
+ }
+ else if( type == Character.TYPE )
+ {
+ return Character.class;
+ }
+ else if( type == Boolean.TYPE )
+ {
+ return Boolean.class;
+ }
+ else
+ {
+ return Void.class;
+ }
+ }
+ else
+ {
+ return type;
+ }
+ }
+ }
+ else
+ {
+ if( m_target.endsWith( "[]" ) )
+ {
+ int n = m_target.length() - 2;
+ String componentClassname = m_target.substring( 0, n );
+ Class componentClass = resolveType( loader,
componentClassname );
+ return Array.newInstance( componentClass, 0 ).getClass();
+ }
+ else
+ {
+ return resolveClass( loader, m_target );
+ }
+ }
+ }
+
+ /**
+ * Return the instance class using the context classloader.
+ * @return the class
+ * @exception ComponentException if the parameter class cannot be
resolved
+ */
+ private Class resolveClass( ClassLoader loader, String classname )
throws ValueException
+ {
+ if( classname.equals( "int" ) )
+ {
+ return Integer.class;
+ }
+ else if( classname.equals( "short" ) )
+ {
+ return Short.class;
+ }
+ else if( classname.equals( "long" ) )
+ {
+ return Long.class;
+ }
+ else if( classname.equals( "byte" ) )
+ {
+ return Byte.class;
+ }
+ else if( classname.equals( "double" ) )
+ {
+ return Double.class;
+ }
+ else if( classname.equals( "float" ) )
+ {
+ return Float.class;
+ }
+ else if( classname.equals( "char" ) )
+ {
+ return Character.class;
+ }
+ else if( classname.equals( "boolean" ) )
+ {
+ return Boolean.class;
+ }
+ else
+ {
+ try
+ {
+ return Class.forName( classname, false, loader );
+ }
+ catch( final ClassNotFoundException cnfe )
+ {
+ final String error =
+ "Value class not found ["
+ + classname
+ + "].";
+ throw new ValueException( error, cnfe );
+ }
+ }
+ }
+
+ /**
+ * Return the instance class using the context classloader.
+ * @return the class
+ * @exception ComponentException if the parameter class cannot be
resolved
+ */
+ private Class resolveType( ClassLoader loader, String classname ) throws
ValueException
+ {
+ if( classname.equals( "int" ) )
+ {
+ return Integer.TYPE;
+ }
+ else if( classname.equals( "short" ) )
+ {
+ return Short.TYPE;
+ }
+ else if( classname.equals( "long" ) )
+ {
+ return Long.TYPE;
+ }
+ else if( classname.equals( "byte" ) )
+ {
+ return Byte.TYPE;
+ }
+ else if( classname.equals( "double" ) )
+ {
+ return Double.TYPE;
+ }
+ else if( classname.equals( "float" ) )
+ {
+ return Float.TYPE;
+ }
+ else if( classname.equals( "char" ) )
+ {
+ return Character.TYPE;
+ }
+ else if( classname.equals( "boolean" ) )
+ {
+ return Boolean.TYPE;
+ }
+ else
+ {
+ try
+ {
+ return loader.loadClass( classname );
+ }
+ catch( final ClassNotFoundException e )
+ {
+ final String error =
+ "Class not found ["
+ + classname
+ + "].";
+ throw new ValueException( error, e );
+ }
+ }
+ }
+
+ private ClassLoader resolveClassLoader( ClassLoader classloader )
+ {
+ if( null != classloader )
+ {
+ return classloader;
+ }
+ else
+ {
+ ClassLoader loader =
Thread.currentThread().getContextClassLoader();
+ if( null != loader )
+ {
+ return loader;
+ }
+ else
+ {
+ return Construct.class.getClassLoader();
+ }
+ }
+ }
+
+ /**
+ * Return a string representation of the construct.
+ * @return the string value
+ */
+ public String toString()
+ {
+ if( !m_compound )
+ {
+ return "construct "
+ + " target: " + m_target
+ + " method: " + m_method
+ + " value: " + m_value;
+ }
+ else
+ {
+ return "construct "
+ + " target: " + m_target
+ + " method: " + m_method
+ + " values: " + m_args.length;
+ }
+ }
+
+ /**
+ * Compare this instance with a supplied object for equality.
+ * @param other the other object
+ * @return true if the supplied instance is equal to this instance
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ if( other instanceof Construct )
+ {
+ Construct construct = (Construct) other;
+ if( !equals( m_target, construct.m_target ) )
+ {
+ return false;
+ }
+ if( m_compound != construct.m_compound )
+ {
+ return false;
+ }
+ if( !equals( m_method, construct.m_method ) )
+ {
+ return false;
+ }
+ if( m_compound )
+ {
+ return Arrays.equals( m_args, construct.m_args );
+ }
+ else
+ {
+ return equals( m_value, construct.m_value );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the instance hashcode value.
+ * @return the hashcode
+ */
+ public int hashCode()
+ {
+ int hash = 0;
+ if( null != m_target )
+ {
+ hash ^= m_target.hashCode();
+ }
+ if( null != m_method )
+ {
+ hash ^= m_method.hashCode();
+ }
+ if( m_compound )
+ {
+ for( int i=0; i<m_args.length; i++ )
+ {
+ hash ^= m_args[i].hashCode();
+ }
+ }
+ else
+ {
+ if( m_value != null )
+ {
+ hash ^= m_value.hashCode();
+ }
+ }
+ return hash;
+ }
+
+ private boolean equals( Object a, Object b )
+ {
+ if( null == a )
+ {
+ return ( null == b );
+ }
+ else
+ {
+ return a.equals( b );
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/ContextInvocationHandler.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/ContextInvocationHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/ContextInvocationHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2004-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 dpml.lang;
+
+import java.util.Map;
+import java.beans.Introspector;
+import java.beans.Expression;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import net.dpml.annotation.Context;
+
+import dpml.lang.Value;
+
+/**
+ * Invocation handler utility for a Context class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ContextInvocationHandler implements InvocationHandler
+{
+ //-------------------------------------------------------------------
+ // static
+ //-------------------------------------------------------------------
+
+ private static final String GET = "get";
+
+ /**
+ * Test if the supplied class is recognized as a context class. If
+ * the supplied policy is true then evaluation is based on the presence
+ * of the <tt>net.dpml.lang.Context</tt> annotation and resulting
+ * value of annotation evaluation. If no context annnotation is present
+ * and strict processing is disabled then evaluation will return true if
+ * the classname ends with the string <tt>$Context</tt>.
+ *
+ * @param c the candidate class
+ * @param policy the strict evaluation policy
+ * @return true if this class is recognized as a context class
+ */
+ public static boolean isaContext( final Class<?> c, final boolean policy
)
+ {
+ boolean flag = c.isAnnotationPresent( Context.class );
+ if( flag )
+ {
+ return c.getAnnotation( Context.class ).value();
+ }
+ else if( policy )
+ {
+ return false;
+ }
+ else
+ {
+ return c.getName().endsWith( "$Context" );
+ }
+ }
+
+ /**
+ * Validate that the supplied map properly fulfills the required
+ * context entry. Specifically, for all non-optional methods declared
+ * by the context class, the validation process checks the the supplied
+ * map has a corresponding key and associated non-null value.
+ *
+ * @param clazz the context class
+ * @param map a map of context entry values
+ * @exception IllegalArgumentException if validation fails
+ */
+ public static void validate( Class clazz, Map<String,Object> map )
+ throws IllegalArgumentException
+ {
+ for( Method method : clazz.getMethods() )
+ {
+ String key = getKeyForMethod( method );
+ boolean optional = isOptionalEntry( method );
+ if( !optional )
+ {
+ if( !map.containsKey( key ) )
+ {
+ final String error =
+ "Missing required key ["
+ + key
+ + "]";
+ throw new IllegalArgumentException( error );
+ }
+ else if( null == map.get( key ) )
+ {
+ final String error =
+ "Missing value for the required key ["
+ + key
+ + "]";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a new context instance implementing the supplied class
+ * backed by entries in the supplied map.
+ *
+ * @param clazz the context class
+ * @param map a map of context entry keys and values
+ * @return the constructed context instance
+ */
+ public static <T>T getProxiedInstance( final Class<T> clazz, final
Map<String,Object> map )
+ {
+ ClassLoader classloader = clazz.getClassLoader();
+ ContextInvocationHandler handler =
+ new ContextInvocationHandler( map );
+ final Object instance =
+ Proxy.newProxyInstance( classloader, new Class[]{clazz}, handler );
+ return clazz.cast( instance );
+ }
+
+ //-------------------------------------------------------------------
+ // state
+ //-------------------------------------------------------------------
+
+ /**
+ * A map containing key values.
+ */
+ private final Map<String,Object> m_map;
+
+ //-------------------------------------------------------------------
+ // constructor
+ //-------------------------------------------------------------------
+
+ /**
+ * Create a context invocation handler.
+ *
+ * @param map a map containing context key/value pairs.
+ */
+ private ContextInvocationHandler( final Map<String,Object> map )
+ {
+ if( null == map )
+ {
+ throw new NullPointerException( "map" );
+ }
+ m_map = map;
+ }
+
+ //-------------------------------------------------------------------
+ // implementation
+ //-------------------------------------------------------------------
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by the proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ public Object invoke( final Object proxy, final Method method, final
Object[] args ) throws Throwable
+ {
+ Class source = method.getDeclaringClass();
+ if( Object.class == source )
+ {
+ return method.invoke( this, args );
+ }
+ else
+ {
+ String name = method.getName();
+ if( name.startsWith( "get" ) )
+ {
+ String key = Introspector.decapitalize( name.substring( 3 )
);
+ Object value = m_map.get( key );
+ if( null != value )
+ {
+ Class<?> clazz = method.getReturnType();
+ if( isAssignableFrom( clazz, value.getClass() ) )
+ {
+ return value;
+ }
+ else if( isaContext( clazz, STRICT_PROCESSING ) )
+ {
+ if( value instanceof Map )
+ {
+ Map m = (Map) value;
+ return getProxiedInstance( clazz, m );
+ }
+ else
+ {
+ final String error =
+ "Supplied context solution value ["
+ + value.getClass().getName()
+ + "] is not an instance of java.util.Map.";
+ throw new IllegalStateException( error );
+ }
+ }
+ else if( value instanceof Value )
+ {
+ Value v = (Value) value;
+ return v.resolve( clazz, (Map) null );
+ }
+ else
+ {
+ Expression expression = new Expression( clazz,
"new", new Object[]{value} );
+ return expression.getValue();
+ }
+ }
+ else if( ( null != args ) && args.length > 0 )
+ {
+ return args[0];
+ }
+ else
+ {
+ final String error =
+ "Unable to resolve a context entry value for the key
["
+ + key
+ + "]";
+ throw new IllegalStateException( error );
+ }
+ }
+ else
+ {
+ throw new UnsupportedOperationException( name );
+ }
+ }
+ }
+
+ private static boolean isAssignableFrom( Class<?> clazz, Class<?> c )
+ {
+ if( clazz.isPrimitive() )
+ {
+ if( Integer.TYPE == clazz )
+ {
+ return Integer.class.isAssignableFrom( c );
+ }
+ else if( Boolean.TYPE == clazz )
+ {
+ return Boolean.class.isAssignableFrom( c );
+ }
+ else if( Byte.TYPE == clazz )
+ {
+ return Byte.class.isAssignableFrom( c );
+ }
+ else if( Short.TYPE == clazz )
+ {
+ return Short.class.isAssignableFrom( c );
+ }
+ else if( Long.TYPE == clazz )
+ {
+ return Long.class.isAssignableFrom( c );
+ }
+ else if( Float.TYPE == clazz )
+ {
+ return Float.class.isAssignableFrom( c );
+ }
+ else if( Double.TYPE == clazz )
+ {
+ return Double.class.isAssignableFrom( c );
+ }
+ else
+ {
+ final String error =
+ "Primitive type ["
+ + c.getName()
+ + "] not supported.";
+ throw new RuntimeException( error );
+ }
+ }
+ else
+ {
+ return clazz.isAssignableFrom( c );
+ }
+ }
+
+ private static boolean isOptionalEntry( Method method )
+ {
+ return method.getParameterTypes().length == 1;
+ }
+
+ private static String getKeyForMethod( Method method )
+ {
+ String name = method.getName();
+ if( name.startsWith( GET ) )
+ {
+ String remainder = name.substring( GET.length() );
+ return Introspector.decapitalize( remainder );
+ }
+ else
+ {
+ final String error =
+ "Method name is not a recognized pattern: "
+ + name;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private static final String STRICT_PROCESSING_KEY =
"dpml.lang.context.policy";
+ private static final String STRICT_PROCESSING_KEYWORD = "strict";
+ private static final boolean STRICT_PROCESSING =
getStrictProcessingPolicy();
+
+ private static boolean getStrictProcessingPolicy()
+ {
+ return STRICT_PROCESSING_KEYWORD.equalsIgnoreCase(
+ System.getProperty(
+ STRICT_PROCESSING_KEY,
+ STRICT_PROCESSING_KEYWORD ) );
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/DOM3DocumentBuilder.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/DOM3DocumentBuilder.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/DOM3DocumentBuilder.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,310 @@
+/*
+/*
+ * 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 dpml.lang;
+
+import dpml.util.DefaultLogger;
+
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URISyntaxException;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.ServiceLoader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.FileNotFoundException;
+
+import javax.xml.XMLConstants;
+
+import net.dpml.lang.PartError;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.InvalidArtifactException;
+
+import net.dpml.util.Logger;
+
+import org.w3c.dom.DOMError;
+import org.w3c.dom.DOMLocator;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.DOMErrorHandler;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.Document;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSParser;
+import org.w3c.dom.ls.LSSerializer;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSException;
+
+/**
+ * Utility class that creates a schema validating DOM3 parser.
+ */
+public class DOM3DocumentBuilder
+{
+ private final Logger m_logger;
+
+ /**
+ * Creation of a new DOM3 document builder.
+ */
+ public DOM3DocumentBuilder()
+ {
+ this( new DefaultLogger( "dpml.lang" ) );
+ }
+
+ /**
+ * Creation of a new DOM3 document builder.
+ * @param logger the assigned logging channel
+ */
+ public DOM3DocumentBuilder( final Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ /**
+ * Parse an xml schema document.
+ * @param uri the document uri
+ * @return the validated document
+ * @exception IOException if an IO error occurs
+ */
+ public Document parse( final URI uri ) throws IOException
+ {
+ if( null == uri )
+ {
+ throw new NullPointerException( "uri" );
+ }
+ URL url = Artifact.toURL( uri );
+ return parse( url );
+ }
+
+ /**
+ * Parse an xml schema document.
+ * @param url the document url
+ * @return the validated document
+ * @exception IOException if an IO error occurs
+ */
+ public Document parse( URL url ) throws IOException
+ {
+ if( null == url )
+ {
+ throw new NullPointerException( "url" );
+ }
+ URLConnection connection = url.openConnection();
+ return parse( connection );
+ }
+
+ public Document parse( URLConnection connection ) throws IOException
+ {
+ if( null == connection )
+ {
+ throw new NullPointerException( "connection" );
+ }
+ URL url = connection.getURL();
+ try
+ {
+ DOMImplementationRegistry registry =
+ DOMImplementationRegistry.newInstance();
+ DOMImplementationLS impl =
+ (DOMImplementationLS) registry.getDOMImplementation( "LS" );
+ if( null == impl )
+ {
+ final String error =
+ "Unable to locate a DOM3 parser.";
+ throw new IllegalStateException( error );
+ }
+ LSParser builder = impl.createLSParser(
DOMImplementationLS.MODE_SYNCHRONOUS, null );
+ DOMConfiguration config = builder.getDomConfig();
+
+ URI uri = url.toURI();
+ config.setParameter( "error-handler", new InternalErrorHandler(
m_logger, uri ) );
+ config.setParameter( "resource-resolver", new
InternalResourceResolver( m_logger ) );
+ config.setParameter( "validate", Boolean.TRUE );
+ DOMInput input = new DOMInput();
+
+ InputStream stream = connection.getInputStream();
+ InputStreamReader reader = new InputStreamReader( stream );
+ input.setCharacterStream( reader );
+
+ Document doc = builder.parse( input );
+ doc.setDocumentURI( uri.toASCIIString() );
+ return doc;
+ }
+ catch( FileNotFoundException e )
+ {
+ throw e;
+ }
+ catch( InvalidArtifactException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "DOM3 error while attempting to parse document."
+ + "\nSource: " + url;
+ IOException ioe = new IOException( error );
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+
+ /**
+ * Write a document to an output stream.
+ * @param doc the document to write
+ * @param output the output stream
+ * @exception Exception if an error occurs
+ */
+ public void write( Document doc, OutputStream output ) throws Exception
+ {
+ DOMImplementationRegistry registry =
+ DOMImplementationRegistry.newInstance();
+ DOMImplementationLS impl =
+ (DOMImplementationLS) registry.getDOMImplementation( "LS" );
+ if( null == impl )
+ {
+ final String error =
+ "Unable to locate a DOM3 implementation.";
+ throw new IllegalStateException( error );
+ }
+ LSSerializer domWriter = impl.createLSSerializer();
+ LSOutput lsOut = impl.createLSOutput();
+ lsOut.setByteStream( output );
+ domWriter.write( doc, lsOut );
+ }
+
+ /**
+ * Utility class to handle namespace uri resolves.
+ */
+ private static class InternalResourceResolver implements
LSResourceResolver
+ {
+ private static StandardNamespaceResolver RESOLVER =
+ new StandardNamespaceResolver();
+
+ private final Logger m_logger;
+
+ /**
+ * Creation of a new InternalResourceResolver.
+ * @param map the namespace to builder map
+ */
+ InternalResourceResolver( Logger logger )
+ {
+ m_logger = logger;
+ }
+
+ /**
+ * Resolve an LS input.
+ * @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
+ */
+ public LSInput resolveResource(
+ String type, String namespace, String publicId, String systemId,
String base )
+ {
+ LSResourceResolver[] resolvers = getNamespaceResolvers();
+ for( LSResourceResolver resolver : resolvers )
+ {
+ LSInput input = resolver.resolveResource( type, namespace,
publicId, systemId, base );
+ if( null != input )
+ {
+ return input;
+ }
+ }
+
+ final String error =
+ "Unable to resolve a schema for the namespace ["
+ + namespace
+ + "]";
+ throw new LSException( LSException.PARSE_ERR, error );
+ }
+
+ private LSResourceResolver[] getNamespaceResolvers()
+ {
+ ArrayList<LSResourceResolver> list = new
ArrayList<LSResourceResolver>();
+ ServiceLoader<LSResourceResolver> loaders =
+ ServiceLoader.load( LSResourceResolver.class );
+ for( LSResourceResolver resolver : loaders )
+ {
+ list.add( resolver );
+ }
+ return list.toArray( new LSResourceResolver[0] );
+ }
+ }
+
+ /**
+ * Internal error handler with room for improvement.
+ */
+ private static final class InternalErrorHandler implements
DOMErrorHandler
+ {
+ private final URI m_uri;
+ private final Logger m_logger;
+
+ InternalErrorHandler( Logger logger, URI uri )
+ {
+ m_uri = uri;
+ m_logger = logger;
+ }
+
+ /**
+ * Handle the supplied error.
+ * @param error the error
+ * @return a boolean value
+ */
+ public boolean handleError( DOMError error )
+ {
+ DOMLocator locator = error.getLocation();
+ int line = locator.getLineNumber();
+ int column = locator.getColumnNumber();
+ String uri = locator.getUri();
+ if( null == uri )
+ {
+ uri = m_uri.toString();
+ }
+
+ String source = uri;
+ if( !( ( line == -1 ) && column == -1 ) )
+ {
+ source = source + " [" + line + ":" + column + "]";
+ }
+ String message = error.getMessage();
+ final String notice =
+ message
+ + "\n"
+ + source;
+ short severity = error.getSeverity();
+ if( severity == DOMError.SEVERITY_WARNING )
+ {
+ m_logger.warn( notice );
+ return true;
+ }
+ else
+ {
+ m_logger.error( notice );
+ return false;
+ }
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/DOMInput.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/DOMInput.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/DOMInput.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,276 @@
+/*
+ * 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 dpml.lang;
+
+import java.io.Reader;
+import java.io.InputStream;
+
+import org.w3c.dom.ls.LSInput;
+
+/**
+ * This Class <code>DOMInput</code> represents a single input source for an
XML entity.
+ * <p> This Class allows an application to encapsulate information about
+ * an input source in a single object, which may include a public
+ * identifier, a system identifier, a byte stream (possibly with a specified
+ * encoding), and/or a character stream.
+ * <p> The exact definitions of a byte stream and a character stream are
+ * binding dependent.
+ * <p> There are two places that the application will deliver this input
+ * source to the parser: as the argument to the <code>parse</code> method,
+ * or as the return value of the
<code>DOMResourceResolver.resolveEntity</code>
+ * method.
+ * <p> The <code>DOMParser</code> will use the <code>LSInput</code>
+ * object to determine how to read XML input. If there is a character stream
+ * available, the parser will read that stream directly; if not, the parser
+ * will use a byte stream, if available; if neither a character stream nor a
+ * byte stream is available, the parser will attempt to open a URI
+ * connection to the resource identified by the system identifier.
+ * <p> An <code>LSInput</code> object belongs to the application: the
+ * parser shall never modify it in any way (it may modify a copy if
+ * necessary). Eventhough all attributes in this interface are writable the
+ * DOM implementation is expected to never mutate a LSInput.
+ * <p>See also the <a
href='http://www.w3.org/TR/2001/WD-DOM-Level-3-ASLS-20011025'>Document Object
Model (DOM) Level 3 Abstract Schemas and Load
+and Save Specification</a>.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DOMInput implements LSInput
+{
+ private String m_publicId = null;
+ private String m_systemId = null;
+ private String m_base = null;
+ private InputStream m_byteStream = null;
+ private Reader m_reader = null;
+ private String m_data = null;
+ private String m_encoding = null;
+ private boolean m_certified = false;
+
+ /**
+ * Default constructor.
+ */
+ public DOMInput()
+ {
+ }
+
+ /**
+ * An attribute of a language-binding dependent type that represents a
+ * stream of bytes.
+ * <br>The parser will ignore this if there is also a character stream
+ * specified, but it will use a byte stream in preference to opening a
+ * URI connection itself.
+ * <br>If the application knows the character encoding of the byte stream,
+ * it should set the encoding property. Setting the encoding in this way
+ * will override any encoding specified in the XML declaration itself.
+ */
+ public InputStream getByteStream()
+ {
+ return m_byteStream;
+ }
+
+ /**
+ * An attribute of a language-binding dependent type that represents a
+ * stream of bytes.
+ * <br>The parser will ignore this if there is also a character stream
+ * specified, but it will use a byte stream in preference to opening a
+ * URI connection itself.
+ * <br>If the application knows the character encoding of the byte stream,
+ * it should set the encoding property. Setting the encoding in this way
+ * will override any encoding specified in the XML declaration itself.
+ */
+ public void setByteStream( InputStream byteStream )
+ {
+ m_byteStream = byteStream;
+ }
+
+ /**
+ * An attribute of a language-binding dependent type that represents a
+ * stream of 16-bit units. Application must encode the stream using
+ * UTF-16 (defined in and Amendment 1 of ).
+ * <br>If a character stream is specified, the parser will ignore any byte
+ * stream and will not attempt to open a URI connection to the system
+ * identifier.
+ */
+ public Reader getCharacterStream()
+ {
+ return m_reader;
+ }
+ /**
+ * An attribute of a language-binding dependent type that represents a
+ * stream of 16-bit units. Application must encode the stream using
+ * UTF-16 (defined in and Amendment 1 of ).
+ * <br>If a character stream is specified, the parser will ignore any byte
+ * stream and will not attempt to open a URI connection to the system
+ * identifier.
+ */
+ public void setCharacterStream( Reader characterStream )
+ {
+ m_reader = characterStream;
+ }
+
+ /**
+ * A string attribute that represents a sequence of 16 bit units (utf-16
+ * encoded characters).
+ * <br>If string data is available in the input source, the parser will
+ * ignore the character stream and the byte stream and will not attempt
+ * to open a URI connection to the system identifier.
+ */
+ public String getStringData()
+ {
+ return m_data;
+ }
+
+ /**
+ * A string attribute that represents a sequence of 16 bit units (utf-16
+ * encoded characters).
+ * <br>If string data is available in the input source, the parser will
+ * ignore the character stream and the byte stream and will not attempt
+ * to open a URI connection to the system identifier.
+ */
+ public void setStringData( String stringData )
+ {
+ m_data = stringData;
+ }
+
+ /**
+ * The character encoding, if known. The encoding must be a string
+ * acceptable for an XML encoding declaration ( section 4.3.3 "Character
+ * Encoding in Entities").
+ * <br>This attribute has no effect when the application provides a
+ * character stream. For other sources of input, an encoding specified
+ * by means of this attribute will override any encoding specified in
+ * the XML claration or the Text Declaration, or an encoding obtained
+ * from a higher level protocol, such as HTTP .
+ */
+ public String getEncoding()
+ {
+ return m_encoding;
+ }
+
+ /**
+ * The character encoding, if known. The encoding must be a string
+ * acceptable for an XML encoding declaration ( section 4.3.3 "Character
+ * Encoding in Entities").
+ * <br>This attribute has no effect when the application provides a
+ * character stream. For other sources of input, an encoding specified
+ * by means of this attribute will override any encoding specified in
+ * the XML claration or the Text Declaration, or an encoding obtained
+ * from a higher level protocol, such as HTTP .
+ */
+ public void setEncoding( String encoding )
+ {
+ m_encoding = encoding;
+ }
+
+ /**
+ * The public identifier for this input source. The public identifier is
+ * always optional: if the application writer includes one, it will be
+ * provided as part of the location information.
+ */
+ public String getPublicId()
+ {
+ return m_publicId;
+ }
+ /**
+ * The public identifier for this input source. The public identifier is
+ * always optional: if the application writer includes one, it will be
+ * provided as part of the location information.
+ */
+ public void setPublicId( String publicId )
+ {
+ m_publicId = publicId;
+ }
+
+ /**
+ * The system identifier, a URI reference , for this input source. The
+ * system identifier is optional if there is a byte stream or a
+ * character stream, but it is still useful to provide one, since the
+ * application can use it to resolve relative URIs and can include it in
+ * error messages and warnings (the parser will attempt to fetch the
+ * ressource identifier by the URI reference only if there is no byte
+ * stream or character stream specified).
+ * <br>If the application knows the character encoding of the object
+ * pointed to by the system identifier, it can register the encoding by
+ * setting the encoding attribute.
+ * <br>If the system ID is a relative URI reference (see section 5 in ),
+ * the behavior is implementation dependent.
+ */
+ public String getSystemId()
+ {
+ return m_systemId;
+ }
+ /**
+ * The system identifier, a URI reference , for this input source. The
+ * system identifier is optional if there is a byte stream or a
+ * character stream, but it is still useful to provide one, since the
+ * application can use it to resolve relative URIs and can include it in
+ * error messages and warnings (the parser will attempt to fetch the
+ * ressource identifier by the URI reference only if there is no byte
+ * stream or character stream specified).
+ * <br>If the application knows the character encoding of the object
+ * pointed to by the system identifier, it can register the encoding by
+ * setting the encoding attribute.
+ * <br>If the system ID is a relative URI reference (see section 5 in ),
+ * the behavior is implementation dependent.
+ */
+ public void setSystemId( String systemId )
+ {
+ m_systemId = systemId;
+ }
+
+ /**
+ * The base URI to be used (see section 5.1.4 in ) for resolving relative
+ * URIs to absolute URIs. If the baseURI is itself a relative URI, the
+ * behavior is implementation dependent.
+ */
+ public String getBaseURI()
+ {
+ return m_base;
+ }
+
+ /**
+ * The base URI to be used (see section 5.1.4 in ) for resolving relative
+ * URIs to absolute URIs. If the baseURI is itself a relative URI, the
+ * behavior is implementation dependent.
+ */
+ public void setBaseURI( String baseURI )
+ {
+ m_base = baseURI;
+ }
+
+ /**
+ * If set to true, assume that the input is certified (see section 2.13
+ * in [<a href='http://www.w3.org/TR/2002/CR-xml11-20021015/'>XML
1.1</a>]) when
+ * parsing [<a href='http://www.w3.org/TR/2002/CR-xml11-20021015/'>XML
1.1</a>].
+ */
+ public boolean getCertifiedText()
+ {
+ return m_certified;
+ }
+
+ /**
+ * If set to true, assume that the input is certified (see section 2.13
+ * in [<a href='http://www.w3.org/TR/2002/CR-xml11-20021015/'>XML
1.1</a>]) when
+ * parsing [<a href='http://www.w3.org/TR/2002/CR-xml11-20021015/'>XML
1.1</a>].
+ */
+ public void setCertifiedText( boolean certifiedText )
+ {
+ m_certified = certifiedText;
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/DefaultPartManager.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/DefaultPartManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/DefaultPartManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,64 @@
+/*
+ * 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 dpml.lang;
+
+import net.dpml.lang.PartManager;
+
+/**
+ * Abstract base class for artifact content handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DefaultPartManager implements PartManager
+{
+ private final Part m_part;
+
+ DefaultPartManager( Part part )
+ {
+ m_part = part;
+ }
+
+ /**
+ * Returns the part URI as a string.
+ * @return the codebase uri
+ */
+ public String getCodebaseURI()
+ {
+ return m_part.getCodebaseURI();
+ }
+
+ /**
+ * Returns the part title.
+ * @return the title
+ */
+ public String getTitle()
+ {
+ return m_part.getTitle();
+ }
+
+ /**
+ * Returns the part description.
+ * @return the description
+ */
+ public String getDescription()
+ {
+ return m_part.getDescription();
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/Disposable.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Disposable.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Disposable.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,36 @@
+/*
+ * 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.lang;
+
+/**
+ * The Disposable interface is implemented by a disposable sub-system within
Transit.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Disposable
+{
+ /**
+ * Dispose of the service. During disposal a sub-system is required to
+ * release all references such as listeners and internal resources
+ * in preparation for garbage collection.
+ */
+ void dispose();
+}
+

Added: trunk/main/lang/part/src/main/dpml/lang/DocumentRuntimeException.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/DocumentRuntimeException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/DocumentRuntimeException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,55 @@
+/*
+ * 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.lang;
+
+/**
+ * Exception throw in the event of a DOM parse fatal condition.
+
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DocumentRuntimeException extends RuntimeException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ValueRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ */
+ public DocumentRuntimeException( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ValueRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public DocumentRuntimeException( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/lang/Info.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Info.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Info.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,125 @@
+/*
+ * 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 dpml.lang;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.Arrays;
+
+import javax.xml.XMLConstants;
+
+import net.dpml.util.Logger;
+import dpml.util.ObjectUtils;
+
+
+/**
+ * Part info description.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Info
+{
+ private final String m_title;
+ private final String m_description;
+ private final URI m_uri;
+
+ /**
+ * Creation of a new part info descriptor.
+ * @param uri the part uri
+ * @param title the title of the part
+ * @param description the part description
+ */
+ public Info( URI uri, String title, String description )
+ {
+ m_uri = uri;
+ m_title = title;
+ m_description = description;
+ }
+
+ /**
+ * Get the part uri.
+ *
+ * @return the uri
+ */
+ public URI getURI()
+ {
+ return m_uri;
+ }
+
+ /**
+ * Get the part title.
+ *
+ * @return the title
+ */
+ public String getTitle()
+ {
+ return m_title;
+ }
+
+ /**
+ * Get the part 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( other instanceof Info )
+ {
+ Info info = (Info) other;
+ if( !ObjectUtils.equals( m_title, info.m_title ) )
+ {
+ return false;
+ }
+ else
+ {
+ return ObjectUtils.equals( m_description, info.m_description
);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the hashcode for this instance.
+ * @return the hash value
+ */
+ public int hashCode()
+ {
+ int hash = getClass().hashCode();
+ hash ^= ObjectUtils.hashValue( m_title );
+ hash ^= ObjectUtils.hashValue( m_description );
+ return hash;
+ }
+}
\ No newline at end of file

Added: trunk/main/lang/part/src/main/dpml/lang/LoggingInvocationHandler.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/LoggingInvocationHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/LoggingInvocationHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,127 @@
+/*
+ * 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.lang;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
+import java.util.Hashtable;
+
+import net.dpml.util.Logger;
+
+/**
+ * Invocation handler utility for the legacy net.dpml.util.Logger that
+ * redirects to an instance of net.dpml.util.Logger.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class LoggingInvocationHandler implements InvocationHandler
+{
+ //-------------------------------------------------------------------
+ // static
+ //-------------------------------------------------------------------
+
+ private static final Map<String,Method> METHODS = getMethodMap();
+
+ /**
+ * Construct a new context instance implementing the supplied class
+ * backed by entries in the supplied map.
+ *
+ * @param clazz the context class
+ * @param logger the logging channel
+ * @return the constructed context instance
+ */
+ public static <T>T getProxiedInstance( final Class<T> clazz, final
Logger logger )
+ {
+ ClassLoader classloader = clazz.getClassLoader();
+ LoggingInvocationHandler handler = new LoggingInvocationHandler(
clazz, logger );
+ final Object instance =
+ Proxy.newProxyInstance( classloader, new Class[]{clazz}, handler );
+ return clazz.cast( instance );
+ }
+
+ //-------------------------------------------------------------------
+ // state
+ //-------------------------------------------------------------------
+
+ /**
+ * Context datatype.
+ */
+ private final Logger m_logger;
+ private final Class m_class;
+ private final Map<String,Method> m_methods = new
Hashtable<String,Method>();
+
+ //-------------------------------------------------------------------
+ // constructor
+ //-------------------------------------------------------------------
+
+ /**
+ * Create a context invocation handler.
+ *
+ * @param map a map containing context key/value pairs.
+ */
+ private LoggingInvocationHandler( final Class clazz, final Logger logger
)
+ {
+ m_logger = logger;
+ m_class = clazz;
+ }
+
+ //-------------------------------------------------------------------
+ // implementation
+ //-------------------------------------------------------------------
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by the proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ public Object invoke( final Object proxy, final Method method, final
Object[] args ) throws Throwable
+ {
+ String name = method.getName();
+ Method m = METHODS.get( name );
+ if( m.getReturnType() == Logger.class )
+ {
+ Logger logger = (Logger) m.invoke( m_logger, args );
+ return getProxiedInstance( m_class, logger );
+ }
+ else
+ {
+ return m.invoke( m_logger, args );
+ }
+ }
+
+ private static Map<String,Method> getMethodMap()
+ {
+ Hashtable<String,Method> map = new Hashtable<String,Method>();
+ Method[] methods = Logger.class.getMethods();
+ for( Method method : methods )
+ {
+ map.put( method.getName(), method );
+ }
+ return map;
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/Part.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Part.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Part.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,362 @@
+/*
+ * 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 dpml.lang;
+
+import dpml.util.ObjectUtils;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.lang.management.ManagementFactory;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Hashtable;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.management.InstanceAlreadyExistsException;
+
+import javax.xml.XMLConstants;
+
+import dpml.util.Category;
+import net.dpml.lang.Buffer;
+import net.dpml.lang.Strategy;
+import net.dpml.lang.PartContentHandler;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.SimpleServiceRegistry;
+import net.dpml.lang.PartManager;
+
+import net.dpml.util.Logger;
+
+/**
+ * Part datastructure.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Part implements PartManager
+{
+ private final Info m_info;
+ private final Strategy m_strategy;
+ private final Classpath m_classpath;
+
+ /**
+ * Creation of a new part datastructure.
+ * @param info the info descriptor
+ * @param classpath the part classpath definition
+ * @param strategy the part deployment strategy
+ * @exception IOException if an I/O error occurs
+ */
+ public Part( Info info, Classpath classpath, Strategy strategy ) throws
IOException
+ {
+ if( null == info )
+ {
+ throw new NullPointerException( "info" );
+ }
+ if( null == strategy )
+ {
+ throw new NullPointerException( "strategy" );
+ }
+
+ m_info = info;
+ m_strategy = strategy;
+ m_classpath = classpath;
+
+ 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", "Parts" );
+ table.put( "name", "" + System.identityHashCode( this ) );
+ ObjectName name =
+ ObjectName.getInstance( "net.dpml.transit", table );
+ server.registerMBean( this, name );
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Service instantiation.
+ * @return the instantiated instance
+ * @exception IOException if an error occurs
+ * @deprecated Replaced by getInstance( Class<T> )
+ */
+ public Object getContent() throws IOException
+ {
+ return m_strategy.getContentForClass( Object.class );
+ }
+
+ /**
+ * Return the part content or null if the result type is unresolvable
+ * relative to the supplied classes argument.
+ * @param classes the content type selection classes
+ * @return the content
+ * @exception IOException if an IO error occurs
+ * @deprecated Replaced by getContentForClass(Class) method
+ */
+ public Object getContent( Class[] classes ) throws IOException
+ {
+ if( classes.length == 0 )
+ {
+ return this;
+ }
+ else
+ {
+ for( int i=0; i<classes.length; i++ )
+ {
+ Class<?> c = classes[i];
+ Object content = m_strategy.getContentForClass( c );
+ if( null != content )
+ {
+ return content;
+ }
+ }
+ return null;
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ // PartManager
+ //-----------------------------------------------------------------------
+
+ /**
+ * Returns the part URI as a string.
+ * @return the codebase uri
+ */
+ public String getCodebaseURI()
+ {
+ return m_info.getURI().toASCIIString();
+ }
+
+ /**
+ * Returns the part title.
+ * @return the title
+ */
+ public String getTitle()
+ {
+ return m_info.getTitle();
+ }
+
+ /**
+ * Returns the part description.
+ * @return the description
+ */
+ public String getDescription()
+ {
+ return m_info.getDescription();
+ }
+
+ //-----------------------------------------------------------------------
+ // Part
+ //-----------------------------------------------------------------------
+
+ /**
+ * Get the part strategy.
+ *
+ * @return the strategy definition.
+ */
+ public Strategy getStrategy()
+ {
+ return m_strategy;
+ }
+
+ /**
+ * Get the part classpath.
+ *
+ * @return the classpath definition.
+ */
+ public Classpath getClasspath()
+ {
+ return m_classpath;
+ }
+
+ /**
+ * Instantiate a value.
+ * @param args supplimentary arguments
+ * @return the resolved instance
+ * @exception Exception if a deployment error occurs
+ * @deprecated Replaced by getInstance( Class<T>, Object[] )
+ */
+ public Object instantiate( Object[] args ) throws Exception
+ {
+ Strategy strategy = getStrategy();
+ ServiceRegistry registry = new SimpleServiceRegistry( args );
+ strategy.initialize( registry );
+ return strategy.getInstance( Object.class );
+ }
+
+ public void save( OutputStream output ) throws IOException
+ {
+ final Writer writer = new OutputStreamWriter( output );
+ Buffer b = new Buffer( writer, PartContentHandler.NAMESPACE, "" );
+ try
+ {
+ b.write( XML_HEADER );
+ b.nl( "\n" + PART_HEADER );
+ Buffer b2 = b.indent( " " );
+ encodeInfo( b2, m_info );
+ Strategy strategy = getStrategy();
+ strategy.encode( b2, null );
+ encodeClasspath( b2, getClasspath() );
+ b.nl( PART_FOOTER );
+ b.nl( "" );
+ }
+ finally
+ {
+ writer.flush();
+ output.close();
+ }
+ }
+
+ /**
+ * Test if this part is equivalent to the supplied part.
+ *
+ * @param other the other object
+ * @return true if the parts are equivalent
+ */
+ public boolean equals( Object other )
+ {
+ if( other instanceof Part )
+ {
+ Part part = (Part) other;
+ if( !m_info.equals( part.m_info ) )
+ {
+ return false;
+ }
+ else if( !m_classpath.equals( part.m_classpath ) )
+ {
+ return false;
+ }
+ else
+ {
+ return m_strategy.equals( part.m_strategy );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the part hashcode.
+ *
+ * @return the hash value
+ */
+ public int hashCode()
+ {
+ int hash = m_info.hashCode();
+ hash ^= m_strategy.hashCode();
+ hash ^= m_classpath.hashCode();
+ return hash;
+ }
+
+ private static void encodeInfo( Buffer b, Info info ) throws IOException
+ {
+ String title = info.getTitle();
+ String description = info.getDescription();
+ if( null == description )
+ {
+ if( null == title )
+ {
+ b.nl( "<info/>" );
+ }
+ else
+ {
+ b.nl( "<info title=\"" + title + "\"/>" );
+ }
+ }
+ else
+ {
+ if( null == title )
+ {
+ b.nl( "<info>" );
+ }
+ else
+ {
+ b.nl( "<info title=\"" + title + "\">" );
+ }
+ Buffer b2 = b.indent();
+ b2.nl( "<description>" + description + "</description>" );
+ b.nl( "</info>" );
+ }
+ }
+
+ private static void encodeClasspath( Buffer b, Classpath classpath )
throws IOException
+ {
+ b.nl( "<classpath>" );
+ if( null != classpath )
+ {
+ Buffer b2 = b.indent();
+ encodeClasspathCategory( b2, classpath, Category.SYSTEM );
+ encodeClasspathCategory( b2, classpath, Category.PUBLIC );
+ encodeClasspathCategory( b2, classpath, Category.PROTECTED );
+ encodeClasspathCategory( b2, classpath, Category.PRIVATE );
+ }
+ b.nl( "</classpath>" );
+ }
+
+ private static void encodeClasspathCategory(
+ Buffer b, Classpath classpath, Category category ) throws IOException
+ {
+ URI[] uris = classpath.getDependencies( category );
+ if( uris.length > 0 )
+ {
+ String name = category.name().toLowerCase();
+ b.nl( "<" + name + ">" );
+ Buffer b2 = b.indent();
+ for( int i=0; i<uris.length; i++ )
+ {
+ URI uri = uris[i];
+ b2.nl( "<uri>" + uri.toASCIIString() + "</uri>" );
+ }
+ b.nl( "</" + name + ">" );
+ }
+ }
+
+ /**
+ * Default XML header.
+ */
+ private static final String XML_HEADER = "<?xml version=\"1.0\"?>";
+
+ /**
+ * Part header.
+ */
+ private static final String PART_HEADER =
+ "<part xmlns=\""
+ + PartContentHandler.NAMESPACE
+ + "\""
+ + "\n xmlns:xsi=\""
+ + XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
+ + "\">";
+
+ /**
+ * Part footer.
+ */
+ private static final String PART_FOOTER = "</part>";
+}

Added: trunk/main/lang/part/src/main/dpml/lang/StandardNamespaceResolver.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/StandardNamespaceResolver.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/StandardNamespaceResolver.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,118 @@
+/*
+ * 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 dpml.lang;
+
+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 StandardNamespaceResolver implements LSResourceResolver
+{
+ /**
+ * Return the schema definition for a supplied namespace. This
implementation
+ * handles the resolution of the standard DPML language XDSs through the
binding
+ * standard schema uris to resource resolvable from the context
classloader.
+ *
+ * Standard schema uris include:
+ *
+ * <ul>
+ * <li>dpml:part</li>
+ * <li>dpml:metro</li>
+ * <li>dpml:state</li>
+ * <li>dpml:antlib</li>
+ * <li>dpml:library</li>
+ * </ul>
+ *
+ * @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( "dpml:part".equals( namespace ) )
+ {
+ return classloader.getResource( "dpml/lang/dpml-lang-part.xsd" );
+ }
+ else if( "dpml:metro".equals( namespace ) )
+ {
+ return classloader.getResource(
"dpml/lang/dpml-lang-component.xsd" );
+ }
+ else if( "dpml:state".equals( namespace ) )
+ {
+ return classloader.getResource( "dpml/lang/dpml-lang-state.xsd"
);
+ }
+ else if( "dpml:antlib".equals( namespace ) )
+ {
+ return classloader.getResource(
"dpml/lang/dpml-lang-resource.xsd" );
+ }
+ else if( "dpml:library".equals( namespace ) )
+ {
+ return classloader.getResource(
"dpml/lang/dpml-lang-library.xsd" );
+ }
+ else
+ {
+ return null;
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/Value.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/Value.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/Value.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,68 @@
+/*
+ * 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.lang;
+
+import java.io.IOException;
+import java.util.Map;
+
+import net.dpml.lang.Buffer;
+
+/**
+ * An object resolvable from primitive and symbolic arguments.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Value
+{
+ /**
+ * Resolve an instance from the value using the context classloader.
+ * @return the resolved instance
+ * @exception Exception if error occurs during instance resolution
+ */
+ Object resolve() throws Exception;
+
+ /**
+ * Resolve an instance from the value using a supplied context map. If
any
+ * target expressions in immediate or nested values contain a symbolic
+ * expression the value will be resolved using the supplied map.
+ *
+ * @param map the context map
+ * @return the resolved instance
+ * @exception Exception if error occurs during instance resolution
+ */
+ Object resolve( Map<String,Object> map ) throws Exception;
+
+ /**
+ * Resolve an instance from the value using a supplied context map. If
any
+ * target expressions in immediate or nested values contain a symbolic
+ * expression the value will be resolved using the supplied map.
+ *
+ * @param type the type
+ * @param map the context map
+ * @return the resolved instance
+ * @exception Exception if error occurs during instance resolution
+ */
+ Object resolve( Class<?> type, Map<String,Object> map ) throws Exception;
+
+ void encode( Buffer buffer ) throws IOException;
+
+ void encode( Buffer buffer, String label, String key ) throws
IOException;
+
+}

Added: trunk/main/lang/part/src/main/dpml/lang/ValueDecoder.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/ValueDecoder.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/ValueDecoder.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,75 @@
+/*
+ * 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 dpml.lang;
+
+import dpml.lang.Construct;
+
+import dpml.util.ElementHelper;
+
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * Utility used to decode values from DOM elements.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class ValueDecoder
+{
+ /**
+ * Build an array of values for the supplied element array.
+ * @param elements the elements
+ * @param resolver symbolic value property resolver
+ * @return the resolved values
+ */
+ public Value[] decodeValues( Element[] elements, Resolver resolver )
+ {
+ Value[] values = new Value[ elements.length ];
+ for( int i=0; i<elements.length; i++ )
+ {
+ values[i] = decodeValue( elements[i], resolver );
+ }
+ return values;
+ }
+
+ /**
+ * Build a single value instance from a supplied element.
+ * @param element the element
+ * @param resolver symbolic value property resolver
+ * @return the resolved value
+ */
+ public Value decodeValue( Element element, Resolver resolver )
+ {
+ String classname = ElementHelper.getAttribute( element, "class",
null, resolver );
+ String method = ElementHelper.getAttribute( element, "method", null,
resolver );
+ Element[] elements = ElementHelper.getChildren( element, "param" );
+ if( elements.length > 0 )
+ {
+ Value[] values = decodeValues( elements, resolver );
+ return new Construct( classname, method, values );
+ }
+ else
+ {
+ String value = ElementHelper.getAttribute( element, "value",
null, resolver );
+ return new Construct( classname, method, value );
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/lang/ValueException.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/ValueException.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/ValueException.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,55 @@
+/*
+ * 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.lang;
+
+/**
+ * Exception to indicate an error arrising from a value type.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ValueException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ValueException</code> instance.
+ *
+ * @param message the exception message
+ */
+ public ValueException( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ValueException</code> instance.
+ *
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public ValueException( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/lang/ValueRuntimeException.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/lang/ValueRuntimeException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/lang/ValueRuntimeException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,55 @@
+/*
+ * 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.lang;
+
+/**
+ * Exception to indicate an error arrising from a value type.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ValueRuntimeException extends RuntimeException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ValueRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ */
+ public ValueRuntimeException( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ValueRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public ValueRuntimeException( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
+

Added: trunk/main/lang/part/src/main/dpml/state/DefaultInterface.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/DefaultInterface.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/DefaultInterface.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,109 @@
+/*
+ * 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.state;
+
+import net.dpml.state.Interface;
+
+import java.io.Serializable;
+
+/**
+ * Default implementation of an operation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultInterface implements Interface, Serializable
+{
+ private final String m_classname;
+
+ /**
+ * Creation of a new interface declaration.
+ * @param classname the overriding method name
+ * @exception NullPointerException if the operation name is null
+ */
+ public DefaultInterface( String classname ) throws NullPointerException
+ {
+ if( null == classname )
+ {
+ throw new NullPointerException( "classname" );
+ }
+ m_classname = classname;
+ }
+
+ /**
+ * Overriden method returning the interface classname.
+ * @return the name (interface classname)
+ * @see #getClassname()
+ */
+ public String getName()
+ {
+ return getClassname();
+ }
+
+ /**
+ * Return the interface classname.
+ * @return the classname
+ */
+ public String getClassname()
+ {
+ return m_classname;
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "interface:" + m_classname;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof DefaultInterface )
+ {
+ DefaultInterface description = (DefaultInterface) other;
+ return m_classname.equals( description.m_classname );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ int hash = getClass().hashCode();
+ hash ^= m_classname.hashCode();
+ return hash;
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/DefaultOperation.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/DefaultOperation.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/DefaultOperation.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,139 @@
+/*
+ * 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.state;
+
+import java.io.Serializable;
+
+import net.dpml.state.Operation;
+
+/**
+ * Default implementation of an operation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultOperation implements Operation, Serializable
+{
+ private final String m_name;
+ private final String m_method;
+
+ /**
+ * Creation of a new operation.
+ * @param name the operation name
+ * @exception NullPointerException if the operation name is null
+ */
+ public DefaultOperation( final String name ) throws NullPointerException
+ {
+ this( name, null );
+ }
+
+ /**
+ * Creation of a new operation.
+ * @param name the operation name
+ * @param method the overriding method name
+ * @exception NullPointerException if the operation name is null
+ */
+ public DefaultOperation( final String name, String method ) throws
NullPointerException
+ {
+ if( null == name )
+ {
+ throw new NullPointerException( "name" );
+ }
+ m_name = name;
+ m_method = method;
+ }
+
+ /**
+ * Return the action name.
+ * @return the name
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Return the optional overriding method name. If the
+ * value returned is null the method shall be assumed to be the
+ * equivalent of "get[Name]().
+ * @return the operation method name
+ */
+ public String getMethodName()
+ {
+ return m_method;
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "operation:" + m_name;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof DefaultOperation )
+ {
+ DefaultOperation operation = (DefaultOperation) other;
+
+ if( !m_name.equals( operation.getName() ) )
+ {
+ return false;
+ }
+ else if( null == m_method )
+ {
+ return null == operation.m_method;
+ }
+ else
+ {
+ return m_method.equals( operation.m_method );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ int hash = getClass().hashCode();
+ hash ^= m_name.hashCode();
+ if( null != m_method )
+ {
+ hash ^= m_method.hashCode();
+ }
+ return hash;
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/DefaultState.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/DefaultState.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/DefaultState.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,383 @@
+/*
+ * 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.state;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import net.dpml.state.Action;
+import net.dpml.state.Interface;
+import net.dpml.state.Operation;
+import net.dpml.state.State;
+import net.dpml.state.Transition;
+import net.dpml.state.Trigger;
+
+/**
+ * Default implementation of an application state descriptor.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultState implements State, Serializable
+{
+ /**
+ * Null state.
+ */
+ public static final State NULL_STATE = new NullState();
+
+ private final String m_name;
+ private final Transition[] m_transitions;
+ private final Operation[] m_operations;
+ private final Interface[] m_interfaces;
+ private final State[] m_states;
+ private final Trigger[] m_triggers;
+ private final boolean m_terminal;
+
+ private transient State m_parent;
+
+ /**
+ * Creation of a new state.
+ */
+ public DefaultState()
+ {
+ this( "root" );
+ }
+
+ /**
+ * Creation of a new state.
+ * @param name the state name
+ */
+ public DefaultState( final String name )
+ {
+ this( name, new Trigger[0], new Transition[0], new Interface[0], new
Operation[0], new State[0], true );
+ }
+
+ /**
+ * Creation of a new non-terminal state.
+ * @param name the state name
+ * @param triggers an array of triggers
+ * @param transitions an array of state transitions
+ * @param interfaces an array of management interface declarations
+ * @param operations an array of operations
+ * @param states an array of substates
+ */
+ public DefaultState(
+ final String name, final Trigger[] triggers, final Transition[]
transitions,
+ final Interface[] interfaces, final Operation[] operations, final
State[] states )
+ {
+ this( name, triggers, transitions, interfaces, operations, states,
false );
+ }
+
+ /**
+ * Creation of a new state.
+ * @param name the state name
+ * @param triggers an array of triggers
+ * @param transitions an array of state transitions
+ * @param interfaces an array of management interface declarations
+ * @param operations an array of operations
+ * @param states an array of substates
+ * @param terminal the terminal flag
+ */
+ public DefaultState(
+ final String name, final Trigger[] triggers, final Transition[]
transitions,
+ final Interface[] interfaces, final Operation[] operations, final
State[] states, boolean terminal )
+ {
+ if( null == name )
+ {
+ throw new NullPointerException( "name" );
+ }
+
+ for( int i=0; i<operations.length; i++ )
+ {
+ Operation operation = operations[i];
+ if( null == operation )
+ {
+ throw new NullPointerException( "operation/" + i );
+ }
+ }
+
+ m_name = name;
+ m_triggers = triggers;
+ m_transitions = transitions;
+ m_operations = operations;
+ m_interfaces = interfaces;
+ m_states = states;
+ m_terminal = terminal;
+
+ for( int i=0; i<transitions.length; i++ )
+ {
+ Transition transition = transitions[i];
+ if( null == transition )
+ {
+ throw new NullPointerException( "transition/" + i );
+ }
+ transition.setState( this );
+ }
+
+ for( int i=0; i<triggers.length; i++ )
+ {
+ Trigger trigger = triggers[i];
+ if( null == trigger )
+ {
+ throw new NullPointerException( "trigger/" + i );
+ }
+ Action action = trigger.getAction();
+ if( action instanceof Transition )
+ {
+ Transition transition = (Transition) action;
+ transition.setState( this );
+ }
+ }
+
+ for( int i=0; i<interfaces.length; i++ )
+ {
+ Interface description = interfaces[i];
+ if( null == description )
+ {
+ throw new NullPointerException( "interface/" + i );
+ }
+ }
+
+ for( int i=0; i<states.length; i++ )
+ {
+ State state = states[i];
+ if( null == state )
+ {
+ throw new NullPointerException( "state/ " + i );
+ }
+ state.setParent( this );
+ }
+ }
+
+ /**
+ * Return the parent state to this state or null if this is the root of a
+ * state graph.
+ * @return the parent state
+ */
+ public State getParent()
+ {
+ return m_parent;
+ }
+
+ /**
+ * Set the parent state.
+ * @param state the parent state
+ */
+ public void setParent( State state )
+ {
+ if( null == m_parent )
+ {
+ m_parent = state;
+ }
+ else
+ {
+ final String error =
+ "Illegal attempt to reassign parent.";
+ throw new IllegalStateException( error );
+ }
+ }
+
+ /**
+ * Return the name of the state.
+ * @return the state name
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Return the array of triggers associated with the state.
+ * @return the trigger array
+ */
+ public Trigger[] getTriggers()
+ {
+ return m_triggers;
+ }
+
+ /**
+ * Return the state path. The path is composed of a sequence of states
+ * from the root to this state.
+ * @return the state path
+ */
+ public State[] getStatePath()
+ {
+ if( null == m_parent )
+ {
+ return new State[]{this};
+ }
+ else
+ {
+ State[] path = m_parent.getStatePath();
+ State[] result = new State[ path.length + 1 ];
+ System.arraycopy( path, 0, result, 0, path.length );
+ result[ path.length ] = this;
+ return result;
+ }
+ }
+
+ /**
+ * Return the substates within this state.
+ * @return the substate array
+ */
+ public State[] getStates()
+ {
+ return m_states;
+ }
+
+ /**
+ * Return the array of transtions associated with the state.
+ * @return the transition array
+ */
+ public Transition[] getTransitions()
+ {
+ return m_transitions;
+ }
+
+ /**
+ * Return the array of operations associated with the state.
+ * @return the operation array
+ */
+ public Operation[] getOperations()
+ {
+ return m_operations;
+ }
+
+ /**
+ * Return the array of management interfaces associated with the state.
+ * @return the interfaces array
+ */
+ public Interface[] getInterfaces()
+ {
+ return m_interfaces;
+ }
+
+ /**
+ * Return the terminal flag.
+ * @return true if terminal
+ */
+ public boolean getTerminal()
+ {
+ return isTerminal();
+ }
+
+ /**
+ * Test is the state is a terminal state.
+ * @return true if terminal
+ */
+ public boolean isTerminal()
+ {
+ return m_terminal;
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+ State[] path = getStatePath();
+ for( int i=0; i<path.length; i++ )
+ {
+ State state = path[i];
+ if( i>0 )
+ {
+ buffer.append( "/" );
+ }
+ buffer.append( state.getName() );
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof DefaultState )
+ {
+ DefaultState state = (DefaultState) other;
+ if( !m_name.equals( state.getName() ) )
+ {
+ return false;
+ }
+ else if( m_terminal != state.isTerminal() )
+ {
+ return false;
+ }
+ else if( !Arrays.equals( m_triggers, state.getTriggers() ) )
+ {
+ return false;
+ }
+ else if( !Arrays.equals( m_transitions, state.getTransitions() )
)
+ {
+ return false;
+ }
+ else if( !Arrays.equals( m_operations, state.getOperations() ) )
+ {
+ return false;
+ }
+ else
+ {
+ return Arrays.equals( m_states, state.getStates() );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ if( null == m_parent )
+ {
+ return m_name.hashCode();
+ }
+ else
+ {
+ int hash = m_parent.hashCode();
+ hash ^= m_name.hashCode();
+ return hash;
+ }
+ }
+
+ private boolean equals( Object a, Object b )
+ {
+ if( null == a )
+ {
+ return null == b;
+ }
+ else
+ {
+ return a.equals( b );
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/DefaultTransition.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/DefaultTransition.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/DefaultTransition.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,203 @@
+/*
+ * 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.state;
+
+import java.io.Serializable;
+
+import net.dpml.state.State;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+
+/**
+ * Default implemention of a state transition descriptor.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultTransition implements Transition, Serializable
+{
+ private final String m_name;
+ private final String m_target;
+ private final Operation m_operation;
+
+ private transient State m_state;
+
+ /**
+ * Creation of a new transition.
+ * @param name the transition name
+ * @param target the transit target state name
+ */
+ public DefaultTransition( final String name, final String target )
+ {
+ this( name, target, null );
+ }
+
+ /**
+ * Creation of a new transition.
+ * @param name the transition name
+ * @param target the transit target state name
+ * @param operation optional transition operation
+ */
+ public DefaultTransition( final String name, final String target, final
Operation operation )
+ {
+ if( null == name )
+ {
+ throw new NullPointerException( "name" );
+ }
+ if( null == target )
+ {
+ throw new NullPointerException( "target" );
+ }
+ m_name = name;
+ m_target = target;
+ m_operation = operation;
+ }
+
+ /**
+ * Set the state that this transition is a part of.
+ * @param state the owning state
+ */
+ public void setState( State state )
+ {
+ if( null == state )
+ {
+ throw new NullPointerException( "state" );
+ }
+ if( null == m_state )
+ {
+ m_state = state;
+ }
+ else
+ {
+ throw new IllegalStateException( "State already set." );
+ }
+ }
+
+ /**
+ * Return the state that this transition is a part of.
+ * @return the owning state
+ */
+ public State getState()
+ {
+ if( null != m_state )
+ {
+ return m_state;
+ }
+ else
+ {
+ throw new IllegalStateException( "Enclosing state has not been
declared." );
+ }
+ }
+
+ /**
+ * Return the transition name
+ * @return the name
+ */
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Return the transition target state name
+ * @return the target state name
+ */
+ public String getTargetName()
+ {
+ return m_target;
+ }
+
+ /**
+ * Return an operation associated with the transition.
+ * @return a possibly null operation
+ */
+ public Operation getOperation()
+ {
+ return m_operation;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof DefaultTransition )
+ {
+ DefaultTransition transition = (DefaultTransition) other;
+ if( !m_name.equals( transition.getName() ) )
+ {
+ return false;
+ }
+ else if( !equals( m_target, transition.getTargetName() ) )
+ {
+ return false;
+ }
+ else
+ {
+ return equals( m_operation, transition.getOperation() );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ int hash = m_name.hashCode();
+ hash ^= m_target.hashCode();
+ if( m_operation != null )
+ {
+ hash ^= m_operation.hashCode();
+ }
+ return hash;
+ }
+
+ private boolean equals( Object a, Object b )
+ {
+ if( null == a )
+ {
+ return null == b;
+ }
+ else
+ {
+ return a.equals( b );
+ }
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "transition:" + getName() + " (target=" + m_target + ")";
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/DefaultTrigger.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/DefaultTrigger.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/DefaultTrigger.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,123 @@
+/*
+ * 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.state;
+
+import java.io.Serializable;
+
+import net.dpml.state.Trigger;
+import net.dpml.state.TriggerPolicy;
+import net.dpml.state.Action;
+
+/**
+ * Default implementation of trigger.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultTrigger implements Trigger, Serializable
+{
+ private final TriggerPolicy m_policy;
+ private final Action m_action;
+
+ /**
+ * Creation of a new trigger.
+ * @param event the trigger event constant
+ * @param action the action fired by the trigger
+ */
+ public DefaultTrigger( final TriggerPolicy event, final Action action )
+ {
+ if( null == event )
+ {
+ throw new NullPointerException( "event" );
+ }
+ if( null == action )
+ {
+ throw new NullPointerException( "action" );
+ }
+ m_policy = event;
+ m_action = action;
+ }
+
+ /**
+ * Return the event enumneration that this trigger is associated with.
+ * @return the triggering event class
+ */
+ public TriggerPolicy getPolicy()
+ {
+ return m_policy;
+ }
+
+ /**
+ * Return the actions that this trigger initiates.
+ * @return the triggered action
+ */
+ public Action getAction()
+ {
+ return m_action;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof DefaultTrigger )
+ {
+ DefaultTrigger trigger = (DefaultTrigger) other;
+ if( !m_policy.equals( trigger.getPolicy() ) )
+ {
+ return false;
+ }
+ else
+ {
+ return m_action.equals( trigger.getAction() );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ int hash = m_policy.hashCode();
+ hash ^= m_action.hashCode();
+ return hash;
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "trigger:" + m_policy.name().toUpperCase();
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/NullState.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/NullState.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/NullState.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,153 @@
+/*
+ * 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.state;
+
+import java.io.Serializable;
+
+import net.dpml.state.State;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+import net.dpml.state.Interface;
+import net.dpml.state.Trigger;
+
+/**
+ * Null state implementation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class NullState implements State, Serializable
+{
+ /**
+ * Return the name of the state.
+ * @return the state name
+ */
+ public String getName()
+ {
+ return "";
+ }
+
+ /**
+ * Set the parent state.
+ * @param state the parent state
+ */
+ public void setParent( State state )
+ {
+ }
+
+ /**
+ * Return the parent state to this state or null if this is
+ * the root of a state graph.
+ * @return the parent state
+ */
+ public State getParent()
+ {
+ return null;
+ }
+
+ /**
+ * Return the state path. The path is composed of a sequence of
+ * states from the root to this state.
+ * @return the state path
+ */
+ public State[] getStatePath()
+ {
+ return new State[0];
+ }
+
+ /**
+ * Return the substates within this state.
+ * @return the substate array
+ */
+ public State[] getStates()
+ {
+ return new State[0];
+ }
+
+ /**
+ * Return the array of triggers associated with the state.
+ * @return the trigger array
+ */
+ public Trigger[] getTriggers()
+ {
+ return new Trigger[0];
+ }
+
+ /**
+ * Return the array of transtions associated with the state.
+ * @return the transition array
+ */
+ public Transition[] getTransitions()
+ {
+ return new Transition[0];
+ }
+
+ /**
+ * Return the array of operations associated with the state.
+ * @return the operation array
+ */
+ public Operation[] getOperations()
+ {
+ return new Operation[0];
+ }
+
+ /**
+ * Return the array of operations associated with the state.
+ * @return the operation array
+ */
+ public Interface[] getInterfaces()
+ {
+ return new Interface[0];
+ }
+
+ /**
+ * Test is the state is a terminal state.
+ * @return true if terminal
+ */
+ public boolean isTerminal()
+ {
+ return false;
+ }
+
+ /**
+ * Test is this state is equal to the supplied object.
+ * @param other the other object
+ * @return true if equal
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else
+ {
+ return ( other instanceof NullState );
+ }
+ }
+
+ /**
+ * Calcualte the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ return getClass().hashCode();
+ }
+}

Added:
trunk/main/lang/part/src/main/dpml/state/StateBuilderRuntimeException.java
===================================================================
---
trunk/main/lang/part/src/main/dpml/state/StateBuilderRuntimeException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/dpml/state/StateBuilderRuntimeException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,49 @@
+/*
+ * 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.state;
+
+/**
+ * Exception thrown when an error occurs during state graph construction.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StateBuilderRuntimeException extends RuntimeException
+{
+ /**
+ * Construct a new <code>StateBuilderRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ */
+ public StateBuilderRuntimeException( String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Construct a new <code>StateBuilderRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public StateBuilderRuntimeException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/StateDecoder.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/StateDecoder.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/StateDecoder.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2006-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.state;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+
+import javax.xml.XMLConstants;
+
+import dpml.lang.DOM3DocumentBuilder;
+
+import dpml.util.ElementHelper;
+
+import net.dpml.state.*;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import net.dpml.util.Logger;
+import dpml.util.DefaultLogger;
+
+/**
+ * Construct a state graph.
+ */
+public class StateDecoder
+{
+ private static final Logger LOGGER = new DefaultLogger( "dpml.state" );
+
+ private static final String XML_HEADER =
+ "<?xml version=\"1.0\"?>";
+
+ private static final String NAMESPACE =
+ "dpml:state";
+
+ private static final String STATE_HEADER =
+ "<state xmlns=\""
+ + NAMESPACE
+ + "\""
+ + "\n xmlns:xsi=\""
+ + XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
+ + "\">";
+
+ private static final String STATE_FOOTER = "</state>";
+
+ private static final DOM3DocumentBuilder BUILDER = new
DOM3DocumentBuilder();
+
+ /**
+ * Load a state graph.
+ * @param uri the graph uri
+ * @return the constructed state graph
+ * @exception IOException if an IO error occurs while reading the
+ * graph data
+ */
+ public State loadState( URI uri ) throws IOException
+ {
+ if( null == uri )
+ {
+ throw new NullPointerException( "uri" );
+ }
+ try
+ {
+ LOGGER.trace( "loading " + uri );
+ final Document document = BUILDER.parse( uri );
+ final Element root = document.getDocumentElement();
+ return buildStateGraph( root );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "An error while attempting to load a state graph."
+ + "\nURI: " + uri;
+ IOException exception = new IOException( error );
+ exception.initCause( e );
+ throw exception;
+ }
+ }
+
+ /**
+ * Load a state graph.
+ * @param url the graph url
+ * @return the constructed state graph
+ * @exception IOException if an IO error occurs while reading the
+ * graph data
+ */
+ public State loadState( URL url ) throws IOException
+ {
+ if( null == url )
+ {
+ throw new NullPointerException( "url" );
+ }
+ try
+ {
+ LOGGER.trace( "loading " + url );
+ final Document document = BUILDER.parse( url );
+ final Element root = document.getDocumentElement();
+ return buildStateGraph( root );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "An error while attempting to load a state graph."
+ + "\nURL: " + url;
+ IOException exception = new IOException( error );
+ exception.initCause( e );
+ throw exception;
+ }
+ }
+
+ /**
+ * Build a state graph.
+ * @param element a DOM element representing the root of the state graph
+ * @return the constructed state
+ */
+ State buildStateGraph( Element element )
+ {
+ if( null == element )
+ {
+ throw new NullPointerException( "element" );
+ }
+
+ boolean terminal = ElementHelper.getBooleanAttribute( element,
"terminal" );
+ DefaultTransition[] transitions = buildNestedTransitions( element );
+ DefaultOperation[] operations = buildNestedOperations( element );
+ DefaultInterface[] interfaces = buildNestedInterfaces( element );
+ DefaultState[] states = buildNestedStates( 1, element );
+ DefaultTrigger[] triggers = buildNestedTriggers( element );
+ return new DefaultState(
+ "root", triggers, transitions, interfaces, operations, states,
terminal );
+ }
+
+ private DefaultTransition[] buildNestedTransitions( Element element )
+ {
+ Element[] children = ElementHelper.getChildren( element,
"transition" );
+ DefaultTransition[] transitions = new DefaultTransition[
children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ transitions[i] = buildTransition( child );
+ }
+ return transitions;
+ }
+
+ private DefaultOperation[] buildNestedOperations( Element element )
+ {
+ Element[] children = ElementHelper.getChildren( element, "operation"
);
+ DefaultOperation[] operations = new DefaultOperation[
children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ operations[i] = buildOperation( child );
+ }
+ return operations;
+ }
+
+ private DefaultInterface[] buildNestedInterfaces( Element element )
+ {
+ Element[] children = ElementHelper.getChildren( element, "interface"
);
+ DefaultInterface[] interfaces = new DefaultInterface[
children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ interfaces[i] = buildInterface( child );
+ }
+ return interfaces;
+ }
+
+ private DefaultState[] buildNestedStates( int n, Element element )
+ {
+ Element[] children = ElementHelper.getChildren( element, "state" );
+ DefaultState[] states = new DefaultState[ children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ states[i] = buildState( n, child );
+ }
+ return states;
+ }
+
+ private DefaultTrigger[] buildNestedTriggers( Element element )
+ {
+ Element[] children = ElementHelper.getChildren( element, "trigger" );
+ DefaultTrigger[] triggers = new DefaultTrigger[ children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ triggers[i] = buildTrigger( child );
+ }
+ return triggers;
+ }
+
+ private DefaultTransition buildTransition( Element element )
+ {
+ String name = ElementHelper.getAttribute( element, "name" );
+ String target = ElementHelper.getAttribute( element, "target" );
+ Element child = ElementHelper.getChild( element, "operation" );
+ DefaultOperation operation = buildOperation( child );
+ return new DefaultTransition( name, target, operation );
+ }
+
+ private DefaultOperation buildOperation( Element element )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ String name = ElementHelper.getAttribute( element, "name" );
+ String method = ElementHelper.getAttribute( element, "method" );
+ return new DefaultOperation( name, method );
+ }
+
+ private DefaultInterface buildInterface( Element element )
+ {
+ String classname = ElementHelper.getAttribute( element, "class" );
+ return new DefaultInterface( classname );
+ }
+
+ private DefaultState buildState( int n, Element element )
+ {
+ String name = ElementHelper.getAttribute( element, "name" );
+ boolean terminal = ElementHelper.getBooleanAttribute( element,
"terminal" );
+ DefaultTransition[] transitions = buildNestedTransitions( element );
+ DefaultOperation[] operations = buildNestedOperations( element );
+ DefaultInterface[] interfaces = buildNestedInterfaces( element );
+ DefaultState[] states = buildNestedStates( n+1, element );
+ DefaultTrigger[] triggers = buildNestedTriggers( element );
+ return new DefaultState(
+ name, triggers, transitions, interfaces, operations, states,
terminal );
+ }
+
+ private DefaultTrigger buildTrigger( Element element )
+ {
+ String type = ElementHelper.getAttribute( element, "event" );
+ TriggerPolicy event = TriggerPolicy.valueOf( type.toUpperCase() );
+ Element child = getSingleNestedElement( element );
+ Action action = buildAction( child );
+ return new DefaultTrigger( event, action );
+ }
+
+ private Action buildAction( Element element )
+ {
+ String name = element.getTagName();
+ if( name.equals( "transition" ) )
+ {
+ return buildTransition( element );
+ }
+ else if( name.equals( "operation" ) )
+ {
+ return buildOperation( element );
+ }
+ else if( name.equals( "apply" ) )
+ {
+ String id = ElementHelper.getAttribute( element, "id" );
+ return new ApplyAction( id );
+ }
+ else if( name.equals( "exec" ) )
+ {
+ String id = ElementHelper.getAttribute( element, "id" );
+ return new ExecAction( id );
+ }
+ else
+ {
+ final String error =
+ "Illegal element name ["
+ + name
+ + "] supplied to action builder.";
+ throw new StateBuilderRuntimeException( error );
+ }
+ }
+
+ private Element getSingleNestedElement( Element parent )
+ {
+ if( null == parent )
+ {
+ throw new NullPointerException( "parent" );
+ }
+ else
+ {
+ Element[] children = ElementHelper.getChildren( parent );
+ if( children.length == 1 )
+ {
+ return children[0];
+ }
+ else
+ {
+ final String error =
+ "Parent element does not contain a single child.";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/dpml/state/StateEncoder.java
===================================================================
--- trunk/main/lang/part/src/main/dpml/state/StateEncoder.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/dpml/state/StateEncoder.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,339 @@
+/*
+ * 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 dpml.state;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.io.OutputStreamWriter;
+
+import javax.xml.XMLConstants;
+
+import net.dpml.state.State;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+import net.dpml.state.Interface;
+import net.dpml.state.Trigger;
+import net.dpml.state.TriggerPolicy;
+import net.dpml.state.Action;
+import net.dpml.state.ExecAction;
+import net.dpml.state.ApplyAction;
+
+/**
+ * Construct a state graph.
+ */
+public class StateEncoder
+{
+ private static final String XML_HEADER =
+ "<?xml version=\"1.0\"?>";
+
+ private static final String STATE_SCHEMA_URN = "dpml:state";
+
+ /**
+ * Externalize the part to XML.
+ * @param state the state graph to externalize
+ * @param output the output stream
+ * @exception IOException if an IO error occurs
+ */
+ public void export( State state, OutputStream output ) throws IOException
+ {
+ final Writer writer = new OutputStreamWriter( output );
+
+ writer.write( XML_HEADER );
+ writer.write( "\n\n" );
+ writer.write( "<state xmlns=\""
+ + STATE_SCHEMA_URN
+ + "\""
+ + "\n xmlns:xsi=\""
+ + XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
+ + "\"" );
+ if( state.isTerminal() )
+ {
+ writer.write( " terminal=\"true\">" );
+ }
+ else
+ {
+ writer.write( ">" );
+ }
+ writer.write( "\n" );
+ writeBody( writer, state, "" );
+ writer.write( "\n" );
+ writer.write( "\n</state>" );
+ writer.write( "\n" );
+ writer.flush();
+ output.close();
+ }
+
+ /**
+ * Write the state.
+ * @param writer the stream writer
+ * @param state the state to externalize
+ * @param pad the pad offset
+ * @exception IOException if an IO error occurs
+ */
+ public void writeState( Writer writer, State state, String pad ) throws
IOException
+ {
+ if( isEmpty( state ) )
+ {
+ return;
+ }
+ else
+ {
+ writer.write( "\n" + pad + "<state xmlns=\"" + STATE_SCHEMA_URN
+ "\"" );
+ if( state.isTerminal() )
+ {
+ writer.write( " terminal=\"true\"" );
+ }
+ writer.write( ">" );
+ writeBody( writer, state, pad + " " );
+ writer.write( "\n" + pad + "</state>" );
+ }
+ }
+
+ private void writeBody( Writer writer, State state, String pad ) throws
IOException
+ {
+ Trigger[] triggers = state.getTriggers();
+ Transition[] transitions = state.getTransitions();
+ Operation[] operations = state.getOperations();
+ Interface[] interfaces = state.getInterfaces();
+ State[] states = state.getStates();
+
+ writeTriggers( writer, triggers, pad );
+ writeTransitions( writer, transitions, pad );
+ writeOperations( writer, operations, pad );
+ writeInterfaces( writer, interfaces, pad );
+ writeStates( writer, states, pad );
+ }
+
+ private void writeTriggers( Writer writer, Trigger[] triggers, String
pad ) throws IOException
+ {
+ if( triggers.length == 0 )
+ {
+ return;
+ }
+ else
+ {
+ for( int i=0; i<triggers.length; i++ )
+ {
+ Trigger trigger = triggers[i];
+ writeTrigger( writer, trigger, pad );
+ }
+ }
+ }
+
+ private void writeTrigger( Writer writer, Trigger trigger, String pad )
throws IOException
+ {
+ TriggerPolicy event = trigger.getPolicy();
+ writer.write( "\n" + pad + "<trigger event=\"" );
+ writer.write( event.name().toLowerCase() );
+ writer.write( "\">" );
+ Action action = trigger.getAction();
+ writeAction( writer, action, pad + " " );
+ writer.write( "\n" + pad + "</trigger>" );
+ }
+
+ private void writeTransitions( Writer writer, Transition[] transitions,
String pad ) throws IOException
+ {
+ if( transitions.length == 0 )
+ {
+ return;
+ }
+ else
+ {
+ for( int i=0; i<transitions.length; i++ )
+ {
+ Transition transition = transitions[i];
+ writeTransition( writer, transition, pad );
+ }
+ }
+ }
+
+ private void writeOperations( Writer writer, Operation[] operations,
String pad ) throws IOException
+ {
+ if( operations.length == 0 )
+ {
+ return;
+ }
+ else
+ {
+ for( int i=0; i<operations.length; i++ )
+ {
+ Operation operation = operations[i];
+ writeOperation( writer, operation, pad );
+ }
+ }
+ }
+
+ private void writeInterfaces( Writer writer, Interface[] interfaces,
String pad ) throws IOException
+ {
+ if( interfaces.length == 0 )
+ {
+ return;
+ }
+ else
+ {
+ for( int i=0; i<interfaces.length; i++ )
+ {
+ Interface spec = interfaces[i];
+ writeInterface( writer, spec, pad );
+ }
+ }
+ }
+
+ private void writeStates( Writer writer, State[] states, String pad )
throws IOException
+ {
+ if( states.length == 0 )
+ {
+ return;
+ }
+ else
+ {
+ for( int i=0; i<states.length; i++ )
+ {
+ State state = states[i];
+ writeNestedState( writer, state, pad );
+ }
+ }
+ }
+
+ private void writeTransition( Writer writer, Transition transition,
String pad ) throws IOException
+ {
+ String name = transition.getName();
+ String target = transition.getTargetName();
+ writer.write( "\n" + pad + "<transition name=\"" + name + "\"
target=\"" + target + "\"" );
+ Operation operation = transition.getOperation();
+ if( null == operation )
+ {
+ writer.write( "/>" );
+ }
+ else
+ {
+ writer.write( ">" );
+ writeOperation( writer, operation, pad + " " );
+ writer.write( "\n" + pad + "</transition>" );
+ }
+ }
+
+ private void writeOperation( Writer writer, Operation operation, String
pad ) throws IOException
+ {
+ String name = operation.getName();
+ String method = operation.getMethodName();
+ writer.write( "\n" + pad + "<operation name=\"" + name + "\"" );
+ if( null != method )
+ {
+ writer.write( " method=\"" + method + "\"" );
+ }
+ writer.write( "/>" );
+ }
+
+ private void writeInterface( Writer writer, Interface spec, String pad )
throws IOException
+ {
+ String classname = spec.getClassname();
+ writer.write( "\n" + pad + "<interface class=\"" + classname +
"\"/>" );
+ }
+
+ private void writeAction( Writer writer, Action action, String pad )
throws IOException
+ {
+ if( action instanceof Transition )
+ {
+ Transition transition = (Transition) action;
+ writeTransition( writer, transition, pad );
+ }
+ else if( action instanceof Operation )
+ {
+ Operation operation = (Operation) action;
+ writeOperation( writer, operation, pad );
+ }
+ else if( action instanceof Interface )
+ {
+ Interface spec = (Interface) action;
+ writeInterface( writer, spec, pad );
+ }
+ else if( action instanceof ExecAction )
+ {
+ ExecAction exec = (ExecAction) action;
+ writeExecAction( writer, exec, pad );
+ }
+ else if( action instanceof ApplyAction )
+ {
+ ApplyAction apply = (ApplyAction) action;
+ writeApplyAction( writer, apply, pad );
+ }
+ else
+ {
+ final String error =
+ "Unrecognized action class ["
+ + action.getClass().getName()
+ + "].";
+ throw new IOException( error );
+ }
+ }
+ private void writeExecAction( Writer writer, ExecAction action, String
pad ) throws IOException
+ {
+ String id = action.getID();
+ writer.write( "\n" + pad + "<exec id=\"" + id + "\"/>" );
+ }
+
+ private void writeApplyAction( Writer writer, ApplyAction action, String
pad ) throws IOException
+ {
+ String id = action.getID();
+ writer.write( "\n" + pad + "<apply id=\"" + id + "\"/>" );
+ }
+
+ private void writeNestedState( Writer writer, State state, String pad )
throws IOException
+ {
+ String name = state.getName();
+ writer.write( "\n" + pad + "<state name=\"" + name + "\"" );
+ if( state.isTerminal() )
+ {
+ writer.write( " terminal=\"true\">" );
+ }
+ else
+ {
+ writer.write( ">" );
+ }
+ writeBody( writer, state, pad + " " );
+ writer.write( "\n" + pad + "</state>" );
+ }
+
+ private boolean isEmpty( State state )
+ {
+ if( state.getTriggers().length > 0 )
+ {
+ return false;
+ }
+ if( state.getTransitions().length > 0 )
+ {
+ return false;
+ }
+ if( state.getOperations().length > 0 )
+ {
+ return false;
+ }
+ if( state.getInterfaces().length > 0 )
+ {
+ return false;
+ }
+ if( state.getStates().length > 0 )
+ {
+ return false;
+ }
+ return true;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/Activation.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/Activation.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/Activation.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Component activation policy annotation.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Target( ElementType.TYPE )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Activation
+{
+ /**
+ * Returns the activation assertion status. The default
+ * assertion status is {@link ActivationPolicy#SYSTEM}.
+ */
+ ActivationPolicy value() default ActivationPolicy.SYSTEM;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/ActivationPolicy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/ActivationPolicy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/ActivationPolicy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 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 net.dpml.annotation;
+
+/**
+ * Activation policy.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum ActivationPolicy
+{
+ /**
+ * System managed activation policy.
+ */
+ SYSTEM,
+
+ /**
+ * Activation on startup enabled.
+ */
+ STARTUP,
+
+ /**
+ * Activation on startup disabled.
+ */
+ DEMAND;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/CollectionPolicy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/CollectionPolicy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/CollectionPolicy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package net.dpml.annotation;
+
+/**
+ * Collection policy.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum CollectionPolicy
+{
+ /**
+ * Weak collection policy.
+ */
+ WEAK,
+
+ /**
+ * Soft collection policy.
+ */
+ SOFT,
+
+ /**
+ * Hard collection policy.
+ */
+ HARD;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/Component.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/Component.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/Component.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2004-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.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Component annotation dealing with lifestyle policy, lifecycle model, and
collection semantics.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ @Target( ElementType.TYPE )
+ @Retention( RetentionPolicy.RUNTIME )
+public @interface Component
+{
+ String name() default "";
+ LifestylePolicy lifestyle() default LifestylePolicy.THREAD;
+ CollectionPolicy collection() default CollectionPolicy.HARD;
+ String lifecycle() default "";
+ String handlerURI() default "link:part:dpml/lang/dpml-lang-component";
+ String handlerClassname() default
"net.dpml.runtime.ComponentStrategyHandler";
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/Context.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/Context.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/Context.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Assertion that an interface is expressed in terms of a context model.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Target( ElementType.TYPE )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Context
+{
+ /**
+ * Returns the context support assertion status. The default
+ * assertion status is true.
+ */
+ boolean value() default true;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/LifestylePolicy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/LifestylePolicy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/LifestylePolicy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2004-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.annotation;
+
+/**
+ * Lifecycle policy.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum LifestylePolicy
+{
+ /**
+ * Declares that a single instance created from the component class
+ * shall be shared across all instance requests. Components declaring
+ * this policy must ensure that implementations are threadsafe.
+ */
+ SINGLETON,
+
+ /**
+ * Declares that a new instance of the class shall be created for
+ * each thread context.
+ */
+ THREAD,
+
+ /**
+ * Declares that a new instance shall be created per request.
+ */
+ TRANSIENT;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/Parts.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/Parts.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/Parts.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Assertion that an interface is expressed in terms of a parts model.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Target( ElementType.TYPE )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Parts
+{
+ /**
+ * Returns the context support assertion status. The default
+ * assertion status is true.
+ */
+ boolean value() default true;
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/Services.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/Services.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/Services.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,43 @@
+/*
+ * 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.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Assertion that a class implementation should be isolated as a
+ * proxy using the declared set of interface classes.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Target( ElementType.TYPE )
+@Retention( RetentionPolicy.RUNTIME )
+@Documented
+public @interface Services
+{
+ /**
+ * Returns the array of interfaces published by an implementation.
+ */
+ Class[] value() default {};
+}

Added: trunk/main/lang/part/src/main/net/dpml/annotation/package-info.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/annotation/package-info.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/annotation/package-info.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * <p>Component annotations supporting lifestyle, lifecycle, collection,
+ * activiation, and service publication policies.</p>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.annotation;

Added: trunk/main/lang/part/src/main/net/dpml/appliance/Appliance.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/Appliance.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/Appliance.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,53 @@
+/*
+ * 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.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Appliance interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Appliance extends Remote
+{
+ void addApplianceListener( ApplianceListener listener ) throws
RemoteException;
+
+ void removeApplianceListener( ApplianceListener listener ) throws
RemoteException;
+
+ void commission() throws IOException;
+
+ void decommission() throws RemoteException;
+
+ /**
+ * 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;
+
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceConnector.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceConnector.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceConnector.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.appliance;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Appliance connector.
+ */
+public interface ApplianceConnector extends Remote
+{
+ /**
+ * Connect a appliance to the station.
+ * @param appliance the appliance
+ * @exception RemoteException if a remote error occurs
+ */
+ void connect( Appliance appliance ) throws RemoteException;
+
+ Appliance getAppliance( TimeUnit units, int timeout ) throws IOException;
+
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceContentManager.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceContentManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceContentManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,35 @@
+/*
+ * 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.appliance;
+
+import net.dpml.transit.ContentManager;
+
+import javax.management.MXBean;
+
+/**
+ * Application content manager interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ @MXBean
+public interface ApplianceContentManager extends ContentManager
+{
+ ApplianceManager[] getApplianceManagers();
+}

Added: trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceError.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceError.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceError.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,59 @@
+/*
+ * 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.appliance;
+
+/**
+ * Application management center.
+ */
+/**
+ * Critical appliance error.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceError extends Error
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ApplianceError</code>.
+ *
+ * @param message the error message
+ */
+ public ApplianceError( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ApplianceError</code>.
+ *
+ * @param message the error message
+ * @param cause the causal exception
+ */
+ public ApplianceError( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceEvent.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceEvent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceEvent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,71 @@
+/*
+ * 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 net.dpml.appliance;
+
+import java.util.EventObject;
+
+import net.dpml.runtime.Status;
+
+/**
+ * Event triggered as a result of a state change.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceEvent extends EventObject
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final Appliance m_appliance;
+ private final Status m_status;
+
+ /**
+ * Construct a new <code>StateEvent</code>.
+ *
+ * @param source the source component
+ */
+ public ApplianceEvent( final Appliance source, Status status )
+ {
+ super( source );
+ m_appliance = source;
+ m_status = status;
+ }
+
+ /**
+ * Return the appliance that initiated the event.
+ * @return the source appliance
+ */
+ public Appliance getAppliance()
+ {
+ return m_appliance;
+ }
+
+ /**
+ * Return the appliance status.
+ * @return the status enumeration
+ */
+ public Status getStatus()
+ {
+ return m_status;
+ }
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,75 @@
+/*
+ * 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.appliance;
+
+import java.io.IOException;
+
+import net.dpml.lang.DecodingException;
+
+import org.w3c.dom.Element;
+
+
+/**
+ * Appliance related exception.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplianceException extends DecodingException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ApplianceException</code>.
+ *
+ * @param message the error message
+ */
+ public ApplianceException( final String message )
+ {
+ super( message, null, null );
+ }
+
+ /**
+ * Construct a new <code>ApplianceException</code>.
+ *
+ * @param message the error message
+ * @param cause the causal exception
+ */
+ public ApplianceException( 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 ApplianceException( final String message, Throwable cause,
Element element )
+ {
+ super( message, cause, element );
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceFactory.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceFactory.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceFactory.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,41 @@
+/*
+ * 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 net.dpml.appliance;
+
+import java.io.IOException;
+import java.net.URLConnection;
+
+/**
+ * Interface implementated by remote listeners to state change events.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface ApplianceFactory
+{
+ /**
+ * 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
+ */
+ Appliance newAppliance( URLConnection connection, String partition )
throws IOException;
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceListener.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceListener.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceListener.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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 net.dpml.appliance;
+
+import java.util.EventListener;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Interface implementated by remote listeners to state change events.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface ApplianceListener extends EventListener, Remote
+{
+ /**
+ * Notify the listener of an event within the appliance.
+ *
+ * @param event the comnponent event
+ * @exception RemoteException if a remote transport error occurs
+ */
+ void applianceChanged( final ApplianceEvent event ) throws
RemoteException;
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceManager.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/ApplianceManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,39 @@
+/*
+ * 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.appliance;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import javax.management.MXBean;
+
+/**
+ * Management interface for applications.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@MXBean
+public interface ApplianceManager extends Remote
+{
+ /**
+ * Returns the part URI as a string.
+ * @return the codebase uri
+ */
+ String getCodebaseURI() throws RemoteException;
+}

Added: trunk/main/lang/part/src/main/net/dpml/appliance/PlanManager.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/PlanManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/PlanManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,33 @@
+/*
+ * 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.appliance;
+
+import javax.management.MXBean;
+
+/**
+ * Management interface for applications.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@MXBean
+public interface PlanManager extends ApplianceManager
+{
+ ApplianceManager[] getApplianceManagers();
+}

Added: trunk/main/lang/part/src/main/net/dpml/appliance/package-info.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/appliance/package-info.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/appliance/package-info.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -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>Interfaces represening a managed process.</p>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.appliance;

Added: trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,209 @@
+/*
+ * 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.lang;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URL;
+
+import net.dpml.state.StateListener;
+
+import net.dpml.util.Logger;
+import dpml.lang.Disposable;
+
+/**
+ * Simple resource deployment strategy.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class AntlibStrategy extends Strategy
+{
+ private final String m_urn;
+ private final String m_path;
+
+ /**
+ * Creation of resource datatype.
+ * @param classloader the classloader
+ * @param urn the resource urn
+ * @param path the resource path
+ * @exception IOException if an I/O error occurs
+ */
+ public AntlibStrategy( ClassLoader classloader, String urn, String path )
+ throws IOException
+ {
+ super( classloader );
+ if( null == urn )
+ {
+ throw new NullPointerException( "urn" );
+ }
+ if( null == path )
+ {
+ throw new NullPointerException( "path" );
+ }
+ m_urn = urn;
+ m_path = path;
+ }
+
+ public String getName()
+ {
+ return m_urn;
+ }
+
+ public int getPriority()
+ {
+ return 0;
+ }
+
+ /**
+ * Return the part content or null if the result type is unresolvable
+ * relative to the supplied classes argument. Class arguments recognized
+ * over an above plugin include the URL and String classes. If the URL
+ * class is supplied a URL referencing the resource identified by path
+ * is returned. If a String is requested the urn value is returned.
+ *
+ * @param c the content class
+ * @return the content
+ * @exception IOException if an IO error occurs
+ */
+ public <T>T getContentForClass( Class<T> c ) throws IOException
+ {
+ if( Strategy.class.equals( c ) )
+ {
+ return c.cast( this );
+ }
+ else if( URL.class.equals( c ) )
+ {
+ URL url = getClassLoader().getResource( m_path );
+ return c.cast( url );
+ }
+ else if( String.class.equals( c ) )
+ {
+ String urn = getURN();
+ return c.cast( urn );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the resource urn.
+ * @return the urn
+ */
+ public String getURN()
+ {
+ return m_urn;
+ }
+
+ /**
+ * Get the resource path.
+ * @return the path
+ */
+ public String getPath()
+ {
+ return m_path;
+ }
+
+ public boolean isaCandidate( Class<?> type )
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void initialize( ServiceRegistry registry )
+ {
+ // not required
+ }
+
+ /**
+ * Instantiate a value.
+ * @param type the return type
+ * @return the resolved instance
+ */
+ public <T>T getInstance( Class<T> type )
+ {
+ try
+ {
+ ClassLoader classloader = getClassLoader();
+ Object resource = classloader.getResource( m_path );
+ return type.cast( resource );
+ }
+ catch( Exception e )
+ {
+ throw new PartError( e.getMessage(), e.getCause() );
+ }
+ }
+
+ /**
+ * Encode the resource strategy to XML.
+ * @param buffer the output buffer
+ * @param key the key
+ * @exception IOException if an I/O error occurs
+ */
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ String urn = getURN();
+ String path = getPath();
+ buffer.nl( "<resource xmlns=\"" + AntlibStrategyHandler.NAMESPACE +
"\"" );
+ if( null != key )
+ {
+ buffer.write( " key=\"" + key + "\"" );
+ }
+ buffer.write( " urn=\"" + urn + "\" " );
+ buffer.write( " path=\"" + path + "\"" );
+ buffer.write( "/>" );
+ }
+
+ /**
+ * Test if this instance is equal to the supplied instance.
+ * @param other the supplied instance
+ * @return the equality status
+ */
+ public boolean equals( Object other )
+ {
+ if( other instanceof AntlibStrategy )
+ {
+ AntlibStrategy resource = (AntlibStrategy) other;
+ if( !m_path.equals( resource.m_path ) )
+ {
+ return false;
+ }
+ else
+ {
+ return m_urn.equals( resource.m_urn );
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the hashcode for this instance.
+ * @return the hash value
+ */
+ public int hashCode()
+ {
+ int hash = 99875845;
+ hash ^= m_path.hashCode();
+ hash ^= m_urn.hashCode();
+ return hash;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategyHandler.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategyHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/AntlibStrategyHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,79 @@
+/*
+ * 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.lang;
+
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+import dpml.util.StandardClassLoader;
+import dpml.util.SystemClassLoader;
+import dpml.util.Category;
+
+import dpml.lang.Classpath;
+import dpml.lang.ValueDecoder;
+import dpml.lang.Value;
+
+import net.dpml.runtime.ComponentStrategyHandler;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+
+import net.dpml.util.Logger;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Antlib strategy handler implementation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class AntlibStrategyHandler implements StrategyHandler
+{
+ public static final String NAMESPACE = "dpml:antlib";
+
+ public Strategy newStrategy( Class<?> c ) throws IOException
+ {
+ return newStrategy( c, null );
+ }
+
+ public Strategy newStrategy( Class<?> c, String name ) throws IOException
+ {
+ throw new UnsupportedOperationException( "newStrategy" );
+ }
+
+ /**
+ * Construct a strategy definition using a supplied element and value
resolver.
+ * @param classloader the classloader
+ * @param element the DOM element definining the deployment strategy
+ * @param resolver symbolic property resolver
+ * @param query the query fragment (ignored)
+ * @return the strategy definition
+ * @exception IOException if an I/O error occurs
+ */
+ public Strategy build(
+ ClassLoader classloader, Element element, Resolver resolver, String
partition, String query ) throws IOException
+ {
+ String urn = ElementHelper.getAttribute( element, "urn", null,
resolver );
+ String path = ElementHelper.getAttribute( element, "path", null,
resolver );
+ return new AntlibStrategy( classloader, urn, path );
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/Buffer.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/Buffer.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/Buffer.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,133 @@
+/*
+ * 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 net.dpml.lang;
+
+import java.io.Writer;
+import java.io.IOException;
+
+/**
+ * Utility class used as a destination during generalized object encoding.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Buffer
+{
+ private final String m_namespace;
+ private final String m_pad;
+ private final Writer m_writer;
+
+ /**
+ * Construct a new encoding buffer.
+ *
+ * @param writer the output stream writer
+ * @param namespace the current namespace
+ * @param pad the current offset
+ * @exception NullPointerException of the writer or namespace arguments
are null
+ */
+ public Buffer( final Writer writer, final String namespace, final String
pad )
+ {
+ if( null == writer )
+ {
+ throw new NullPointerException( "writer" );
+ }
+ if( null == namespace )
+ {
+ throw new NullPointerException( "namespace" );
+ }
+ if( null == pad )
+ {
+ m_pad = "";
+ }
+ else
+ {
+ m_pad = pad;
+ }
+ m_namespace = namespace;
+ m_writer = writer;
+ }
+
+ public String getEnclosingNamespace()
+ {
+ return m_namespace;
+ }
+
+ public String getOffset()
+ {
+ return m_pad;
+ }
+
+ public void write( String value ) throws IOException
+ {
+ m_writer.write( value );
+ }
+
+ public void write( int n ) throws IOException
+ {
+ m_writer.write( n );
+ }
+
+ public void write( char[] array ) throws IOException
+ {
+ m_writer.write( array );
+ }
+
+ public void nl( String value ) throws IOException
+ {
+ m_writer.write( "\n" + m_pad + value );
+ }
+
+ public void nl( int n ) throws IOException
+ {
+ m_writer.write( "\n" + m_pad + n );
+ }
+
+ public void nl( char[] array ) throws IOException
+ {
+ m_writer.write( "\n" + m_pad );
+ m_writer.write( array );
+ }
+
+ public Buffer indent()
+ {
+ return indent( " " );
+ }
+
+ public Buffer indent( String indent )
+ {
+ return new Buffer( m_writer, m_namespace, m_pad + indent );
+ }
+
+ public boolean isNamespace( String namespace )
+ {
+ return m_namespace.equals( namespace );
+ }
+
+ public Buffer namespace( String namespace )
+ {
+ if( m_namespace.equals( namespace ) )
+ {
+ return this;
+ }
+ else
+ {
+ return new Buffer( m_writer, namespace, m_pad );
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/ClassLoaderHelper.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/ClassLoaderHelper.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/ClassLoaderHelper.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,147 @@
+/*
+ * 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.lang;
+
+import dpml.lang.ValueDecoder;
+import dpml.util.StandardClassLoader;
+import dpml.util.SystemClassLoader;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+
+import dpml.lang.Classpath;
+import dpml.util.Category;
+
+import net.dpml.util.Logger;
+import net.dpml.util.Resolver;
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Interace implemented by part strategy handlers.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class ClassLoaderHelper
+{
+ private static final ValueDecoder VALUE_DECODER = new ValueDecoder();
+
+ private static final Logger LOGGER = new DefaultLogger( "dpml.lang" );
+
+ /**
+ * Create a classloader given a classpath defintion.
+ * @param anchor the parent classloader
+ * @param classpath the classpath definition
+ * @return the new classloader
+ */
+ public static ClassLoader newClassLoader( ClassLoader anchor, URI
codebase, Classpath classpath ) throws IOException
+ {
+ if( null == anchor )
+ {
+ throw new NullPointerException( "anchor" );
+ }
+ //ClassLoader anchor = getAnchorClassLoader( parent );
+ String spec = codebase.toASCIIString();
+ return newClassLoader( anchor, classpath, spec, true );
+ }
+
+ private static ClassLoader newClassLoader(
+ ClassLoader base, Classpath classpath, String spec, boolean expand )
throws IOException
+ {
+ if( expand )
+ {
+ Classpath cp = classpath.getBaseClasspath();
+ if( null != cp )
+ {
+ String label = spec + " (base)";
+ ClassLoader cl = newClassLoader( base, cp, label, true );
+ return newClassLoader( cl, classpath, spec, false );
+ }
+ }
+
+ URI[] uris = classpath.getDependencies( Category.SYSTEM );
+ if( uris.length > 0 )
+ {
+ for( URI uri : uris )
+ {
+ LOGGER.warn( "Ignoring system reference: " + uri );
+ }
+ //updateSystemClassLoader( uris );
+ }
+
+ URI[] apis = classpath.getDependencies( Category.PUBLIC );
+ ClassLoader api =
+ StandardClassLoader.buildClassLoader( LOGGER, spec,
Category.PUBLIC, base, apis );
+ URI[] spis = classpath.getDependencies( Category.PROTECTED );
+ ClassLoader spi =
+ StandardClassLoader.buildClassLoader( LOGGER, spec,
Category.PROTECTED, api, spis );
+ URI[] imps = classpath.getDependencies( Category.PRIVATE );
+ return StandardClassLoader.buildClassLoader( LOGGER, spec,
Category.PRIVATE, spi, imps );
+ }
+
+ /*
+ private static void updateSystemClassLoader( URI[] uris ) throws
IOException
+ {
+ ClassLoader parent = ClassLoader.getSystemClassLoader();
+ synchronized( parent )
+ {
+ if( parent instanceof SystemClassLoader )
+ {
+ SystemClassLoader loader = (SystemClassLoader) parent;
+ loader.addDelegates( uris );
+ }
+ else
+ {
+ final String message =
+ "Cannot load ["
+ + uris.length
+ + "] system artifacts into a foreign system classloader.";
+ LOGGER.trace( message );
+ }
+ }
+ }
+ */
+
+ /*
+ private static ClassLoader getAnchorClassLoader( ClassLoader parent )
+ {
+ if( null != parent )
+ {
+ return parent;
+ }
+ else
+ {
+ ClassLoader current =
Thread.currentThread().getContextClassLoader();
+ if( null != current )
+ {
+ return current;
+ }
+ else
+ {
+ return ClassLoaderHelper.class.getClassLoader();
+ }
+ }
+ }
+ */
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/DecodingException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/DecodingException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/DecodingException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,187 @@
+/*
+ * 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.lang;
+
+import dpml.util.ElementHelper;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+
+import net.dpml.transit.Artifact;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * Exception related to data decoding from a DOM element.
+ */
+public class DecodingException extends IOException
+{
+ private final Element m_element;
+
+ /**
+ * Create a new decoding exception.
+ * @param element the element representing the source of the error
+ * @param message the exception message
+ */
+ public DecodingException( String message, Element element )
+ {
+ this( message, null, element );
+ }
+
+ /**
+ * Create a new decoding exception.
+ * @param element the element representing the source of the error
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public DecodingException( String message, Throwable cause, Element
element )
+ {
+ super( message );
+ if( null != cause )
+ {
+ super.initCause( cause );
+ }
+ m_element = element;
+ }
+
+ /**
+ * Get the element that is the subject of this exception.
+ * @return the subject element
+ */
+ public Element getElement()
+ {
+ return m_element;
+ }
+
+ /**
+ * Return a string representation of the exception.
+ * @return the string value
+ */
+ public String getMessage()
+ {
+ try
+ {
+ String message = super.getMessage();
+ StringBuffer buffer = new StringBuffer( message );
+ Element element = getElement();
+ if( null != element )
+ {
+ Document document = element.getOwnerDocument();
+ String uri = document.getDocumentURI();
+ if( null != uri )
+ {
+ buffer.append( "\nSource: " + uri );
+ String filename = getSourceFilePath( uri );
+ if( null != filename )
+ {
+ buffer.append( "\nFile: " + filename );
+ }
+ buffer.append( "\n" );
+ }
+ String listing = list( element );
+ buffer.append( listing );
+ }
+ return buffer.toString();
+ }
+ catch( Throwable e )
+ {
+ return super.getMessage();
+ }
+ }
+
+ /**
+ * Static utility operation that returns a string representation of a DOM
element.
+ * @param element the element to stringify
+ * @return the string value
+ */
+ public static String list( Element element )
+ {
+ return list( element, "" );
+ }
+
+ /**
+ * Static utility operation that returns a syring representation of a DOM
element.
+ * @param element the element to stringify
+ * @param pad padding offset
+ * @return the string value
+ */
+ public static String list( Element element, String pad )
+ {
+ if( null == element )
+ {
+ return "";
+ }
+ StringBuffer buffer = new StringBuffer();
+ String tag = element.getTagName();
+ buffer.append( pad + "<" );
+ buffer.append( tag );
+ NamedNodeMap map = element.getAttributes();
+ for( int i=0; i<map.getLength(); i++ )
+ {
+ Node item = map.item( i );
+ buffer.append( " " + item.getNodeName() + "=\"" );
+ buffer.append( item.getNodeValue() );
+ buffer.append( "\"" );
+ }
+
+ Element[] children = ElementHelper.getChildren( element );
+ if( children.length > 0 )
+ {
+ buffer.append( ">" );
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ String listing = list( child, pad + " " );
+ String tagName = child.getTagName();
+ buffer.append( "\n" + listing );
+ }
+ buffer.append( "\n" + pad + "</" + tag + ">" );
+ }
+ else
+ {
+ buffer.append( "/>" );
+ }
+ return buffer.toString();
+ }
+
+ private static String getSourceFilePath( String value )
+ {
+ try
+ {
+ URI uri = URI.create( value );
+ if( Artifact.isRecognized( uri ) )
+ {
+ URL url = Artifact.toURL( uri );
+ File file = (File) url.getContent( new Class[]{ File.class }
);
+ return file.getCanonicalPath();
+ }
+ return null;
+ }
+ catch( Throwable e )
+ {
+ return null;
+ }
+ }
+
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/DuplicateKeyException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/DuplicateKeyException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/DuplicateKeyException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,53 @@
+/*
+ * 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 net.dpml.lang;
+
+/**
+ * Exception to indicate an error arrising from the use of a duplicate key.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DuplicateKeyException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>DuplicateKeyException</code> instance.
+ *
+ * @param key the duplicate key
+ */
+ public DuplicateKeyException( final String key )
+ {
+ super( key );
+ }
+
+ /**
+ * Return the key.
+ * @return the key
+ */
+ public String getKey()
+ {
+ return super.getMessage();
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/NamespaceError.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/NamespaceError.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/NamespaceError.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-2005 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman.
+ *
+ * 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.lang;
+
+/**
+ * Error related to schmema namespace resolution.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class NamespaceError extends Error
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>PartError</code> instance.
+ *
+ * @param message The detail message for this exception.
+ */
+ public NamespaceError( final String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Construct a new <code>PartError</code> instance.
+ *
+ * @param message The detail message for this exception.
+ * @param cause the root cause of the exception
+ */
+ public NamespaceError( final String message, final Throwable cause )
+ {
+ super( message );
+ super.initCause( cause );
+ }
+}
+
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/PartContentHandler.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/PartContentHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/PartContentHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,701 @@
+/*
+ * 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.lang;
+
+import dpml.lang.Info;
+import dpml.lang.Classpath;
+import dpml.lang.Part;
+import dpml.lang.DOM3DocumentBuilder;
+
+import dpml.util.DefaultLogger;
+import dpml.util.SimpleResolver;
+import dpml.util.ElementHelper;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.ServiceLoader;
+import java.util.ArrayList;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanException;
+import javax.management.InstanceAlreadyExistsException;
+
+import net.dpml.annotation.Component;
+
+import net.dpml.appliance.Appliance;
+import net.dpml.appliance.ApplianceFactory;
+
+import net.dpml.lang.PartManager;
+import net.dpml.lang.PartContentManager;
+
+import net.dpml.runtime.ComponentStrategyHandler;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Transit;
+import net.dpml.transit.ContentHandler;
+
+import net.dpml.util.Logger;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Content handler for the 'part' artifact type.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class PartContentHandler extends ContentHandler implements
PartContentManager, ApplianceFactory
+{
+ /**
+ * Part XSD uri.
+ */
+ public static final String NAMESPACE = "dpml:part";
+
+ private static final String PART_CONTENT_TYPE = "part";
+
+ private static final Logger LOGGER = new DefaultLogger( "dpml.part" );
+
+ // DOES NOT WORK
+ //private static final Map<String, WeakReference<Part>> CACHE =
+ // new Hashtable<String, WeakReference<Part>>();
+
+ // POTENTIAL SOLUTION: map of anchor classloader (keys) to a map of part
classloader and parts
+ //private static final Map<ClassLoader,Map<ClassLoader,Part>> CACHE =
+ // new Hashtable<ClassLoader,Map<ClassLoader,Part>>();
+
+ private static final Map<String,Part> CACHE = new
Hashtable<String,Part>();
+
+ private static final DOM3DocumentBuilder DOCUMENT_BUILDER =
+ new DOM3DocumentBuilder();
+
+ private static final ClassLoaderHelper CLASSLOADER_HELPER = new
ClassLoaderHelper();
+
+ private static final ComponentStrategyHandler STANDARD_STRATEGY_HANDLER
=
+ new ComponentStrategyHandler();
+
+ /**
+ * Return a strategy handler based on the supplied component annotation.
+ * @param annotation the component annotation
+ * @return the strategy handler
+ * @exception Exception if an error ocurrs during handler establishment
+ */
+ public static StrategyHandler getStrategyHandler( Component annotation )
throws Exception
+ {
+ String classname = annotation.handlerClassname();
+ try
+ {
+ return getStrategyHandler( classname );
+ }
+ catch( UnknownServiceException e )
+ {
+ String urn = annotation.handlerURI();
+ URI uri = new URI( urn );
+ return getStrategyHandler( uri );
+ }
+ }
+
+ /**
+ * Return the strategy handler supporting the supplied class. If the
class
+ * contains the component annotation the handler is resolved relative to
the
+ * annotation properties, otherwise a default strategy handler is
returned.
+ *
+ * @param subject the subject class
+ * @return the strategy handler
+ * @exception Exception if a general loading error occurs
+ */
+ public static StrategyHandler getStrategyHandler( Class<?> subject )
throws Exception
+ {
+ if( subject.isAnnotationPresent( Component.class ) )
+ {
+ Component annotation =
+ subject.getAnnotation( Component.class );
+ return PartContentHandler.getStrategyHandler( annotation );
+ }
+ else
+ {
+ return STANDARD_STRATEGY_HANDLER;
+ }
+ }
+
+ /**
+ * Load a potentially foreign strategy handler.
+ * Strategy resolution is based on the following rules relative to the
namespace
+ * of the supplied element:
+ * <ul>
+ * <li>if a system property named <tt>handler:[namespace]</tt> is
defined,
+ * it is assumed to be a handler classname and the implementation
will
+ * load the class and instantiate the handler instance.</li>
+ * <li>if the namespace is recognized as a standard strategy the
appropriate
+ * strategy handler is returned</li>
+ * <li>the implementation will evaluate the <tt<handler</tt> attribute
on the
+ * supplied element - if the attribute value is not null, then
+ * the values will interprited as either a classname or a uri. If
the
+ * value contains the ':' character the value will be interprited as
a
+ * uri to a part definition from which a strategy handler can be
established,
+ * otherwise, the implementation assumes the the value is a strategy
handler
+ * classname resolvable form the current context classloader</li>
+ * </ul>
+ *
+ * @param element the strategy element
+ * @exception Exception if loading error occurs
+ */
+ public static StrategyHandler getStrategyHandler( Element element )
throws Exception
+ {
+ TypeInfo info = element.getSchemaTypeInfo();
+ String namespace = info.getTypeNamespace();
+ String override = System.getProperty( "handler:" + namespace );
+ if( null != override )
+ {
+ return getStrategyHandler( override );
+ }
+ if( AntlibStrategyHandler.NAMESPACE.equals( namespace ) )
+ {
+ return new AntlibStrategyHandler();
+ }
+ else if( ComponentStrategyHandler.NAMESPACE.equals( namespace ) )
+ {
+ return new ComponentStrategyHandler();
+ }
+ else
+ {
+ String urn = ElementHelper.getAttribute( element, "handler" );
+ if( null != urn )
+ {
+ if( urn.indexOf( ":" ) > -1 )
+ {
+ URI uri = new URI( urn );
+ return getStrategyHandler( uri );
+ }
+ else
+ {
+ return getStrategyHandler( urn );
+ }
+ }
+ else
+ {
+ try
+ {
+ URI uri = getURIFromNamespaceURI( namespace );
+ return getStrategyHandler( uri );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Cannot resolve strategy handler for element.";
+ throw new DecodingException( error, element );
+ }
+ }
+ }
+ }
+
+ /**
+ * Load a strategy handler. The implementation will attempt to resolve a
+ * part defintion from the supplied uri, caching a reference to
+ * the handler, and returning the strategy handler instance.
+ *
+ * @param uri the part handler part uri
+ * @exception Exception if part loading error occurs
+ */
+ static StrategyHandler getStrategyHandler( URI uri ) throws Exception
+ {
+ ClassLoader context = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(
ClassLoader.getSystemClassLoader() ); // TODO
+ try
+ {
+ Strategy strategy = Strategy.load( null, null, uri, null );
+ StrategyHandler handler = strategy.getContentForClass(
StrategyHandler.class );
+ if( null == handler )
+ {
+ final String error =
+ "URI does not resolve to a strategy handler ["
+ + uri
+ + "]";
+ throw new ServiceError( error );
+ }
+ else
+ {
+ return handler;
+ }
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader( context );
+ }
+ }
+
+ static StrategyHandler getStrategyHandler( String classname ) throws
Exception
+ {
+ ServiceLoader<StrategyHandler> handlers = ServiceLoader.load(
StrategyHandler.class );
+ for( StrategyHandler handler : handlers )
+ {
+ if( handler.getClass().getName().equals( classname ) )
+ {
+ return handler;
+ }
+ }
+ throw new UnknownServiceException( classname );
+ }
+
+
//--------------------------------------------------------------------------------
+ // constructor
+
//--------------------------------------------------------------------------------
+
+ public PartContentHandler() throws Exception
+ {
+ 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", "Parts" );
+ ObjectName name =
+ ObjectName.getInstance( "net.dpml.transit", table );
+ server.registerMBean( this, name );
+ }
+ catch( InstanceAlreadyExistsException e )
+ {
+ //e.printStackTrace();
+ }
+ }
+ }
+
+
//--------------------------------------------------------------------------------
+ // ContentHandler
+
//--------------------------------------------------------------------------------
+
+ /**
+ * Returns the type tha the content handler supports.
+ * @return the content type name
+ */
+ public String getType()
+ {
+ return PART_CONTENT_TYPE;
+ }
+
+ /**
+ * Returns the content in the form of a {@link net.dpml.lang.Strategy}
datatype.
+ * @param connection the url connection
+ * @return the part datatype
+ * @exception IOException if an IO error occurs
+ */
+ public Object getContent( URLConnection connection ) throws IOException
+ {
+ Part part = getPartContent( connection );
+ return part.getStrategy();
+ }
+
+ /**
+ * Returns the content assignable to the first recognized class in the
list
+ * os supppied classes. If the class array is empty the part datatype 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
+ {
+ Part part = getPartContent( connection );
+ return getContentForClasses( part, classes );
+ }
+
+
//--------------------------------------------------------------------------------
+ // ApplianceFactory
+
//--------------------------------------------------------------------------------
+
+ /**
+ * 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
+ {
+ Part part = getPartContent( connection, partition );
+ return getContentForClass( part, Appliance.class );
+ }
+
+
//--------------------------------------------------------------------------------
+ // ContentManager
+
//--------------------------------------------------------------------------------
+
+ public PartManager[] getPartManagers()
+ {
+ ArrayList<PartManager> list = new ArrayList<PartManager>();
+ Part[] parts = CACHE.values().toArray( new Part[0] );
+ for( Part part : parts )
+ {
+ if( part instanceof PartManager )
+ {
+ PartManager manager = (PartManager) part;
+ list.add( manager );
+ }
+ }
+ return list.toArray( new PartManager[0] );
+ }
+
+
//--------------------------------------------------------------------------------
+ // internals
+
//--------------------------------------------------------------------------------
+
+ private Logger getLogger()
+ {
+ return LOGGER;
+ }
+
+ /**
+ * Return a resolved value given a supplied part instance and class.
+ * @param part the part to resolve against
+ * @param c the return type
+ * @return the resolved value
+ * @exception IOException if an error occurs
+ */
+ private <T>T getContentForClass( Part part, Class<T> c ) throws
IOException
+ {
+ if( Part.class == c )
+ {
+ return c.cast( part );
+ }
+ Strategy strategy = part.getStrategy();
+ return strategy.getContentForClass( c );
+ }
+
+ private Object getContentForClasses( Part part, Class[] classes ) throws
IOException
+ {
+ Strategy strategy = part.getStrategy();
+ for( Class<?> c : classes )
+ {
+ Object content = strategy.getContentForClass( c );
+ if( null != content )
+ {
+ return content;
+ }
+ }
+ return null;
+ }
+
+ static Part getPartContent( URLConnection connection ) throws IOException
+ {
+ return getPartContent( connection, null, true );
+ }
+
+ static Part getPartContent( URLConnection connection, String name )
throws IOException
+ {
+ return getPartContent( connection, name, true );
+ }
+
+ static Part getPartContent( URLConnection connection, String name,
boolean cache ) throws IOException
+ {
+ return getPartContent( null, connection, name, cache );
+ }
+
+ static Part getPartContent( ClassLoader anchor, URLConnection
connection, String name, boolean cache ) throws IOException
+ {
+ ClassLoader classloader = getAnchorClassLoader( anchor );
+ URL url = connection.getURL();
+ try
+ {
+ String key = buildKey( classloader, url );
+ if( cache )
+ {
+ //WeakReference ref = CACHE.get( key );
+ //if( null != ref )
+ //{
+ // Part part = (Part) ref.get();
+ //if( null != part )
+ //{
+ // if( getLogger().isTraceEnabled() )
+ // {
+ // getLogger().trace( "located cached part: " +
url );
+ // }
+ // return part;
+ //}
+ //else
+ //{
+ // if( getLogger().isTraceEnabled() )
+ // {
+ // getLogger().trace( "located disgarded ref: " +
key );
+ // }
+ //}
+ //}
+
+ Part part = CACHE.get( key );
+ if( null != part )
+ {
+ return part;
+ }
+ else
+ {
+ // otherwise we need to build it
+
+ part = buildPart( classloader, connection, name );
+ //if( part instanceof PartManager )
+ //{
+ // // register it with the mbean server
+ //}
+
+ //WeakReference<Part> reference = new
WeakReference<Part>( part );
+ //CACHE.put( key, reference );
+ CACHE.put( key, part );
+ if( LOGGER.isTraceEnabled() )
+ {
+ LOGGER.trace( "caching part"
+ + "\n url: " + url
+ + "\n key: " + key );
+ }
+ return part;
+ }
+ }
+ else
+ {
+ if( LOGGER.isTraceEnabled() )
+ {
+ LOGGER.trace( "building new part: " + url );
+ }
+ return buildPart( classloader, connection, name );
+ }
+ }
+ catch( IOException e )
+ {
+ throw e;
+ }
+ catch( NoClassDefFoundError e )
+ {
+ LOGGER.error(
+ e.toString()
+ + "\n"
+ + classloader.toString() );
+ throw e;
+ }
+ catch( Exception e )
+ {
+ final String error = "Unexpected error in part handling: " + url;
+ IOException ioe = new IOException();
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+
+ private static Part buildPart( ClassLoader anchor, URLConnection
connection, String name ) throws Exception
+ {
+ URL url = connection.getURL();
+ if( LOGGER.isTraceEnabled() )
+ {
+ LOGGER.trace(
+ "building part ["
+ + url
+ + "] with anchor ["
+ + System.identityHashCode( anchor )
+ + "]" );
+ }
+
+ Document document = DOCUMENT_BUILDER.parse( connection );
+ final Element element = document.getDocumentElement();
+ TypeInfo type = element.getSchemaTypeInfo();
+ String namespace = type.getTypeNamespace();
+ if( isNamespaceRecognized( namespace ) )
+ {
+ URI uri = url.toURI();
+ Resolver resolver = new SimpleResolver();
+ Info info = getInfo( uri, element );
+ Classpath classpath = getClasspath( element );
+ ClassLoader classloader = CLASSLOADER_HELPER.newClassLoader(
anchor, uri, classpath );
+ ClassLoader context =
Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader( classloader );
+ try
+ {
+ Element elem = getStrategyElement( element );
+ StrategyHandler handler = getStrategyHandler( elem );
+ String query = url.getQuery();
+ Strategy strategy = handler.build( classloader, elem,
resolver, name, query );
+ if( LOGGER.isTraceEnabled() )
+ {
+ LOGGER.trace(
+ "establised new part using ["
+ + strategy.getClass().getName()
+ + "]" );
+ }
+ return new Part( info, classpath, strategy );
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader( context );
+ }
+ }
+ else
+ {
+ final String error =
+ "Part namespace not recognized."
+ + "\nFound: " + namespace
+ + "\nExpecting: " + PartContentHandler.NAMESPACE;
+ throw new DecodingException( error, element );
+ }
+ }
+
+ private static boolean isNamespaceRecognized( String namespace )
+ {
+ if( NAMESPACE.equals( namespace ) )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private static Info getInfo( URI uri, Element root )
+ {
+ Element element = ElementHelper.getChild( root, "info" );
+ if( null == element )
+ {
+ return new Info( uri, null, null );
+ }
+ String title = ElementHelper.getAttribute( element, "title" );
+ Element descriptionElement = ElementHelper.getChild( element,
"description" );
+ String description = ElementHelper.getValue( descriptionElement );
+ return new Info( uri, title, description );
+ }
+
+ /**
+ * Construct the classpath defintion.
+ * @param root the element containing a 'classpath' element.
+ * @return the classpath definition
+ * @exception DecodingException if an error occurs during element
evaluation
+ */
+ private static Classpath getClasspath( Element root ) throws
DecodingException
+ {
+ Element classpath = ElementHelper.getChild( root, "classpath" );
+ if( null == classpath )
+ {
+ return new Classpath();
+ }
+
+ try
+ {
+ Element[] children = ElementHelper.getChildren( classpath );
+ URI[] sys = buildURIs( classpath, "system" );
+ URI[] pub = buildURIs( classpath, "public" );
+ URI[] prot = buildURIs( classpath, "protected" );
+ URI[] priv = buildURIs( classpath, "private" );
+ return new Classpath( sys, pub, prot, priv );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unable to decode classpath due to an unexpected error.";
+ throw new DecodingException( error, e, classpath );
+ }
+ }
+
+ private static URI[] buildURIs( Element classpath, String key ) throws
Exception
+ {
+ Element category = ElementHelper.getChild( classpath, key );
+ Element[] children = ElementHelper.getChildren( category, "uri" );
+ URI[] uris = new URI[ children.length ];
+ for( int i=0; i<children.length; i++ )
+ {
+ Element child = children[i];
+ String value = ElementHelper.getValue( child );
+ uris[i] = new URI( value );
+ }
+ return uris;
+ }
+
+ // cache utils
+
+ private static String buildKey( ClassLoader classloader, URL url )
throws IOException
+ {
+ try
+ {
+ int n = System.identityHashCode( classloader );
+ return "" + n + "#" + url.toURI().toASCIIString();
+ }
+ catch( Exception e )
+ {
+ final String error = "Internal error while resolving part key
from url: " + url;
+ IOException ioe = new IOException();
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+
+ static ClassLoader getAnchorClassLoader( ClassLoader parent )
+ {
+ if( null != parent )
+ {
+ return parent;
+ }
+ else
+ {
+ return Strategy.class.getClassLoader();
+ //ClassLoader classloader =
Thread.currentThread().getContextClassLoader();
+ //if( null == classloader )
+ //{
+ // return getClass().getClassLoader();
+ //}
+ //else
+ //{
+ // return classloader;
+ //}
+ }
+ }
+
+ private static Element getStrategyElement( Element root ) throws
DecodingException
+ {
+ Element[] children = ElementHelper.getChildren( root );
+ for( Element element : children )
+ {
+ String name = element.getLocalName();
+ if( !name.equals( "info" ) && !name.equals( "classpath" ) )
+ {
+ return element;
+ }
+ }
+ final String error =
+ "Missing part strategy element.";
+ throw new DecodingException( error, root );
+ }
+
+ /**
+ * Resolve the part handler given an element namespace.
+ * @param urn the namespace value
+ * @return the decoder uri
+ * @exception Exception if an error occurs
+ */
+ private static URI getURIFromNamespaceURI( String urn ) throws Exception
+ {
+ URI raw = new URI( urn );
+ Artifact artifact = Artifact.createArtifact( raw );
+ String group = artifact.getGroup();
+ String name = artifact.getName();
+ String path = "link:part:" + group + "/" + name;
+ Artifact link = Artifact.createArtifact( path );
+ return link.toURI();
+ }
+}
\ No newline at end of file

Added: trunk/main/lang/part/src/main/net/dpml/lang/PartContentManager.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/PartContentManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/PartContentManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,35 @@
+/*
+ * 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.lang;
+
+import net.dpml.transit.ContentManager;
+
+import javax.management.MXBean;
+
+/**
+ * Abstract base class for artifact content handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ @MXBean
+public interface PartContentManager extends ContentManager
+{
+ PartManager[] getPartManagers();
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/PartError.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/PartError.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/PartError.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-2005 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman.
+ *
+ * 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.lang;
+
+/**
+ * Fatal part related error.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PartError extends Error
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>PartError</code> instance.
+ *
+ * @param message The detail message for this exception.
+ */
+ public PartError( final String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Construct a new <code>PartError</code> instance.
+ *
+ * @param message The detail message for this exception.
+ * @param cause the root cause of the exception
+ */
+ public PartError( final String message, final Throwable cause )
+ {
+ super( message );
+ super.initCause( cause );
+ }
+}
+
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/PartException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/PartException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/PartException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2004-2005 Stephen J. McConnell.
+ * Copyright 2004 Niclas Hedhman.
+ *
+ * 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.lang;
+
+import java.io.IOException;
+
+/**
+ * Exception to indicate that there was a part handler related error.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class PartException extends IOException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>PartException</code> instance.
+ *
+ * @param message The detail message for this exception.
+ */
+ public PartException( final String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Construct a new <code>PartException</code> instance.
+ *
+ * @param message The detail message for this exception.
+ * @param cause the root cause of the exception
+ */
+ public PartException( final String message, final Throwable cause )
+ {
+ super( message );
+ super.initCause( cause );
+ }
+}
+
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/PartManager.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/PartManager.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/PartManager.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,49 @@
+/*
+ * 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.lang;
+
+import javax.management.MXBean;
+
+/**
+ * Management interface to a generic part instance.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@MXBean
+public interface PartManager
+{
+ /**
+ * Returns the part URI as a string.
+ * @return the codebase uri
+ */
+ String getCodebaseURI();
+
+ /**
+ * Returns the part title.
+ * @return the title
+ */
+ String getTitle();
+
+ /**
+ * Returns the part description.
+ * @return the description
+ */
+ String getDescription();
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/ServiceError.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/ServiceError.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/ServiceError.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,56 @@
+/*
+ * 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 net.dpml.lang;
+
+/**
+ * Fatal service handling error.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ServiceError extends Error
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ServiceError</code>.
+ *
+ * @param message the error message
+ */
+ public ServiceError( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ServiceError</code>.
+ *
+ * @param message the error message
+ * @param cause the causal exception
+ */
+ public ServiceError( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/ServiceRegistry.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/ServiceRegistry.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/ServiceRegistry.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,31 @@
+/*
+ * 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.lang;
+
+/**
+ * Component interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface ServiceRegistry
+{
+ <T>T lookup( Class<T> service );
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/SimpleServiceRegistry.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/SimpleServiceRegistry.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/SimpleServiceRegistry.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,88 @@
+/*
+ * 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.lang;
+
+import java.util.ServiceLoader;
+
+import net.dpml.lang.ServiceRegistry;
+
+/**
+ * Simple service registry implementation that selects the first service
+ * that is type assignable from the list of service instance supplied to
+ * the registry constructor.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class SimpleServiceRegistry implements ServiceRegistry
+{
+ private final ServiceRegistry m_parent;
+ private final Object[] m_args;
+
+ /**
+ * Creation of a new service registry with no parent.
+ * @param args an ordered sequence of thread-safe services
+ */
+ public SimpleServiceRegistry( Object... args )
+ {
+ this( null, args );
+ }
+
+ /**
+ * Creation of a new service registry with no parent.
+ * @param parent an optional fallback registry
+ * @param args an ordered sequence of thread-safe services
+ */
+ public SimpleServiceRegistry( ServiceRegistry parent, Object... args )
+ {
+ if( null == args )
+ {
+ throw new NullPointerException( "args" );
+ }
+ m_parent = parent;
+ m_args = args;
+ }
+
+ /**
+ * Matches a service in the registry with the supplied type. If no
+ * match is found and a parent registry has been delclared, the lookup
+ * request is passed onto the parent registry, otherwise null is
+ * returned.
+ */
+ public <T>T lookup( Class<T> type )
+ {
+ for( Object object : m_args )
+ {
+ if( null != object )
+ {
+ Class c = object.getClass();
+ if( type.isAssignableFrom( c ) )
+ {
+ return type.cast( object );
+ }
+ }
+ }
+ if( null != m_parent )
+ {
+ return m_parent.lookup( type );
+ }
+ return null;
+ }
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/lang/StandardServiceRegistry.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/StandardServiceRegistry.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/StandardServiceRegistry.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,73 @@
+/*
+ * 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.lang;
+
+import java.util.ServiceLoader;
+
+/**
+ * Default service registry implementation that resolves services via
+ * services resolvable using <tt>java.util.ServiceLoader</tt>.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandardServiceRegistry implements ServiceRegistry
+{
+ private final ServiceRegistry m_parent;
+
+ /**
+ * Creation of a new service registry with no parent.
+ */
+ public StandardServiceRegistry()
+ {
+ this( null );
+ }
+
+ /**
+ * Creation of a new service registry with fallback delegation to
+ * a parent registry.
+ *
+ * @param parent an optional parent registry
+ */
+ public StandardServiceRegistry( ServiceRegistry parent )
+ {
+ m_parent = parent;
+ }
+
+ /**
+ * Matches a service in the registry with the supplied type. If no
+ * match is found and a parent registry has been delclared, the lookup
+ * request is passed onto the parent registry, otherwise null is
+ * returned.
+ */
+ public <T>T lookup( Class<T> type )
+ {
+ ServiceLoader<T> loaders = ServiceLoader.load( type );
+ for( T service : loaders )
+ {
+ return service; // the first available
+ }
+ if( null != m_parent )
+ {
+ return m_parent.lookup( type );
+ }
+ return null;
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/Strategy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/Strategy.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/Strategy.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,258 @@
+/*
+ * 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.lang;
+
+import dpml.lang.Part;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ServiceLoader;
+
+import javax.xml.XMLConstants;
+
+import net.dpml.transit.Artifact;
+import net.dpml.transit.Transit;
+
+import net.dpml.runtime.ComponentStrategyHandler;
+import net.dpml.util.Logger;
+
+import dpml.util.DefaultLogger;
+import dpml.util.ElementHelper;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * Abstract component deployment strategy.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class Strategy implements Comparable<Strategy>
+{
+ private static final Logger LOGGER = new DefaultLogger( "dpml.lang" );
+
+ /**
+ * Creation of a new management strategy.
+ *
+ * @param subject the implementation class to be managed
+ * @param registry the service registry
+ * @param name the path under which the strategy will be established
+ * @return the management strategy
+ * @exception Exception if a general loading error occurs
+ */
+ public static Strategy load( Class<?> subject, ServiceRegistry registry,
String name ) throws Exception
+ {
+ if( null == subject )
+ {
+ throw new NullPointerException( "subject" );
+ }
+ StrategyHandler handler = PartContentHandler.getStrategyHandler(
subject );
+ Strategy strategy = handler.newStrategy( subject, name );
+ if( null == registry )
+ {
+ StandardServiceRegistry standard = new StandardServiceRegistry();
+ strategy.initialize( standard );
+ }
+ else
+ {
+ strategy.initialize( registry );
+ }
+ return strategy;
+ }
+
+ /**
+ * Load a strategy defined by the supplied uri.
+ *
+ * @param uri the source uri to a part definition
+ * @return the strategy
+ * @exception Exception if a general loading error occurs
+ * @exception NullPointerException if the uri argument is null
+ */
+ public static Strategy load( URI uri ) throws Exception,
NullPointerException
+ {
+ return load( null, null, uri, null );
+ }
+
+ /**
+ * Load a strategy defined by the supplied uri, name, classloader and
service
+ * registry, and return a value assignable to the supplied type.
+ *
+ * @param classloader the anchor classloader
+ * @param registry the service registry
+ * @param uri the source uri to a part definition
+ * @param name the path under which the strategy will be established
+ * @return an instance of the supplied type
+ * @exception Exception if a general loading error occurs
+ * @exception NullPointerException if the uri argument is null
+ */
+ public static Strategy load(
+ ClassLoader classloader, ServiceRegistry registry, URI uri, String
name ) throws Exception, NullPointerException
+ {
+ if( null == uri )
+ {
+ throw new NullPointerException( "uri" );
+ }
+ Transit transit = Transit.getInstance();
+ URL url = Artifact.toURL( uri );
+ URLConnection connection = url.openConnection();
+ Part part = PartContentHandler.getPartContent( classloader,
connection, name, true );
+ Strategy strategy = part.getStrategy();
+ if( null == registry )
+ {
+ StandardServiceRegistry standard = new StandardServiceRegistry();
+ strategy.initialize( standard );
+ }
+ else
+ {
+ strategy.initialize( registry );
+ }
+ return strategy;
+ }
+
+ //--------------------------------------------------------------------
+ // state
+ //--------------------------------------------------------------------
+
+ private ClassLoader m_classloader;
+
+ //--------------------------------------------------------------------
+ // constructor
+ //--------------------------------------------------------------------
+
+ /**
+ * Creation of a new deployment strategy.
+ * @param classloader the classloader
+ */
+ protected Strategy( ClassLoader classloader )
+ {
+ m_classloader = classloader;
+ }
+
+ //--------------------------------------------------------------------
+ // public operations
+ //--------------------------------------------------------------------
+
+ /**
+ * Return the classloader establised by the strategy implementation.
+ * @return the classloader
+ */
+ public ClassLoader getClassLoader()
+ {
+ return m_classloader;
+ }
+
+ /**
+ * Return the priority assigned to this strategy.
+ * @return the priority value
+ */
+ public abstract int getPriority();
+
+ /**
+ * Return true if this strategy is a candidate with result to the
+ * supply of an instance assignable to the supplied type.
+ *
+ * @param type the requested type
+ * @return type if this strategy is a condidate
+ */
+ public abstract boolean isaCandidate( Class<?> type );
+
+ /**
+ * Instantiate a service returning an instance assigned to the supplied
type.
+ *
+ * @param type the return type
+ * @return an instance of the type
+ */
+ public abstract <T>T getInstance( Class<T> type );
+
+ /**
+ * Write the strategy to the supplied buffer in XML format.
+ * @param buffer the output buffer
+ * @param key the optional identifying key
+ * @exception IOException if an IO error occurs
+ */
+ public abstract void encode( Buffer buffer, String key ) throws
IOException;
+
+ /**
+ * Composite strategies are strategy implementations that contain subidary
+ * strategies. During lookup operations, a subsidiary strategy may
request
+ * a service from the enclosing strategy. To enable traversal from a
subsidary
+ * to enclosing context a service registry shall be provided to all
subsidiary
+ * strategies.
+ *
+ * @param registry the service registry
+ */
+ public abstract void initialize( ServiceRegistry registry );
+
+ /**
+ * Return the short name of this strategy.
+ * @return the name
+ */
+ public abstract String getName();
+
+ /**
+ * Compares a supplied strategy with this strategy. If the supplied
+ * strategy has a priority greater than this strategy the returned value
+ * is 1, otherwise if the supplied strategy has a priority lower than this
+ * strategy then the return value is -1,otherwise the returned value is 0.
+ *
+ * @param strategy the strategy to evaluate relative to this strategy
+ * @return the priority comparative index
+ */
+ public int compareTo( Strategy strategy )
+ {
+ int n = getPriority();
+ int m = strategy.getPriority();
+ if( n > m )
+ {
+ return -1;
+ }
+ else if( n == m )
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // protected operations
+ //--------------------------------------------------------------------
+
+ /**
+ * Return a value assignable to the supplied type or null if the type
+ * cannot be resolved from this strategy.
+ * @param c the target class
+ * @return an instance of the class or null
+ * @exception IOException if an IO error occurs
+ */
+ public abstract <T>T getContentForClass( Class<T> c ) throws IOException;
+
+ //--------------------------------------------------------------------
+ // private implementation
+ //--------------------------------------------------------------------
+
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/StrategyHandler.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/StrategyHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/StrategyHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,66 @@
+/*
+ * 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.lang;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import dpml.lang.Classpath;
+
+import net.dpml.util.Logger;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * Interace implemented by part strategy handlers.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface StrategyHandler
+{
+ /**
+ * Creation of a new strategy handler for the supplied implementation
class.
+ * @param c the component implementation class
+ * @exception IOException if an I/O error occurs
+ */
+ Strategy newStrategy( Class<?> c ) throws IOException;
+
+ /**
+ * Creation of a new strategy handler for the supplied implementation
class.
+ * @param c the component implementation class
+ * @param name the component name
+ * @exception IOException if an I/O error occurs
+ */
+ Strategy newStrategy( Class<?> c, String name ) throws IOException;
+
+ /**
+ * Construct a new strategy using a supplied element and value resolver.
+ * @param classloader the classloader
+ * @param element the DOM element definining the deployment strategy
+ * @param resolver symbolic property resolver
+ * @param partition the assigned partition
+ * @param query the query
+ * @return the strategy
+ * @exception IOException if an I/O error occurs
+ */
+ Strategy build(
+ ClassLoader classloader, Element element, Resolver resolver, String
partition, String query ) throws IOException;
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/TypeCastException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/TypeCastException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/TypeCastException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,68 @@
+/*
+ * 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.lang;
+
+import dpml.util.StandardClassLoader;
+
+/**
+ * Exception raised when class cannot be cast to a requested type.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class TypeCastException extends ClassCastException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final Class m_base;
+ private final Class m_type;
+
+ /**
+ * Construct a new <code>TypeCastException</code> instance.
+ *
+ * @param message the message
+ * @param base the base class against which a failed cast was attempted
+ * @param type the class used as the cast criteria
+ */
+ public TypeCastException( final String message, Class base, Class type )
+ {
+ super( message );
+ m_base = base;
+ m_type = type;
+ }
+
+ public Class getBase()
+ {
+ return m_base;
+ }
+
+ public Class getType()
+ {
+ return m_type;
+ }
+
+ public String getReport()
+ {
+ return StandardClassLoader.toString( m_base, m_type );
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/UnknownKeyException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/UnknownKeyException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/UnknownKeyException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,57 @@
+/*
+ * 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 net.dpml.lang;
+
+/**
+ * Exception to indicate an error arrising from the use of an unknown key.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class UnknownKeyException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final String m_key;
+
+ /**
+ * Construct a new <code>UnknownKeyException</code> instance.
+ *
+ * @param key the unknown key
+ */
+ public UnknownKeyException( final String key )
+ {
+ super( "[" + key + "]" );
+
+ m_key = key;
+ }
+
+ /**
+ * Return the key.
+ * @return the key
+ */
+ public String getKey()
+ {
+ return m_key;
+ }
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/lang/UnknownServiceException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/UnknownServiceException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/UnknownServiceException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,44 @@
+/*
+ * 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.lang;
+
+/**
+ * Exception raised if a requested service cannot be found.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class UnknownServiceException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>UnknownServiceException</code> instance.
+ *
+ * @param classname the class name
+ */
+ public UnknownServiceException( final String classname )
+ {
+ super( classname );
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/lang/Version.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/Version.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/Version.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2004-2006 Stephen J. McConnell.
+ * Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.dpml.lang;
+
+import java.io.Serializable;
+
+import java.util.StringTokenizer;
+
+/**
+ * This class is used to hold version information.
+ * <p />
+ *
+ * The version number is made up of three dot-separated fields:
+ * <p />
+ * &quot;<b>major.minor.micro</b>&quot;
+ * <p />
+ * The <b>major</b>, <b>minor</b> and <b>micro</b> fields are
+ * <i>integer</i> numbers represented in decimal notation and have the
+ * following meaning:
+ * <ul>
+ *
+ * <p /><li><b>major</b> - When the major version changes (in ex. from
+ * &quot;1.5.12&quot; to &quot;2.0.0&quot;), then backward compatibility
+ * with previous releases is not granted.</li><p />
+ *
+ * <p /><li><b>minor</b> - When the minor version changes (in ex. from
+ * &quot;1.5.12&quot; to &quot;1.6.0&quot;), then backward compatibility
+ * with previous releases is granted, but something changed in the
+ * implementation of the Component. (ie it methods could have been
added)</li><p />
+ *
+ * <p /><li><b>micro</b> - When the micro version changes (in ex.
+ * from &quot;1.5.12&quot; to &quot;1.5.13&quot;), then the the changes are
+ * small forward compatible bug fixes or documentation modifications etc.
+ * </li>
+ * </ul>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public final class Version implements Comparable, Serializable
+{
+ /**
+ * Version -1.0.0.
+ */
+ public static final Version NULL_VERSION = new Version( -1, 0, 0 );
+
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private int m_major;
+ private int m_minor;
+ private int m_micro;
+
+ /**
+ * Parse a version out of a string.
+ * The version string format is <major>.<minor>.<micro> where
+ * both minor and micro are optional.
+ *
+ * @param version The input version string
+ * @return the new Version object
+ * @throws NumberFormatException if an error occurs
+ * @throws IllegalArgumentException if an error occurs
+ * @throws NullPointerException if the version argument is
<code>null</code>.
+ * @since 4.1
+ */
+ public static Version parse( final String version )
+ throws NumberFormatException, IllegalArgumentException,
NullPointerException
+ {
+ if( version == null )
+ {
+ throw new NullPointerException( "version" );
+ }
+
+ final StringTokenizer tokenizer = new StringTokenizer( version, "."
);
+ final String[] levels = new String[ tokenizer.countTokens() ];
+ for( int i = 0; i < levels.length; i++ )
+ {
+ levels[ i ] = tokenizer.nextToken();
+ }
+
+ int major = -1;
+ if( 0 < levels.length )
+ {
+ major = Integer.parseInt( levels[ 0 ] );
+ }
+
+ int minor = 0;
+ if( 1 < levels.length )
+ {
+ minor = Integer.parseInt( levels[ 1 ] );
+ }
+
+ int micro = 0;
+ if( 2 < levels.length )
+ {
+ micro = Integer.parseInt( levels[ 2 ] );
+ }
+
+ return new Version( major, minor, micro );
+ }
+
+ /**
+ * Create a new instance of a <code>Version</code> object with the
+ * specified version numbers.
+ *
+ * @param major This <code>Version</code> major number.
+ * @param minor This <code>Version</code> minor number.
+ * @param micro This <code>Version</code> micro number.
+ */
+ public Version( final int major, final int minor, final int micro )
+ {
+ m_major = major;
+ m_minor = minor;
+ m_micro = micro;
+ }
+
+ /**
+ * Retrieve major component of version.
+ *
+ * @return the major component of version
+ * @since 4.1
+ */
+ public int getMajor()
+ {
+ return m_major;
+ }
+
+ /**
+ * Retrieve minor component of version.
+ *
+ * @return the minor component of version
+ * @since 4.1
+ */
+ public int getMinor()
+ {
+ return m_minor;
+ }
+
+ /**
+ * Retrieve micro component of version.
+ *
+ * @return the micro component of version.
+ * @since 4.1
+ */
+ public int getMicro()
+ {
+ return m_micro;
+ }
+
+ /**
+ * Check this <code>Version</code> against another for equality.
+ * <p />
+ * If this <code>Version</code> is compatible with the specified one,
then
+ * <b>true</b> is returned, otherwise <b>false</b>.
+ *
+ * @param other The other <code>Version</code> object to be compared
with this
+ * for equality.
+ * @return <b>true</b> if this <code>Version</code> is compatible with
the specified one
+ * @since 4.1
+ */
+ public boolean equals( final Version other )
+ {
+ if( other == null )
+ {
+ return false;
+ }
+ boolean isEqual = ( getMajor() == other.getMajor() );
+ if( isEqual )
+ {
+ isEqual = ( getMinor() == other.getMinor() );
+ }
+ if( isEqual )
+ {
+ isEqual = ( getMicro() == other.getMicro() );
+ }
+ return isEqual;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this
<code>Version</code>.
+ * Returns <b>true</b> if the other object is an instance of
<code>Version</code>
+ * and has the same major, minor, and micro components.
+ *
+ * @param other an <code>Object</code> value
+ * @return <b>true</b> if the other object is equal to this
<code>Version</code>
+ */
+ public boolean equals( final Object other )
+ {
+ boolean isEqual = false;
+ if( other instanceof Version )
+ {
+ isEqual = equals( (Version) other );
+ }
+ return isEqual;
+ }
+
+ /**
+ * Add a hashing function to ensure the Version object is
+ * treated as expected in hashmaps and sets. NOTE: any
+ * time the equals() is overridden, hashCode() should also
+ * be overridden.
+ *
+ * @return the hashCode
+ */
+ public int hashCode()
+ {
+ int hash = 61486123 * getMajor();
+ hash = hash + 1273621 * getMinor();
+ hash = hash + 8912738 * getMicro();
+ return hash;
+ }
+
+ /**
+ * Check this <code>Version</code> against another for compliancy
+ * (compatibility).
+ * <p />
+ * If this <code>Version</code> is compatible with the specified one,
then
+ * <b>true</b> is returned, otherwise <b>false</b>. Be careful when using
+ * this method since, in example, version 1.3.7 is compliant to version
+ * 1.3.6, while the opposite is not.
+ * <p />
+ * The following example displays the expected behaviour and results of
version.
+ * <pre>
+ * final Version v1 = new Version( 1, 3, 6 );
+ * final Version v2 = new Version( 1, 3, 7 );
+ * final Version v3 = new Version( 1, 4, 0 );
+ * final Version v4 = new Version( 2, 0, 1 );
+ *
+ * assert( v1.complies( v1 ) );
+ * assert( ! v1.complies( v2 ) );
+ * assert( v2.complies( v1 ) );
+ * assert( ! v1.complies( v3 ) );
+ * assert( v3.complies( v1 ) );
+ * assert( ! v1.complies( v4 ) );
+ * assert( ! v4.complies( v1 ) );
+ * </pre>
+ *
+ * @param other The other <code>Version</code> object to be compared
with this
+ * for compliancy (compatibility).
+ * @return <b>true</b> if this <code>Version</code> is compatible with
the specified one
+ */
+ public boolean complies( final Version other )
+ {
+ if( other == null )
+ {
+ return false;
+ }
+ if( other.m_major == -1 )
+ {
+ return true;
+ }
+ if( m_major != other.m_major )
+ {
+ return false;
+ }
+ else if( m_minor < other.m_minor )
+ {
+ //If of major version but lower minor version then incompatible
+ return false;
+ }
+ else
+ {
+ //If same major version, same minor version but lower micro level
+ //then incompatible
+ return !( m_minor == other.m_minor && m_micro < other.m_micro );
+ }
+ }
+
+ /**
+ * Overload toString to report version correctly.
+ *
+ * @return the dot seperated version string
+ */
+ public String toString()
+ {
+ return m_major + "." + m_minor + "." + m_micro;
+ }
+
+ /**
+ * Compare two versions together according to the
+ * {@link Comparable} interface.
+ * @param o the other object
+ * @return number indicating relative value (-1, 0, 1)
+ * @throws NullPointerException if the argument is null.
+ */
+ public int compareTo( Object o )
+ throws NullPointerException
+ {
+ if( o == null )
+ {
+ throw new NullPointerException ( "o" );
+ }
+
+ Version other = (Version) o;
+
+ if( getMajor() < other.getMajor() )
+ {
+ return -1;
+ }
+
+ if( getMajor() > other.getMajor() )
+ {
+ return 1;
+ }
+
+ if( getMinor() < other.getMinor() )
+ {
+ return -1;
+ }
+
+ if( getMinor() > other.getMinor() )
+ {
+ return 1;
+ }
+
+ if( getMicro() < other.getMicro() )
+ {
+ return -1;
+ }
+
+ if( getMicro() > other.getMicro() )
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/lang/package-info.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/lang/package-info.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/lang/package-info.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2004-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.
+ */
+
+/**
+ * <p>Low-level services dealing with part deployment and management.</p>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.lang;

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Component.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Component.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Component.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,66 @@
+/*
+ * 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.runtime;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Component interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Component
+{
+ /**
+ * Return the component name.
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * Add a listener to the component.
+ * @param listener the component listener
+ */
+ void addComponentListener( ComponentListener listener );
+
+ /**
+ * Remove a listener from the component.
+ * @param listener the component listener
+ */
+ void removeComponentListener( ComponentListener listener );
+
+ /**
+ * Return a decommissioning provider.
+ * @return the provider
+ */
+ Provider getProvider();
+
+ /**
+ * Release a provider.
+ * @param provider the provider to release
+ */
+ void release( Provider provider );
+
+ /**
+ * Terminate the component.
+ */
+ void terminate();
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ComponentError.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ComponentError.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ComponentError.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,56 @@
+/*
+ * 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 net.dpml.runtime;
+
+/**
+ * Exception to indicate an error arrising from the use of a duplicate key.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ComponentError extends Error
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>ComponentError</code>.
+ *
+ * @param message the error message
+ */
+ public ComponentError( final String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new <code>ComponentError</code>.
+ *
+ * @param message the error message
+ * @param cause the causal exception
+ */
+ public ComponentError( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ComponentEvent.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ComponentEvent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ComponentEvent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,59 @@
+/*
+ * 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 net.dpml.runtime;
+
+import java.util.EventObject;
+
+
+/**
+ * Event triggered as a result of a state change.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class ComponentEvent extends EventObject
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final Component m_component;
+
+ /**
+ * Construct a new <code>StateEvent</code>.
+ *
+ * @param source the source component
+ */
+ public ComponentEvent( final Component source )
+ {
+ super( source );
+ m_component = source;
+ }
+
+ /**
+ * Return the component that initiated the event.
+ * @return the source component
+ */
+ public Component getComponent()
+ {
+ return m_component;
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ComponentException.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ComponentException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ComponentException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -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.runtime;
+
+import net.dpml.lang.DecodingException;
+
+import dpml.util.ElementHelper;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * Component related exception.
+ */
+public class ComponentException extends DecodingException
+{
+ /**
+ * Create a new decoding exception.
+ * @param message the exception message
+ */
+ public ComponentException( String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Create a new decoding exception.
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public ComponentException( String message, Throwable cause )
+ {
+ this( message, cause, null );
+ }
+
+ /**
+ * Create a new decoding exception.
+ * @param message the exception message
+ * @param cause the causal exception
+ * @param element the element representing the source definition
+ */
+ public ComponentException( String message, Throwable cause, Element
element )
+ {
+ super( message, cause, element );
+ }
+}

Added:
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentInvocationHandler.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentInvocationHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentInvocationHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,69 @@
+/*
+ * 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.runtime;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import net.dpml.annotation.Services;
+
+import dpml.lang.Disposable;
+
+/**
+* Invocation handler supporting instance isolation relative to services
+* declared by a target implementation class.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+*/
+class ComponentInvocationHandler implements InvocationHandler
+{
+ private Object m_instance;
+
+ /**
+ * Creation of a new component invocation handler.
+ * @param instance the instance to be isolated
+ */
+ protected ComponentInvocationHandler( Object instance )
+ {
+ m_instance = instance;
+ }
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by the proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ public Object invoke( final Object proxy, final Method method, final
Object[] args )
+ throws InvocationTargetException, IllegalAccessException
+ {
+ return method.invoke( m_instance, args );
+ }
+
+ protected Object getInstance()
+ {
+ return m_instance;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ComponentListener.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ComponentListener.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ComponentListener.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,39 @@
+/*
+ * 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 net.dpml.runtime;
+
+import java.util.EventListener;
+
+/**
+ * Interface implementated by remote listeners to state change events.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface ComponentListener extends EventListener
+{
+ /**
+ * Notify the listener of an event within the component.
+ *
+ * @param event the comnponent event
+ * @exception RemoteException if a remote transport error occurs
+ */
+ void componentChanged( final ComponentEvent event );
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,889 @@
+/*
+ * 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.runtime;
+
+import dpml.appliance.StandardAppliance;
+import dpml.lang.Value;
+import dpml.lang.Disposable;
+import dpml.state.StateDecoder;
+import dpml.util.DefaultLogger;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.io.File;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ServiceLoader;
+import java.util.WeakHashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.TimeUnit;
+
+import net.dpml.annotation.Activation;
+import net.dpml.annotation.CollectionPolicy;
+import net.dpml.annotation.LifestylePolicy;
+import net.dpml.annotation.ActivationPolicy;
+
+import net.dpml.appliance.Appliance;
+
+import net.dpml.lang.Buffer;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.StandardServiceRegistry;
+import net.dpml.lang.Strategy;
+import net.dpml.lang.TypeCastException;
+
+import net.dpml.state.State;
+import net.dpml.state.StateMachine;
+
+import net.dpml.transit.Artifact;
+
+import net.dpml.util.Logger;
+
+import static dpml.state.DefaultState.NULL_STATE;
+
+/**
+ * Component strategy.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ComponentStrategy extends Strategy implements Component,
ServiceRegistry
+{
+ private static final Logger LOGGER = new DefaultLogger(
"dpml.lang.component" );
+ private static final ComponentStrategyHandler HANDLER = new
ComponentStrategyHandler();
+
+ private final String m_name;
+ private final int m_priority;
+ private final Class<?> m_class;
+ private final String m_path;
+ private final LifestylePolicy m_lifestyle;
+ private final CollectionPolicy m_collection;
+ private final State m_graph;
+ private final LifestyleHandler m_handler;
+ private final ContextModel m_context;
+ private final ActivationPolicy m_activation;
+ private final PartsDirective m_parts;
+ private final Logger m_logger;
+ private final Map<String,Object> m_map = new Hashtable<String,Object>();
+
+ private final Set<ComponentListener> m_listeners = new
CopyOnWriteArraySet<ComponentListener>();
+ private final ExecutorService m_queue =
Executors.newSingleThreadExecutor();
+
+ private ServiceRegistry m_registry;
+
+ ComponentStrategy(
+ final String partition, final String name, int priority, final Class
type, ContextModel context, PartsDirective parts )
+ throws IOException
+ {
+ super( type.getClassLoader() );
+
+ m_class = type;
+ m_priority = priority;
+ m_name = getComponentName( name, m_class );
+ m_collection = getCollectionPolicy( m_class );
+ m_lifestyle = getLifestylePolicy( m_class );
+ m_path = getComponentPath( partition, m_name, m_class );
+ m_context = context;
+ m_logger = getComponentLogger( m_path );
+ m_graph = getLifecycleGraph( m_class );
+ m_activation = getActivationPolicy( m_class );
+ m_parts = getPartsDirective( parts );
+
+ m_parts.initialize( this );
+
+ m_map.put( "name", m_name );
+ m_map.put( "path", m_path );
+ m_map.put( "work", new File( System.getProperty( "user.dir" )
).getCanonicalFile() );
+ m_map.put( "temp", new File( System.getProperty( "java.io.tmpdir" )
).getCanonicalFile() );
+
+ try
+ {
+ m_map.put( "uri", new URI( "component:" + m_path ) );
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+
+ if( m_logger.isTraceEnabled() )
+ {
+ final String message =
+ "new "
+ + m_collection.toString().toLowerCase()
+ + " "
+ + m_lifestyle.toString().toLowerCase()
+ + " ["
+ + m_class.getName()
+ + "]";
+ m_logger.trace( message );
+ }
+
+ m_handler = getLifestyleHandler( m_lifestyle );
+ }
+
+ public String getName()
+ {
+ return m_name;
+ }
+
+ public int getPriority()
+ {
+ return m_priority;
+ }
+
+ /**
+ * Add a listener to the component.
+ * @param listener the component listener
+ */
+ public void addComponentListener( ComponentListener listener )
+ {
+ m_listeners.add( listener );
+ }
+
+ /**
+ * Remove a listener from the component.
+ * @param listener the component listener
+ */
+ public void removeComponentListener( ComponentListener listener )
+ {
+ m_listeners.remove( listener );
+ }
+
+ void processEvent( ComponentEvent event )
+ {
+ Logger logger= getLogger();
+ for( ComponentListener listener : m_listeners )
+ {
+ m_queue.execute( new ComponentEventDistatcher( logger, listener,
event ) );
+ }
+ }
+
+ Map<String,Object> getContextMap()
+ {
+ return m_map;
+ }
+
+ public Provider getProvider()
+ {
+ synchronized( m_handler )
+ {
+ return m_handler.getProvider();
+ }
+ }
+
+ public void release( Provider provider )
+ {
+ synchronized( m_handler )
+ {
+ m_handler.release( provider );
+ }
+ }
+
+ public void initialize( ServiceRegistry registry ) // TODO: parts
initialization should occur here?
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "initialization" );
+ }
+ m_registry = registry;
+ }
+
+ public boolean isaCandidate( Class<?> type )
+ {
+ return type.isAssignableFrom( m_class );
+ }
+
+ public <T>T lookup( Class<T> service )
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "lookup: " + service.getName() );
+ }
+
+ for( String key : m_parts.getKeys() )
+ {
+ Strategy strategy = m_parts.getStrategy( key );
+ if( strategy.isaCandidate( service ) )
+ {
+ try
+ {
+ return strategy.getInstance( service );
+ }
+ catch( Exception e )
+ {
+ if( strategy instanceof ComponentStrategy )
+ {
+ ComponentStrategy s = (ComponentStrategy) strategy;
+ String path = s.getComponentPath();
+
+ final String error =
+ "Lookup aquisition in ["
+ + getComponentPath()
+ + "] failed while aquiring the service ["
+ + service.getName()
+ + "] from the provider ["
+ + path
+ + "].";
+ throw new ComponentError( error, e );
+ }
+ else
+ {
+ final String error =
+ "Lookup aquisition in ["
+ + getComponentPath()
+ + "] failed while aquiring the service ["
+ + service.getName()
+ + "].";
+ throw new ComponentError( error, e );
+ }
+ }
+ }
+ }
+
+ if( null != m_registry )
+ {
+ return m_registry.lookup( service );
+ }
+ else
+ {
+ ServiceRegistry registry = new StandardServiceRegistry();
+ return registry.lookup( service );
+ }
+ }
+
+ public void terminate()
+ {
+ terminate( 10, TimeUnit.SECONDS );
+ }
+
+ void terminate( long timeout, TimeUnit units )
+ {
+ synchronized( this )
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "termination" );
+ }
+ m_handler.terminate();
+ m_queue.shutdown();
+ try
+ {
+ boolean ok = m_queue.awaitTermination( timeout, units );
+ if( !ok )
+ {
+ final String message =
+ "Component termination timeout in ["
+ + getName()
+ + "] (some events may not have been processed).";
+ getLogger().warn( message );
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Internal support for the resolution of a context service lookup
request.
+ * The service classname comes from a context entry in this component and
+ * is resolved by the parent component. The parent evaluates off of its
+ * internal parts for a component implementing the service and if found,
+ * the instance is returned.
+ */
+ <T>T getService( Class<?> clazz, Class<T> type ) throws Exception //
TODO: ensure we don't evaluate the requestor
+ {
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace( "invoking lookup in " + getComponentPath() +
" for " + clazz.getName() );
+ }
+ if( null != m_registry )
+ {
+ try
+ {
+ Object value = m_registry.lookup( clazz );
+ return type.cast( value );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Service lookup in component ["
+ + getComponentPath()
+ + "] failed.";
+ throw new ComponentException( error, e );
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ Class getComponentClass()
+ {
+ return m_class;
+ }
+
+ String getComponentName()
+ {
+ return m_name;
+ }
+
+ String getComponentPath()
+ {
+ return m_path;
+ }
+
+ ContextModel getContextModel()
+ {
+ return m_context;
+ }
+
+ PartsDirective getPartsDirective()
+ {
+ return m_parts;
+ }
+
+ State getStateGraph()
+ {
+ return m_graph;
+ }
+
+ Logger getComponentLogger()
+ {
+ return m_logger;
+ }
+
+ Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ CollectionPolicy getCollectionPolicy()
+ {
+ return m_collection;
+ }
+
+ LifestylePolicy getLifestylePolicy()
+ {
+ return m_lifestyle;
+ }
+
+ ActivationPolicy getActivationPolicy()
+ {
+ return m_activation;
+ }
+
+ private Logger getComponentLogger( String path )
+ {
+ return new DefaultLogger( path );
+ }
+
+ public <T>T getInstance( Class<T> clazz )
+ {
+ if( clazz.equals( Component.class ) )
+ {
+ return clazz.cast( this );
+ }
+ synchronized( m_handler )
+ {
+ Provider provider = getProvider();
+ if( clazz.equals( Provider.class ) )
+ {
+ return clazz.cast( provider );
+ }
+ Object instance = provider.getInstance( clazz );
+ return clazz.cast( instance );
+ }
+ }
+
+ public <T>T getContentForClass( Class<T> c ) throws IOException
+ {
+ if( c.isAssignableFrom( m_class ) )
+ {
+ return getInstance( c );
+ }
+ else if( c == Provider.class )
+ {
+ synchronized( m_handler )
+ {
+ Provider provider = m_handler.getProvider();
+ return c.cast( provider );
+ }
+ }
+ else if( ( c == Component.class ) || ( c == Strategy.class ) )
+ {
+ return c.cast( this );
+ }
+ else if( c == Appliance.class )
+ {
+ Logger logger = getComponentLogger();
+ Appliance appliance = new StandardAppliance( logger, this );
+ return c.cast( appliance );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ String name = getComponentName();
+ String classname = getComponentClass().getName();
+ ContextDirective context = getContextModel().getDirective();
+ PartsDirective parts = getPartsDirective();
+
+ boolean flag = buffer.isNamespace( NAMESPACE );
+ if( flag )
+ {
+ buffer.nl( "<component" );
+ }
+ else
+ {
+ buffer.nl( "<component xmlns=\"" + NAMESPACE + "\"" );
+ buffer.nl( " " );
+ }
+ if( null != key )
+ {
+ buffer.write( " key=\"" + key + "\"" );
+ }
+ if( null != name )
+ {
+ buffer.write( " name=\"" + name + "\"" );
+ }
+ if( m_priority != 0 )
+ {
+ buffer.write( " priority=\"" + m_priority + "\"" );
+ }
+ buffer.write( " type=\"" + classname + "\"" );
+ if( ( context.size() == 0 ) && ( parts.size() == 0 ) )
+ {
+ buffer.write( "/>" );
+ }
+ else
+ {
+ buffer.write( ">" );
+ Buffer b = buffer.namespace( NAMESPACE );
+ context.encode( b.indent(), null );
+ parts.encode( b.indent() );
+ buffer.nl( "</component>" );
+ }
+ }
+
+ private PartsDirective getPartsDirective( PartsDirective directive )
+ {
+ if( null == directive )
+ {
+ return new PartsDirective();
+ }
+ else
+ {
+ return directive;
+ }
+ }
+
+ private String getComponentPath( String partition, String name, Class c )
+ {
+ if( null == partition )
+ {
+ return "/" + name;
+ }
+ else
+ {
+ return "/" + partition.replace( ".", "/" ) + "/" + name;
+ }
+ }
+
+ private String getComponentName( String name, Class<?> c )
+ {
+ if( null != name )
+ {
+ return name;
+ }
+ else
+ {
+ return getComponentName( c );
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ // Lifestyle handlers
+ //-----------------------------------------------------------------------
+
+ private LifestyleHandler getLifestyleHandler( LifestylePolicy policy )
+ {
+ if( policy.equals( LifestylePolicy.SINGLETON ) )
+ {
+ return new SingletonLifestyleHandler( this );
+ }
+ else if( policy.equals( LifestylePolicy.THREAD ) )
+ {
+ return new ThreadLifestyleHandler( this );
+ }
+ else
+ {
+ return new TransientLifestyleHandler( this );
+ }
+ }
+
+ /**
+ * Singleton holder class. The singleton holder mains a single
+ * <tt>LifestyleHandler</tt> of a component relative to the component
model
+ * identity within the scope of the controller. References to the
+ * singleton instance will be shared across mutliple threads.
+ */
+ private class SingletonLifestyleHandler extends LifestyleHandler
+ {
+ private Reference<Provider> m_reference;
+
+ SingletonLifestyleHandler( ComponentStrategy strategy )
+ {
+ super( strategy );
+ Provider provider = new StandardProvider( strategy );
+ m_reference = createReference( null );
+ }
+
+ Provider getProvider()
+ {
+ Provider provider = m_reference.get();
+ if( null == provider )
+ {
+ ComponentStrategy strategy = getComponentStrategy();
+ provider = new StandardProvider( strategy );
+ m_reference = createReference( provider );
+ }
+ return provider;
+ }
+
+ void release( Provider provider )
+ {
+ }
+
+ void terminate()
+ {
+ synchronized( this )
+ {
+ Provider provider = m_reference.get();
+ if( null != provider )
+ {
+ if( provider instanceof Disposable )
+ {
+ Disposable disposable = (Disposable) provider;
+ disposable.dispose();
+ }
+ m_reference = createReference( null );
+ }
+ }
+ }
+ }
+
+ /**
+ * Transient holder class. The transient holder provides support for
+ * the transient lifestyle ensuing the creation of a new
<tt>LifestyleHandler</tt>
+ * per request.
+ */
+ private class TransientLifestyleHandler extends LifestyleHandler
+ {
+ private final WeakHashMap<Provider,Void> m_providers = new
WeakHashMap<Provider,Void>(); // transients
+
+ TransientLifestyleHandler( ComponentStrategy strategy )
+ {
+ super( strategy );
+ }
+
+ Provider getProvider()
+ {
+ ComponentStrategy strategy = getComponentStrategy();
+ Provider provider = new StandardProvider( strategy );
+ m_providers.put( provider, null );
+ return provider;
+ }
+
+ void release( Provider provider )
+ {
+ if( null == provider )
+ {
+ return;
+ }
+ if( m_providers.containsKey( provider ) )
+ {
+ m_providers.remove( provider );
+ if( provider instanceof Disposable )
+ {
+ Disposable disposable = (Disposable) provider;
+ disposable.dispose();
+ }
+ }
+ }
+
+ void terminate()
+ {
+ Provider[] providers = m_providers.keySet().toArray( new
Provider[0] );
+ for( Provider provider : providers )
+ {
+ release( provider );
+ }
+ }
+ }
+
+ /**
+ * The ThreadHolder class provides support for the per-thread lifestyle
+ * policy within which new <tt>LifestyleHandler</tt> creation is based on
a single
+ * <tt>LifestyleHandler</tt> per thread.
+ */
+ private class ThreadLifestyleHandler extends LifestyleHandler
+ {
+ private final ThreadLocalHolder m_threadLocalHolder = new
ThreadLocalHolder();
+
+ ThreadLifestyleHandler( ComponentStrategy strategy )
+ {
+ super( strategy );
+ }
+
+ Provider getProvider()
+ {
+ return (Provider) m_threadLocalHolder.get();
+ }
+
+ void release( Provider provider )
+ {
+ m_threadLocalHolder.release( provider );
+ }
+
+ void terminate()
+ {
+ m_threadLocalHolder.terminate();
+ }
+
+ /**
+ * Internal thread local holder for the per-thread lifestyle holder.
+ */
+ private class ThreadLocalHolder extends ThreadLocal
+ {
+ private final WeakHashMap<Provider,Void> m_providers =
+ new WeakHashMap<Provider,Void>(); // per thread instances
+
+ synchronized protected Provider initialValue()
+ {
+ ComponentStrategy strategy = getComponentStrategy();
+ Provider provider = new StandardProvider( strategy );
+ m_providers.put( provider, null );
+ return provider;
+ }
+
+ synchronized void release( Provider provider )
+ {
+ if( m_providers.containsKey( provider ) )
+ {
+ m_providers.remove( provider );
+ if( provider instanceof Disposable )
+ {
+ Disposable disposable = (Disposable) provider;
+ disposable.dispose();
+ }
+ }
+ }
+
+ synchronized void terminate()
+ {
+ Provider[] providers = m_providers.keySet().toArray( new
Provider[0] );
+ for( Provider provider : providers )
+ {
+ release( provider );
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ // utilities
+ //-----------------------------------------------------------------------
+
+ private static String getComponentName( Class<?> c )
+ {
+ if( c.isAnnotationPresent( net.dpml.annotation.Component.class ) )
+ {
+ net.dpml.annotation.Component annotation =
+ c.getAnnotation( net.dpml.annotation.Component.class );
+ String name = annotation.name();
+ if( !"".equals( name ) )
+ {
+ return name;
+ }
+ }
+ return c.getName();
+ }
+
+ private static String getComponentNameFromClass( Class<?> c )
+ {
+ String classname = c.getName();
+ int n = classname.lastIndexOf( "." );
+ if( n > -1 )
+ {
+ return classname.substring( n+1 );
+ }
+ else
+ {
+ return classname;
+ }
+ }
+
+ private static CollectionPolicy getCollectionPolicy( Class<?> c )
+ {
+ if( c.isAnnotationPresent( net.dpml.annotation.Component.class ) )
+ {
+ net.dpml.annotation.Component annotation =
+ c.getAnnotation( net.dpml.annotation.Component.class );
+ return annotation.collection();
+ }
+ return CollectionPolicy.HARD;
+ }
+
+ private static LifestylePolicy getLifestylePolicy( Class<?> c )
+ {
+ if( c.isAnnotationPresent( net.dpml.annotation.Component.class ) )
+ {
+ net.dpml.annotation.Component annotation =
+ c.getAnnotation( net.dpml.annotation.Component.class );
+ return annotation.lifestyle();
+ }
+ return LifestylePolicy.THREAD;
+ }
+
+ private static ActivationPolicy getActivationPolicy( Class<?> c )
+ {
+ if( c.isAnnotationPresent( Activation.class ) )
+ {
+ Activation annotation =
+ c.getAnnotation( Activation.class );
+ return annotation.value();
+ }
+ return ActivationPolicy.SYSTEM;
+ }
+
+ private static State getLifecycleGraph( Class<?> c ) throws IOException
+ {
+ String name = getComponentNameFromClass( c );
+ String spec = name + ".xgraph";
+ URL url = getLifecycleURL( c, spec );
+ if( null != url )
+ {
+ StateDecoder decoder = new StateDecoder();
+ return decoder.loadState( url );
+ }
+ if( c.isAnnotationPresent( net.dpml.annotation.Component.class ) )
+ {
+ net.dpml.annotation.Component annotation =
+ c.getAnnotation( net.dpml.annotation.Component.class );
+ String path = annotation.lifecycle();
+ return getLifecycleGraph( c, path );
+ }
+ else
+ {
+ return NULL_STATE;
+ }
+ }
+
+ private static State getLifecycleGraph( Class<?> c, String path ) throws
IOException
+ {
+ if( ( null == path ) || "".equals( path ) )
+ {
+ return NULL_STATE;
+ }
+ else
+ {
+ URL url = getLifecycleURL( c, path );
+ StateDecoder decoder = new StateDecoder();
+ return decoder.loadState( url );
+ }
+ }
+
+ private static URL getLifecycleURL( Class<?> c, String path ) throws
IOException
+ {
+ int n = path.indexOf( ":" );
+ if( n > -1 )
+ {
+ try
+ {
+ return Artifact.toURL( new URI( path ) );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Bad url: " + path;
+ IOException ioe = new IOException( error );
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+ else
+ {
+ return c.getResource( path );
+ }
+ }
+
+ private static final String NAMESPACE =
ComponentStrategyHandler.NAMESPACE;
+
+ public String toString()
+ {
+ return getComponentPath();
+ }
+
+ private static class ComponentEventDistatcher implements Runnable
+ {
+ private Logger m_logger;
+ private ComponentListener m_listener;
+ private ComponentEvent m_event;
+
+ ComponentEventDistatcher( Logger logger, ComponentListener listener,
ComponentEvent event )
+ {
+ m_logger = logger;
+ m_listener = listener;
+ m_event = event;
+ }
+
+ public void run()
+ {
+ try
+ {
+ m_listener.componentChanged( m_event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Event distatch error.";
+ m_logger.error( error, e );
+ }
+ }
+ }
+}

Added:
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategyHandler.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategyHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/runtime/ComponentStrategyHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2004-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.runtime;
+
+import dpml.lang.Classpath;
+import dpml.lang.DOM3DocumentBuilder;
+import dpml.lang.Value;
+import dpml.util.StandardClassLoader;
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URL;
+import java.util.Map;
+import java.lang.reflect.Constructor;
+
+import net.dpml.lang.DecodingException;
+import net.dpml.lang.Strategy;
+import net.dpml.lang.StrategyHandler;
+import net.dpml.lang.Buffer;
+
+import net.dpml.util.Resolver;
+import net.dpml.util.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ComponentStrategyHandler implements StrategyHandler
+{
+ public static final String NAMESPACE = "dpml:metro";
+
+ private static final DOM3DocumentBuilder BUILDER = new
DOM3DocumentBuilder();
+
+ public Strategy newStrategy( Class<?> c ) throws IOException
+ {
+ return newStrategy( c, null );
+ }
+
+ public Strategy newStrategy( Class<?> c, String name ) throws IOException
+ {
+ String spec = getComponentName( c, name );
+ Profile profile = new Profile( c, spec, null );
+ ContextModel context = getContextModel( null, c, spec, profile,
null, null, null );
+ PartsDirective parts = profile.getPartsDirective();
+ return new ComponentStrategy( null, spec, 0, c, context, parts );
+ }
+
+ public Component newComponent( Class<?> c, String name ) throws
IOException
+ {
+ return (Component) newStrategy( c, name );
+ }
+
+ /**
+ * Construct a strategy definition using a supplied element and value
resolver.
+ * @param classloader the operational classloader
+ * @param element the DOM element definining the deployment strategy
+ * @param resolver symbolic property resolver
+ * @param partition the enclosing partition
+ * @return the strategy definition
+ * @exception IOException if an I/O error occurs
+ */
+ public Strategy build(
+ ClassLoader classloader, Element element, Resolver resolver, String
partition, String query ) throws IOException
+ {
+ Class c = loadComponentClass( classloader, element, resolver );
+ String name = getComponentName( c, element, resolver );
+ int priority = getPriority( element, resolver );
+ String path = getComponentPath( partition, name );
+ Profile profile = new Profile( c, path, resolver );
+
+ Query q = new Query( query );
+ Element contextElement = ElementHelper.getChild( element, "context"
);
+ ContextModel context = getContextModel( classloader, c, path,
profile, contextElement, resolver, q );
+
+ //ContextDirective context =
+ // new ContextDirective(
+ // profile.getContextDirective(),
+ // classloader,
+ // contextElement,
+ // resolver,
+ // query );
+
+ try
+ {
+ Element partsElement = ElementHelper.getChild( element, "parts"
);
+ PartsDirective parts =
+ new PartsDirective(
+ profile.getPartsDirective(),
+ classloader,
+ partsElement,
+ resolver,
+ path );
+
+ ComponentStrategy strategy = new ComponentStrategy( partition,
name, priority, c, context, parts );
+ return strategy;
+ }
+ catch( IOException ioe )
+ {
+ throw ioe;
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Unable to construct component strategy for the class ["
+ + c.getName()
+ + "] under the partition ["
+ + partition
+ + "]";
+ IOException ioe = new IOException( error );
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+
+ private int getPriority( Element element, Resolver resolver )
+ {
+ String value = ElementHelper.getAttribute( element, "priority",
null, resolver );
+ if( null == value )
+ {
+ return 0;
+ }
+ else
+ {
+ return Integer.parseInt( value );
+ }
+ }
+
+ private Class loadComponentClass( ClassLoader classloader, Element
element, Resolver resolver ) throws DecodingException
+ {
+ String classname = buildComponentClassname( element, resolver );
+ try
+ {
+ return classloader.loadClass( classname );
+ }
+ catch( ClassNotFoundException e )
+ {
+ final String error =
+ "Class not found [" + classname + "].";
+ Logger logger = new DefaultLogger( "dpml.lang" );
+ String stack = StandardClassLoader.toString( classloader, null );
+ logger.error( error + stack );
+ throw new DecodingException( error, e, element );
+ }
+ }
+
+ private String buildComponentClassname( Element element, Resolver
resolver )
+ {
+ String classname = ElementHelper.getAttribute( element, "class",
null, resolver );
+ if( null != classname )
+ {
+ return classname;
+ }
+ else
+ {
+ return ElementHelper.getAttribute( element, "type", null,
resolver );
+ }
+ }
+
+ private static String getComponentName( Class c, Element element,
Resolver resolver )
+ {
+ String name = getComponentName( element, resolver );
+ return getComponentName( c, name );
+ }
+
+ private static String getComponentName( Element element, Resolver
resolver )
+ {
+ if( null == element )
+ {
+ return null;
+ }
+ else
+ {
+ String key = ElementHelper.getAttribute( element, "key", null,
resolver );
+ if( null != key )
+ {
+ return key;
+ }
+ else
+ {
+ return ElementHelper.getAttribute( element, "name", null,
resolver );
+ }
+ }
+ }
+
+ private static String getComponentName( Class<?> c )
+ {
+ if( c.isAnnotationPresent( net.dpml.annotation.Component.class ) )
+ {
+ net.dpml.annotation.Component annotation =
+ c.getAnnotation( net.dpml.annotation.Component.class );
+ String name = annotation.name();
+ if( !"".equals( name ) )
+ {
+ return name;
+ }
+ }
+ return c.getName();
+ }
+
+ private static String getComponentNameFromClass( Class<?> c )
+ {
+ String classname = c.getName();
+ int n = classname.lastIndexOf( "." );
+ if( n > -1 )
+ {
+ return classname.substring( n+1 );
+ }
+ else
+ {
+ return classname;
+ }
+ }
+
+ private static String getComponentPath( String partition, String name )
+ {
+ if( null == partition )
+ {
+ return name;
+ }
+ else
+ {
+ return partition + "." + name;
+ }
+ }
+
+ private static String getComponentName( Class c, String name )
+ {
+ if( null != name )
+ {
+ return name;
+ }
+ else
+ {
+ return getComponentName( c );
+ }
+ }
+
+ static Constructor getSingleConstructor( Class c )
+ {
+ Constructor[] constructors = c.getConstructors();
+ if( constructors.length < 1 )
+ {
+ final String error =
+ "The component class ["
+ + c.getName()
+ + "] does not declare a public constructor.";
+ throw new ComponentError( error );
+ }
+ else if( constructors.length > 1 )
+ {
+ final String error =
+ "The component class ["
+ + c.getName()
+ + "] declares more than one public constructor.";
+ throw new ComponentError( error );
+ }
+ else
+ {
+ return constructors[0];
+ }
+ }
+
+ private static Class getContextClass( Constructor constructor, boolean
policy )
+ {
+ final Class<?>[] types = constructor.getParameterTypes();
+ for( Class c : types )
+ {
+ if( ContextInvocationHandler.isaContext( c, policy ) )
+ {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ private static ContextModel getContextModel(
+ ClassLoader classloader, Class clazz, String path,
+ Profile profile, Element element, Resolver resolver, Query query )
throws IOException
+ {
+ boolean policy = getContextHandlingPolicy( clazz );
+ Constructor constructor = getSingleConstructor( clazz );
+ Class subject = getContextClass( constructor, policy );
+ ContextDirective bundled = profile.getContextDirective();
+ ContextDirective declared = new ContextDirective( classloader,
element, resolver );
+ return new ContextModel( clazz, path, subject, policy, bundled,
declared, query );
+ }
+
+ private static boolean getContextHandlingPolicy( Class c )
+ {
+ // TODO: update to get policy as a class annotation
+ return false; // return classic evaluation policy
+ }
+
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ContextDirective.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ContextDirective.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ContextDirective.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,279 @@
+/*
+ * 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 net.dpml.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+import java.util.Hashtable;
+
+import dpml.lang.Construct;
+import dpml.lang.ValueDecoder;
+
+import dpml.lang.Value;
+import net.dpml.lang.DecodingException;
+import net.dpml.lang.Buffer;
+
+import net.dpml.runtime.Directive.Resolvable;
+import net.dpml.runtime.Directive.Encodable;
+
+import dpml.util.ElementHelper;
+import net.dpml.util.Resolver;
+
+import org.w3c.dom.Element;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class ContextDirective extends Directive implements Encodable
+{
+ private static final ValueDecoder VALUE_DECODER = new ValueDecoder();
+
+ private final Element m_element;
+
+ private final Map<String,Encodable> m_entries = new
Hashtable<String,Encodable>();
+
+ /**
+ * Creation of a new top-level context argument.
+ */
+ ContextDirective()
+ {
+ m_element = null;
+ }
+
+ /**
+ * Creation of a new context argument resolved from a packaged context
definition.
+ */
+ ContextDirective( ClassLoader classloader, Element element, Resolver
resolver ) throws DecodingException
+ {
+ m_element = element;
+
+ if( null != element )
+ {
+ Element[] elements = ElementHelper.getChildren( element );
+ for( Element child : elements )
+ {
+ String key = ElementHelper.getAttribute( child, "key" );
+ if( null == key )
+ {
+ final String error =
+ "Context entry does not declare a key.";
+ throw new DecodingException( error, null, child );
+ }
+
+ if( "context".equals( child.getLocalName() ) )
+ {
+ ContextDirective directive = new ContextDirective(
classloader, child, resolver );
+ m_entries.put( key, directive );
+ }
+ else if( "entry".equals( child.getLocalName() ) )
+ {
+ String service = ElementHelper.getAttribute( child,
"lookup" );
+ if( null == service )
+ {
+ Value value = VALUE_DECODER.decodeValue( child,
resolver );
+ ValueWrapper wrapper = new ValueWrapper( child,
value );
+ m_entries.put( key, wrapper );
+ }
+ else
+ {
+ Lookup loookup = new Lookup( classloader, child,
service );
+ m_entries.put( key, loookup );
+ }
+ }
+ else
+ {
+ final String error =
+ "Context entry element not recognized.";
+ throw new ComponentException( error, null, child );
+ }
+ }
+ }
+
+ /*
+ // override context with query arguments if present
+ if( null != query )
+ {
+ Map<String,String> map = new Hashtable<String,String>();
+ String[] segments = query.split( "," );
+ for( String segment : segments )
+ {
+ String[] args = segment.split( "=" );
+ if( args.length != 2 )
+ {
+ throw new IllegalArgumentException( "Invalid query [" +
segment + "]" );
+ }
+ String key = args[0];
+ String param = args[1];
+ Value value = new Construct( param );
+ m_entries.put( key, new ValueWrapper( null, value ) );
+ }
+ }
+ */
+ }
+
+ int size()
+ {
+ return m_entries.size();
+ }
+
+ //String[] getKeys()
+ //{
+ // return m_entries.keySet().toArray( new String[0] );
+ //}
+
+ public Element getElement()
+ {
+ return m_element;
+ }
+
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ if( null != m_element )
+ {
+ buffer.nl( "<context" );
+ if( null != key )
+ {
+ buffer.write( " key=\"" + key + "\"" );
+ }
+ buffer.write( ">" );
+ Buffer b2 = buffer.indent();
+ for( String k : m_entries.keySet().toArray( new String[0] ) )
+ {
+ Encodable entry = m_entries.get( k );
+ entry.encode( b2, k );
+ }
+ buffer.nl( "</context>" );
+ }
+ }
+
+ Resolvable getEntry( String key )
+ {
+ Encodable entry = m_entries.get( key );
+ if( null != entry )
+ {
+ if( entry instanceof Resolvable )
+ {
+ return (Resolvable) entry;
+ }
+ }
+ return null;
+ }
+
+ ContextDirective getContextDirective( String key )
+ {
+ Encodable entry = m_entries.get( key );
+ if( null != entry )
+ {
+ if( entry instanceof ContextDirective )
+ {
+ return (ContextDirective) entry;
+ }
+ }
+ return null;
+ }
+
+ private static abstract class AbstractResolvable implements Resolvable,
Encodable
+ {
+ private final Element m_element;
+
+ AbstractResolvable( Element element )
+ {
+ m_element = element;
+ }
+
+ public Element getElement()
+ {
+ return m_element;
+ }
+ }
+
+ static class ValueWrapper extends AbstractResolvable
+ {
+ private final Value m_value;
+
+ ValueWrapper( Value value )
+ {
+ this( null, value );
+ }
+
+ ValueWrapper( Element element, Value value )
+ {
+ super( element );
+ m_value = value;
+ }
+
+ public <T>T resolve( ComponentStrategy parent, Class<T> type )
throws Exception
+ {
+ Object value = m_value.resolve( type, parent.getContextMap() );
+ return type.cast( value );
+ }
+
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ m_value.encode( buffer, "entry", key );
+ }
+ }
+
+ static class Lookup extends AbstractResolvable
+ {
+ private final Class m_class;
+
+ Lookup( ClassLoader classloader, Element element, String classname )
throws ComponentException
+ {
+ super( element );
+ try
+ {
+ m_class = classloader.loadClass( classname );
+ }
+ catch( ClassNotFoundException cnfe )
+ {
+ final String error =
+ "Class not found: ["
+ + classname
+ + "].";
+ throw new ComponentException( error, cnfe, element );
+ }
+ }
+
+ public <T>T resolve( ComponentStrategy strategy, Class<T> type )
throws Exception
+ {
+ T value = strategy.getService( m_class, type );
+ if( null != value )
+ {
+ return value;
+ }
+ else
+ {
+ Element element = getElement();
+ final String error =
+ "Service not found ["
+ + m_class.getName()
+ + "].";
+ throw new ComponentException( error, null, element );
+ }
+ }
+
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ buffer.nl( "<entry key=\"" + key + "\" lookup=\"" +
m_class.getName() + "\"/>" );
+ }
+ }
+}
\ No newline at end of file

Added:
trunk/main/lang/part/src/main/net/dpml/runtime/ContextInvocationHandler.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/runtime/ContextInvocationHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/runtime/ContextInvocationHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2004-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.runtime;
+
+import java.util.Map;
+import java.beans.Introspector;
+import java.beans.Expression;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import net.dpml.annotation.Context;
+import net.dpml.runtime.Directive.Resolvable;
+import dpml.lang.Value;
+
+import org.w3c.dom.Element;
+
+/**
+ * Invocation handler utility for a Context class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class ContextInvocationHandler implements InvocationHandler
+{
+ //-------------------------------------------------------------------
+ // static
+ //-------------------------------------------------------------------
+
+ private static final String GET = "get";
+
+ /**
+ * Test if the supplied class is recognized as a context class. If
+ * the supplied policy is true then evaluation is based on the presence
+ * of the <tt>net.dpml.lang.Context</tt> annotation and resulting
+ * value of annotation evaluation. If no context annnotation is present
+ * and strict processing is disabled then evaluation will return true if
+ * the classname ends with the string <tt>$Context</tt>.
+ *
+ * @param c the candidate class
+ * @param policy the strict evaluation policy
+ * @return true if this class is recognized as a context class
+ */
+ public static boolean isaContext( final Class<?> c, final boolean policy
)
+ {
+ boolean flag = c.isAnnotationPresent( Context.class );
+ if( flag )
+ {
+ return c.getAnnotation( Context.class ).value();
+ }
+ else if( policy )
+ {
+ return false;
+ }
+ else
+ {
+ return c.getName().endsWith( "$Context" );
+ }
+ }
+
+ /**
+ * Validate that the supplied map properly fulfills the required
+ * context entry. Specifically, for all non-optional methods declared
+ * by the context class, the validation process checks the the supplied
+ * map has a corresponding key and associated non-null value.
+ *
+ * @param clazz the context class
+ * @param map a map of context entry values
+ * @exception IllegalArgumentException if validation fails
+ */
+ public static void validate( Class clazz, Map<String,Object> map )
+ throws IllegalArgumentException
+ {
+ for( Method method : clazz.getMethods() )
+ {
+ String key = getKeyForMethod( method );
+ boolean optional = isOptionalEntry( method );
+ if( !optional )
+ {
+ if( !map.containsKey( key ) )
+ {
+ final String error =
+ "Missing required key ["
+ + key
+ + "]";
+ throw new IllegalArgumentException( error );
+ }
+ else if( null == map.get( key ) )
+ {
+ final String error =
+ "Missing value for the required key ["
+ + key
+ + "]";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ }
+ }
+
+ /**
+ * Construct a new context instance implementing the supplied class
+ * backed by entries in the supplied map.
+ *
+ * @param clazz the context class
+ * @param map a map of context entry keys and values
+ * @return the constructed context instance
+ */
+ public static <T>T getProxiedInstance(
+ final Class<T> clazz, final ComponentStrategy strategy, final
ContextModel model )
+ {
+ ClassLoader classloader = clazz.getClassLoader();
+ ContextInvocationHandler handler =
+ new ContextInvocationHandler( strategy, model );
+ final Object instance =
+ Proxy.newProxyInstance( classloader, new Class[]{clazz}, handler );
+ return clazz.cast( instance );
+ }
+
+ //-------------------------------------------------------------------
+ // state
+ //-------------------------------------------------------------------
+
+ /**
+ * Context datatype.
+ */
+ private final ContextModel m_model;
+
+ /**
+ * Component strategy handler.
+ */
+ private final ComponentStrategy m_strategy;
+
+ //-------------------------------------------------------------------
+ // constructor
+ //-------------------------------------------------------------------
+
+ /**
+ * Create a context invocation handler.
+ *
+ * @param map a map containing context key/value pairs.
+ */
+ private ContextInvocationHandler( final ComponentStrategy strategy,
final ContextModel model )
+ {
+ m_model = model;
+ m_strategy = strategy;
+ }
+
+ //-------------------------------------------------------------------
+ // implementation
+ //-------------------------------------------------------------------
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by the proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ public Object invoke( final Object proxy, final Method method, final
Object[] args ) throws Throwable
+ {
+ Class source = method.getDeclaringClass();
+ if( Object.class == source )
+ {
+ return method.invoke( this, args );
+ }
+ else
+ {
+ String name = method.getName();
+ if( name.startsWith( "get" ) )
+ {
+ Class<?> clazz = method.getReturnType();
+ String key = Introspector.decapitalize( name.substring( 3 )
);
+ Resolvable entry = m_model.getResolvable( key );
+ if( null != entry )
+ {
+ Class nc = normalize( clazz );
+ Object v = resolve( entry, key, nc );
+ if( nc.isAssignableFrom( v.getClass() ) )
+ {
+ return v;
+ }
+ else
+ {
+ final String error =
+ "Cannot cast ["
+ + v.getClass().getName()
+ + "] to the return type ["
+ + clazz.getName()
+ + "] on the context entry ["
+ + key
+ + "]";
+ Element element = entry.getElement();
+ throw new ComponentException( error, null, element );
+ }
+ }
+ if( ( null != args ) && ( args.length > 0 ) )
+ {
+ return args[0];
+ }
+ else
+ {
+ // should not happen
+
+ final String error =
+ "Unresolvable context entry ["
+ + key
+ + "] in the component model ["
+ + m_strategy.getComponentPath()
+ + "].";
+ throw new ComponentError( error );
+ }
+ }
+ else
+ {
+ throw new UnsupportedOperationException( name );
+ }
+ }
+ }
+
+ private Object resolve( Resolvable entry, String key, Class<?> c )
throws ComponentException
+ {
+ try
+ {
+ return entry.resolve( m_strategy, c );
+ }
+ catch( ClassCastException e )
+ {
+ final String error =
+ "Failed to resolve the value for the context entry ["
+ + key
+ + "] in the component ["
+ + m_strategy.getComponentPath()
+ + "] for the return type ["
+ + c.getName()
+ + "]";
+ throw new ComponentException( error, e, entry.getElement() );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Failed to resolve the value for the context entry ["
+ + key
+ + "] in the component ["
+ + m_strategy.getComponentPath()
+ + "]";
+ throw new ComponentException( error, e, entry.getElement() );
+ }
+ }
+
+ private static boolean isAssignableFrom( Class<?> clazz, Class<?> c )
+ {
+ Class<?> normalized = normalize( clazz );
+ return normalized.isAssignableFrom( c );
+ }
+
+ private static Class<?> normalize( Class<?> clazz )
+ {
+ if( clazz.isPrimitive() )
+ {
+ if( Integer.TYPE == clazz )
+ {
+ return Integer.class;
+ }
+ else if( Boolean.TYPE == clazz )
+ {
+ return Boolean.class;
+ }
+ else if( Byte.TYPE == clazz )
+ {
+ return Byte.class;
+ }
+ else if( Short.TYPE == clazz )
+ {
+ return Short.class;
+ }
+ else if( Long.TYPE == clazz )
+ {
+ return Long.class;
+ }
+ else if( Float.TYPE == clazz )
+ {
+ return Float.class;
+ }
+ else if( Character.TYPE == clazz )
+ {
+ return Character.class;
+ }
+ else if( Double.TYPE == clazz )
+ {
+ return Double.class;
+ }
+ else
+ {
+ final String error =
+ "Primitive type ["
+ + clazz.getName()
+ + "] not supported.";
+ throw new RuntimeException( error );
+ }
+ }
+ else
+ {
+ return clazz;
+ }
+ }
+
+ private static boolean isOptionalEntry( Method method )
+ {
+ return method.getParameterTypes().length == 1;
+ }
+
+ static String getKeyForMethod( Method method )
+ {
+ String name = method.getName();
+ if( name.startsWith( GET ) )
+ {
+ String remainder = name.substring( GET.length() );
+ return Introspector.decapitalize( remainder );
+ }
+ else
+ {
+ final String error =
+ "Method name is not a recognized pattern: "
+ + name;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private static final String STRICT_PROCESSING_KEY =
"dpml.lang.context.policy";
+ private static final String STRICT_PROCESSING_KEYWORD = "strict";
+ private static final boolean STRICT_PROCESSING =
getStrictProcessingPolicy();
+
+ private static boolean getStrictProcessingPolicy()
+ {
+ return STRICT_PROCESSING_KEYWORD.equalsIgnoreCase(
+ System.getProperty(
+ STRICT_PROCESSING_KEY,
+ STRICT_PROCESSING_KEYWORD ) );
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ContextModel.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ContextModel.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ContextModel.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,191 @@
+/*
+ * 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.runtime;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Hashtable;
+import java.lang.reflect.Method;
+
+import net.dpml.lang.Buffer;
+
+import net.dpml.runtime.Directive.Resolvable;
+
+import org.w3c.dom.Element;
+
+/**
+ * Context model interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class ContextModel implements Resolvable
+{
+ private ContextDirective m_directive;
+
+ private final Map<String,Resolvable> m_map = new
Hashtable<String,Resolvable>();
+
+ ContextModel(
+ Class clazz, String path, Class subject, boolean policy,
+ ContextDirective bundled, ContextDirective directive, Query query )
throws IOException
+ {
+ this( clazz, path, subject, policy, null, bundled, directive, query
);
+ }
+
+ private ContextModel(
+ Class clazz, String path, Class subject, boolean policy, String
keyPath,
+ ContextDirective bundled, ContextDirective directive, Query query )
throws IOException
+ {
+ m_directive = directive;
+
+ if( null != subject )
+ {
+ for( Method method : subject.getMethods() )
+ {
+ Class c = method.getReturnType();
+ String key = ContextInvocationHandler.getKeyForMethod(
method );
+ boolean optional = isOptionalEntry( method );
+ boolean composite = ContextInvocationHandler.isaContext( c,
policy );
+
+ Resolvable value = null;
+ if( composite )
+ {
+ ContextDirective parent = getContextDirective( bundled,
key );
+ ContextDirective nested = getContextDirective(
directive, key );
+ value = new ContextModel( clazz, path, c, policy, key,
parent, nested, query );
+ }
+ else
+ {
+ if( null != query )
+ {
+ String scopedKey = getScopedKey( keyPath, key );
+ value = query.getEntry( scopedKey );
+ }
+ if( ( null == value ) && null != directive )
+ {
+ value = directive.getEntry( key );
+ }
+ if( ( null == value ) && null != bundled )
+ {
+ value = bundled.getEntry( key );
+ }
+ }
+ if( null != value )
+ {
+ m_map.put( key, value );
+ }
+ else if( !optional )
+ {
+ final String error =
+ "No solution declared for the context entry ["
+ + key
+ + "] within the context definition ["
+ + subject.getName()
+ + "] as a constructor argument to the component class
["
+ + clazz.getName()
+ + "] within the component model ["
+ + path
+ + "].";
+ throw new ComponentException( error );
+ }
+ }
+ }
+ }
+
+ private String getScopedKey( String base, String key )
+ {
+ if( null == base )
+ {
+ return key;
+ }
+ else
+ {
+ return base + "." + key;
+ }
+ }
+
+ public Element getElement()
+ {
+ if( null != m_directive )
+ {
+ return m_directive.getElement();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void encode( Buffer buffer, String key ) throws IOException
+ {
+ if( null != m_directive )
+ {
+ m_directive.encode( buffer, key );
+ }
+ }
+
+ private boolean isOptionalEntry( Method method )
+ {
+ return ( method.getParameterTypes().length > 0 );
+ }
+
+ public <T>T resolve( ComponentStrategy strategy, Class<T> type ) throws
Exception
+ {
+ return ContextInvocationHandler.getProxiedInstance( type, strategy,
this );
+ }
+
+ Resolvable getResolvable( String key )
+ {
+ return m_map.get( key );
+ }
+
+ ContextDirective getDirective()
+ {
+ return m_directive;
+ }
+
+ private ContextDirective getContextDirective( ContextDirective
directive, String key )
+ {
+ if( null == directive )
+ {
+ return null;
+ }
+ else
+ {
+ return directive.getContextDirective( key );
+ }
+ }
+
+ /*
+ private static class Entry
+ {
+ private final String m_key;
+ private final boolean m_optional;
+ private final boolean m_composite;
+
+ Entry( String key, boolean optional, boolean composite )
+ {
+ m_key = key;
+ m_optional = optional;
+ m_composite = composite;
+ }
+ }
+ */
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/DefaultStateMachine.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/DefaultStateMachine.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/DefaultStateMachine.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,1037 @@
+/*
+ * 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 net.dpml.runtime;
+
+import java.beans.Expression;
+import java.beans.Statement;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.WeakHashMap;
+import java.util.EventObject;
+import java.util.EventListener;
+
+import net.dpml.state.State;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+import net.dpml.state.Interface;
+import net.dpml.state.Trigger;
+import net.dpml.state.TriggerPolicy;
+import net.dpml.state.Action;
+import net.dpml.state.StateMachine;
+import net.dpml.state.UnknownOperationException;
+import net.dpml.state.UnknownTransitionException;
+import net.dpml.state.IntegrityRuntimeException;
+import net.dpml.state.StateListener;
+import net.dpml.state.StateEvent;
+import net.dpml.state.ExecAction;
+import net.dpml.state.ApplyAction;
+
+import net.dpml.util.Logger;
+
+/**
+ * Default state-machine implementation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class DefaultStateMachine implements StateMachine, EventQueue.EventHandler
+{
+ /**
+ * Constant name used to reference a state change in a property event.
+ */
+ public static final String PROPERTY_NAME = "state";
+
+ /**
+ * Validate the state integrity.
+ * @param state the state to validate
+ */
+ public static void validate( State state )
+ {
+ validateState( state );
+ }
+
+
//-------------------------------------------------------------------------------
+ // state
+
//-------------------------------------------------------------------------------
+
+ private State m_state;
+ private boolean m_active = false;
+ private boolean m_disposed = false;
+
+ private final Object m_lock = new Object();
+
+ private final EventQueue m_queue;
+
+ private final WeakHashMap<StateListener,Void> m_listeners = new
WeakHashMap<StateListener,Void>();
+
+ private final Logger m_logger;
+
+
//-------------------------------------------------------------------------------
+ // constructor
+
//-------------------------------------------------------------------------------
+
+ /**
+ * Creation of a new state machine using a state graph.
+ * @param queue the event queue
+ * @param logger the logging channel
+ * @param state the state graph
+ */
+ public DefaultStateMachine( EventQueue queue, Logger logger, State state
)
+ {
+ m_queue = queue;
+ m_logger = logger;
+ m_state = state;
+ }
+
+
//-------------------------------------------------------------------------------
+ // StateMachine
+
//-------------------------------------------------------------------------------
+
+ /**
+ * Add a state change listener to the state machine.
+ * @param listener the state listener
+ */
+ public void addStateListener( final StateListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+ checkDisposed();
+ synchronized( m_lock )
+ {
+ m_listeners.put( listener, null );
+ }
+ }
+
+ /**
+ * Remove a state listener from the state machine.
+ * @param listener the state listener
+ */
+ public void removeStateListener( final StateListener listener )
+ {
+ if( null == listener )
+ {
+ throw new NullPointerException( "listener" );
+ }
+ checkDisposed();
+ synchronized( m_lock )
+ {
+ m_listeners.remove( listener );
+ }
+ }
+
+ /**
+ * Return the assigned state event listeners.
+ * @return the event listeners
+ */
+ public EventListener[] getEventListeners()
+ {
+ return getStateListeners();
+ }
+
+ private StateListener[] getStateListeners()
+ {
+ synchronized( m_lock )
+ {
+ return (StateListener[]) m_listeners.keySet().toArray( new
StateListener[0] );
+ }
+ }
+
+ /**
+ * Process the supplied event.
+ * @param event the event to process
+ */
+ public void processEvent( EventObject event )
+ {
+ StateListener[] listeners = getStateListeners();
+ for( int i=0; i < listeners.length; i++ )
+ {
+ StateListener listener = listeners[i];
+ if( event instanceof StateEvent )
+ {
+ try
+ {
+ StateEvent e = (StateEvent) event;
+ listener.stateChanged( e );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "StateListener notification error.";
+ getLogger().error( error, e );
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the current state.
+ * @return the current state
+ */
+ public State getState()
+ {
+ checkDisposed();
+ synchronized( m_state )
+ {
+ return m_state;
+ }
+ }
+
+ /**
+ * Locate and return the most immediate initialization action defined
relative to
+ * the current state. If an action is located within the current state
it will be
+ * return otherwise the search will continue up the state graph until
either an
+ * action is located or no further parent state is available in which
case a null
+ * value is returned.
+ *
+ * @return the initialization action or null if no action declared
+ */
+ public Action getInitializationAction()
+ {
+ checkDisposed();
+ try
+ {
+ return getAction( m_state, TriggerPolicy.INITIALIZATION );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error during resolution of initialization
actions.";
+ throw new IntegrityRuntimeException( error, e );
+ }
+ }
+
+ /**
+ * Locate and return the most immediate termination action defined
relative to
+ * the current state. If an action is located within the current state
it will be
+ * return otherwise the search will continue up the state graph until
either an
+ * action is located or no further parent state is available in which
case a null
+ * value is returned.
+ *
+ * @return the termination action or null if no action declared
+ */
+ public Action getTerminationAction()
+ {
+ checkDisposed();
+ try
+ {
+ return getAction( m_state, TriggerPolicy.TERMINATION );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error during resolution of termination actions.";
+ throw new IntegrityRuntimeException( error, e );
+ }
+ }
+
+ /**
+ * Invoke initialization of the supplied object using the initialization
action
+ * declared under the current state path.
+ *
+ * @param object the object to initialize
+ * @return the state established as a sidee effect of the initialization
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of initialization
+ */
+ public State initialize( Object object ) throws InvocationTargetException
+ {
+ checkDisposed();
+ ArrayList<Action> visited = new ArrayList<Action>();
+ try
+ {
+ State result = initialize( visited, object );
+ m_active = true;
+ return result;
+ }
+ catch( UnknownTransitionException e )
+ {
+ final String error =
+ "Internal state machine error raised due to an unresolved
transition.";
+ throw new IntegrityRuntimeException( error, e );
+ }
+ catch( UnknownOperationException e )
+ {
+ final String error =
+ "Internal state machine error raised due to an unresolved
operation.";
+ throw new IntegrityRuntimeException( error, e );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e;
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error during state-machine initialization.";
+ throw new IntegrityRuntimeException( error, e );
+ }
+ }
+
+ /**
+ * Execute a named operation on the supplied object.
+ * @param name an operation name
+ * @param object the target object
+ * @param args operation arguments
+ * @return the result of operation invocation
+ * @exception UnknownOperationException if the operation is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of operation execution
+ */
+ public Object execute( String name, Object object, Object[] args )
+ throws UnknownOperationException, InvocationTargetException
+ {
+ checkDisposed();
+ Operation operation = getOperation( getState(), name );
+ return execute( operation, object, args );
+ }
+
+ /**
+ * Invoke a management method on the supplied object.
+ * @param object the target object
+ * @param method the method name
+ * @param args method parameter arguments
+ * @return the return value
+ * @exception IllegalStateException if the method is recognized but not
available
+ * @exception UnknownOperationException if the operation is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of operation execution
+ */
+ public Object invoke( Object object, String method, Object[] args )
+ throws UnknownOperationException, InvocationTargetException,
IllegalStateException
+ {
+ checkDisposed();
+
+ // TODO: validate exposure of declaring interface
+
+ try
+ {
+ Expression expression = new Expression( object, method, args );
+ return expression.getValue();
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ throw new InvocationTargetException( e );
+ }
+ }
+
+ /**
+ * Apply a named transition to the target object.
+ * @param name the transition name
+ * @param object the object against which any transition handler action
are to be applied
+ * @return the state established by the application of the transition
+ * @exception UnknownTransitionException if the transition is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of transition invocation
+ */
+ public State apply( String name, Object object )
+ throws UnknownTransitionException, InvocationTargetException
+ {
+ checkDisposed();
+ synchronized( m_state )
+ {
+ Transition transition = getTransition( m_state, name );
+ return apply( transition, object );
+ }
+ }
+
+ /**
+ * Return all of the available transitions relative to the current state.
+ * @return the available transitions
+ */
+ public Transition[] getTransitions()
+ {
+ checkDisposed();
+ Hashtable<String,Transition> table = new
Hashtable<String,Transition>();
+ State[] states = m_state.getStatePath();
+ for( int i=( states.length-1 ); i>-1; i-- )
+ {
+ State state = states[i];
+ Transition[] transitions = state.getTransitions();
+ for( int j=0; j<transitions.length; j++ )
+ {
+ Transition transition = transitions[j];
+ String name = transition.getName();
+ if( null == table.get( name ) )
+ {
+ table.put( name, transition );
+ }
+ }
+ }
+ return (Transition[]) table.values().toArray( new Transition[0] );
+ }
+
+ /**
+ * Return all of the available operations relative to the current state.
+ * @return the available operations
+ */
+ public Operation[] getOperations()
+ {
+ checkDisposed();
+ Hashtable<String,Operation> table = new
Hashtable<String,Operation>();
+ State[] states = m_state.getStatePath();
+ for( int i=( states.length-1 ); i>-1; i-- )
+ {
+ State state = states[i];
+ Operation[] operations = state.getOperations();
+ for( int j=0; j<operations.length; j++ )
+ {
+ Operation operation = operations[j];
+ String name = operation.getName();
+ if( null == table.get( name ) )
+ {
+ table.put( name, operation );
+ }
+ }
+ }
+ return table.values().toArray( new Operation[0] );
+ }
+
+ /**
+ * Return all of the available interfaces relative to the current state.
+ * @return the available interface declarations
+ */
+ public Interface[] getInterfaces()
+ {
+ checkDisposed();
+ Hashtable<String,Interface> table = new
Hashtable<String,Interface>();
+ State[] states = m_state.getStatePath();
+ for( int i=( states.length-1 ); i>-1; i-- )
+ {
+ State state = states[i];
+ Interface[] interfaces = state.getInterfaces();
+ for( int j=0; j<interfaces.length; j++ )
+ {
+ Interface data = interfaces[j];
+ String name = data.getName();
+ if( null == table.get( name ) )
+ {
+ table.put( name, data );
+ }
+ }
+ }
+ return table.values().toArray( new Interface[0] );
+ }
+
+ /**
+ * Invoke termination of the supplied object using the termination action
+ * declared under the current state path.
+ *
+ * @param object the object to terminate
+ * @return the state established as a side-effect of the termination
+ */
+ public State terminate( Object object )
+ {
+ checkDisposed();
+ ArrayList visited = new ArrayList();
+ try
+ {
+ State result = terminate( visited, object );
+ m_active = false;
+ return result;
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ return getState();
+ }
+ }
+
+ /**
+ * Returns the active status of the state machine.
+ * @return TRUE if the state machine has invoked initialization and
+ * termination has not been performed otherwise FALSE
+ */
+ public boolean isActive()
+ {
+ return m_active;
+ }
+
+ /**
+ * Dispose of the state machine.
+ */
+ public void dispose()
+ {
+ synchronized( m_lock )
+ {
+ StateListener[] listeners = getStateListeners();
+ for( int i=0; i<listeners.length; i++ )
+ {
+ StateListener listener = listeners[i];
+ removeStateListener( listener );
+ }
+ }
+ m_disposed = true;
+ m_state = null;
+ }
+
+
//-------------------------------------------------------------------------------
+ // implementation
+
//-------------------------------------------------------------------------------
+
+ //private String getTag( final Object object )
+ //{
+ // return DefaultProvider.createTag( object );
+ //}
+
+ private State initialize( List<Action> list, Object object ) throws
Exception
+ {
+ Action action = getInitializationAction();
+ if( null == action )
+ {
+ return m_state;
+ }
+ else if( list.contains( action ) )
+ {
+ return m_state;
+ }
+ else
+ {
+ list.add( action );
+ if( action instanceof Operation )
+ {
+ Operation operation = (Operation) action;
+ execute( operation, object, new Object[0] );
+ return m_state;
+ }
+ else if( action instanceof Transition )
+ {
+ Transition transition = (Transition) action;
+ State current = getState();
+ State result = apply( transition, object );
+ if( !current.equals( result ) )
+ {
+ return initialize( list, object );
+ }
+ else
+ {
+ return getState();
+ }
+ }
+ else
+ {
+ final String error = "Unrecognized action: " + action;
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+
+ private Object execute( Operation operation, Object object, Object[]
args ) throws InvocationTargetException
+ {
+ if( null == object )
+ {
+ return null;
+ }
+
+ String method = getMethodName( operation );
+
+ try
+ {
+ Expression expression = new Expression( object, method, args );
+ return expression.getValue();
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ throw new InvocationTargetException( e );
+ }
+ }
+
+ private State terminate( List list, Object object ) throws Exception
+ {
+ Action action = getTerminationAction();
+ if( null == action )
+ {
+ return m_state;
+ }
+ else if( list.contains( action ) )
+ {
+ return m_state;
+ }
+ else
+ {
+ if( action instanceof Operation )
+ {
+ Operation operation = (Operation) action;
+ execute( operation, object, new Object[0] );
+ return m_state;
+ }
+ else if( action instanceof Transition )
+ {
+ Transition transition = (Transition) action;
+ State current = getState();
+ State result = apply( transition, object );
+ if( !current.equals( result ) )
+ {
+ return terminate( list, object );
+ }
+ else
+ {
+ return getState();
+ }
+ }
+ else
+ {
+ final String error = "Unrecognized action: " + action;
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+
+ private State apply( Transition transition, Object object ) throws
InvocationTargetException
+ {
+ synchronized( m_state )
+ {
+ State context = transition.getState();
+ String target = transition.getTargetName();
+ State state = getState( context, target );
+ Operation operation = transition.getOperation();
+ if( getLogger().isTraceEnabled() )
+ {
+ String name = transition.getName();
+ getLogger().trace(
+ "applying transition ["
+ + name
+ + "]." );
+ }
+ if( null != operation )
+ {
+ execute( operation, object, new Object[0] ); // TODO: add
resolved values as args
+ }
+ setState( object, state );
+ return state;
+ }
+ }
+
+ private void execute( URI handler, Object object ) throws
InvocationTargetException
+ {
+ if( null == object )
+ {
+ return;
+ }
+ String scheme = handler.getScheme();
+ if( "method".equals( scheme ) )
+ {
+ String methodName = handler.getSchemeSpecificPart();
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace(
+ "executing operation ["
+ + methodName
+ + "]" );
+ }
+ Statement statement = new Statement( object, methodName, new
Object[0] );
+ try
+ {
+ statement.execute();
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ throw new InvocationTargetException( e );
+ }
+ }
+ else
+ {
+ final String error =
+ "Operation scheme not recognized."
+ + "\nScheme: " + scheme
+ + "\nURI: " + handler;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private void setState( final Object object, final State state )
+ {
+ synchronized( m_state )
+ {
+ if( m_state != state )
+ {
+ final State oldState = m_state;
+ m_state = state;
+
+ if( getLogger().isTraceEnabled() )
+ {
+ getLogger().trace(
+ "transitioning from ["
+ + oldState
+ + "] to ["
+ + state
+ + "]" );
+ }
+
+ final StateEvent event = new StateEvent( this, oldState,
state );
+ m_queue.enqueueEvent( event );
+ }
+ }
+ }
+
+ private Action getAction( State state, TriggerPolicy category )
+ throws UnknownTransitionException, UnknownOperationException
+ {
+ Trigger[] triggers = state.getTriggers();
+ for( int i=0; i<triggers.length; i++ )
+ {
+ Trigger trigger = triggers[i];
+ if( trigger.getPolicy().equals( category ) )
+ {
+ Action action = trigger.getAction();
+ if( action instanceof ApplyAction )
+ {
+ ApplyAction apply = (ApplyAction) action;
+ String id = apply.getID();
+ return getTransition( state, id );
+ }
+ else if( action instanceof ExecAction )
+ {
+ ExecAction exec = (ExecAction) action;
+ String id = exec.getID();
+ return getOperation( state, id );
+ }
+ else
+ {
+ return action;
+ }
+ }
+ }
+ State parent = state.getParent();
+ if( null != parent )
+ {
+ return getAction( parent, category );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private Transition getTransition( State state, String name ) throws
UnknownTransitionException
+ {
+ Transition[] transitions = state.getTransitions();
+ for( int i=0; i<transitions.length; i++ )
+ {
+ Transition transition = transitions[i];
+ if( name.equals( transition.getName() ) )
+ {
+ return transition;
+ }
+ }
+ State parent = state.getParent();
+ if( null == parent )
+ {
+ final String error =
+ "Unable to resolve a transition named ["
+ + name
+ + "] relative to the state ["
+ + state.getName()
+ + "].";
+ throw new UnknownTransitionException( error );
+ }
+ else
+ {
+ try
+ {
+ return getTransition( parent, name );
+ }
+ catch( UnknownTransitionException e )
+ {
+ final String error =
+ "Unable to resolve a transition named ["
+ + name
+ + "] relative to the current state ["
+ + state
+ + "].";
+ throw new UnknownTransitionException( error );
+ }
+ }
+ }
+
+ private Operation getOperation( State state, String name ) throws
UnknownOperationException
+ {
+ Operation[] operations = state.getOperations();
+ for( int i=0; i<operations.length; i++ )
+ {
+ Operation operation = operations[i];
+ if( name.equals( operation.getName() ) )
+ {
+ return operation;
+ }
+ }
+ State parent = state.getParent();
+ if( null == parent )
+ {
+ throw new UnknownOperationException( name );
+ }
+ else
+ {
+ return getOperation( parent, name );
+ }
+ }
+
+
//-------------------------------------------------------------------------------
+ // static internals used to validate the integrity of a state graph
+
//-------------------------------------------------------------------------------
+
+ private static void validateState( State state )
+ {
+ Trigger[] triggers = state.getTriggers();
+ validateTriggers( state, triggers );
+ Transition[] transitions = state.getTransitions();
+ validateTransitions( state, transitions );
+ Operation[] operations = state.getOperations();
+ validateOperations( state, operations );
+ State[] states = state.getStates();
+ validateStates( state, states );
+ }
+
+ private static void validateTransitions( State state, Transition[]
transitions )
+ {
+ for( int i=0; i<transitions.length; i++ )
+ {
+ Transition transition = transitions[i];
+ validateTransition( state, transition );
+ }
+ }
+
+ private static void validateOperations( State state, Operation[]
operations )
+ {
+ for( int i=0; i<operations.length; i++ )
+ {
+ Operation operation = operations[i];
+ validateOperation( state, operation );
+ }
+ }
+
+ private static void validateTriggers( State state, Trigger[] triggers )
+ {
+ for( int i=0; i<triggers.length; i++ )
+ {
+ Trigger trigger = triggers[i];
+ validateTrigger( state, trigger );
+ }
+ }
+
+ private static void validateStates( State state, State[] states )
+ {
+ for( int i=0; i<states.length; i++ )
+ {
+ State s = states[i];
+ validateState( s );
+ }
+ }
+
+ private static void validateTrigger( State state, Trigger trigger )
+ {
+ TriggerPolicy event = trigger.getPolicy();
+ Action action = trigger.getAction();
+ if( action instanceof Transition )
+ {
+ Transition transition = (Transition) action;
+ validateTransition( state, transition );
+ }
+ else if( action instanceof Operation )
+ {
+ Operation operation = (Operation) action;
+ validateOperation( state, operation );
+ }
+ else if( action instanceof ApplyAction )
+ {
+ ApplyAction apply = (ApplyAction) action;
+ String id = apply.getID();
+ validateTransition( state, id );
+ }
+ else if( action instanceof ExecAction )
+ {
+ ExecAction exec = (ExecAction) action;
+ String id = exec.getID();
+ validateOperation( state, id );
+ }
+ }
+
+ private static void validateTransition( State state, String id )
+ {
+ //System.out.println( "# v/transition: " + id );
+ }
+
+ private static void validateTransition( State state, Transition
transition )
+ {
+ String target = transition.getTargetName();
+ State s = getState( state, target );
+ if( null == state )
+ {
+ final String error =
+ "Transition target ["
+ + target
+ + "] does not exist relative to state ["
+ + state;
+ throw new IllegalStateException( error );
+ }
+ }
+
+ private static void validateOperation( State state, String id )
+ {
+ //System.out.println( "# v/operation: " + operation );
+ }
+
+ private static void validateOperation( State state, Operation operation )
+ {
+ //System.out.println( "# v/operation: " + operation );
+ }
+
+ private static State getState( State state, String target )
+ {
+ if( target.startsWith( "/" ) )
+ {
+ //
+ // its an absolute target
+ //
+
+ String spec = target.substring( 1 );
+ State root = state.getStatePath()[0];
+ return getState( root, spec );
+ }
+ else if( target.startsWith( "../" ) )
+ {
+ //
+ // its relative to the state's parent
+ //
+
+ String spec = target.substring( 3 );
+ State parent = state.getParent();
+ if( null != parent )
+ {
+ return getState( parent, spec );
+ }
+ else
+ {
+ final String error =
+ "Invalid relative reference ["
+ + spec
+ + "] passed to root state.";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ else if( target.indexOf( "/" ) > -1 )
+ {
+ //
+ // its a composition address
+ //
+
+ int index = target.indexOf( "/" );
+ String base = target.substring( 0, index );
+ String remainder = target.substring( index + 1 );
+ State s = getState( state, base );
+ return getState( s, remainder );
+ }
+ else
+ {
+ //
+ // its a name relative to the supplied state
+ //
+
+ State[] states = state.getStates();
+ for( int i=0; i<states.length; i++ )
+ {
+ State s = states[i];
+ if( target.equals( s.getName() ) )
+ {
+ return s;
+ }
+ }
+ final String error =
+ "Requested target state ["
+ + target
+ + "] does not exist within the state ["
+ + state.getName()
+ + "].";
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private void checkDisposed() throws IllegalStateException
+ {
+ if( m_disposed )
+ {
+ final String error =
+ "Instance has been disposed.";
+ throw new IllegalStateException( error );
+ }
+ }
+
+ private String getMethodName( Operation operation )
+ {
+ if( null != operation.getMethodName() )
+ {
+ return operation.getMethodName();
+ }
+
+ //
+ // otherwise resolve it using java beans style getXxxx
+ //
+
+ String name = operation.getName();
+ int n = name.length();
+ if( n == 0 )
+ {
+ throw new IllegalArgumentException( "Operation name is empty." );
+ }
+ else if( n == 1 )
+ {
+ return "get" + name.toUpperCase();
+ }
+ else
+ {
+ return "get"
+ + name.substring( 0, 1 ).toUpperCase()
+ + name.substring( 1 );
+ }
+ }
+
+ private static URI createURI( String path ) throws Exception
+ {
+ if( null == path )
+ {
+ return null;
+ }
+ else
+ {
+ return new URI( path );
+ }
+ }
+
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Directive.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Directive.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Directive.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,47 @@
+/*
+ * 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 net.dpml.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import net.dpml.lang.Buffer;
+
+import org.w3c.dom.Element;
+
+/**
+ * Exception to indicate an error arrising from the use of a duplicate key.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+abstract class Directive
+{
+ public interface Encodable
+ {
+ Element getElement();
+
+ void encode( Buffer buffer, String key ) throws IOException;
+ }
+
+ public interface Resolvable extends Encodable
+ {
+ <T>T resolve( ComponentStrategy parent, Class<T> clazz ) throws
Exception;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/EventQueue.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/EventQueue.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/EventQueue.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,315 @@
+/*
+ * 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.runtime;
+
+import java.util.EventObject;
+import java.util.EventListener;
+import java.util.List;
+import java.util.LinkedList;
+
+import net.dpml.util.Logger;
+import dpml.util.DefaultLogger;
+
+/**
+ * A abstract base class that established an event queue and handles event
dispatch
+ * operations for listeners declared in classes extending this base class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class EventQueue
+{
+ /**
+ * Interface implemented by objects that maintain a collection of event
listeners
+ * and support for operational event propergation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+ public interface EventHandler
+ {
+ /**
+ * Return the associated event listeners.
+ * @return the event listeners
+ */
+ EventListener[] getEventListeners();
+
+ /**
+ * Process the supplied event.
+ * @param event the event to be processed
+ */
+ void processEvent( EventObject event );
+ }
+
+ //
------------------------------------------------------------------------
+ // state
+ //
------------------------------------------------------------------------
+
+ private final EventDispatchThread m_thread;
+
+ private final Logger m_logger;
+
+ private final List<EventObject> m_queue = new LinkedList<EventObject>();
+
+ //
------------------------------------------------------------------------
+ // constructor
+ //
------------------------------------------------------------------------
+
+ /**
+ * Creation of a new event queue.
+ * @param category the name used to construct a logging channel
+ * @deprecated Use new EventQueue( logger, "Thread name" ) instead.
+ */
+ public EventQueue( String category )
+ {
+ this( category, "Event Dispatch Thread" );
+ }
+
+ /**
+ * Creation of a new model.
+ * @param logger the assigned logging channel
+ * @exception NullPointerException if the supplied logging channel is null
+ * @deprecated Use new EventQueue( logger, "Thread name" ) instead.
+ */
+ public EventQueue( Logger logger )
+ throws NullPointerException
+ {
+ this( logger, "Event Dispatch Thread" );
+ }
+
+ /**
+ * Creation of a new event queue.
+ * @param category the name used to construct a logging channel
+ * @param name the name to assign to the thread
+ */
+ public EventQueue( String category, String name )
+ {
+ this( getLoggerForCategory( category ), name );
+ }
+
+ /**
+ * Creation of a new model.
+ * @param logger the assigned logging channel
+ * @param name the name to assign to the thread
+ * @exception NullPointerException if the supplied logging channel or
+ * thread name is null
+ */
+ public EventQueue( Logger logger, String name )
+ throws NullPointerException
+ {
+ if( null == logger )
+ {
+ throw new NullPointerException( "logger" );
+ }
+ if( null == name )
+ {
+ throw new NullPointerException( "name" );
+ }
+ m_logger = logger;
+ m_thread = new EventDispatchThread();
+ m_thread.setName( name );
+ m_thread.setDaemon( true );
+ m_thread.start();
+ }
+
+ //
------------------------------------------------------------------------
+ // EventQueue
+ //
------------------------------------------------------------------------
+
+ /**
+ * Terminate the dispatch thread.
+ */
+ public synchronized void terminateDispatchThread()
+ {
+ if( null != m_thread )
+ {
+ m_thread.dispose();
+ }
+ }
+
+ /**
+ * Return the assigned logging channel.
+ * @return the logging channel
+ */
+ private Logger getLogger()
+ {
+ return m_logger;
+ }
+
+ /**
+ * A single background thread ("the event notification thread") monitors
+ * the event queue and delivers events that are placed on the queue.
+ */
+ private class EventDispatchThread extends Thread
+ {
+ private boolean m_continue = true;
+
+ void dispose()
+ {
+ synchronized( m_queue )
+ {
+ m_continue = false;
+ m_queue.notify();
+ }
+ }
+
+ public void run()
+ {
+ while( m_continue )
+ {
+ // Wait on m_queue till an event is present
+ EventObject event = null;
+ synchronized( m_queue )
+ {
+ try
+ {
+ while( m_continue && m_queue.isEmpty() )
+ {
+ m_queue.wait();
+ }
+ if ( !m_continue )
+ {
+ break;
+ }
+ Object object = m_queue.remove( 0 );
+ try
+ {
+ event = (EventObject) object;
+ }
+ catch( ClassCastException cce )
+ {
+ final String error =
+ "Unexpected class cast exception while
processing an event."
+ + "\nEvent: " + object;
+ throw new IllegalStateException( error );
+ }
+ }
+ catch( InterruptedException e )
+ {
+ return;
+ }
+ }
+
+ Object source = event.getSource();
+ if( source instanceof EventHandler )
+ {
+ EventHandler handler = (EventHandler) source;
+ try
+ {
+ handler.processEvent( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while processing event."
+ + "\nEvent: " + event
+ + "\nSource: " + this;
+ getLogger().error( error, e );
+ }
+ }
+ else
+ {
+ final String error =
+ "Event source is not an instance of "
+ + EventHandler.class.getName();
+ getLogger().error( error );
+ }
+ }
+ }
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ *
+ * @param event the event object to add to the queue
+ */
+ public void enqueueEvent( EventObject event )
+ {
+ enqueueEvent( event, false );
+ }
+
+ /**
+ * Enqueue an event for delivery to registered
+ * listeners unless there are no registered
+ * listeners.
+ *
+ * @param event the event object to add to the queue
+ * @param waitForCompletion if TRUE the implementation will apply
+ * the event to the event source event handler and return on
+ * copmpletion of evetn delivery
+ */
+ public void enqueueEvent( EventObject event, boolean waitForCompletion )
+ {
+ if( !waitForCompletion )
+ {
+ synchronized( m_queue )
+ {
+ m_queue.add( event );
+ m_queue.notify();
+ }
+ }
+ else
+ {
+ Object source = event.getSource();
+ if( source instanceof EventHandler )
+ {
+ EventHandler handler = (EventHandler) source;
+ try
+ {
+ handler.processEvent( event );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unexpected error while processing event."
+ + "\nEvent: " + event
+ + "\nSource: " + source;
+ getLogger().error( error );
+ }
+ }
+ else
+ {
+ final String error =
+ "Event source is not an instance of "
+ + EventHandler.class.getName()
+ + "\nSource: " + source.getClass().getName();
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+
+ /**
+ * Return a logging channel for the supplied name.
+ * @param name the name to use in construction of the logging channel
+ * @return the logging channel
+ */
+ static Logger getLoggerForCategory( String name )
+ {
+ if( null == name )
+ {
+ return new DefaultLogger( "" );
+ }
+ else
+ {
+ return new DefaultLogger( name );
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/LifestyleHandler.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/LifestyleHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/LifestyleHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,127 @@
+/*
+ * 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.runtime;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ServiceLoader;
+
+import net.dpml.annotation.CollectionPolicy;
+
+import net.dpml.state.State;
+import net.dpml.state.StateMachine;
+
+import net.dpml.util.Logger;
+import dpml.util.DefaultLogger;
+
+/**
+ * Abstract lifestyle handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+abstract class LifestyleHandler
+{
+ private static final EventQueue QUEUE =
+ new EventQueue(
+ new DefaultLogger( "dpml.metro" ),
+ "DPML Component Event Queue" );
+
+ private final ComponentStrategy m_strategy;
+
+ LifestyleHandler( ComponentStrategy strategy )
+ {
+ m_strategy = strategy;
+ }
+
+ /**
+ * Return the component strategy.
+ * @return a component strategy
+ */
+ protected ComponentStrategy getComponentStrategy()
+ {
+ return m_strategy;
+ }
+
+ /**
+ * Return a component provider.
+ * @return a provider instance
+ * @exception Exception if an error occurs
+ */
+ abstract void release( Provider provider );
+
+ /**
+ * Return an instance of the component taking into account the lifestyle
policy.
+ * @return a component instance
+ * @exception Exception if an error occurs
+ */
+ abstract Provider getProvider();
+
+ abstract void terminate();
+
+ protected <T> Reference<T> createReference( T referent )
+ {
+ CollectionPolicy policy =
getComponentStrategy().getCollectionPolicy();
+ if( policy.equals( CollectionPolicy.SOFT ) )
+ {
+ return new SoftReference<T>( referent );
+ }
+ else if( policy.equals( CollectionPolicy.WEAK ) )
+ {
+ return new WeakReference<T>( referent );
+ }
+ else
+ {
+ return new HardReference<T>( referent );
+ }
+ }
+
+ /**
+ * A reference class that implements hard reference semantics.
+ */
+ private static class HardReference<T> extends SoftReference<T>
+ {
+ private final T m_referent; // hard reference
+
+ /**
+ * Creation of a new hard reference.
+ * @param referent the referenced object
+ */
+ public HardReference( T referent )
+ {
+ super( referent );
+ m_referent = referent;
+ }
+
+ /**
+ * Return the referent.
+ * @return the referent object
+ */
+ public T get()
+ {
+ return m_referent;
+ }
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/PartsDirective.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/PartsDirective.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/PartsDirective.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,309 @@
+/*
+ * 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 net.dpml.runtime;
+
+import dpml.util.ElementHelper;
+import dpml.util.DefaultLogger;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Hashtable;
+import java.lang.reflect.Array;
+
+import net.dpml.lang.Buffer;
+import net.dpml.lang.DecodingException;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.Strategy;
+import net.dpml.lang.StrategyHandler;
+import net.dpml.lang.PartContentHandler;
+
+import net.dpml.util.Resolver;
+import net.dpml.util.Logger;
+
+import org.w3c.dom.Element;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class PartsDirective
+{
+ private final PartsDirective m_parent;
+ private final Map<String,Strategy> m_parts = new
Hashtable<String,Strategy>();
+
+ /**
+ * Creation of parts datastructure.
+ */
+ PartsDirective()
+ {
+ m_parent = null;
+ }
+
+ PartsDirective(
+ ClassLoader classloader,
+ Element element, Resolver resolver, String partition ) throws
DecodingException
+ {
+ this( null, classloader, element, resolver, partition );
+ }
+
+ PartsDirective(
+ PartsDirective parent, ClassLoader classloader,
+ Element element, Resolver resolver, String partition ) throws
DecodingException
+ {
+ m_parent = parent;
+ if( null != element )
+ {
+ Element[] elements = ElementHelper.getChildren( element );
+ for( Element child : elements )
+ {
+ boolean implicit = false;
+ String key = ElementHelper.getAttribute( child, "key" );
+ Strategy strategy = buildStrategy( classloader, child,
resolver, partition );
+ if( null == key )
+ {
+ implicit = true;
+ key = strategy.getName();
+ }
+ if( m_parts.containsKey( key ) )
+ {
+ if( implicit )
+ {
+ final String error =
+ "Strategy declaration resolving to the implicit
key ["
+ + key
+ + "] cannot be added because the key has already
been assigned.";
+ throw new DecodingException( error, null, child );
+ }
+ else
+ {
+ final String error =
+ "Strategy declaration references a duplicate key ["
+ + key
+ + "].";
+ throw new DecodingException( error, null, child );
+ }
+ }
+ else
+ {
+ m_parts.put( key, strategy );
+ }
+ }
+ }
+ }
+
+ private Strategy buildStrategy( ClassLoader classloader,
+ Element element, Resolver resolver, String partition ) throws
DecodingException
+ {
+ try
+ {
+ StrategyHandler handler = PartContentHandler.getStrategyHandler(
element );
+ return handler.build( classloader, element, resolver, partition,
null );
+ }
+ catch( DecodingException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ if( null != partition )
+ {
+ final String error =
+ "Error building part strategy in partition ["
+ + partition
+ + "]";
+ throw new DecodingException( error, e, element );
+ }
+ else
+ {
+ final String error =
+ "Error building part strategy.";
+ throw new DecodingException( error, e, element );
+ }
+ }
+ }
+
+ void initialize( ServiceRegistry registry )
+ {
+ if( null != m_parent )
+ {
+ m_parent.initialize( registry );
+ }
+ for( Strategy strategy : m_parts.values() )
+ {
+ strategy.initialize( registry );
+ }
+ }
+
+ int size()
+ {
+ return m_parts.size();
+ }
+
+ String[] getKeys()
+ {
+ return m_parts.keySet().toArray( new String[0] );
+ }
+
+ Strategy getStrategy( String key )
+ {
+ Strategy strategy = m_parts.get( key );
+ if( null != strategy )
+ {
+ return strategy;
+ }
+ else if( null != m_parent )
+ {
+ return m_parent.getStrategy( key );
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ String[] getAllKeys()
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ if( null != m_parent )
+ {
+ String[] keys = m_parent.getAllKeys();
+ for( String key : keys )
+ {
+ if( !list.contains( key ) )
+ {
+ list.add( key );
+ }
+ }
+ }
+ for( String key : getKeys() )
+ {
+ if( !list.contains( key ) )
+ {
+ list.add( key );
+ }
+ }
+ return list.toArray( new String[0] );
+ }
+
+ /**
+ * Returns an array of type T where the contents of the array
+ * will be composed of all parts returning a non-null value
+ * from getContentForClass( T ).
+ * @param type the component type of the returned array
+ * @return an array of values matching the type selection criteria
+ * @exception IOException if a content resolution error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ <T>T[] select( Class<T> type ) throws IOException
+ {
+ return select( type, null );
+ }
+
+ /**
+ * Returns an array of type T where the contents of the array
+ * will be composed of all parts returning a non-null value
+ * from getContentForClass( c ).
+ * @param type the component type of the returned array
+ * @param criteria the content type selection constraint
+ * @return an array of values matching the type selection criteria
+ * @exception IOException if a content resolution error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ <T>T[] select( Class<T> type, Class criteria ) throws IOException
+ {
+ Strategy[] strategies = getAllStrategies();
+
+ ArrayList<T> list = new ArrayList<T>();
+ for( Strategy strategy : strategies )
+ {
+ if( null != criteria )
+ {
+ if( strategy.isaCandidate( criteria ) )
+ {
+ T value = strategy.getInstance( type );
+ list.add( value );
+ }
+ }
+ else
+ {
+ T value = strategy.getContentForClass( type );
+ if( null != value )
+ {
+ list.add( value );
+ }
+ }
+ }
+ T[] result = (T[]) Array.newInstance( type, list.size() );
+ int n = list.size();
+ for( int i=0; i<n; i++ )
+ {
+ result[i] = list.get( i );
+ }
+ return result;
+ }
+
+ Strategy[] getAllStrategies()
+ {
+ return getAllStrategies( true );
+ }
+
+ Strategy[] getAllStrategies( boolean sort )
+ {
+ ArrayList<Strategy> list = new ArrayList<Strategy>();
+ if( null != m_parent )
+ {
+ Strategy[] values = m_parent.getAllStrategies( sort );
+ for( Strategy strategy : values )
+ {
+ list.add( strategy );
+ }
+ }
+ Collection<Strategy> collection = m_parts.values();
+ for( Strategy strategy : collection )
+ {
+ list.add( strategy );
+ }
+ Strategy[] result = list.toArray( new Strategy[0] );
+ if( sort )
+ {
+ Arrays.sort( result );
+ }
+ return result;
+ }
+
+ public void encode( Buffer buffer ) throws IOException
+ {
+ if( size() > 0 )
+ {
+ buffer.nl( "<parts>" );
+ Buffer b2 = buffer.indent();
+ for( String key : getKeys() )
+ {
+ Strategy strategy = getStrategy( key );
+ strategy.encode( b2, key );
+ }
+ buffer.nl( "</parts>" );
+ }
+ }
+}

Added:
trunk/main/lang/part/src/main/net/dpml/runtime/PartsInvocationHandler.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/runtime/PartsInvocationHandler.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/runtime/PartsInvocationHandler.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2004-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.runtime;
+
+import java.util.Map;
+import java.beans.Introspector;
+import java.beans.Expression;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.TypeVariable;
+
+import net.dpml.annotation.Parts;
+
+import net.dpml.lang.Strategy;
+
+/**
+ * Invocation handler utility for a Context class.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+final class PartsInvocationHandler implements InvocationHandler
+{
+ //-------------------------------------------------------------------
+ // static
+ //-------------------------------------------------------------------
+
+ private static final String GET = "get";
+
+ /**
+ * Test if the supplied class is recognized as a context class. If
+ * the supplied policy is true then evaluation is based on the presence
+ * of the <tt>net.dpml.lang.Context</tt> annotation and resulting
+ * value of annotation evaluation. If no context annnotation is present
+ * and strict processing is disabled then evaluation will return true if
+ * the classname ends with the string <tt>$Context</tt>.
+ *
+ * @param c the candidate class
+ * @param policy the strict evaluation policy
+ * @return true if this class is recognized as a context class
+ */
+ public static boolean isaParts( final Class<?> c, final boolean policy )
+ {
+ boolean flag = c.isAnnotationPresent( Parts.class );
+ if( flag )
+ {
+ return c.getAnnotation( Parts.class ).value();
+ }
+ else if( policy )
+ {
+ return false;
+ }
+ else
+ {
+ return c.getName().endsWith( "$Parts" );
+ }
+ }
+
+ /**
+ * Construct a new context instance implementing the supplied class
+ * backed by entries in the supplied map.
+ *
+ * @param clazz the context class
+ * @param map a map of context entry keys and values
+ * @return the constructed context instance
+ */
+ public static <T>T getProxiedInstance(
+ final Class<T> clazz, final PartsDirective directive )
+ {
+ ClassLoader classloader = clazz.getClassLoader();
+ PartsInvocationHandler handler =
+ new PartsInvocationHandler( directive );
+ final Object instance =
+ Proxy.newProxyInstance( classloader, new Class[]{clazz}, handler );
+ return clazz.cast( instance );
+ }
+
+ //-------------------------------------------------------------------
+ // state
+ //-------------------------------------------------------------------
+
+ /**
+ * A map containing key values.
+ */
+ private final PartsDirective m_directive;
+
+ //-------------------------------------------------------------------
+ // constructor
+ //-------------------------------------------------------------------
+
+ /**
+ * Create a parts invocation handler.
+ *
+ * @param directive the parts directive
+ */
+ private PartsInvocationHandler( final PartsDirective directive )
+ {
+ m_directive = directive;
+ }
+
+ //-------------------------------------------------------------------
+ // implementation
+ //-------------------------------------------------------------------
+
+ /**
+ * Invoke the specified method on underlying object.
+ * This is called by the proxy object.
+ *
+ * @param proxy the proxy object
+ * @param method the method invoked on proxy object
+ * @param args the arguments supplied to method
+ * @return the return value of method
+ * @throws Throwable if an error occurs
+ */
+ @SuppressWarnings( "unchecked" )
+ public Object invoke( final Object proxy, final Method method, final
Object[] args ) throws Throwable
+ {
+ String name = method.getName();
+ if( name.startsWith( "get" ) )
+ {
+ Class<?> clazz = method.getReturnType();
+ if( clazz.isArray() )
+ {
+ // build an array of all parts matching the array type
+ Class<?> type = clazz.getComponentType();
+ if( null == args )
+ {
+ return m_directive.select( type );
+ }
+ else
+ {
+ Class<?> c = getClassArgument( args );
+ return m_directive.select( type, c );
+ }
+ }
+ else
+ {
+ String key = Introspector.decapitalize( name.substring( 3 )
);
+ Strategy strategy = m_directive.getStrategy( key );
+ if( null != strategy )
+ {
+ if( ( null != args ) && ( args.length > 0 ) && (
args[0].getClass() == Class.class ) )
+ {
+ return strategy.getInstance( (Class) args[0] );
+ }
+ else
+ {
+ return strategy.getInstance( clazz );
+ }
+ }
+ if( ( null != args ) && ( args.length > 0 ) )
+ {
+ return args[0];
+ }
+ else
+ {
+ final String error =
+ "Unable to resolve a parts entry value for the key ["
+ + key
+ + "]";
+ throw new IllegalStateException( error );
+ }
+ }
+ }
+ else
+ {
+ throw new UnsupportedOperationException( name );
+ }
+ }
+
+ private static final String STRICT_PROCESSING_KEY =
"dpml.lang.parts.policy";
+ private static final String STRICT_PROCESSING_KEYWORD = "strict";
+ private static final boolean STRICT_PROCESSING =
getStrictProcessingPolicy();
+
+ private static boolean getStrictProcessingPolicy()
+ {
+ return STRICT_PROCESSING_KEYWORD.equalsIgnoreCase(
+ System.getProperty(
+ STRICT_PROCESSING_KEY,
+ STRICT_PROCESSING_KEYWORD ) );
+ }
+
+ private Class<?> getClassArgument( Object[] args )
+ {
+ if( null == args )
+ {
+ throw new NullPointerException( "args" ); // will not happen
+ }
+ else if( args.length == 0 )
+ {
+ throw new IllegalArgumentException( "args" ); // will not happen
+ }
+ else
+ {
+ Object arg = args[0];
+ if( arg.getClass() == Class.class )
+ {
+ return (Class) arg;
+ }
+ else
+ {
+ String classname = arg.getClass().getName();
+ final String error =
+ "Expacting a class parameter but found an integer of ["
+ + classname
+ + "].";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Profile.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Profile.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Profile.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,117 @@
+/*
+ * 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.runtime;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+
+import dpml.lang.DOM3DocumentBuilder;
+
+import net.dpml.util.Resolver;
+import dpml.util.ElementHelper;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Component interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class Profile
+{
+ private static final DOM3DocumentBuilder BUILDER = new
DOM3DocumentBuilder();
+
+ private Class m_clazz;
+ private Element m_element;
+ private ContextDirective m_context;
+ private PartsDirective m_parts;
+
+ Profile( Class<?> c, String path, Resolver resolver ) throws IOException
+ {
+ m_element = getProfileElement( c );
+ ClassLoader classloader = c.getClassLoader();
+ m_context = getContextProfile( classloader, m_element, resolver );
+ m_parts = getPartsProfile( classloader, m_element, resolver, path );
+ }
+
+ ContextDirective getContextDirective()
+ {
+ return m_context;
+ }
+
+ PartsDirective getPartsDirective()
+ {
+ return m_parts;
+ }
+
+ private static Element getProfileElement( Class<?> c ) throws IOException
+ {
+ ClassLoader classloader = c.getClassLoader();
+ String path = c.getName().replace( ".", "/" );
+ String profile = path + ".xprofile";
+ URL url = classloader.getResource( profile );
+ if( null != url )
+ {
+ try
+ {
+ URI uri = url.toURI();
+ final Document document = BUILDER.parse( uri );
+ return document.getDocumentElement();
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Bad url: " + url;
+ IOException ioe = new IOException( error );
+ ioe.initCause( e );
+ throw ioe;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private static ContextDirective getContextProfile(
+ ClassLoader classloader, Element profile, Resolver resolver ) throws
IOException
+ {
+ if( null == profile )
+ {
+ return null;
+ }
+ Element context = ElementHelper.getChild( profile, "context" );
+ return new ContextDirective( classloader, context, resolver );
+ }
+
+ private static PartsDirective getPartsProfile(
+ ClassLoader classloader, Element profile, Resolver resolver, String
path ) throws IOException
+ {
+ if( null == profile )
+ {
+ return null;
+ }
+ Element partsElement = ElementHelper.getChild( profile, "parts" );
+ return new PartsDirective( classloader, partsElement, resolver, path
);
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Provider.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Provider.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Provider.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,50 @@
+/*
+ * 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.runtime;
+
+import net.dpml.state.StateListener;
+
+/**
+ * Component interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Provider
+{
+ /**
+ * Add a state change listener to the state machine.
+ * @param listener the state listener
+ */
+ void addStateListener( final StateListener listener );
+
+ /**
+ * Remove a state listener from the state machine.
+ * @param listener the state listener
+ */
+ void removeStateListener( final StateListener listener );
+
+ /**
+ * Return a fully commissioned instance.
+ * @return the instance
+ */
+ <T>T getInstance( Class<T> type );
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/ProviderEvent.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/ProviderEvent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/ProviderEvent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,63 @@
+/*
+ * 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 net.dpml.runtime;
+
+/**
+ * Event triggered as a result of a state change.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ProviderEvent extends ComponentEvent
+{
+ private final Provider m_provider;
+ private final Status m_action;
+
+ /**
+ * Construct a new <code>StateEvent</code>.
+ *
+ * @param source the source component
+ * @param provider the provider instance initiating the event
+ * @param action the modified Status enumeration
+ */
+ public ProviderEvent( final Component source, Provider provider, Status
action )
+ {
+ super( source );
+
+ m_provider = provider;
+ m_action = action;
+ }
+
+ public Provider getProvider()
+ {
+ return m_provider;
+ }
+
+ public Status getStatus()
+ {
+ return m_action;
+ }
+
+ public String toString()
+ {
+ String id = super.toString();
+ return id + "#" + getStatus();
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Query.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Query.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Query.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,206 @@
+/*
+ * 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.runtime;
+
+import dpml.lang.Value;
+import dpml.lang.Construct;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import net.dpml.runtime.Directive.Resolvable;
+import net.dpml.runtime.ContextDirective.ValueWrapper;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class Query
+{
+ private final Map<String,Resolvable> m_entries = new
Hashtable<String,Resolvable>();
+
+ Query( String query )
+ {
+ this( expand( query ) );
+ }
+
+ Query( List<Binding> values )
+ {
+ for( Binding binding : values )
+ {
+ String key = binding.getKey();
+ Resolvable value = binding.getValue();
+ m_entries.put( key, value );
+ }
+ }
+
+ public Resolvable getEntry( String key )
+ {
+ return m_entries.get( key );
+ }
+
+ private static List<Binding> expand( String query )
+ {
+ final List<Binding> list = new ArrayList<Binding>();
+ if( null == query )
+ {
+ return list;
+ }
+ String[] segments = query.split( "," );
+ for( String segment : segments )
+ {
+ String[] args = segment.split( "=" );
+ if( args.length != 2 )
+ {
+ throw new IllegalArgumentException(
+ "Invalid query [" + segment + "]" );
+ }
+ String address = args[0];
+ String param = args[1];
+ String decoded = decode( param );
+ Value value = new Construct( decoded );
+ Resolvable entry = new ValueWrapper( value );
+ Binding binding = new Binding( address, entry );
+ list.add( binding );
+ }
+ return list;
+ }
+
+ private static String decode( String param )
+ {
+ try
+ {
+ return URLDecoder.decode( param, "UTF8" );
+ }
+ catch( UnsupportedEncodingException uee )
+ {
+ // will not happen
+ uee.printStackTrace();
+ return param;
+ }
+ }
+
+ private static class Binding
+ {
+ private final String m_key;
+ private final Resolvable m_value;
+
+ Binding( String key, Resolvable value )
+ {
+ m_key = key;
+ m_value = value;
+ }
+
+ String getKey()
+ {
+ return m_key;
+ }
+
+ Resolvable getValue()
+ {
+ return m_value;
+ }
+ }
+
+ //public <T>T resolve( ComponentStrategy parent, Class<T> clazz ) throws
Exception
+ //{
+ // return null;
+ //}
+
+ /*
+ private final List<Binding> m_list = new ArrayList<Binding>();
+
+ Query( String query )
+ {
+ if( null != query )
+ {
+ String[] segments = query.split( "," );
+ for( String segment : segments )
+ {
+ String[] args = segment.split( "=" );
+ if( args.length != 2 )
+ {
+ throw new IllegalArgumentException(
+ "Invalid query [" + segment + "]" );
+ }
+ String address = args[0];
+ String param = args[1];
+ String[] keys = address.split( "." );
+ Binding binding = new Binding( keys, param );
+ m_list.add( binding );
+ }
+ }
+ }
+
+ Binding getBinding( String key )
+ {
+ for( Binding binding : m_list )
+ {
+ if( key.equals( binding.getKey() ) )
+ {
+ return binding;
+ }
+ }
+ return null;
+ }
+
+ static class Binding
+ {
+ private final String m_key;
+ private final Object m_value;
+
+ Binding( String[] keys, String value )
+ {
+ int n = keys.length;
+ if( n == 0 )
+ {
+ throw new IllegalArgumentException(
+ "Invalid query expression." );
+ }
+ else if( n == 1 )
+ {
+ m_key = keys[0];
+ m_value = value;
+ }
+ else
+ {
+ int m = n-1;
+ m_key = keys[0];
+ String[] newKeys = new String[ m ];
+ System.arrayCopy( keys, 1, newKeys, 0, m );
+ m_value = new Binding( newKeys, value );
+ }
+ }
+
+ String getKey()
+ {
+ return m_key;
+ }
+
+ Object getValue()
+ {
+ return m_value;
+ }
+ }
+ */
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/StandardProvider.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/StandardProvider.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/StandardProvider.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,434 @@
+/*
+ * 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.runtime;
+
+import dpml.util.DefaultLogger;
+import dpml.util.StandardClassLoader;
+import dpml.lang.Disposable;
+
+import dpml.lang.LoggingInvocationHandler;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ServiceLoader;
+
+import net.dpml.annotation.Services;
+import net.dpml.annotation.LifestylePolicy;
+import net.dpml.annotation.ActivationPolicy;
+
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.StandardServiceRegistry;
+import net.dpml.lang.TypeCastException;
+
+import net.dpml.state.State;
+import net.dpml.state.StateListener;
+import net.dpml.state.StateMachine;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.runtime.Status.CREATION;
+import static net.dpml.runtime.Status.INCARNATION;
+import static net.dpml.runtime.Status.ETHERIALIZATION;
+import static net.dpml.runtime.Status.TERMINATION;
+
+import static net.dpml.annotation.ActivationPolicy.STARTUP;
+
+
+/**
+ * Abstract lifestyle handler.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+class StandardProvider implements Provider, Disposable
+{
+ private static final EventQueue QUEUE =
+ new EventQueue(
+ new DefaultLogger( "dpml.metro" ),
+ "DPML Provider Event Queue" );
+
+ private static final ServiceRegistry REGISTRY =
+ new StandardServiceRegistry();
+
+ private final ComponentStrategy m_strategy;
+ private final StateMachine m_machine;
+ private final Class<?> m_class;
+ private final String m_category;
+ private final Logger m_logger;
+
+ private Object m_instance = null;
+
+ StandardProvider( ComponentStrategy strategy )
+ {
+ m_strategy = strategy;
+ m_class = m_strategy.getComponentClass();
+ final Logger logger = strategy.getComponentLogger();
+ final State graph = strategy.getStateGraph();
+ LifestylePolicy lifestyle = m_strategy.getLifestylePolicy();
+ m_category = getLoggingCategory( lifestyle );
+ m_logger = new DefaultLogger( m_category );
+ m_machine = getStateMachine( m_logger, graph );
+
+ ComponentEvent event = new ProviderEvent( m_strategy, this, CREATION
);
+ strategy.processEvent( event );
+
+ ActivationPolicy activation = m_strategy.getActivationPolicy();
+ if( STARTUP.equals( activation ) )
+ {
+ m_instance = newInstance();
+ }
+ }
+
+ /**
+ * Add a state change listener to the state machine.
+ * @param listener the state listener
+ */
+ public void addStateListener( final StateListener listener )
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "adding state listener" );
+ }
+ m_machine.addStateListener( listener );
+ }
+
+ /**
+ * Remove a state listener from the state machine.
+ * @param listener the state listener
+ */
+ public void removeStateListener( final StateListener listener )
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "removing state listener" );
+ }
+ m_machine.removeStateListener( listener );
+ }
+
+ public <T>T getInstance( Class<T> type )
+ {
+ synchronized( this )
+ {
+ Object instance = getCachedInstance();
+ if( type.isInterface() )
+ {
+ if( m_class.isAnnotationPresent( Services.class ) )
+ {
+ InvocationHandler handler = new
ComponentInvocationHandler( instance );
+ ClassLoader classloader = m_class.getClassLoader();
+ Services annotation = m_class.getAnnotation(
Services.class );
+ Class[] services = annotation.value();
+ Object proxy = Proxy.newProxyInstance( classloader,
services, handler );
+ try
+ {
+ return type.cast( proxy );
+ }
+ catch( ClassCastException cce )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "Cannot assign component class [" );
+ buffer.append( instance.getClass().getName() + "]" );
+ buffer.append( " to the return type [" );
+ buffer.append( type.getName() + "] " );
+ buffer.append( "because the requested service type
is not " );
+ buffer.append( "included in the public services
published by the component." );
+ String error = buffer.toString();
+ throw new TypeCastException( error, m_class, type );
+ }
+ }
+ else
+ {
+ try
+ {
+ return type.cast( instance );
+ }
+ catch( ClassCastException cce )
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "Cannot assign component class [" );
+ buffer.append( instance.getClass().getName() + "]" );
+ buffer.append( " to the return type [" );
+ buffer.append( type.getName() + "]" );
+ String error = buffer.toString();
+ throw new TypeCastException( error, m_class, type );
+ }
+ }
+ }
+ else if( type.isAssignableFrom( m_class ) )
+ {
+ return type.cast( instance );
+ }
+ else
+ {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append( "Cannot assign component class [" );
+ buffer.append( instance.getClass().getName() + "]" );
+ buffer.append( " to the return type [" );
+ buffer.append( type.getName() + "]" );
+ String error = buffer.toString();
+ throw new TypeCastException( error, m_class, type );
+ }
+ }
+ }
+
+ private Object getCachedInstance()
+ {
+ if( null == m_instance )
+ {
+ m_instance = newInstance();
+ }
+ return m_instance;
+ }
+
+ private Object newInstance()
+ {
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "incarnation [" + m_class + "]" );
+ }
+
+ ComponentEvent event = new ProviderEvent( m_strategy, this,
INCARNATION );
+ m_strategy.processEvent( event );
+
+ final String path = m_strategy.getComponentPath();
+ final Constructor<?> constructor = getConstructor( m_class );
+ final Class<?>[] types = constructor.getParameterTypes();
+ final Object[] args = new Object[ types.length ];
+
+ for( int i=0; i<types.length; i++ )
+ {
+ Class<?> type = types[i];
+ if( java.util.logging.Logger.class.isAssignableFrom( type ) )
+ {
+ String category = getLoggingCategory();
+ java.util.logging.Logger logger =
+ java.util.logging.Logger.getLogger( category );
+ args[i] = logger;
+ }
+ else if( Logger.class.isAssignableFrom( type ) )
+ {
+ args[i] = getTargetLogger();
+ }
+ else if( ContextInvocationHandler.isaContext( type, false ) )
+ {
+ ContextModel context = m_strategy.getContextModel();
+ args[i] = ContextInvocationHandler.getProxiedInstance( type,
m_strategy, context );
+ }
+ else if( PartsInvocationHandler.isaParts( type, false ) )
+ {
+ PartsDirective directive = m_strategy.getPartsDirective();
+ args[i] = PartsInvocationHandler.getProxiedInstance( type,
directive );
+ }
+ else if( "net.dpml.logging.Logger".equals( type.getName() ) ) //
legacy
+ {
+ Logger logger = getTargetLogger();
+ args[i] = LoggingInvocationHandler.getProxiedInstance( type,
logger );
+ }
+ else
+ {
+ Object service = m_strategy.lookup( type );
+ if( null != service )
+ {
+ args[i] = service;
+ }
+ else
+ {
+ service = REGISTRY.lookup( type );
+ if( null != service )
+ {
+ args[i] = service;
+ }
+ else if( type.isArray() )
+ {
+ args[i] = Array.newInstance(
type.getComponentType(), 0 );
+ }
+ else
+ {
+ String stack = StandardClassLoader.toString(
getClass(), m_class );
+ System.out.println( stack );
+ final String error =
+ "No solution for the constructor parameter ["
+ + type.getName()
+ + "] at position " + i
+ + " for the component ["
+ + path
+ + "] ("
+ + m_class.getName()
+ + ").";
+ throw new ComponentError( error );
+ }
+ }
+ }
+ }
+
+ try
+ {
+ Object instance = constructor.newInstance( args );
+ m_machine.initialize( instance );
+ return instance;
+ }
+ catch( Throwable e )
+ {
+ ComponentError error = getComponentError( path, e );
+ throw error;
+ }
+ }
+
+ private Logger getTargetLogger()
+ {
+ String category = getLoggingCategory();
+ return new DefaultLogger( category );
+ }
+
+ public void dispose()
+ {
+ if( null != m_instance )
+ {
+ ComponentEvent etherialization = new ProviderEvent( m_strategy,
this, ETHERIALIZATION );
+ m_strategy.processEvent( etherialization );
+ if( m_logger.isTraceEnabled() )
+ {
+ m_logger.trace( "etherialization" );
+ }
+ Object instance = getUnwrappedInstance( m_instance );
+ m_machine.terminate( instance );
+ m_instance = null;
+ }
+ ComponentEvent termination = new ProviderEvent( m_strategy, this,
TERMINATION );
+ m_strategy.processEvent( termination );
+ }
+
+ private ComponentError getComponentError( String path, Throwable e )
+ {
+ if( e instanceof ComponentError )
+ {
+ return (ComponentError) e;
+ }
+ if( e instanceof UndeclaredThrowableException )
+ {
+ Throwable cause = e.getCause();
+ if( null != cause )
+ {
+ return getComponentError( path, cause );
+ }
+ }
+ if( e instanceof InvocationTargetException )
+ {
+ Throwable cause = e.getCause();
+ if( null != cause )
+ {
+ return getComponentError( path, cause );
+ }
+ }
+ final String error =
+ "Component '"
+ + path
+ + "' could not be instantiated ["
+ + m_class.getName()
+ + "]";
+ return new ComponentError( error, e );
+ }
+
+ /**
+ * Loacate and return the single public constructor declared by the
component class.
+ * @return the constructor
+ * @exception ControlException if the class does not declare a unique
public constructor
+ */
+ private Constructor getConstructor( Class c )
+ {
+ return ComponentStrategyHandler.getSingleConstructor( c );
+ }
+
+ private StateMachine getStateMachine( Logger logger, State graph )
+ {
+ return new DefaultStateMachine( QUEUE, logger, graph );
+ }
+
+ private Object getUnwrappedInstance( Object instance )
+ {
+ Class c = instance.getClass();
+ if( Proxy.isProxyClass( c ) )
+ {
+ InvocationHandler handler = Proxy.getInvocationHandler( instance
);
+ if( handler instanceof ComponentInvocationHandler )
+ {
+ ComponentInvocationHandler h = (ComponentInvocationHandler)
handler;
+ return h.getInstance();
+ }
+ else
+ {
+ final String error =
+ "Invocation handler class ["
+ + handler.getClass().getName()
+ + "] is not recognized.";
+ throw new IllegalArgumentException( error );
+ }
+ }
+ else
+ {
+ return instance;
+ }
+ }
+
+ private String getLoggingCategory()
+ {
+ return m_category;
+ }
+
+ private String getLoggingCategory( LifestylePolicy lifestyle )
+ {
+ String category = getBaseLoggingCategory();
+ if( LifestylePolicy.SINGLETON.equals( lifestyle ) )
+ {
+ return category;
+ }
+ else
+ {
+ int id = System.identityHashCode( this );
+ return category + "." + id;
+ }
+ }
+
+ private String getBaseLoggingCategory()
+ {
+ String path = m_strategy.getComponentPath();
+ if( path.startsWith( "/" ) )
+ {
+ return path.substring( 1 );
+ }
+ else
+ {
+ return path;
+ }
+ }
+
+ public String toString()
+ {
+ String lifestyle =
m_strategy.getLifestylePolicy().toString().toLowerCase();
+ String path = m_strategy.getComponentPath();
+ int id = System.identityHashCode( this );
+ return lifestyle + ":" + path + "#" + id;
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/runtime/Status.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/Status.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/Status.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,32 @@
+/*
+ * 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.runtime;
+
+/**
+ * Provider status enumeration.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum Status
+{
+ CREATION,
+ INCARNATION,
+ ETHERIALIZATION,
+ TERMINATION,
+}

Added: trunk/main/lang/part/src/main/net/dpml/runtime/package-info.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/runtime/package-info.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/runtime/package-info.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2004-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.
+ */
+
+/**
+ * Component strategy runtime implementation.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.runtime;

Added: trunk/main/lang/part/src/main/net/dpml/state/Action.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/Action.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/Action.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,35 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Interface marking a a direct or implict actionable instance.
+ *
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Action
+{
+ /**
+ * Return the action name.
+ * @return the name
+ */
+ String getName();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/ApplyAction.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/ApplyAction.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/ApplyAction.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,103 @@
+/*
+ * 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 net.dpml.state;
+
+import java.io.Serializable;
+
+/**
+ * Default implementation of delegating action.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ApplyAction implements Action, Serializable
+{
+ private final String m_id;
+
+ /**
+ * Creation of a new apply action.
+ * @param id transition name
+ */
+ public ApplyAction( final String id )
+ {
+ if( null == id )
+ {
+ throw new NullPointerException( "id" );
+ }
+ m_id = id;
+ }
+
+ /**
+ * Return the action name.
+ * @return the name
+ */
+ public String getName()
+ {
+ return "apply:"+ m_id;
+ }
+
+ /**
+ * Return the id of the transition to apply.
+ * @return the transition id
+ */
+ public String getID()
+ {
+ return m_id;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof ApplyAction )
+ {
+ ApplyAction action = (ApplyAction) other;
+ return m_id.equals( action.getID() );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ return m_id.hashCode();
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "apply:" + m_id;
+ }
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/ExecAction.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/ExecAction.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/ExecAction.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,103 @@
+/*
+ * 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 net.dpml.state;
+
+import java.io.Serializable;
+
+/**
+ * Default implementation of delegating action.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ExecAction implements Action, Serializable
+{
+ private final String m_id;
+
+ /**
+ * Creation of a new exec action.
+ * @param id operation name
+ */
+ public ExecAction( final String id )
+ {
+ if( null == id )
+ {
+ throw new NullPointerException( "id" );
+ }
+ m_id = id;
+ }
+
+ /**
+ * Return the action name.
+ * @return the name
+ */
+ public String getName()
+ {
+ return "exec:" + m_id;
+ }
+
+ /**
+ * Return the id of the transition to apply.
+ * @return the transition id
+ */
+ public String getID()
+ {
+ return m_id;
+ }
+
+ /**
+ * Compare this object to another for equality.
+ * @param other the other object
+ * @return true if the object is equal to this object
+ */
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( other instanceof ExecAction )
+ {
+ ExecAction action = (ExecAction) other;
+ return m_id.equals( action.getID() );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Compute the hashcode for this instance.
+ * @return the hashcode value
+ */
+ public int hashCode()
+ {
+ return m_id.hashCode();
+ }
+
+ /**
+ * Return a string representation of the instance.
+ * @return the string value
+ */
+ public String toString()
+ {
+ return "exec:" + m_id;
+ }
+}

Added:
trunk/main/lang/part/src/main/net/dpml/state/IntegrityRuntimeException.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/state/IntegrityRuntimeException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/state/IntegrityRuntimeException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,55 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Runtime exception thrown when an inconsitent state is encounted within a
state-machine.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class IntegrityRuntimeException extends RuntimeException
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>IntegrityRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ */
+ public IntegrityRuntimeException( final String message )
+ {
+ this( message, null );
+ }
+
+ /**
+ * Construct a new <code>IntegrityRuntimeException</code> instance.
+ *
+ * @param message the exception message
+ * @param cause the causal exception
+ */
+ public IntegrityRuntimeException( final String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/state/Interface.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/Interface.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/Interface.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,38 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * An Interface action declares the classname of an interface
+ * implemented by a component class that may be dynamically
+ * exposed by a component through the assocation of the interface
+ * with an active state.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Interface extends Action
+{
+ /**
+ * Return the classname of a management interface implemented and
+ * potentially exposed by a component.
+ * @return the interface classname
+ */
+ String getClassname();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/Operation.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/Operation.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/Operation.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,38 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * An operation defines the name of a bean style accessor that
+ * may be invoked by a management application while the operation
+ * is exposed within the active path.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Operation extends Action
+{
+ /**
+ * Return the optional overriding method name. If the
+ * value returned is null the method shall be assumed to be the
+ * equivalent of "get[Name]().
+ * @return the operation method name
+ */
+ String getMethodName();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/State.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/State.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/State.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,96 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Interface describing an application state.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface State
+{
+ /**
+ * Constant artifact type for a state graph.
+ */
+ static final String TYPE = "state";
+
+ /**
+ * Return the name of the state.
+ * @return the state name
+ */
+ String getName();
+
+ /**
+ * Set the parent state.
+ * @param state the parent state
+ */
+ void setParent( State state );
+
+ /**
+ * Return the parent state to this state or null if this is
+ * the root of a state graph.
+ * @return the parent state
+ */
+ State getParent();
+
+ /**
+ * Return the state path. The path is composed of a sequence of
+ * states from the root to this state.
+ * @return the state path
+ */
+ State[] getStatePath();
+
+ /**
+ * Return the substates within this state.
+ * @return the substate array
+ */
+ State[] getStates();
+
+ /**
+ * Return the array of triggers associated with the state.
+ * @return the trigger array
+ */
+ Trigger[] getTriggers();
+
+ /**
+ * Return the array of transtions associated with the state.
+ * @return the transition array
+ */
+ Transition[] getTransitions();
+
+ /**
+ * Return the array of operations associated with the state.
+ * @return the operation array
+ */
+ Operation[] getOperations();
+
+ /**
+ * Return the array of management interfaces associated with
+ * the state.
+ * @return the interfaces array
+ */
+ Interface[] getInterfaces();
+
+ /**
+ * Test is the state is a terminal state.
+ * @return true if terminal
+ */
+ boolean isTerminal();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/StateEvent.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/StateEvent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/StateEvent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,73 @@
+/*
+ * 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 net.dpml.state;
+
+import java.util.EventObject;
+
+
+/**
+ * Event triggered as a result of a state change.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StateEvent extends EventObject
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private final State m_from;
+ private final State m_to;
+
+ /**
+ * Construct a new <code>StateEvent</code>.
+ *
+ * @param source the source compoent model
+ * @param from the originating state
+ * @param to the new current state
+ */
+ public StateEvent( final Object source, State from, State to )
+ {
+ super( source );
+ m_from = from;
+ m_to = to;
+ }
+
+ /**
+ * Return the state that existed prior to the transition.
+ * @return the original state
+ */
+ public State getFromState()
+ {
+ return m_from;
+ }
+
+ /**
+ * Return the state that was established by a transition.
+ * @return the new current state
+ */
+ public State getToState()
+ {
+ return m_to;
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/state/StateListener.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/StateListener.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/StateListener.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,41 @@
+/*
+ * 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 net.dpml.state;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.EventListener;
+
+/**
+ * Interface implementated by remote listeners to state change events.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface StateListener extends EventListener, Remote
+{
+ /**
+ * Notify the listener of a state change.
+ *
+ * @param event the state change event
+ * @exception RemoteException if a remote transport error occurs
+ */
+ void stateChanged( final StateEvent event ) throws RemoteException;
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/state/StateMachine.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/StateMachine.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/StateMachine.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,171 @@
+/*
+ * 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 net.dpml.state;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * <p>Defintion of the state machine. The state machine handles the
maintenance
+ * of a single current state and supports the invocation of transition and
operations
+ * relative to the current state. Invocation of transiton and operations
are handled
+ * via two mechansims:</p>
+ *
+ * <ol>
+ * <li>triggers</li>
+ * <li>explicit invocation of the 'appply' and 'execute' operations</li>
+ * </ol>
+ *
+ * <p>Triggers, Transitions, and Operations may be declared within any state
and enter
+ * active scope when when the enclosing state is within the current state
path
+ * (where the current state path is the sequence of state's from the current
state to
+ * the root state).</p>
+ *
+ * <p>Transitions and operations available at any given time are a function
of
+ * all uniquely named transitions and operations exposed within the current
state path.
+ * If multiple instances of a transition or operation share the same name,
the instance
+ * closest to the current state takes precedence and the duplicate instance
will not be
+ * exposed (equivalent to overriding the characteristics of a super-state).
+ *
+ * <p>Triggers are structures that hold a single action (transition or
operation) and
+ * are invoked automatically by a state machine implementation as a part of
initialization
+ * and termination requests. If a trigger contains a transition resulting
that results in
+ * a change to the current state a state-machine will recursively evaluate
triggers in the
+ * new current state path. The process of recursive evaluation of triggers
will continue
+ * until a state is reached where no further trigger invocation is
possible.</p>
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface StateMachine
+{
+ /**
+ * Add a property change listener to the state machine.
+ * @param listener the property change listener
+ */
+ //void addPropertyChangeListener( final PropertyChangeListener listener
);
+
+ /**
+ * Remove a property change listener from the state machine.
+ * @param listener the property change listener
+ */
+ //void removePropertyChangeListener( final PropertyChangeListener
listener );
+
+ /**
+ * Add a state change listener to the state machine.
+ * @param listener the state listener
+ */
+ void addStateListener( final StateListener listener );
+
+ /**
+ * Remove a state listener from the state machine.
+ * @param listener the state listener
+ */
+ void removeStateListener( final StateListener listener );
+
+ /**
+ * Return the current state.
+ * @return the current state
+ */
+ State getState();
+
+ /**
+ * Invoke initialization of the supplied object using the initialization
action
+ * declared under the current state path.
+ *
+ * @param object the object to initialize
+ * @return the state established as a side-effect of initialization
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of initialization
+ */
+ State initialize( Object object ) throws InvocationTargetException;
+
+ /**
+ * Execute a named operation on the supplied object.
+ * @param name an operation name
+ * @param object the target object
+ * @param args operation argument array
+ * @return the return value
+ * @exception UnknownOperationException if the operation is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of operation execution
+ */
+ Object execute( String name, Object object, Object[] args )
+ throws UnknownOperationException, InvocationTargetException;
+
+ /**
+ * Invoke a management method on the supplied object.
+ * @param object the target object
+ * @param method the method name
+ * @param args method parameter arguments
+ * @return the return value
+ * @exception IllegalStateException if the method is recognized but not
available
+ * @exception UnknownOperationException if the operation is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of operation execution
+ */
+ Object invoke( Object object, String method, Object[] args )
+ throws UnknownOperationException, InvocationTargetException,
IllegalStateException;
+
+ /**
+ * Apply a named state transition.
+ * @param name the transition name
+ * @param object the object against which any transition handler action
are to be applied
+ * @return the state established by the application of the transition
+ * @exception UnknownTransitionException if the transition is unknown
+ * @exception InvocationTargetException if an invocation error occurs as
a
+ * result of transition invocation
+ */
+ State apply( String name, Object object )
+ throws UnknownTransitionException, InvocationTargetException;
+
+ /**
+ * Return all of the available transitions relative to the current state.
+ * @return the available transitions
+ */
+ Transition[] getTransitions();
+
+ /**
+ * Return all of the available operations relative to the current state.
+ * @return the available operations
+ */
+ Operation[] getOperations();
+
+ /**
+ * Return all of the available interfaces relative to the current state.
+ * @return the available interface declarations
+ */
+ Interface[] getInterfaces();
+
+ /**
+ * Invoke termination of the supplied object using the termination action
+ * declared under the current state path.
+ *
+ * @param object the object to terminate
+ * @return the state established as a side-effect of the termination
+ */
+ State terminate( Object object );
+
+ /**
+ * Returns the active status of the state machine.
+ * @return TRUE if the state machine has invoked initialization and
+ * termination has not been performed otherwise FALSE
+ */
+ boolean isActive();
+
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/Transition.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/Transition.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/Transition.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,53 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Interface describing a transition that may be performed under an activate
+ * state.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Transition extends Action
+{
+ /**
+ * Set the state that this transition is a part of.
+ * @param state the owning state
+ */
+ void setState( State state );
+
+ /**
+ * Return the state that this transition is a part of.
+ * @return the owning state
+ */
+ State getState();
+
+ /**
+ * Return the transition target state name
+ * @return the target state name
+ */
+ String getTargetName();
+
+ /**
+ * Return an operation associated with the transition.
+ * @return a possibly null operation
+ */
+ Operation getOperation();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/Trigger.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/Trigger.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/Trigger.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,40 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Interface describing a condition within which an action may be invoked.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Trigger
+{
+ /**
+ * Return the event enumneration that this trigger is associated with.
+ * @return the triggering event class
+ */
+ TriggerPolicy getPolicy();
+
+ /**
+ * Return the actions that this trigger initiates.
+ * @return the triggered action
+ */
+ Action getAction();
+}

Added: trunk/main/lang/part/src/main/net/dpml/state/TriggerPolicy.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/TriggerPolicy.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/TriggerPolicy.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,38 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Interface describing a condition within which an action may be invoked.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public enum TriggerPolicy
+{
+ /**
+ * Initialization event emumeration.
+ */
+ INITIALIZATION,
+
+ /**
+ * Termination event emumeration.
+ */
+ TERMINATION;
+}

Added:
trunk/main/lang/part/src/main/net/dpml/state/UnknownOperationException.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/state/UnknownOperationException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/state/UnknownOperationException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,46 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Exception thrown when a request is made for retrival of an operation
+ * via an operation key and the key is unresolvable.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class UnknownOperationException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a new <code>UnknownOperationException</code> instance.
+ *
+ * @param key the operation key
+ */
+ public UnknownOperationException( final String key )
+ {
+ super( key );
+ }
+
+}
+

Added:
trunk/main/lang/part/src/main/net/dpml/state/UnknownTransitionException.java
===================================================================
---
trunk/main/lang/part/src/main/net/dpml/state/UnknownTransitionException.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/main/net/dpml/state/UnknownTransitionException.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,48 @@
+/*
+ * 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 net.dpml.state;
+
+/**
+ * Exception thrown when a request is made to apply a transition that is
unknown
+ * relative to the target state.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class UnknownTransitionException extends Exception
+{
+ /**
+ * Serial version identifier.
+ */
+ static final long serialVersionUID = 1L;
+
+ private String m_transition;
+
+ /**
+ * Construct a new <code>UnknownTransitionException</code> instance.
+ *
+ * @param transition the transition name
+ */
+ public UnknownTransitionException( final String transition )
+ {
+ super( transition );
+ }
+
+}
+

Added: trunk/main/lang/part/src/main/net/dpml/state/package-info.java
===================================================================
--- trunk/main/lang/part/src/main/net/dpml/state/package-info.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/main/net/dpml/state/package-info.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2004-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.
+ */
+
+/**
+ * States, transitons, operations and triggers and a state machine
supporting
+ * orderly management of state transitions and dynamic operations.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+package net.dpml.state;

Added: trunk/main/lang/part/src/test/META-INF/services/org.acme.Gizmo
===================================================================
--- trunk/main/lang/part/src/test/META-INF/services/org.acme.Gizmo
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/META-INF/services/org.acme.Gizmo
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1 @@
+org.acme.GizmoAdapter

Added: trunk/main/lang/part/src/test/META-INF/services/org.acme.Widget
===================================================================
--- trunk/main/lang/part/src/test/META-INF/services/org.acme.Widget
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/META-INF/services/org.acme.Widget
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1 @@
+org.acme.StandaloneWidgetAdapter

Added: trunk/main/lang/part/src/test/Widget.java
===================================================================
--- trunk/main/lang/part/src/test/Widget.java 2007-02-09 01:28:27 UTC (rev
1858)
+++ trunk/main/lang/part/src/test/Widget.java 2007-02-09 01:29:45 UTC (rev
1859)
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+
+/**
+ * Sample object used in test case.
+ */
+public class Widget
+{
+}
\ No newline at end of file

Added: trunk/main/lang/part/src/test/dpml/lang/AbstractTestCase.java
===================================================================
--- trunk/main/lang/part/src/test/dpml/lang/AbstractTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/dpml/lang/AbstractTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2005-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 dpml.lang;
+
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+
+import junit.framework.TestCase;
+
+/**
+ * AbstractEncodingTestCase.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public abstract class AbstractTestCase extends TestCase
+{
+ /**
+ * Utility operation to encode and decode an supplied object using an
intermidiate file.
+ * @param object the object to enciode
+ * @return the result of decoding the encoded structure
+ * @exception Exception if an error occurs
+ */
+ public Object executeEncodingTest( Object object ) throws Exception
+ {
+ ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
+ ObjectOutputStream output = new ObjectOutputStream( byteOutputStream
);
+ output.writeObject( object );
+ output.close();
+
+ ByteArrayInputStream byteInputStream = new ByteArrayInputStream(
byteOutputStream.toByteArray() );
+ ObjectInputStream input = new ObjectInputStream( byteInputStream );
+ Object serialized = input.readObject();
+ input.close();
+
+ assertTrue( "!=", object != serialized ); // Ensure this is not the
same instance
+ assertEquals( "equals", object, serialized );
+ assertEquals( "hash", object.hashCode(), serialized.hashCode() );
+
+ return serialized;
+ }
+
+}

Added: trunk/main/lang/part/src/test/dpml/lang/ConstructTestCase.java
===================================================================
--- trunk/main/lang/part/src/test/dpml/lang/ConstructTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/dpml/lang/ConstructTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2004-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 dpml.lang;
+
+import java.awt.Color;
+import java.io.File;
+import java.util.Date;
+import java.util.Map;
+import java.util.Hashtable;
+import java.util.Arrays;
+
+import dpml.lang.Value;
+
+/**
+ * Construct testcase.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ConstructTestCase extends AbstractTestCase
+{
+ public void setUp()
+ {
+ ClassLoader loader = ConstructTestCase.class.getClassLoader();
+ Thread.currentThread().setContextClassLoader( loader );
+ }
+
+ /**
+ * Test creation of a simple construct.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testSimpleConstruct() throws Exception
+ {
+ Construct construct = new Construct( "fred" );
+ Object value = construct.resolve();
+ if( null == value )
+ {
+ throw new NullPointerException( "value" );
+ }
+ assertEquals( "isa-string", value.getClass(), String.class );
+ assertEquals( "simple construct value", value, "fred" );
+ }
+
+ /**
+ * Test creation of a construct using a null value.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testNullArgConstruct() throws Exception
+ {
+ Construct construct = new Construct( Date.class.getName(), (String)
null );
+ Object value = construct.resolve();
+ assertEquals( "isa-data", value.getClass(), Date.class );
+ }
+
+ /**
+ * Test creation of a construct using a primitive type.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testPrimitiveConstruct() throws Exception
+ {
+ Construct construct = new Construct( "int", "10" );
+ ClassLoader cl = ConstructTestCase.class.getClassLoader();
+ Object value = construct.resolve();
+ assertEquals( "isa-Integer", Integer.class, value.getClass() );
+ }
+
+ /**
+ * Test creation of a construct using a single typed argument.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testSingleArgConstruct() throws Exception
+ {
+ Construct construct = new Construct( File.class.getName(), "abc" );
+ Object value = construct.resolve();
+ assertEquals( "isa-file", value.getClass(), File.class );
+ assertEquals( "file", value, new File( "abc" ) );
+ }
+
+ /**
+ * Test creation of a construct using a multiple primitate arguments.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testPrimitiveMultiArgConstruct() throws Exception
+ {
+ Value a = new Construct( "int", "100" );
+ Value b = new Construct( "boolean", "true" );
+ Value c = new Construct( Context2.class.getName(), new Value[]{a, b}
);
+ Object value = c.resolve();
+ assertEquals( "isa-context", value.getClass(), Context2.class );
+ Context2 context = (Context2) value;
+ if( !( context.getNumber() == 100 ) )
+ {
+ System.out.println( "# number: " + context.getNumber() );
+ fail( "context2 number return value is not 100" );
+ }
+ if( !context.getLogical() )
+ {
+ System.out.println( "# logical: " + context.getLogical() );
+ fail( "context2 logical return value is not 'true'" );
+ }
+ }
+
+ /**
+ * Test creation of a construct using a static method operator.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testStaticMethod() throws Exception
+ {
+ Value v = new Construct( Context2.class.getName(), "create", new
Value[0] );
+ Object value = v.resolve();
+ assertEquals( "isa-context", value.getClass(), Context2.class );
+ Context2 context = (Context2) value;
+ if( !( context.getNumber() == 100 ) )
+ {
+ System.out.println( "# number: " + context.getNumber() );
+ fail( "context2 number return value is not 100" );
+ }
+ if( !context.getLogical() )
+ {
+ System.out.println( "# logical: " + context.getLogical() );
+ fail( "context2 logical return value is not 'true'" );
+ }
+ }
+
+ /**
+ * Test creation of a construct using a static field operator.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testStaticField() throws Exception
+ {
+ Value v = new Construct( Color.class.getName(), "RED", (String) null
);
+ Object value = v.resolve();
+ assertEquals( "color", Color.RED, value );
+ }
+
+ /**
+ * Test creation of a composite construct using a static field operator.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testStaticFieldInComposite() throws Exception
+ {
+ Value v = new Construct( Color.class.getName(), "RED", new Value[0]
);
+ Object value = v.resolve();
+ assertEquals( "color", Color.RED, value );
+ }
+
+ /**
+ * Test creation of a construct using a symbolic reference.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testSymbolicReference() throws Exception
+ {
+ Map<String, Object> map = new Hashtable<String, Object>();
+ File file = new File( "somewhere" );
+ map.put( "test", file );
+ Value construct = new Construct( "${test}" );
+ Object value = construct.resolve( map );
+ assertEquals( "value", file, value );
+ }
+
+ /**
+ * Test creation of a construct using a typed symbolic reference.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testTypedSymbolicReference() throws Exception
+ {
+ Map<String, Object> map = new Hashtable<String, Object>();
+ map.put( "number", new Integer( 100 ) );
+ map.put( "logical", new Boolean( true ) );
+
+ Value number = new Construct( "int", "${number}" );
+ Value logical = new Construct( "boolean", "${logical}" );
+ Value construct = new Construct( Context2.class.getName(), new
Value[]{number, logical} );
+ Object value = construct.resolve( map );
+
+ assertEquals( "isa-context", value.getClass(), Context2.class );
+ Context2 context = (Context2) value;
+ if( !( context.getNumber() == 100 ) )
+ {
+ System.out.println( "# number: " + context.getNumber() );
+ fail( "context2 number return value is not 100" );
+ }
+ if( !context.getLogical() )
+ {
+ System.out.println( "# logical: " + context.getLogical() );
+ fail( "context2 logical return value is not true" );
+ }
+ }
+
+ /**
+ * Test array return type.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testSimpleArray() throws Exception
+ {
+ String[] args = new String[]{"aaa", "bbb"};
+ Value s1 = new Construct( "aaa" );
+ Value s2 = new Construct( "bbb" );
+ Value construct = new Construct( args.getClass().getName(), new
Value[]{s1, s2} );
+ String[] result = (String[]) construct.resolve();
+ boolean equal = Arrays.equals( args, result );
+ assertTrue( "simple-array", equal );
+ }
+
+ /**
+ * Test array with zero entries.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testZeroLengthArray() throws Exception
+ {
+ String[] args = new String[0];
+ Value construct = new Construct( args.getClass().getName(), new
Value[0] );
+ String[] result = (String[]) construct.resolve();
+ boolean equal = Arrays.equals( args, result );
+ assertTrue( "zero-length-array", equal );
+ }
+
+ /**
+ * Test creation of a simple construct.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testArrayAsCompositeArgument() throws Exception
+ {
+ Construct a = new Construct( "Hello " );
+ Construct b = new Construct( "World!" );
+ Construct array = new Construct( String[].class.getName(), new
Value[]{a, b} );
+ Construct construct = new Construct( Demo.class.getName(), new
Value[]{array} );
+ Demo demo = (Demo) construct.resolve();
+ assertNotNull( "demo", demo );
+ }
+
+ /**
+ * Test creation of a simple construct.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testPrimitiveArray() throws Exception
+ {
+ int[] args = new int[]{1, 2, 3};
+ Value p1 = new Construct( "int", "1" );
+ Value p2 = new Construct( "int", "2" );
+ Value p3 = new Construct( "int", "3" );
+ Value construct = new Construct( "int[]", new Value[]{p1, p2, p3} );
+ Object result = construct.resolve();
+ int[] array = (int[]) construct.resolve();
+ boolean equal = Arrays.equals( args, array );
+ assertTrue( "primitive-array", equal );
+ }
+
+ /**
+ * Test construct encoding.
+ * @exception Exception if an unexpected error occurs.
+ */
+ public void testEncoding() throws Exception
+ {
+ Value number = new Construct( "int", "${number}" );
+ Value logical = new Construct( "boolean", "${logical}" );
+ Value construct = new Construct( Context2.class.getName(), new
Value[]{number, logical} );
+ Value result = (Value) executeEncodingTest( construct );
+ assertEquals( "encoding", construct, result );
+ }
+
+ /**
+ * Test class.
+ */
+ public static class Demo
+ {
+ /**
+ * Create a new demo class.
+ * @param args the args
+ */
+ public Demo( String[] args )
+ {
+ for( int i=0; i<args.length; i++ )
+ {
+ System.out.print( args[i] );
+ }
+ System.out.println( "" );
+ }
+ }
+
+ /**
+ * Mock class.
+ */
+ public static class Context
+ {
+ private File m_a;
+ private File m_b;
+
+ /**
+ * Creation of a mock composite argument object.
+ * @param a the primary argument
+ * @param b the secondary argument
+ */
+ public Context( File a, File b )
+ {
+ m_a = a;
+ m_b = b;
+ }
+
+ /**
+ * Return the primary argument.
+ * @return the primary argument value
+ */
+ public File getA()
+ {
+ return m_a;
+ }
+
+ /**
+ * Return the secondary argument.
+ * @return the secondary argument value
+ */
+ public File getB()
+ {
+ return m_b;
+ }
+ }
+
+ /**
+ * Another mock class.
+ */
+ public static class Context2
+ {
+ private int m_number;
+ private boolean m_logical;
+
+ /**
+ * Static constructor method.
+ * @return an instance
+ */
+ public static Context2 create()
+ {
+ return new Context2( 100, true );
+ }
+
+ /**
+ * Creation of a mock object using primiative arguments.
+ * @param number a primitive number
+ * @param logical a boolean value
+ */
+ public Context2( int number, boolean logical )
+ {
+ m_number = number;
+ m_logical = logical;
+ }
+
+ /**
+ * Return the number.
+ * @return the number
+ */
+ public int getNumber()
+ {
+ return m_number;
+ }
+
+ /**
+ * Return the boolean.
+ * @return the boolean
+ */
+ public boolean getLogical()
+ {
+ return m_logical;
+ }
+ }
+}

Added: trunk/main/lang/part/src/test/dpml/lang/ContextTestCase.java
===================================================================
--- trunk/main/lang/part/src/test/dpml/lang/ContextTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/dpml/lang/ContextTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2004-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 dpml.lang;
+
+import java.awt.Color;
+import java.net.URI;
+import java.util.Hashtable;
+import java.util.HashMap;
+
+import junit.framework.TestCase;
+
+//import net.dpml.lang.Plugin;
+import net.dpml.lang.ServiceRegistry;
+import net.dpml.lang.SimpleServiceRegistry;
+
+import org.acme.Sample;
+import org.acme.Sample.Context;
+import org.acme.Sample.AnotherContext;
+import org.acme.Sample.Negation;
+
+/**
+ * Context test case.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ContextTestCase extends TestCase
+{
+ /**
+ * Test the isaContext implementation for strict evaluation
+ * of the org.acme.Sample.Context class.
+ * @exception Exception if a test error occurs
+ */
+ public void testIsaContextUsingStrictAssessment() throws Exception
+ {
+ boolean foo = ContextInvocationHandler.isaContext( Context.class,
true );
+ assertEquals( "isa-context", false, foo );
+ }
+
+ /**
+ * Test the isaContext implementation for non-strict evaluation
+ * of the org.acme.Sample.Context class.
+ * @exception Exception if a test error occurs
+ */
+ public void testIsaContextUsingLegacyAssessment() throws Exception
+ {
+ boolean foo = ContextInvocationHandler.isaContext( Context.class,
false );
+ assertEquals( "isa-context", true, foo );
+ }
+
+ /**
+ * Test the isaContext implementation for negation using the
+ * org.acme.Sample.Negation.Context class.
+ * @exception Exception if a test error occurs
+ */
+ public void testIsaContextNegation() throws Exception
+ {
+ boolean foo = ContextInvocationHandler.isaContext(
Negation.Context.class, true );
+ assertEquals( "isa-context-negation", false, foo );
+ }
+
+ /**
+ * Test missing context entry detection.
+ * @exception Exception if a test error occurs
+ */
+ public void testMissingRequiredEntry() throws Exception
+ {
+ try
+ {
+ Hashtable<String,Object > map = new Hashtable<String,Object>();
+ ContextInvocationHandler.validate( Context.class, map );
+ fail( "Did not throw IllegalArgumentException for missing key
'message'." );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ /**
+ * Test null value for an entry detection.
+ * @exception Exception if a test error occurs
+ */
+ public void testNullEntryValue() throws Exception
+ {
+ try
+ {
+ HashMap<String,Object> map = new HashMap< String,Object>();
+ map.put( "message", null );
+ ContextInvocationHandler.validate( Context.class, map );
+ fail( "Did not throw IllegalArgumentException for null value" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ /**
+ * Test missing required entry detection.
+ * @exception Exception if a test error occurs
+ */
+ public void testSimpleRequiredEntry() throws Exception
+ {
+ Hashtable<String,Object> map = new Hashtable<String,Object>();
+ map.put( "message", MESSAGE );
+ Context context =
+ ContextInvocationHandler.getProxiedInstance( Context.class, map );
+ assertEquals( "message", MESSAGE, context.getMessage() );
+ }
+
+ /**
+ * Test optional entry processing.
+ * @exception Exception if a test error occurs
+ */
+ public void testSimpleOptionalEntry() throws Exception
+ {
+ Hashtable<String,Object> map = new Hashtable<String,Object>();
+ map.put( "message", MESSAGE );
+ map.put( "resourceURI", RESOURCE );
+ Context context =
+ ContextInvocationHandler.getProxiedInstance( Context.class, map );
+ assertEquals( "resourceURI", RESOURCE, context.getResourceURI( null
) );
+ }
+
+ /**
+ * Test compound optional entry processing.
+ * @exception Exception if a test error occurs
+ */
+ public void testCompoundOptionalEntry() throws Exception
+ {
+ Hashtable<String,Object> external = new Hashtable<String,Object>();
+ external.put( "color", Color.RED );
+ Hashtable<String,Object> map = new Hashtable<String,Object>();
+ map.put( "message", MESSAGE );
+ map.put( "external", external );
+ Context context =
+ ContextInvocationHandler.getProxiedInstance( Context.class, map );
+ AnotherContext ext = context.getExternal( null );
+ assertEquals( "color", Color.RED, ext.getColor( null ) );
+ }
+
+ /**
+ * Test instantiation of a class referencing a context parameter.
+ * @exception Exception if a test error occurs
+ */
+ //public void testPluginInstantiation() throws Exception
+ //{
+ // Hashtable<String,Object> external = new Hashtable<String,Object>();
+ // external.put( "color", Color.RED );
+ // Hashtable<String,Object> map = new Hashtable<String,Object>();
+ // map.put( "message", MESSAGE );
+ // map.put( "resourceURI", RESOURCE );
+ // map.put( "external", external );
+ // Context context =
+ // ContextInvocationHandler.getProxiedInstance( Context.class, map
);
+ // ServiceRegistry registry = new SimpleServiceRegistry( context );
+ // Plugin plugin = new Plugin( Sample.class );
+ // plugin.initialize( registry );
+ // Sample sample = plugin.getInstance( Sample.class );
+ //}
+
+ private static final String MESSAGE = "Hello.";
+ private static final URI RESOURCE = setupURI();
+
+ private static URI setupURI()
+ {
+ try
+ {
+ return
ContextTestCase.class.getProtectionDomain().getCodeSource().getLocation().toURI();
+ }
+ catch( Throwable e )
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}

Added: trunk/main/lang/part/src/test/net/dpml/runtime/AbstractTestCase.java
===================================================================
--- trunk/main/lang/part/src/test/net/dpml/runtime/AbstractTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/net/dpml/runtime/AbstractTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,64 @@
+/*
+ * 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.runtime;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import net.dpml.lang.Strategy;
+import net.dpml.lang.TypeCastException;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class AbstractTestCase extends TestCase
+{
+ static
+ {
+ System.setProperty(
+ "handler:dpml:metro",
+ "net.dpml.runtime.ComponentStrategyHandler" );
+ }
+
+ protected <T>T load( Class<T> type, String path ) throws Exception
+ {
+ return load( type, path, null );
+ }
+
+ protected <T>T load( Class<T> type, String path, String name ) throws
Exception
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ File dir = new File( System.getProperty( "project.test.dir" ) );
+ File file = new File( dir, path );
+ try
+ {
+ Strategy strategy = Strategy.load( classloader, null,
file.toURI(), name );
+ return strategy.getContentForClass( type );
+ }
+ catch( TypeCastException e )
+ {
+ String report = e.getReport();
+ System.out.println( report );
+ throw e;
+ }
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/composition/CompositeTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/composition/CompositeTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/composition/CompositeTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,39 @@
+/*
+ * 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.runtime.composition;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.CompositeComponent;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class CompositeTestCase extends AbstractTestCase
+{
+ public void testComponent() throws Exception
+ {
+ CompositeComponent component =
+ load( CompositeComponent.class, "composite.xml", "composite" );
+ assertNotNull( "widget", component.getParts().getWidget() );
+ assertNotNull( "gizmo", component.getParts().getGizmo() );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/composition/ControllerTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/composition/ControllerTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/composition/ControllerTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,40 @@
+/*
+ * 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.runtime.composition;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.ControllerComponent;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ControllerTestCase extends AbstractTestCase
+{
+ public void testComponent() throws Exception
+ {
+ ControllerComponent component =
+ load( ControllerComponent.class, "controller.xml", "controller" );
+
+ assertNotNull( "widget", component.getParts().getWidget() );
+ assertNotNull( "gizmo", component.getParts().getGizmo() );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/composition/GenericTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/composition/GenericTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/composition/GenericTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,56 @@
+/*
+ * 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.runtime.composition;
+
+import java.awt.Color;
+import java.io.File;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import net.dpml.runtime.Provider;
+import net.dpml.runtime.Component;
+
+import org.acme.Widget;
+import org.acme.Gizmo;
+import org.acme.GenericComponent;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class GenericTestCase extends AbstractTestCase
+{
+ public void testComponent() throws Exception
+ {
+ GenericComponent component =
+ load( GenericComponent.class, "generics.xml", "generic" );
+
+ assertNotNull( "widget", component.getParts().getWidget(
Provider.class ) );
+ assertNotNull( "gizmo", component.getParts().getGizmo(
Component.class ) );
+ Component c = component.getParts().getWidget( Component.class );
+ Provider provider = c.getProvider();
+ Widget w1 = provider.getInstance( Widget.class );
+ Widget w2 = component.getParts().getWidget( Widget.class );
+ assertEquals( "equality", w1, w2 );
+ Gizmo gizmo = component.getParts().getGizmo( Gizmo.class );
+ int number = gizmo.getNumber();
+ assertEquals( "gizmo", 42, number );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/composition/LookupTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/composition/LookupTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/composition/LookupTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,40 @@
+/*
+ * 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.runtime.composition;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.CompositeComponent;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class LookupTestCase extends AbstractTestCase
+{
+ public void testComponent() throws Exception
+ {
+ CompositeComponent component =
+ load( CompositeComponent.class, "lookup.xml", "lookup" );
+
+ assertNotNull( "widget", component.getParts().getWidget() );
+ assertNotNull( "gizmo", component.getParts().getGizmo() );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/composition/SelectTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/composition/SelectTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/composition/SelectTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,70 @@
+/*
+ * 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.runtime.composition;
+
+import net.dpml.runtime.Provider;
+import net.dpml.runtime.Component;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.SelectComponent;
+import org.acme.Widget;
+import org.acme.Gizmo;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class SelectTestCase extends AbstractTestCase
+{
+ public void testSelectionByServiceReturnType() throws Exception
+ {
+ SelectComponent.Parts parts = getParts();
+ Widget[] widgets = parts.getWidgets();
+ assertEquals( "size-widget", 2, widgets.length );
+ }
+
+ public void testSelectionByServiceCriteria() throws Exception
+ {
+ SelectComponent.Parts parts = getParts();
+ Provider[] providers = parts.getProviders( Widget.class );
+ assertEquals( "size-providers", 2, providers.length );
+ Component[] components = parts.getComponents( Widget.class );
+ assertEquals( "size-providers", 2, components.length );
+ Component[] gizmos = parts.getComponents( Gizmo.class );
+ assertEquals( "gizmos", 1, gizmos.length );
+ Provider[] gizmoProviders = parts.getProviders( Gizmo.class );
+ assertEquals( "gizmo-providers", 1, gizmoProviders.length );
+ }
+
+ public void testAllSelectionCriteria() throws Exception
+ {
+ SelectComponent.Parts parts = getParts();
+ Component[] all = parts.getAllComponents();
+ assertEquals( "size-all", 3, all.length );
+ }
+
+ private SelectComponent.Parts getParts() throws Exception
+ {
+ SelectComponent component =
+ load( SelectComponent.class, "select.xml", "select" );
+ return component.getParts();
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/context/ArrayTestCase.java
===================================================================
--- trunk/main/lang/part/src/test/net/dpml/runtime/context/ArrayTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/net/dpml/runtime/context/ArrayTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,47 @@
+/*
+ * 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.runtime.context;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.ArrayWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ArrayTestCase extends AbstractTestCase
+{
+ public void testEquality() throws Exception
+ {
+ ArrayWidget widget =
+ load( ArrayWidget.class, "array.xml", "array" );
+
+ char[] chars = new char[]{ 'h','e','l','l','o'};
+ char[] result = widget.getContext().getMessage();
+ assertEquals( "length", chars.length, result.length );
+ for( int i=0; i<chars.length; i++ )
+ {
+ String assertion = "character-" + i;
+ assertEquals( assertion, chars[i], result[i] );
+ }
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/context/ContextualTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/context/ContextualTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/context/ContextualTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,48 @@
+/*
+ * 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.runtime.context;
+
+import java.awt.Color;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.ContextualWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ContextualTestCase extends AbstractTestCase
+{
+ public void testEquality() throws Exception
+ {
+ ContextualWidget widget =
+ load( ContextualWidget.class, "contextual.xml", "contextual" );
+
+ assertEquals( "message", "Batman", widget.getMessage() );
+ assertEquals( "primary", Color.RED, widget.getPrimary() );
+ assertEquals( "secondary", Color.BLUE, widget.getSecondary() );
+ assertEquals( "numbers.length", 3, widget.getNumbers().length );
+ assertEquals( "numbers[0]", 1, widget.getNumbers()[0] );
+ assertEquals( "numbers[1]", 2, widget.getNumbers()[1] );
+ assertEquals( "numbers[2]", 3, widget.getNumbers()[2] );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/isolation/SampleTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/isolation/SampleTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/isolation/SampleTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,57 @@
+/*
+ * 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.runtime.isolation;
+
+import java.lang.reflect.Proxy;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import org.acme.DefaultWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class SampleTestCase extends AbstractTestCase
+{
+ public void testNormalUsage() throws Exception
+ {
+ Widget widget =
+ load( Widget.class, "component.xml", "normal" );
+
+ String message = widget.getMessage();
+ assertEquals( "message", "Hello", message );
+ }
+
+ public void testNoIsolation() throws Exception
+ {
+ Widget widget =
+ load( DefaultWidget.class, "component.xml", "isolation" );
+ assertFalse( "isa-proxy", Proxy.isProxyClass( widget.getClass() ) );
+ }
+
+ public void testWithIsolation() throws Exception
+ {
+ Widget widget =
+ load( Widget.class, "component.xml", "no-isolation" );
+ assertTrue( "isa-proxy", Proxy.isProxyClass( widget.getClass() ) );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/lifecycle/StateTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/lifecycle/StateTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/lifecycle/StateTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,48 @@
+/*
+ * 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.runtime.lifecycle;
+
+import java.util.concurrent.TimeUnit;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import net.dpml.runtime.Component;
+import net.dpml.runtime.Provider;
+
+import org.acme.StateWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StateTestCase extends AbstractTestCase
+{
+ public void testLifecycle() throws Exception
+ {
+ Component component = load( Component.class, "state.xml", "state" );
+ Provider provider = component.getProvider();
+ StateWidget widget = provider.getInstance( StateWidget.class );
+ assertEquals( "started", 1, widget.getState() );
+ component.release( provider );
+ component.terminate();
+ assertEquals( "stopped", 2, widget.getState() );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/SingletonTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/SingletonTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/SingletonTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,42 @@
+/*
+ * 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.runtime.lifestyle;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import net.dpml.runtime.Component;
+
+import org.acme.SingletonWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class SingletonTestCase extends AbstractTestCase
+{
+ public void testEquality() throws Exception
+ {
+ Component component = load( Component.class, "singleton.xml",
"singleton" );
+ Widget w1 = component.getProvider().getInstance(
SingletonWidget.class );
+ Widget w2 = component.getProvider().getInstance(
SingletonWidget.class );
+ assertEquals( "equality", w1, w2 );
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/TransientTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/TransientTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/lifestyle/TransientTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,45 @@
+/*
+ * 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.runtime.lifestyle;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import net.dpml.runtime.Component;
+
+import org.acme.DefaultWidget;
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class TransientTestCase extends AbstractTestCase
+{
+ public void testEquality() throws Exception
+ {
+ Component component = load( Component.class, "transient.xml",
"transient" );
+ Widget w1 = component.getProvider().getInstance( DefaultWidget.class
);
+ Widget w2 = component.getProvider().getInstance( DefaultWidget.class
);
+ if( w1 == w2 )
+ {
+ fail( "transients" );
+ }
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/profile/ProfileTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/profile/ProfileTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/profile/ProfileTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -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.runtime.profile;
+
+import java.util.ServiceLoader;
+
+import junit.framework.TestCase;
+
+import org.acme.Widget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ProfileTestCase extends TestCase
+{
+ public void testServiceLoading() throws Exception
+ {
+ Widget widget = getWidget();
+ assertNotNull( "widget", widget );
+ String message = widget.getMessage();
+ assertEquals( "message", "Batman", message );
+ }
+
+ public Widget getWidget() throws Exception
+ {
+ ServiceLoader<Widget> loaders = ServiceLoader.load( Widget.class );
+ for( Widget widget : loaders )
+ {
+ return widget;
+ }
+ return null;
+ }
+}

Added:
trunk/main/lang/part/src/test/net/dpml/runtime/service/ForeignTestCase.java
===================================================================
---
trunk/main/lang/part/src/test/net/dpml/runtime/service/ForeignTestCase.java
2007-02-09 01:28:27 UTC (rev 1858)
+++
trunk/main/lang/part/src/test/net/dpml/runtime/service/ForeignTestCase.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,47 @@
+/*
+ * 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.runtime.service;
+
+import net.dpml.runtime.AbstractTestCase;
+
+import net.dpml.lang.Strategy;
+
+import org.acme.Widget;
+import org.acme.ForeignWidget;
+
+/**
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ForeignTestCase extends AbstractTestCase
+{
+ public void testComponentViaPart() throws Exception
+ {
+ Widget widget = load( Widget.class, "foreign.xml", "foreign" );
+ assertEquals( "message", "42", widget.getMessage() );
+ }
+
+ public void testComponentViaClass() throws Exception
+ {
+ Strategy strategy = Strategy.load( ForeignWidget.class, null,
"foreign" );
+ Widget widget = strategy.getContentForClass( Widget.class );
+ assertEquals( "message", "42", widget.getMessage() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/ArrayWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/ArrayWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/ArrayWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Services;
+
+import net.dpml.util.Logger;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ArrayWidget implements Widget
+{
+ public interface Context
+ {
+ char[] getMessage();
+ }
+
+ private Context m_context;
+
+ public ArrayWidget( Logger logger, Context context )
+ {
+ m_context = context;
+ logger.info( getMessage() );
+ }
+
+ public String getMessage()
+ {
+ return new String( m_context.getMessage() );
+ }
+
+ public Context getContext()
+ {
+ return m_context;
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/CompositeComponent.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/CompositeComponent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/CompositeComponent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.util.Logger;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class CompositeComponent
+{
+ public interface Parts
+ {
+ Widget getWidget();
+ Gizmo getGizmo();
+ }
+
+ private final Parts m_parts;
+
+ public CompositeComponent( Logger logger, Parts parts )
+ {
+ logger.info( "instantiated" );
+ m_parts = parts;
+ }
+
+ public Parts getParts()
+ {
+ return m_parts;
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/ContextualWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/ContextualWidget.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/ContextualWidget.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.awt.Color;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import net.dpml.util.Logger;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component
+@Services( Widget.class )
+public class ContextualWidget implements Widget
+{
+ public interface Context
+ {
+ String getMessage( String value );
+ ColorManager getColors();
+ int[] getNumbers();
+ }
+
+ private final Context m_context;
+
+ public ContextualWidget( Logger logger, Context context )
+ {
+ logger.info( "instantiated" );
+ m_context = context;
+ }
+
+ public String getMessage()
+ {
+ return m_context.getMessage( "Hello" );
+ }
+
+ public Color getPrimary()
+ {
+ return m_context.getColors().getPrimary();
+ }
+
+ public Color getSecondary()
+ {
+ return m_context.getColors().getSecondary();
+ }
+
+ public int[] getNumbers()
+ {
+ return m_context.getNumbers();
+ }
+
+ @net.dpml.annotation.Context
+ public interface ColorManager
+ {
+ Color getPrimary();
+ Color getSecondary();
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/ControllerComponent.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/ControllerComponent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/ControllerComponent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Parts;
+
+import net.dpml.runtime.Component;
+import net.dpml.runtime.Provider;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class ControllerComponent
+{
+ @Parts
+ public interface ControllerParts
+ {
+ Component getWidget();
+ Provider getGizmo();
+ }
+
+ private final ControllerParts m_parts;
+
+ public ControllerComponent( ControllerParts parts )
+ {
+ m_parts = parts;
+ }
+
+ public ControllerParts getParts() // for testcase
+ {
+ return m_parts;
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/DefaultGizmo.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/DefaultGizmo.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/DefaultGizmo.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.util.Logger;
+
+/**
+ * Sample plugin-based implementation of a gizmo.
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class DefaultGizmo implements Gizmo
+{
+ private final Logger m_logger;
+
+ public DefaultGizmo( Logger logger )
+ {
+ m_logger = logger;
+ m_logger.info( "instantiated" );
+ }
+
+ public int getNumber()
+ {
+ return 42;
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/DefaultWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/DefaultWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/DefaultWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Services;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Services( Widget.class )
+public class DefaultWidget implements Widget
+{
+ public String getMessage()
+ {
+ return "Hello";
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/ForeignWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/ForeignWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/ForeignWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.awt.Color;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component( name="foreign" )
+@Services( Widget.class )
+public class ForeignWidget implements Widget
+{
+ private final Gizmo m_gizmo;
+
+ public ForeignWidget( final Logger logger, final Gizmo gizmo )
+ {
+ logger.info( "instantiated" );
+ m_gizmo = gizmo;
+ logger.info( getMessage() );
+ }
+
+ public String getMessage()
+ {
+ return "" + m_gizmo.getNumber();
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/GenericComponent.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/GenericComponent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/GenericComponent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Parts;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class GenericComponent
+{
+ @Parts
+ public interface GenericParts
+ {
+ <T>T getWidget( Class<T> type );
+ <T>T getGizmo( Class<T> type );
+ }
+
+ private final GenericParts m_parts;
+
+ public GenericComponent( GenericParts parts )
+ {
+ m_parts = parts;
+ }
+
+ public GenericParts getParts()
+ {
+ return m_parts;
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/Gizmo.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/Gizmo.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/Gizmo.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Gizmo
+{
+ int getNumber();
+}

Added: trunk/main/lang/part/src/test/org/acme/GizmoAdapter.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/GizmoAdapter.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/GizmoAdapter.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.lang.Strategy;
+
+import net.dpml.runtime.ComponentError;
+import net.dpml.runtime.ComponentStrategyHandler;
+
+/**
+ * Example of a component that is declared as a service (via
META=INF/services)
+ * while actual deployment is handled via net.dpml.runtime.ComponentStrategy.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class GizmoAdapter implements Gizmo
+{
+ private Gizmo m_delegate;
+
+ public int getNumber()
+ {
+ return getDelegate().getNumber();
+ }
+
+ private Gizmo getDelegate()
+ {
+ if( null == m_delegate )
+ {
+ m_delegate = createDelegate();
+ }
+ return m_delegate;
+ }
+
+ private Gizmo createDelegate()
+ {
+ try
+ {
+ Strategy strategy = Strategy.load( DefaultGizmo.class, null,
"gizmo" );
+ return strategy.getInstance( Gizmo.class );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Error in gizmo adapter delegate establishment.";
+ throw new ComponentError( error, e );
+ }
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/Parameterizable.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/Parameterizable.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/Parameterizable.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,49 @@
+/*
+ * 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 org.acme;
+
+import java.net.URI;
+import java.awt.Color;
+
+/**
+ * Sample object used in test case. Contains a number of inner context
classes
+ * used to evaluate strict and non-strict context evaluation strategies and
+ * general part instantiation.
+ */
+public class Parameterizable
+{
+ private String m_name;
+ private int m_id;
+
+ public Parameterizable( String name, int id )
+ {
+ m_name = name;
+ m_id = id;
+ }
+
+ public String getName()
+ {
+ return m_name;
+ }
+
+ public int getID()
+ {
+ return m_id;
+ }
+}
\ No newline at end of file

Added: trunk/main/lang/part/src/test/org/acme/Sample.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/Sample.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/Sample.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,99 @@
+/*
+ * 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 org.acme;
+
+import java.net.URI;
+import java.awt.Color;
+
+/**
+ * Sample object used in test case. Contains a number of inner context
classes
+ * used to evaluate strict and non-strict context evaluation strategies and
+ * general part instantiation.
+ */
+public class Sample
+{
+ /**
+ * Traditional context interface definition with a nested context
+ * interface as a return type and parameter to one of the entries.
+ */
+ public interface Context
+ {
+ /**
+ * @return a message
+ */
+ String getMessage();
+
+ /**
+ * @param uri the default value
+ * @return a uri
+ */
+ URI getResourceURI( URI uri );
+
+ /**
+ * @param value the default value
+ * @return a nested context object
+ */
+ AnotherContext getExternal( AnotherContext value );
+ }
+
+ /**
+ * A context defintion declared as a context using the <tt>ContextDef</tt>
+ * annotation.
+ */
+ @net.dpml.annotation.Context
+ public interface AnotherContext
+ {
+ /**
+ * @param color the default value
+ * @return a color
+ */
+ Color getColor( Color color );
+ }
+
+ /**
+ * Constructor that takes a single context argument as the initial state.
+ * @param context a classic context instance
+ */
+ public Sample( Context context )
+ {
+ System.out.println( " message: " + context.getMessage() );
+ System.out.println( " resourceURI: " + context.getResourceURI( null
) );
+ AnotherContext external = context.getExternal( null );
+ if( null != external )
+ {
+ System.out.println( " external.color: " + external.getColor(
null ) );
+ }
+ }
+
+ /**
+ * Internal class used to validate that a inner context interface
+ * marked as non-a-context using the <tt>ContextDef</tt> annotion is
+ * correctly recognized as such.
+ */
+ public static class Negation
+ {
+ /**
+ * A non-context interface that happens to be named Context.
+ */
+ @net.dpml.annotation.Context( false )
+ public interface Context
+ {
+ }
+ }
+}
\ No newline at end of file

Added: trunk/main/lang/part/src/test/org/acme/SelectComponent.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/SelectComponent.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/SelectComponent.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.util.List;
+
+import net.dpml.util.Logger;
+
+import net.dpml.runtime.Component;
+import net.dpml.runtime.Provider;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class SelectComponent
+{
+ public interface Parts
+ {
+ Widget[] getWidgets();
+ Provider[] getProviders( Class type );
+ Component[] getComponents( Class type );
+ Component[] getAllComponents();
+ }
+
+ private final Parts m_parts;
+
+ public SelectComponent( Logger logger, Parts parts )
+ {
+ logger.info( "instantiated" );
+ m_parts = parts;
+ }
+
+ public Parts getParts()
+ {
+ return m_parts;
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/SingletonWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/SingletonWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/SingletonWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import static net.dpml.annotation.LifestylePolicy.SINGLETON;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Services( Widget.class )
+@Component( name="widget", lifestyle=SINGLETON )
+public class SingletonWidget extends DefaultWidget
+{
+}

Added: trunk/main/lang/part/src/test/org/acme/StandaloneWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/StandaloneWidget.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/StandaloneWidget.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.awt.Color;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import net.dpml.util.Logger;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component
+@Services( Widget.class )
+public class StandaloneWidget implements Widget
+{
+ public interface Context
+ {
+ String getMessage( String value );
+ ColorManager getColors();
+ int[] getNumbers();
+ }
+
+ private final Context m_context;
+
+ public StandaloneWidget( Logger logger, Context context )
+ {
+ logger.info( "instantiated" );
+ logger.info( "message: " + context.getMessage( null ) );
+ logger.info( "colors: " + context.getColors() );
+ for( int n : context.getNumbers() )
+ {
+ logger.info( " " + n );
+ }
+ m_context = context;
+ }
+
+ public String getMessage()
+ {
+ return m_context.getMessage( "Hello" );
+ }
+
+ public Color getPrimary()
+ {
+ return m_context.getColors().getPrimary();
+ }
+
+ public Color getSecondary()
+ {
+ return m_context.getColors().getSecondary();
+ }
+
+ public int[] getNumbers()
+ {
+ return m_context.getNumbers();
+ }
+
+ @net.dpml.annotation.Context
+ public interface ColorManager
+ {
+ Color getPrimary();
+ Color getSecondary();
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/StandaloneWidget.xprofile
===================================================================
--- trunk/main/lang/part/src/test/org/acme/StandaloneWidget.xprofile
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/StandaloneWidget.xprofile
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<profile xmlns="dpml:metro">
+ <context>
+ <entry key="message" value="Batman"/>
+ <context key="colors">
+ <entry key="primary" method="RED"/>
+ <entry key="secondary" method="BLUE"/>
+ </context>
+ <entry key="numbers">
+ <param value="1"/>
+ <param value="2"/>
+ <param value="3"/>
+ </entry>
+ </context>
+</profile>

Added: trunk/main/lang/part/src/test/org/acme/StandaloneWidgetAdapter.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/StandaloneWidgetAdapter.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/StandaloneWidgetAdapter.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.lang.Strategy;
+
+import dpml.util.DefaultLogger;
+import net.dpml.util.Logger;
+
+import net.dpml.runtime.ComponentError;
+import net.dpml.runtime.ComponentStrategyHandler;
+
+/**
+ * Example of a component that is declared as a service (via
META=INF/services)
+ * while actual deployment is handled via net.dpml.runtime.ComponentStrategy.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public class StandaloneWidgetAdapter implements Widget
+{
+ private Widget m_delegate;
+ private Logger m_logger = new DefaultLogger( "adapter" );
+
+ public StandaloneWidgetAdapter()
+ {
+ m_logger.info( "instantiated" );
+ }
+
+ public String getMessage()
+ {
+ return getDelegate().getMessage();
+ }
+
+ private Widget getDelegate()
+ {
+ if( null == m_delegate )
+ {
+ m_delegate = createDelegate();
+ }
+ return m_delegate;
+ }
+
+ private Widget createDelegate()
+ {
+ m_logger.info( "creating delegate" );
+ try
+ {
+ Strategy strategy = Strategy.load( StandaloneWidget.class, null,
"adapter.standalone" );
+ return strategy.getInstance( Widget.class );
+ }
+ catch( Exception e )
+ {
+ final String error =
+ "Error in widget adapter delegate establishment.";
+ throw new ComponentError( error, e );
+ }
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/StateWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/StateWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/StateWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.awt.Color;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+import net.dpml.util.Logger;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component
+@Services( Widget.class )
+public class StateWidget implements Widget
+{
+ private final Logger m_logger;
+
+ private int m_state = 0;
+
+ public StateWidget( Logger logger )
+ {
+ m_logger = logger;
+ if( m_logger.isInfoEnabled() )
+ {
+ m_logger.info( "instantiated" );
+ }
+ }
+
+ public void start() throws Exception
+ {
+ m_state = 1;
+ if( m_logger.isInfoEnabled() )
+ {
+ m_logger.info( "starting" );
+ }
+ }
+
+ public String getMessage()
+ {
+ if( m_state == 0 )
+ {
+ return "constructed";
+ }
+ else if( m_state == 1 )
+ {
+ return "started";
+ }
+ else if( m_state == 2 )
+ {
+ return "stopped";
+ }
+ else
+ {
+ return "unknown";
+ }
+ }
+
+ public int getState()
+ {
+ return m_state;
+ }
+
+ public void stop() throws Exception
+ {
+ m_state = 2;
+ if( m_logger.isInfoEnabled() )
+ {
+ m_logger.info( "stopping" );
+ }
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/part/src/test/org/acme/StateWidget.xgraph
===================================================================
--- trunk/main/lang/part/src/test/org/acme/StateWidget.xgraph 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/StateWidget.xgraph 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<state xmlns="dpml:state"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
+
+ <trigger event="initialization">
+ <transition name="start" target="started">
+ <operation name="startup" method="start"/>
+ </transition>
+ </trigger>
+ <state name="started">
+ <trigger event="termination">
+ <apply id="stop"/>
+ </trigger>
+ <transition name="stop" target="../stopped">
+ <operation name="stop" method="stop"/>
+ </transition>
+ </state>
+ <state name="stopped">
+ <transition name="start" target="../started">
+ <operation name="start" method="start"/>
+ </transition>
+ </state>
+
+</state>

Added: trunk/main/lang/part/src/test/org/acme/TransientWidget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/TransientWidget.java 2007-02-09
01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/TransientWidget.java 2007-02-09
01:29:45 UTC (rev 1859)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Services( Widget.class )
+@Component( name="widget", lifestyle=TRANSIENT )
+public class TransientWidget extends DefaultWidget
+{
+}

Added: trunk/main/lang/part/src/test/org/acme/Widget.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/Widget.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/Widget.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import net.dpml.lang.Strategy;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Widget
+{
+ String getMessage();
+}

Added: trunk/main/lang/part/src/test/org/acme/WidgetUsingGizmo.java
===================================================================
--- trunk/main/lang/part/src/test/org/acme/WidgetUsingGizmo.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/part/src/test/org/acme/WidgetUsingGizmo.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2004-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 org.acme;
+
+import java.awt.Color;
+
+import net.dpml.annotation.Context;
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import net.dpml.util.Logger;
+
+import static net.dpml.annotation.LifestylePolicy.TRANSIENT;
+
+/**
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component( name="foreign" )
+@Services( Widget.class )
+public class WidgetUsingGizmo implements Widget
+{
+ @Context
+ public interface WidgetContext
+ {
+ Gizmo getGizmo();
+ }
+
+ private final Gizmo m_gizmo;
+
+ public WidgetUsingGizmo( final Logger logger, final WidgetContext
context )
+ {
+ logger.info( "instantiated" );
+ m_gizmo = context.getGizmo();
+ logger.info( getMessage() );
+ }
+
+ public String getMessage()
+ {
+ return "" + m_gizmo.getNumber();
+ }
+
+ public boolean equals( Object other )
+ {
+ return ( hashCode() == other.hashCode() );
+ }
+}

Added: trunk/main/lang/sample/etc/component.xml
===================================================================
--- trunk/main/lang/sample/etc/component.xml 2007-02-09 01:28:27 UTC (rev
1858)
+++ trunk/main/lang/sample/etc/component.xml 2007-02-09 01:29:45 UTC (rev
1859)
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<component xmlns="dpml:metro" name="hello" type="org.acme.HelloComponent"/>

Added: trunk/main/lang/sample/project.xml
===================================================================
--- trunk/main/lang/sample/project.xml 2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/sample/project.xml 2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project xmlns="dpml:library" name="dpml-lang-sample">
+
+ <info title="DPML Component Example"/>
+
+ <types>
+ <type id="jar"/>
+ <type id="part" source="etc/component.xml" alias="true"/>
+ </types>
+
+ <dependencies>
+ <runtime>
+ <include ref="dpml/lang/dpml-lang-part"/>
+ </runtime>
+ </dependencies>
+
+</project>
+

Added: trunk/main/lang/sample/src/main/org/acme/AnotherContext.java
===================================================================
--- trunk/main/lang/sample/src/main/org/acme/AnotherContext.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/sample/src/main/org/acme/AnotherContext.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2005 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 org.acme;
+
+import java.net.URI;
+
+import net.dpml.annotation.Context;
+
+
+/**
+ * A context interface referenced by an enclosing context.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Context
+public interface AnotherContext
+{
+ URI getUri( URI value );
+}

Added: trunk/main/lang/sample/src/main/org/acme/Hello.java
===================================================================
--- trunk/main/lang/sample/src/main/org/acme/Hello.java 2007-02-09 01:28:27
UTC (rev 1858)
+++ trunk/main/lang/sample/src/main/org/acme/Hello.java 2007-02-09 01:29:45
UTC (rev 1859)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2005 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 org.acme;
+
+/**
+ * Sample service interface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+public interface Hello
+{
+ String getMessage();
+}

Added: trunk/main/lang/sample/src/main/org/acme/HelloComponent.java
===================================================================
--- trunk/main/lang/sample/src/main/org/acme/HelloComponent.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/sample/src/main/org/acme/HelloComponent.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2005 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 org.acme;
+
+import dpml.util.PID;
+
+import java.net.URI;
+
+import net.dpml.annotation.Component;
+import net.dpml.annotation.Services;
+
+import static net.dpml.annotation.LifestylePolicy.SINGLETON;
+
+import net.dpml.util.Logger;
+
+/**
+ * Sample component used in testing.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Component( lifestyle=SINGLETON )
+@Services( Hello.class )
+public class HelloComponent implements Hello
+{
+ private static final PID ID = new PID();
+ private static final String MESSAGE = "Hello";
+
+ private final Logger m_logger;
+ private final HelloConfiguration m_context;
+
+ public HelloComponent( Logger logger, HelloConfiguration context )
throws Exception
+ {
+ m_logger = logger;
+ m_context = context;
+
+ URI codebase =
+
getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
+
+ m_logger.info( "pid: " + ID );
+ m_logger.info( "message: " + context.getMessage( MESSAGE ) );
+ m_logger.info( "port: " + context.getPort( 0 ) );
+ m_logger.info( "target: " + context.getTarget().getUri( codebase ) );
+ }
+
+ public String getMessage()
+ {
+ return m_context.getMessage( "Hello" );
+ }
+
+ public void start()
+ {
+ m_logger.info( "starting" );
+ m_logger.info( "started" );
+ }
+
+ public void stop()
+ {
+ m_logger.info( "stopping" );
+ m_logger.info( "stopped" );
+ }
+}

Added: trunk/main/lang/sample/src/main/org/acme/HelloComponent.xgraph
===================================================================
--- trunk/main/lang/sample/src/main/org/acme/HelloComponent.xgraph
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/sample/src/main/org/acme/HelloComponent.xgraph
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<state xmlns="dpml:state">
+
+ <trigger event="initialization">
+ <transition name="start" target="started">
+ <operation name="startup" method="start"/>
+ </transition>
+ </trigger>
+
+ <state name="started">
+ <trigger event="termination">
+ <apply id="stop"/>
+ </trigger>
+ <transition name="stop" target="../stopped">
+ <operation name="stop" method="stop"/>
+ </transition>
+ </state>
+
+ <state name="stopped">
+ <transition name="start" target="../started">
+ <operation name="start" method="start"/>
+ </transition>
+ </state>
+
+</state>

Added: trunk/main/lang/sample/src/main/org/acme/HelloConfiguration.java
===================================================================
--- trunk/main/lang/sample/src/main/org/acme/HelloConfiguration.java
2007-02-09 01:28:27 UTC (rev 1858)
+++ trunk/main/lang/sample/src/main/org/acme/HelloConfiguration.java
2007-02-09 01:29:45 UTC (rev 1859)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2005 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 org.acme;
+
+import net.dpml.annotation.Context;
+
+/**
+ * Sample context iterface.
+ *
+ * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
+ * @version @PROJECT-VERSION@
+ */
+@Context
+public interface HelloConfiguration
+{
+ String getMessage( String value );
+ int getPort( int port );
+ AnotherContext getTarget();
+}




  • r1859 - in trunk/main/lang: . part part/src part/src/main part/src/main/dpml part/src/main/dpml/appliance part/src/main/dpml/lang part/src/main/dpml/state part/src/main/net part/src/main/net/dpml part/src/main/net/dpml/annotation part/src/main/net/dpml/appliance part/src/main/net/dpml/lang part/src/main/net/dpml/runtime part/src/main/net/dpml/state part/src/test part/src/test/META-INF part/src/test/META-INF/services part/src/test/dpml part/src/test/dpml/lang part/src/test/net part/src/test/net/dpml part/src/test/net/dpml/runtime part/src/test/net/dpml/runtime/composition part/src/test/net/dpml/runtime/context part/src/test/net/dpml/runtime/isolation part/src/test/net/dpml/runtime/lifecycle part/src/test/net/dpml/runtime/lifestyle part/src/test/net/dpml/runtime/profile part/src/test/net/dpml/runtime/service part/src/test/org part/src/test/org/acme sample sample/etc sample/src sample/src/main sample/src/main/org sample/src/main/org/acme, mcconnell at BerliOS, 02/08/2007

Archive powered by MHonArc 2.6.24.

Top of Page