Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2481 - in development/main/metro: . composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/model composition/part/src/main/net/dpml/composition/state composition/part/src/test/net/dpml/composition/state composition/testing/test/src/main/net/dpml/test/state composition/testing/workshop/src/test/net/dpml/test parts/src/main/net/dpml/parts/state parts/src/test parts/src/test/net parts/src/test/net/dpml parts/src/test/net/dpml/parts parts/src/test/net/dpml/parts/state

notify-dpml AT lists.ibiblio.org

Subject: DPML Notify

List archive

Chronological Thread  
  • From: mcconnell AT dpml.net
  • To: notify-dpml AT lists.ibiblio.org
  • Subject: svn commit: r2481 - in development/main/metro: . composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/model composition/part/src/main/net/dpml/composition/state composition/part/src/test/net/dpml/composition/state composition/testing/test/src/main/net/dpml/test/state composition/testing/workshop/src/test/net/dpml/test parts/src/main/net/dpml/parts/state parts/src/test parts/src/test/net parts/src/test/net/dpml parts/src/test/net/dpml/parts parts/src/test/net/dpml/parts/state
  • Date: Tue, 10 May 2005 01:58:09 -0400

Author: mcconnell AT dpml.net
Date: Tue May 10 01:58:07 2005
New Revision: 2481

Added:

development/main/metro/parts/src/main/net/dpml/parts/state/NoSuchHandlerException.java

development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveInitializationException.java

development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveTerminationException.java
development/main/metro/parts/src/test/
development/main/metro/parts/src/test/net/
development/main/metro/parts/src/test/net/dpml/
development/main/metro/parts/src/test/net/dpml/parts/
development/main/metro/parts/src/test/net/dpml/parts/state/

development/main/metro/parts/src/test/net/dpml/parts/state/OperationTestCase.java

development/main/metro/parts/src/test/net/dpml/parts/state/StateTestCase.java

development/main/metro/parts/src/test/net/dpml/parts/state/TransitionTestCase.java
Removed:

development/main/metro/composition/part/src/main/net/dpml/composition/state/

development/main/metro/composition/part/src/test/net/dpml/composition/state/
Modified:

development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/ManagerInvocationHandler.java

development/main/metro/composition/control/src/main/net/dpml/composition/control/ValueController.java

development/main/metro/composition/control/src/main/net/dpml/composition/model/AbstractComponent.java

development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java

development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagedComponent.java

development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java

development/main/metro/composition/testing/workshop/src/test/net/dpml/test/WorkshopTestCase.java
development/main/metro/index.xml
development/main/metro/parts/src/main/net/dpml/parts/state/Operation.java
development/main/metro/parts/src/main/net/dpml/parts/state/State.java
development/main/metro/parts/src/main/net/dpml/parts/state/Transition.java
Log:
Cleanup some issue related to State implementation and move the content over
the the dpml-parts-api project.

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ComponentController.java
Tue May 10 01:58:07 2005
@@ -39,12 +39,6 @@

import javax.swing.event.ChangeEvent;

-import net.dpml.composition.state.DefaultOperation;
-import net.dpml.composition.state.DefaultState;
-import net.dpml.composition.state.DefaultTransition;
-import net.dpml.composition.state.NoSuchHandlerException;
-import net.dpml.composition.state.RecursiveInitializationException;
-import net.dpml.composition.state.RecursiveTerminationException;

import net.dpml.composition.model.CompositionModel;
import net.dpml.composition.model.ComponentEntry;
@@ -52,6 +46,7 @@
import net.dpml.parts.control.Monitor;
import net.dpml.parts.control.Manager;
import net.dpml.parts.control.ControlRuntimeException;
+import net.dpml.parts.control.Disposable;
import net.dpml.parts.model.Component;
import net.dpml.parts.model.DuplicateKeyException;
import net.dpml.parts.state.State;
@@ -63,7 +58,9 @@
import net.dpml.parts.state.Operation;
import net.dpml.parts.state.StateEvent;
import net.dpml.parts.state.StateListener;
-import net.dpml.parts.control.Disposable;
+import net.dpml.parts.state.NoSuchHandlerException;
+import net.dpml.parts.state.RecursiveInitializationException;
+import net.dpml.parts.state.RecursiveTerminationException;

import net.dpml.system.SystemContext;

@@ -219,14 +216,14 @@

Object instance = getInstance( component );
List visited = new LinkedList();
- DefaultState graph = component.getStateGraph();
+ State graph = component.getStateGraph();
Class subject = component.getModel().getDeploymentClass();
validate( subject, graph );
boolean flag = true;
while( flag )
{
- DefaultState state = component.getCurrentState();
- DefaultTransition initialization = state.getInitialization();
+ State state = component.getCurrentState();
+ Transition initialization = state.getInitialization();
if( null == initialization )
{
flag = false;
@@ -289,13 +286,13 @@
return instance;
}

- private void validate( Class subject, DefaultState state ) throws
ValidationException
+ private void validate( Class subject, State state ) throws
ValidationException
{
if( null == state )
{
throw new NullPointerException( "state" );
}
- DefaultTransition init = state.getInitialization();
+ Transition init = state.getInitialization();
if( null != init )
{
URI uri = init.getHandlerURI();
@@ -317,7 +314,7 @@
for( int i=0; i<operations.length; i++ )
{
String key = operations[i];
- DefaultOperation operation = state.getNamedOperation( key );
+ Operation operation = state.getNamedOperation( key );
URI uri = operation.getHandlerURI();
try
{
@@ -338,7 +335,7 @@
for( int i=0; i<transitions.length; i++ )
{
String key = transitions[i];
- DefaultTransition transition = state.getNamedTransition( key );
+ Transition transition = state.getNamedTransition( key );
URI uri = transition.getHandlerURI();
try
{
@@ -355,7 +352,7 @@
throw new ValidationException( error, e.getCause() );
}
}
- DefaultTransition terminator = state.getTerminator();
+ Transition terminator = state.getTerminator();
if( null != terminator )
{
URI uri = terminator.getHandlerURI();
@@ -408,7 +405,7 @@
/**
* Apply a transition identified by a supplied transition key. The
* implementation will attempt to locate the transition relative to the
current
- * state (taking into account the DefaultState search semantics) from
which
+ * state (taking into account the State search semantics) from which
* a invocation handler is resolve and invoked. If the transition is
successful
* the target transition state declared by the transition will be
assigned as the
* current current state and all listeners will be notified of a state
change.
@@ -425,8 +422,8 @@
if( component instanceof ComponentEntry )
{
ComponentEntry entry = (ComponentEntry) component;
- DefaultState state = entry.getCurrentState();
- DefaultTransition transition = state.getNamedTransition( key );
+ State state = entry.getCurrentState();
+ Transition transition = state.getNamedTransition( key );
applyTransition( entry, transition );
return entry.getState();
}
@@ -444,7 +441,7 @@
/**
* Apply a transition identified by a supplied transition key. The
* implementation will attempt to locate the transition relative to the
current
- * state (taking into account the DefaultState search semantics) from
which
+ * state (taking into account the State search semantics) from which
* a invocation handler is resolve and invoked. If the transition is
successful
* the target transition state declared by the transtion will be assigned
as the
* current current state and all listeners will be notified of a state
change.
@@ -456,7 +453,7 @@
* @return TRUE if the transition was executed
* @exception if a error occurs in transition execution
*/
- private boolean applyTransition( ComponentEntry entry, DefaultTransition
transition ) throws Exception
+ private boolean applyTransition( ComponentEntry entry, Transition
transition ) throws Exception
{
if( null == entry )
{
@@ -468,9 +465,9 @@
}

getInstance( entry );
- DefaultState state = entry.getCurrentState();
+ State state = entry.getCurrentState();
URI handler = transition.getHandlerURI();
- DefaultState target = transition.getTransitionTarget();
+ State target = transition.getTransitionTarget();

if( null != handler )
{
@@ -501,7 +498,7 @@
/**
* Execute an operation identified by a supplied operation key. The
* implementation will attempt to locate the operation relative to the
current
- * state (taking into account the DefaultState search semantics) from
which
+ * state (taking into account the State search semantics) from which
* a invocation handler is resolve and invoked.
*
* @param key the operation key
@@ -512,8 +509,8 @@
if( component instanceof ComponentEntry )
{
ComponentEntry entry = (ComponentEntry) component;
- DefaultState state = entry.getCurrentState();
- DefaultOperation operation = state.getNamedOperation( key );
+ State state = entry.getCurrentState();
+ Operation operation = state.getNamedOperation( key );
URI handler = operation.getHandlerURI();
if( null == handler )
{
@@ -545,7 +542,7 @@

/**
* Internal utility method that handles the resolution of a handler based
on
- * the object assigned to the DefaultTransition handler attribute. If
the
+ * the object assigned to the Transition handler attribute. If the
* handler is an instance of URI, the following schemes will be evaluated:
*
* <ol>
@@ -707,8 +704,8 @@
boolean flag = true;
while( flag )
{
- DefaultState state = component.getCurrentState();
- DefaultTransition terminator = state.getTerminator();
+ State state = component.getCurrentState();
+ Transition terminator = state.getTerminator();
if( null == terminator )
{
return;

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ManagerInvocationHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ManagerInvocationHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ManagerInvocationHandler.java
Tue May 10 01:58:07 2005
@@ -24,7 +24,6 @@
import java.lang.reflect.UndeclaredThrowableException;

import net.dpml.composition.model.ComponentEntry;
-import net.dpml.composition.state.DefaultState;
import net.dpml.lang.DelegationRuntimeException;
import net.dpml.parts.state.State;

@@ -196,6 +195,6 @@
return e;
}

- private static final State TERMINAL_STATE = new DefaultState( true );
+ private static final State TERMINAL_STATE = new State( true );

}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/ValueController.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/ValueController.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/ValueController.java
Tue May 10 01:58:07 2005
@@ -113,51 +113,5 @@
{
}

- public static final State AVAILABLE = new AvailableState();
-
- public static class AvailableState implements State
- {
- /**
- * Return the name of the state.
- * @return the state name
- */
- public String getName()
- {
- return AVAILABLE_NAME;
- }
-
- /**
- * Return the array of available transition names.
- *
- * @return the transition names
- */
- public String[] getTransitionNames()
- {
- return EMPTY_TRANSITIONS;
- }
-
- /**
- * Return the array of available operation names.
- *
- * @return the operation names
- */
- public String[] getOperationNames()
- {
- return EMPTY_OPERATIONS;
- }
-
- /**
- * Return true if this is a terminal state.
- * @return TRUE if terminal
- */
- public boolean isTerminal()
- {
- return true;
- }
-
- private static final String AVAILABLE_NAME = "available";
- private static final String[] EMPTY_TRANSITIONS = new String[0];
- private static final String[] EMPTY_OPERATIONS = new String[0];
- }
-
+ public static final State AVAILABLE = new State( true );
}

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/model/AbstractComponent.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/model/AbstractComponent.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/model/AbstractComponent.java
Tue May 10 01:58:07 2005
@@ -22,7 +22,6 @@
import java.util.EventListener;

import net.dpml.composition.event.WeakEventProducer;
-import net.dpml.composition.state.DefaultState;

import net.dpml.parts.control.Monitor;
import net.dpml.parts.control.Manager;
@@ -44,7 +43,7 @@
*/
public abstract class AbstractComponent extends WeakEventProducer implements
Component
{
- private static final State NULL_STATE = new DefaultState( true );
+ private static final State NULL_STATE = new State( true );

private final Monitor m_monitor;


Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/model/ComponentEntry.java
Tue May 10 01:58:07 2005
@@ -38,7 +38,6 @@

import net.dpml.composition.control.ComponentController;
import net.dpml.composition.control.CompositionController;
-import net.dpml.composition.state.DefaultState;
import net.dpml.composition.event.EventProducer;
import net.dpml.composition.event.WeakEventProducer;

@@ -73,9 +72,9 @@
private final CompositionModel m_model;
private final URI m_uri;
private final ContextMap m_context;
- private final DefaultState m_graph;
+ private final State m_graph;

- private DefaultState m_state;
+ private State m_state;
private boolean m_initialized = false;
private ComponentController m_manager;

@@ -288,7 +287,7 @@
*
* @param state the state to assign as the current state
*/
- public synchronized void setState( DefaultState state )
+ public synchronized void setState( State state )
{
if( false == m_state.equals( state ) )
{
@@ -318,16 +317,13 @@
* current state override transitions declare higher up in the
* state chain. This method is exposed via the ServiceManager
* interface to the controlling application (possibly the enclossing
- * component or the model controller). State instances returned from
- * this method are automatically proxied behind a State invocation
- * handler thereby ensuring the integrity of the state's state and
- * non-disclosure of implemetation features.
+ * component or the model controller).
*
* @return the current state
*/
public synchronized State getState()
{
- return getCurrentState().getProxy();
+ return getCurrentState();
}

/**
@@ -336,7 +332,7 @@
*
* @return the state representing the current state of execution
*/
- public DefaultState getCurrentState()
+ public State getCurrentState()
{
if( null == m_state )
{
@@ -540,12 +536,12 @@
}
}

- private DefaultState resolveStateGraph( Class subject )
+ private State resolveStateGraph( Class subject )
{
try
{
Field field = subject.getField( "STATE_GRAPH" );
- return (DefaultState) field.get( null );
+ return (State) field.get( null );
}
catch( NoSuchFieldException e )
{
@@ -566,7 +562,7 @@
{
final String error =
"The component is declaring a STATE_GRAPH member "
- + "that is not an instance of
net.dpml.composition.state.DefaultState."
+ + "that is not an instance of net.dpml.parts.state.State."
+ "\nObject: " + getURI();
throw new IllegalArgumentException( error );
}
@@ -583,20 +579,20 @@
* The operation returns the state instance represening the state graph.
* @return the root state
*/
- public DefaultState getStateGraph()
+ public State getStateGraph()
{
return m_graph;
}

- private static final DefaultState STARTABLE_OBJECT_GRAPH =
createStartableGraph();
- private static final DefaultState EXECUTABLE_OBJECT_GRAPH =
createExecutableGraph();
- private static final DefaultState NULL_OBJECT_GRAPH = createNullGraph();
-
- private static DefaultState createStartableGraph()
- {
- DefaultState root = new DefaultState();
- DefaultState started = root.addState( "started" );
- DefaultState stopped = root.addState( "stopped" );
+ private static final State STARTABLE_OBJECT_GRAPH =
createStartableGraph();
+ private static final State EXECUTABLE_OBJECT_GRAPH =
createExecutableGraph();
+ private static final State NULL_OBJECT_GRAPH = createNullGraph();
+
+ private static State createStartableGraph()
+ {
+ State root = new State();
+ State started = root.addState( "started" );
+ State stopped = root.addState( "stopped" );
try
{
root.setInitialization( new URI( "method:start" ), started );
@@ -611,9 +607,9 @@
}
}

- private static DefaultState createExecutableGraph()
+ private static State createExecutableGraph()
{
- DefaultState root = new DefaultState();
+ State root = new State();
try
{
root.setInitialization( new URI( "method:execute" ) );
@@ -625,9 +621,9 @@
}
}

- private static DefaultState createNullGraph()
+ private static State createNullGraph()
{
- return new DefaultState( true );
+ return new State( true );
}

/**

Modified:
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagedComponent.java
==============================================================================
---
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagedComponent.java
(original)
+++
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagedComponent.java
Tue May 10 01:58:07 2005
@@ -26,8 +26,6 @@

import javax.swing.event.ChangeListener;

-import net.dpml.composition.state.DefaultState;
-
import net.dpml.parts.state.State;
import net.dpml.parts.state.StateEvent;
import net.dpml.parts.state.StateListener;
@@ -159,7 +157,7 @@
// static utilities
// ------------------------------------------------------------------

- public static final DefaultState STATE_GRAPH = new DefaultState();
+ public static final State STATE_GRAPH = new State();

static
{
@@ -167,12 +165,12 @@
// construct a state graph
//

- DefaultState root = STATE_GRAPH;
- DefaultState initialized = root.addState( "initialized" );
- DefaultState available = root.addState( "available" );
- DefaultState started = available.addState( "started" );
- DefaultState stopped = available.addState( "stopped" );
- DefaultState terminated = root.addTerminalState( "terminated" );
+ State root = STATE_GRAPH;
+ State initialized = root.addState( "initialized" );
+ State available = root.addState( "available" );
+ State started = available.addState( "started" );
+ State stopped = available.addState( "stopped" );
+ State terminated = root.addTerminalState( "terminated" );

//
// create the handler declarations

Modified:
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
==============================================================================
---
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
(original)
+++
development/main/metro/composition/testing/test/src/main/net/dpml/test/state/ManagingContainer.java
Tue May 10 01:58:07 2005
@@ -27,8 +27,6 @@
import net.dpml.parts.model.Component;
import net.dpml.parts.state.State;

-import net.dpml.composition.state.DefaultState;
-
import net.dpml.activity.Startable;

/**

Modified:
development/main/metro/composition/testing/workshop/src/test/net/dpml/test/WorkshopTestCase.java
==============================================================================
---
development/main/metro/composition/testing/workshop/src/test/net/dpml/test/WorkshopTestCase.java
(original)
+++
development/main/metro/composition/testing/workshop/src/test/net/dpml/test/WorkshopTestCase.java
Tue May 10 01:58:07 2005
@@ -63,7 +63,6 @@
URL url = new URL(
"artifact:part:dpml/test/dpml-composition-testing-test#SNAPSHOT" );
Provider provider = (Provider) url.getContent( new Class[]{
Provider.class } );
Object instance = provider.resolve( false );
- System.out.println( "" + instance );
assertEquals( "component class",
"net.dpml.test.state.ManagingContainer", instance.getClass().getName() );
}


Modified: development/main/metro/index.xml
==============================================================================
--- development/main/metro/index.xml (original)
+++ development/main/metro/index.xml Tue May 10 01:58:07 2005
@@ -229,7 +229,7 @@
<dependencies>
<include key="dpml-logging-api" tag="api"/>
<include key="dpml-activity-api" tag="api"/>
- <!--<include key="dpml-parts-api" tag="api"/>-->
+ <include key="dpml-parts-api" tag="api"/>
<include key="dpml-context-api" tag="api"/>
<include key="dpml-transit-main" tag="api"/>
<include key="dpml-system-api" tag="spi"/>
@@ -510,7 +510,6 @@
<include key="dpml-parts-api"/>
<include key="dpml-transit-main"/>
<include key="dpml-activity-api"/>
- <include key="dpml-composition-part"/>
</dependencies>
<plugins>
<include key="dpml-composition-builder"/>

Added:
development/main/metro/parts/src/main/net/dpml/parts/state/NoSuchHandlerException.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/NoSuchHandlerException.java
Tue May 10 01:58:07 2005
@@ -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.parts.state;
+
+/**
+ * Exception thrown when a request for a handler could not be resolved.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ */
+public class NoSuchHandlerException extends RuntimeException
+{
+ /**
+ * Construct a new <code>NoSuchHandlerException</code> instance.
+ *
+ * @param handler the handler name
+ */
+ public NoSuchHandlerException( final String handler )
+ {
+ super( handler );
+ }
+
+}
+

Modified:
development/main/metro/parts/src/main/net/dpml/parts/state/Operation.java
==============================================================================
--- development/main/metro/parts/src/main/net/dpml/parts/state/Operation.java
(original)
+++ development/main/metro/parts/src/main/net/dpml/parts/state/Operation.java
Tue May 10 01:58:07 2005
@@ -18,16 +18,39 @@

package net.dpml.parts.state;

+import java.net.URI;
+
/**
- * The Operation interface is a base interface to actions executable withing
- * scope of a state. An implementation of an operation must implement a
single
- * "execute" method. Argument parameter applied to the execute method will
be
- * resolved by the state manager relative to the runtime context and
declared
- * parameter types.
+ * The Operation links an operation to a handler uri.
*
- * @author <a href="mailto:info AT dpml.net";>The Digital Product Meta
Library</a>
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
*/
-public interface Operation
+public final class Operation
{
- // public void execute( .... ) throws Exception;
+ private final URI m_handler;
+
+ /**
+ * Internal utility to construct a new operation instance. This
constructor
+ * is used by the DefaultState implementation class as part of it's
operation
+ * factory service.
+ *
+ * @param handler the uri identifying the operation handler
+ */
+ protected Operation( URI handler )
+ {
+ if( null == handler )
+ {
+ throw new NullPointerException( "handler" );
+ }
+ m_handler = handler;
+ }
+
+ /**
+ * Return the handler uri identifier associated with this operation.
+ * @return the uri identiifying the handler
+ */
+ public URI getHandlerURI()
+ {
+ return m_handler;
+ }
}

Added:
development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveInitializationException.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveInitializationException.java
Tue May 10 01:58:07 2005
@@ -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.parts.state;
+
+/**
+ * Exception thrown when a recursive initialization sequence is encountered.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ */
+public class RecursiveInitializationException extends ValidationException
+{
+ /**
+ * Construct a new <code>RecursiveTerminationException</code> instance.
+ *
+ * @param handler the handler name
+ */
+ public RecursiveInitializationException( final String message )
+ {
+ super( message );
+ }
+
+}
+

Added:
development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveTerminationException.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/RecursiveTerminationException.java
Tue May 10 01:58:07 2005
@@ -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.parts.state;
+
+/**
+ * Exception thrown when a recursive termination sequence is encountered.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ */
+public class RecursiveTerminationException extends ValidationException
+{
+ /**
+ * Construct a new <code>RecursiveTerminationException</code> instance.
+ *
+ * @param handler the handler name
+ */
+ public RecursiveTerminationException( final String message )
+ {
+ super( message );
+ }
+
+}
+

Modified:
development/main/metro/parts/src/main/net/dpml/parts/state/State.java
==============================================================================
--- development/main/metro/parts/src/main/net/dpml/parts/state/State.java
(original)
+++ development/main/metro/parts/src/main/net/dpml/parts/state/State.java
Tue May 10 01:58:07 2005
@@ -18,37 +18,897 @@

package net.dpml.parts.state;

+import java.util.Map;
+import java.util.Hashtable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.net.URI;
+
+import net.dpml.parts.model.DuplicateKeyException;
+
/**
* The State interface is an interface representing an immutable state of
* a component instance.
*
* @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
*/
-public interface State
+public final class State
{
+ private final String m_name;
+ private final State m_parent;
+ private final boolean m_terminal;
+
+ private final Map m_operations = new Hashtable();
+ private final Map m_transitions = new Hashtable();
+
+ private Transition m_initialization;
+ private Transition m_terminator;
+
+ private final Map m_states = new Hashtable();
+
+ /**
+ * Creation of a new top-level non-terminal state.
+ */
+ public State()
+ {
+ this( false );
+ }
+
+ /**
+ * Creation of a new top-level state.
+ * @param terminal the terminal status of the state
+ */
+ public State( boolean terminal )
+ {
+ this( null, "root", terminal );
+ }
+
+ /**
+ * Internal constructor for a state instance. If the parent argument is
null
+ * the created state representing a root state in a state graph. The
terminal
+ * attribute declares the terminal node status of the state. If the
state is
+ * flagged as terminal, no sub-states or transitions may be added or
assigned
+ * to the state.
+ *
+ * @paren parent the parent of the created state
+ * @param name the name that the state is index under
+ * @param terminal TRUE if this is a terminal state else FALSE
+ * @exception NullPointerException if the name argument is null
+ */
+ private State( State parent, String name, boolean terminal )
+ {
+ if( null == name )
+ {
+ throw new NullPointerException( "name" );
+ }
+ m_name = name;
+ m_parent = parent;
+ m_terminal = terminal;
+ }
+
/**
* Return the name of the state.
+ *
* @return the state name
*/
- String getName();
+ public String getName()
+ {
+ return m_name;
+ }
+
+ /**
+ * Return the parent state.
+ * @return the parent
+ */
+ protected State getParent()
+ {
+ return m_parent;
+ }
+
+ /**
+ * Return the terminal status of this state. If a state is terminal it
cannot
+ * contain sub-states or transitions. Furthermore, a component declaring
a current
+ * state where the current state is terminal cannot change it's state
without explicit
+ * re-initialization of the componet's service manager.
+ *
+ * @return TRUE if this state is a terminal state
+ */
+ public boolean isTerminal()
+ {
+ return m_terminal;
+ }
+
+ /**
+ * Add a new sub-state to the set of states contained within this
+ * state. If the supplied key is not unique within the scope of the graph
+ * an exception will be thrown.
+ *
+ * @param key the key identifying the new state
+ * @return the created state
+ */
+ public State addState( String key )
+ {
+ return addState( this, key, false );
+ }
+
+ /**
+ * Add a new terminal sub-state to the set of states contained within
this
+ * state. If the supplied key is not unique within the scope of the graph
+ * an exception will be thrown.
+ *
+ * @param key the key identifying the new state
+ * @return the created state
+ */
+ public State addTerminalState( String key )
+ {
+ return addState( this, key, true );
+ }
+
+ /**
+ * Internal operation to construct a new sub-state state. The
implementation
+ * will delegate the state addition to the parent under which all states
in the
+ * state graph are aggregated relative to unique keys.
+ *
+ * @param parent the enclosing state
+ * @param key the key identifying the new state
+ * @param terminal true if this is a terminal state
+ * @return the created state
+ * @exception IllegalStateException if the parent state is a terminal
state
+ * @exception DuplicateKeyException if a state with the supplied key is
already assingned
+ * @exception IllegalArgumentException if the initial parameter is true
and an initial
+ * state has already beeen declared
+ */
+ private State addState( State parent, String key, boolean terminal )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ if( m_parent != null )
+ {
+ return m_parent.addState( parent, key, terminal );
+ }
+ else
+ {
+ if( parent.isTerminal() )
+ {
+ final String error =
+ "Cannot add substate to a terminal state."
+ + "\nState: " + parent.getName()
+ + "\nSubstate: " + key;
+ throw new IllegalStateException( error );
+ }
+
+ if( m_states.containsKey( key ) )
+ {
+ throw new DuplicateKeyException( key );
+ }
+ else
+ {
+ State state = new State( parent, key, terminal );
+ m_states.put( key, state );
+ return state;
+ }
+ }
+ }
+
+ /**
+ * Return an array of all states within the state graph. This includes
+ * all substates of the root state and all substates of substates, etc.
+ *
+ * @return the state array
+ */
+ protected State[] getAllStates()
+ {
+ if( null != m_parent )
+ {
+ return m_parent.getAllStates();
+ }
+ else
+ {
+ ArrayList list = new ArrayList( );
+ State[] nested =
+ (State[]) m_states.values().toArray( new State[0] );
+ State[] states = new State[ nested.length + 1 ];
+ states[0] = this;
+ System.arraycopy( nested, 0, states, 1, nested.length );
+ return states;
+ }
+ }
+
+ /**
+ * Return an array of local states directly contained within this state
+ * instance.
+ *
+ * @return the local state array
+ */
+ protected State[] getStates()
+ {
+ return getStates( this );
+ }
+
+ /**
+ * Return an array of all states contained within the supplied state.
+ *
+ * @param parent the enclosing parent state
+ * @return the state array
+ */
+ protected State[] getStates( State parent )
+ {
+ ArrayList list = new ArrayList();
+ State[] states = getAllStates();
+ for( int i=(states.length -1); i>-1; i-- )
+ {
+ State state = states[i];
+ if( parent.equals( state.getParent() ) )
+ {
+ list.add( state );
+ }
+ }
+ return (State[]) list.toArray( new State[0] );
+ }
+
+ /**
+ * Return a state from the state graph matching the supplied key.
+ * The search does not include the root state of the state graph.
+ *
+ * @param key the state key
+ * @return the state assigned to the key
+ * @exception NoSuchStateException if the key does not match a state
+ * within the state graph
+ */
+ protected State getState( String key )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ if( null != m_parent )
+ {
+ return m_parent.getState( key );
+ }
+ else
+ {
+ State state = (State) m_states.get( key );
+ if( null == state )
+ {
+ throw new NoSuchStateException( key );
+ }
+ else
+ {
+ return state;
+ }
+ }
+ }
+
+ /**
+ * Add a transition to the state. Transition keys are unique within the
scope
+ * of the state under which the transition is assigned. Transitions with
the
+ * same name as a transition within a parent state will take precedence
when
+ * selecting transitions.
+ *
+ * @param key the transition key
+ * @param target the transition target state
+ */
+ public void addTransition( String key, State target )
+ {
+ addTransition( key, null, target );
+ }
+
+ /**
+ * Add a transition to the state. Transition keys are unique within the
scope
+ * of the state under which the transition is assigned. Transitions with
the
+ * same name as a transition within a parent state will take precedence
when
+ * selecting transitions.
+ *
+ * @param key the transition key
+ * @param uri the uri identifying the handler to be assigned as the
handler
+ * of the transition action
+ * @param target the transition target state
+ */
+ public void addTransition( String key, URI uri, State target )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ if( m_transitions.containsKey( key ) )
+ {
+ throw new DuplicateKeyException( key );
+ }
+ validateTransition( TRANSITION, key, uri, target );
+ Transition transition = new Transition( uri, target );
+ m_transitions.put( key, transition );
+ }
+
+ /**
+ * Optionally set the initializer for this state. During the state
manager
+ * initialization phase an initializer declared on the assigned state
model
+ * will be invoked. If the current state is modified as a result of
invocation
+ * of an initializer, any initializer associated with the new state will
be
+ * fired. This process will continue until a state is established that
does not
+ * delcare an initializor.
+ *
+ * @param target the target initialization state
+ */
+ public void setInitialization( State target )
+ {
+ setInitialization( null, target );
+ }
+
+ /**
+ * Optionally set the initializer for this state. During the state
manager
+ * initialization phase an initializer declared on the assigned state
model
+ * will be invoked. If the current state is modified as a result of
invocation
+ * of an initializer, any initializer associated with the new state will
be
+ * fired. This process will continue until a state is established that
does not
+ * delcare an initializor.
+ *
+ * @param target the target initialization state
+ */
+ public void setInitialization( URI uri )
+ {
+ setInitialization( uri, this );
+ }
+
+ /**
+ * Optionally set the initializer for this state. During the state
manager
+ * initialization phase an initializer declared on the assigned state
model
+ * will be invoked. If the current state is modified as a result of
invocation
+ * of an initializer, any initializer associated with the new state will
be
+ * fired. This process will continue until a state is established that
does not
+ * delcare an initializor.
+ *
+ * @param uri the uri identifying the handler to be assigned as the
handler
+ * of the initialization action
+ * @param target the target initialization state
+ */
+ public void setInitialization( URI uri, State target )
+ {
+ if( null != m_initialization )
+ {
+ final String error =
+ "Initilization already set."
+ + "\nState: " + getName();
+ throw new IllegalStateException( error );
+ }
+ validateTransition( INITIALIZER, null, uri, target );
+ m_initialization = new Transition( uri, target );
+ }
+
+ /**
+ * Return the initialization transition assigned to the state.
+ * @return the initialization transition (possibly null)
+ */
+ public Transition getInitialization()
+ {
+ return m_initialization;
+ }
+
+ /**
+ * Optionally set the terminator for this state. During the state manager
+ * termination phase a terminator declared on the assigned state model
+ * will be invoked. If the current state is modified as a result of
invocation
+ * of a terminator, a terminator associated with the new state will be
+ * fired (if declared). This process will continue until a terminal
state is
+ * established or no additional terminators can be fired.
+ *
+ * @param target the transition target state
+ */
+ public void setTerminator( State target )
+ {
+ setTerminator( null, target );
+ }
+
+ /**
+ * Optionally set the terminator for this state. During the state manager
+ * termination phase a terminator declared on the assigned state model
+ * will be invoked. If the current state is modified as a result of
invocation
+ * of a terminator, a terminator associated with the new state will be
+ * fired (if declared). This process will continue until a terminal
state is
+ * established or no additional terminators can be fired.
+ *
+ * @param uri the uri identifying the handler to be assigned as the
handler
+ * of the transition action
+ * @param target the transition target state
+ */
+ public void setTerminator( URI uri, State target )
+ {
+ if( null != m_terminator )
+ {
+ final String error =
+ "Terminator already set."
+ + "\nState: " + getName();
+ throw new IllegalStateException( error );
+ }
+ validateTransition( TERMINATOR, null, uri, target );
+ m_terminator = new Transition( uri, target );
+ }
+
+ /**
+ * Return the terminator transition assigned to the state.
+ * @return the terminator transition (possibly null)
+ */
+ public Transition getTerminator()
+ {
+ return m_terminator;
+ }

/**
- * Return the array of available transition names.
+ * Return the first transition matching the supplied key in this state
graph. The search
+ * for a matching transition proceeds from the local state upwards uptil
the root state is
+ * reached unless a local or intermidiate transition matches the supplied
key.
*
- * @return the transition names
+ * @param key the transition key
+ * @return a matching transition
+ * @exception NoSuchTransitionException if no matching transition can be
found
*/
- String[] getTransitionNames();
+ public Transition getTransition( String key )
+ {
+ return getNamedTransition( key );
+ }

/**
- * Return the array of available operation names.
+ * Return the fisrt transition matching the supplied key in this state
graph. The search
+ * for a matching transition proceeds from the local state upwards uptil
the root state is
+ * reached unless a local or intermidiate transition matches the supplied
key.
*
- * @return the operation names
+ * @param key the transition key
+ * @return a matching transition
+ * @exception NoSuchTransitionException if no matching transition can be
found
*/
- String[] getOperationNames();
+ public Transition getNamedTransition( String key )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ Transition transition = (Transition) m_transitions.get( key );
+ if( null != transition )
+ {
+ return transition;
+ }
+ else
+ {
+ if( null == m_parent )
+ {
+ throw new NoSuchTransitionException( key );
+ }
+ else
+ {
+ return m_parent.getNamedTransition( key );
+ }
+ }
+ }

/**
- * Return true if this is a terminal state.
- * @return TRUE if terminal
+ * Returns an array of transition names declared in this state and all
+ * parent states in the active state chain. This method via the
+ * StateManager interface (through exposeure of State) to controlling
+ * applications. The controlling application can apply a tranistion
+ * by invoking the 'apply' operation on the associated ServiceManager.
+ *
+ * @return the available transition names
+ */
+ public String[] getTransitionNames()
+ {
+ if( m_terminal )
+ {
+ return new String[0];
+ }
+ if( null == m_parent )
+ {
+ return getLocalTransitionNames();
+ }
+ else
+ {
+ String[] keys = m_parent.getTransitionNames();
+ String[] local = getLocalTransitionNames();
+ List list = new ArrayList( Arrays.asList( local ) );
+ for( int i=0; i<keys.length; i++ )
+ {
+ String key = keys[i];
+ if( false == list.contains( key ) )
+ {
+ if( false == getNamedTransition( key
).getTargetState().equals( this ) )
+ {
+ list.add( key );
+ }
+ }
+ }
+ return (String[]) list.toArray( new String[0] );
+ }
+ }
+
+ /**
+ * Return the list of transition names local to this state.
+ * @return the array of transition names
+ */
+ public String[] getLocalTransitionNames()
+ {
+ return (String[]) m_transitions.keySet().toArray( new String[0] );
+ }
+
+ /**
+ * An operation is the declarion of the association of a handler with a
particular
+ * state. When the active state chain includes the state the the
operation is
+ * asssigned to the operation is available. Operation do not modify the
current
+ * state maintained by the state manager (unlike transitions). Operations
can be
+ * be considered as dynamic methods that are exposed to a controller as a
function
+ * of the active state of the component. The operation key must be
unique within
+ * the scope of the state to which it is assigned. If the an operation
with the
+ * same name is assigned to a parent or higher state then this operation
will
+ * override the higher operation.
+ *
+ * @param key the operation key
+ * @param uri the uri identifying the operation handler
+ * @exception NullPointerException if key or uri are null
+ * @exception DuplicateKeyException if the key is already locally assigned
+ */
+ public void addOperation( String key, URI uri )
+ {
+ addOperation( key, uri, false );
+ }
+
+ /**
+ * An operation is the declarion of the association of a handler with a
particular
+ * state. When the active state chain includes the state the the
operation is
+ * asssigned to the operation is available. Operation do not modify the
current
+ * state maintained by the state manager (unlike transitions). Operations
can be
+ * be considered as dynamic methods that are exposed to a controller as a
function
+ * of the active state of the component. The operation key must be
unique within
+ * the scope of the state to which it is assigned. If the an operation
with the
+ * same name is assigned to a parent or higher state then this operation
will
+ * override the higher operation. If an operation already exists locally
on this
+ * state matching the supplied key and the replace is policy is true, the
existing
+ * operation will be replaced otherwise a DuplicateKeyException will be
thrown.
+ *
+ * @param key the operation key
+ * @param uri the uri identifying the operation handler
+ * @param replace operation replacement policy
+ * @exception NullPointerException if key or uri are null
+ * @exception DuplicateKeyException if the key is already locally
assigned and
+ * the supplied replacement policy is FALSE
+ */
+ public void addOperation( String key, URI uri, boolean replace )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ if( null == uri )
+ {
+ throw new NullPointerException( "uri" );
+ }
+ if( false == replace )
+ {
+ if( m_operations.containsKey( key ) )
+ {
+ throw new DuplicateKeyException( key );
+ }
+ }
+ Operation operation = new Operation( uri );
+ m_operations.put( key, operation );
+ }
+
+ /**
+ * Return the first operation matching the supplied key in this state
graph. The search
+ * for a matching operation proceeds from the local state upwards uptil
the root state is
+ * reached unless a local or intermidiate operation matches the supplied
key.
+ *
+ * @param key the operation key
+ * @return a matching operation
+ * @exception NoSuchOperationException if no matching operation can be
found
*/
- boolean isTerminal();
+ public Operation getOperation( String key )
+ {
+ return getNamedOperation( key );
+ }
+
+ /**
+ * Return the fisrt operation matching the supplied key in this state
graph. The search
+ * for a matching operation proceeds from the local state upwards uptil
the root state is
+ * reached unless a local or intermidiate operation matches the supplied
key.
+ *
+ * @param key the operation key
+ * @return a matching operation
+ * @exception NoSuchOperationException if no matching operation can be
found
+ */
+ public Operation getNamedOperation( String key )
+ {
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ Operation operation = (Operation) m_operations.get( key );
+ if( null != operation )
+ {
+ return operation;
+ }
+ else
+ {
+ if( null == m_parent )
+ {
+ throw new NoSuchOperationException( key );
+ }
+ else
+ {
+ return m_parent.getNamedOperation( key );
+ }
+ }
+ }
+
+ /**
+ * Returns an array of operation names declared in this state and all
+ * parent states in the active state chain. This method is exposed via
the
+ * StateManager interface (through exposure of State) to controlling
+ * applications. The controlling application can execute an operation
+ * by invoking the 'execute' method on the associated ServiceManager.
+ *
+ * @return the available operation names
+ */
+ public String[] getOperationNames()
+ {
+ if( null == m_parent )
+ {
+ return getLocalOperationNames();
+ }
+ else
+ {
+ String[] keys = m_parent.getOperationNames();
+ String[] local = getLocalOperationNames();
+ String[] result = new String[ keys.length + local.length ];
+ System.arraycopy( keys, 0, result, 0, keys.length );
+ System.arraycopy( local, 0, result, keys.length, local.length );
+ return result;
+ }
+ }
+
+ /**
+ * Return the list of operation names local to this state.
+ * @return the array of operation names
+ */
+ public String[] getLocalOperationNames()
+ {
+ return (String[]) m_operations.keySet().toArray( new String[0] );
+ }
+
+ /**
+ * return a string representation of this state.
+ * @return the string representation
+ */
+ public String toString()
+ {
+ if( null != m_parent )
+ {
+ return "[state " + m_name + " (from:" + m_parent.getName() +
")]";
+ }
+ else
+ {
+ return "[state " + m_name + "]";
+ }
+ }
+
+ public boolean equals( Object other )
+ {
+ if( null == other )
+ {
+ return false;
+ }
+ else if( this.hashCode() == other.hashCode() )
+ {
+ return true;
+ }
+ else if( other instanceof State )
+ {
+ State state = (State) other;
+ return m_name.equals( state.getName() );
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ private boolean equals( Object one, Object two )
+ {
+ if( null == one )
+ {
+ return ( null == two );
+ }
+ else
+ {
+ return one.equals( two );
+ }
+ }
+
+ public int hashCode()
+ {
+ return m_name.hashCode();
+ }
+
+ /**
+ * Untility function that returns a string representation of this state
+ * in the form of a graph.
+ * @return the string representation of the graph represented by this
+ * node and all child nodes
+ */
+ public String list()
+ {
+ StringBuffer buffer = new StringBuffer();
+ graph( buffer, this, "" );
+ return buffer.toString();
+ }
+
+ /**
+ * Internal utility to handle graph construction.
+ * @param buffer a string buffer to write to
+ * @param state the state to include
+ * @param offset a character offset to apply when writting out the state
features
+ */
+ private void graph( StringBuffer buffer, State state, String offset )
+ {
+ String name = state.getName();
+ buffer.append( "\n" + offset );
+ buffer.append( "state: " + name );
+ if( state.isTerminal() )
+ {
+ buffer.append( " (terminal)" );
+ }
+ Transition initializer = state.getInitialization();
+ if( initializer != null )
+ {
+ buffer.append(
+ "\n " + offset + "initializer:" + name + " --> state:"
+ + initializer.getTargetState().getName() );
+ }
+ Transition terminator = state.getTerminator();
+ if( terminator != null )
+ {
+ buffer.append(
+ "\n " + offset + "terminator:" + name + " --> state:"
+ + terminator.getTargetState().getName() );
+ }
+ String[] transitions = state.getLocalTransitionNames();
+ for( int i=0; i<transitions.length; i++ )
+ {
+ String t = transitions[i];
+ Transition transition = state.getNamedTransition( t );
+ State target = transition.getTargetState();
+ buffer.append( "\n " + offset + "transition:" + t + " -->
state:" + target.getName() );
+ }
+ String[] operations = state.getLocalOperationNames();
+ for( int i=0; i<operations.length; i++ )
+ {
+ String o = operations[i];
+ Operation operation = state.getNamedOperation( o );
+ buffer.append( "\n " + offset + "operation:" + o );
+ }
+
+ State[] states = state.getStates();
+ for( int i=0; i<states.length; i++ )
+ {
+ State s = states[i];
+ graph( buffer, s, offset + " " );
+ }
+ }
+
+ private void validateTransition( String role, String key, URI uri, State
target )
+ {
+ validateIsaMember( role, key, target );
+ validateNonNullTarget( role, key, target );
+ if( role.equals( TERMINATOR ) )
+ {
+ validateNotSelf( role, key, target );
+ }
+ else if( role.equals( TRANSITION ) )
+ {
+ validateNotSelf( role, key, target );
+ validateNonTerminal( role, key, target );
+ }
+ }
+
+ private void validateNotSelf( String role, String key, State target )
+ {
+ if( this == target )
+ {
+ String keyLine = "";
+ if( null != key )
+ {
+ keyLine = "\nKey: " + key;
+ }
+ final String error =
+ "Cannot add " + role
+ + " because "
+ + "the containing state and target state are the same."
+ + "\nState: " + getName()
+ + "\nTarget: " + target.getName()
+ + keyLine;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private void validateNonTerminal( String role, String key, State target )
+ {
+ if( isTerminal() )
+ {
+ String line = "";
+ String targetLine = "";
+ if( null != key )
+ {
+ line = "\nKey: " + key;
+ }
+ if( null != target )
+ {
+ targetLine = "\nTarget: " + target.getName();
+ }
+ final String error =
+ "Cannot add " + role + " to a terminal state."
+ + "\nState: " + getName()
+ + targetLine
+ + line;
+ throw new IllegalStateException( error );
+ }
+ }
+
+ private void validateIsaMember( String role, String key, State target )
+ {
+ String keyLine = "";
+ if( null != key )
+ {
+ keyLine = "\nKey: " + key;
+ }
+ if( false == isaMemberOfGraph( target ) )
+ {
+ final String error =
+ "Cannot add " + role
+ + " because "
+ + "the declared target state is not a member of the state
graph."
+ + "\nState: " + getName()
+ + "\nTarget: " + target.getName()
+ + keyLine ;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ private void validateNonNullTarget( String role, String key, State
target )
+ {
+ String keyLine = "";
+ if( null != key )
+ {
+ keyLine = "\nKey: " + key;
+ }
+ if( null == target )
+ {
+ final String error =
+ "Cannot add " + role + " due to undefined target."
+ + "\nState: " + getName()
+ + keyLine;
+ throw new NullPointerException( error );
+ }
+ }
+
+ /**
+ * Utility operation to test if a supplied state instance is an
+ * instance from this state graph.
+ *
+ * @param state the instance to evalue
+ * @return TRUE if the instance is a member else FALSE
+ */
+ private boolean isaMemberOfGraph( State state )
+ {
+ State[] states = getAllStates();
+ for( int i=0; i<states.length; i++ )
+ {
+ State s = states[i];
+ if( s == state ) return true;
+ }
+ return false;
+ }
+
+ public static final String TERMINATOR = "terminator";
+ public static final String INITIALIZER = "initializer";
+ public static final String TRANSITION = "transition";
+
}

Modified:
development/main/metro/parts/src/main/net/dpml/parts/state/Transition.java
==============================================================================
---
development/main/metro/parts/src/main/net/dpml/parts/state/Transition.java
(original)
+++
development/main/metro/parts/src/main/net/dpml/parts/state/Transition.java
Tue May 10 01:58:07 2005
@@ -18,17 +18,63 @@

package net.dpml.parts.state;

+import java.net.URI;
+
/**
- * The Transition interface delcares the target state and system or user
- * mode in which this transition exists.
+ * The DefualtTransition class associated a transition handler and a target
+ * state.
*
* @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
*/
-public interface Transition
+public class Transition
{
+ private final State m_target;
+ private final URI m_handler;
+
+ /**
+ * Internal utility to construct a new transition instance. This
constructor
+ * is used by the State state implementation class as part of it's
transition
+ * factory operations.
+ *
+ * @param handler the uri identifying the handler
+ * @param target the transition target state
+ * @param system if TRUE this is a system transition otherwise the
transition
+ * is a user (application) transition
+ */
+ protected Transition( URI handler, State target )
+ {
+ if( null == target )
+ {
+ throw new NullPointerException( "target" );
+ }
+ m_handler = handler;
+ m_target = target;
+ }
+
+ /**
+ * Return the handler uri identifier associated with this transition.
+ * @return the transition handler identfier
+ */
+ public URI getHandlerURI()
+ {
+ return m_handler;
+ }
+
+ /**
+ * Return the target of this transition.
+ * @return the transition target
+ */
+ public State getTargetState()
+ {
+ return getTransitionTarget();
+ }
+
/**
* Return the target of this transition.
* @return the transition target
*/
- State getTargetState();
+ public State getTransitionTarget()
+ {
+ return m_target;
+ }
}

Added:
development/main/metro/parts/src/test/net/dpml/parts/state/OperationTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/test/net/dpml/parts/state/OperationTestCase.java
Tue May 10 01:58:07 2005
@@ -0,0 +1,67 @@
+/*
+ * 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.parts.state;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import junit.framework.TestCase;
+
+import net.dpml.parts.model.DuplicateKeyException;
+
+/**
+ * Test creation of the default operation implentation.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: AbstractDescriptorTestCase.java 1556 2005-01-22 12:43:42Z
niclas $
+ */
+public class OperationTestCase extends TestCase
+{
+ private URI m_uri;
+ private Operation m_operation;
+
+ /**
+ * Setup the Operation
+ */
+ public void setUp() throws Exception
+ {
+ m_uri = new URI( "method:null" );
+ m_operation = new Operation( m_uri );
+ }
+
+ public void testURI() throws Exception
+ {
+ assertEquals( "uri", m_uri, m_operation.getHandlerURI() );
+ }
+
+ public void testConstructorWithNullURI() throws Exception
+ {
+ try
+ {
+ new Operation( null );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+}
+
+
+

Added:
development/main/metro/parts/src/test/net/dpml/parts/state/StateTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/test/net/dpml/parts/state/StateTestCase.java
Tue May 10 01:58:07 2005
@@ -0,0 +1,756 @@
+/*
+ * 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.parts.state;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import net.dpml.parts.model.DuplicateKeyException;
+
+import junit.framework.TestCase;
+
+/**
+ * Test creation of a state model.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: AbstractDescriptorTestCase.java 1556 2005-01-22 12:43:42Z
niclas $
+ */
+public class StateTestCase extends TestCase
+{
+ private State m_root = null;
+
+ /**
+ * Test the State as a vehicle for the creation of a state model.
+ */
+ public void setUp() throws Exception
+ {
+ State root = new State();
+ root.addOperation( "foo", new URI( "handler:foo" ) );
+ root.addOperation( "bar", new URI( "handler:bar" ) );
+ m_root = root;
+ }
+
+ public void testRootName() throws Exception
+ {
+ String name = m_root.getName();
+ assertEquals( "root name", "root", name );
+ }
+
+ public void testRootParent() throws Exception
+ {
+ State parent = m_root.getParent();
+ assertNull( "root parent", parent );
+ }
+
+ public void testRootNotTerminal() throws Exception
+ {
+ assertFalse( "root is terminal", m_root.isTerminal() );
+ }
+
+ public void testRootTerminal() throws Exception
+ {
+ State root = new State( true );
+ assertTrue( "is terminal", root.isTerminal() );
+ }
+
+ public void testRootOperations() throws Exception
+ {
+ String[] operations = m_root.getOperationNames();
+ if( operations.length < 2 )
+ {
+ fail( "root operation count is less than 2" );
+ }
+ }
+
+ public void testStateCount() throws Exception
+ {
+ State[] states = m_root.getStates();
+ if( states.length > 0 )
+ {
+ fail( "nested state count is not 0" );
+ }
+ }
+
+ public void testAddStateWithNullKey() throws Exception
+ {
+ try
+ {
+ m_root.addState( null );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddState() throws Exception
+ {
+ String name = "running";
+ m_root.addState( name );
+ State[] states = m_root.getStates();
+ if( states.length != 1 )
+ {
+ fail( "sub-state count != 1" );
+ }
+ }
+
+ public void testAddDuplicateState() throws Exception
+ {
+ String name = "running";
+ m_root.addState( name );
+ try
+ {
+ m_root.addState( name );
+ }
+ catch( DuplicateKeyException e )
+ {
+ // success
+ }
+ State[] states = m_root.getStates();
+ if( states.length != 1 )
+ {
+ fail( "sub-state count != 1" );
+ }
+ }
+
+ public void testAddTerminalState() throws Exception
+ {
+ String name = "running";
+ State terminal = m_root.addTerminalState( name );
+ State[] states = m_root.getStates();
+ if( states.length != 1 )
+ {
+ fail( "sub-state count != 1" );
+ }
+ }
+
+ public void testTerminalState() throws Exception
+ {
+ String name = "running";
+ State terminal = m_root.addTerminalState( name );
+ assertTrue( "terminal state is terminal", terminal.isTerminal() );
+ }
+
+ public void testAddDuplicateTerminalState() throws Exception
+ {
+ String name = "running";
+ m_root.addTerminalState( name );
+ try
+ {
+ m_root.addState( name );
+ }
+ catch( DuplicateKeyException e )
+ {
+ // success
+ }
+ State[] states = m_root.getStates();
+ if( states.length != 1 )
+ {
+ fail( "sub-state count != 1" );
+ }
+ }
+
+ public void testLocalStateCount() throws Exception
+ {
+ m_root.addState( "aaa" );
+ m_root.addState( "bbb" );
+ m_root.addState( "ccc" );
+ State[] states = m_root.getStates();
+ if( states.length != 3 )
+ {
+ fail( "sub-state count != 3" );
+ }
+ }
+
+ public void testAllStatesCount() throws Exception
+ {
+ m_root.addState( "aaa" );
+ m_root.addState( "bbb" );
+ m_root.addState( "ccc" );
+ if( m_root.getAllStates().length != 4 )
+ {
+ fail( "total-state count != 4" );
+ }
+ }
+
+ public void testAllStatesCountInGraph() throws Exception
+ {
+ int n = 1;
+ for( int i=0; i<10; i++ )
+ {
+ State s = m_root.addState( "" + i );
+ n++;
+ }
+ State[] states = m_root.getStates( m_root );
+ for( int i=0; i<states.length; i++ )
+ {
+ State p = states[i];
+ for( int j=0; j<10; j++ )
+ {
+ p.addState( p.getName() + "." + j );
+ n++;
+ }
+ }
+ if( m_root.getAllStates().length != n )
+ {
+ fail( "sub-state count != " + n );
+ }
+ }
+
+ public void testStatesCountInTarget() throws Exception
+ {
+ int n = 0;
+ State foo = m_root.addState( "foo" );
+ for( int i=0; i<10; i++ )
+ {
+ State s = foo.addState( "" + i );
+ n++;
+ }
+ State[] states = foo.getStates();
+ if( states.length != n )
+ {
+ fail( "sub-state count " + states.length + " != " + n );
+ }
+ }
+
+ public void testStatesCountInSuppliedTarget() throws Exception
+ {
+ int n = 0;
+ State foo = m_root.addState( "foo" );
+ for( int i=0; i<10; i++ )
+ {
+ State s = foo.addState( "" + i );
+ n++;
+ }
+ State[] states = m_root.getStates( foo );
+ if( states.length != n )
+ {
+ fail( "sub-state count " + states.length + " != " + n );
+ }
+ }
+
+ public void testGetStateWithNull() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.getState( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetInvalidState() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.getState( "bar" );
+ fail( "do not throw NSSE" );
+ }
+ catch( NoSuchStateException e )
+ {
+ // success
+ }
+ }
+
+ public void testRootStateRetrieval() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ State s = m_root.getState( "foo" );
+ assertEquals( "testing created is retrieved", foo, s );
+ }
+
+ public void testSubStateRetrieval() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ State s = foo.getState( "foo" );
+ assertEquals( "testing created is retrieved", foo, s );
+ }
+
+ public void testAddTransitionNullKey() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addTransition( null, new URI( "method:null" ), foo );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddTransitionNullURI() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addTransition( "to-foo", null, foo );
+ }
+ catch( NullPointerException e )
+ {
+ fail( "null uris are allowed in transitions" );
+ }
+ }
+
+ public void testAddTransitionNullTarget() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addTransition( "to-foo", new URI( "method:null" ), null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddTransitionBadTarget() throws Exception
+ {
+ State foo = new State();
+ try
+ {
+ m_root.addTransition( "to-foo", new URI( "method:null" ), foo );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddTransitionInTerminal() throws Exception
+ {
+ State foo = m_root.addTerminalState( "foo" );
+ try
+ {
+ foo.addTransition( "from-foo", new URI( "method:null" ), m_root
);
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalStateException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddTransitionToSelf() throws Exception
+ {
+ try
+ {
+ m_root.addTransition( "nowhere", new URI( "method:null" ),
m_root );
+ fail( "do not throw IAE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationNullURI() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setInitialization( null, foo );
+ }
+ catch( NullPointerException e )
+ {
+ fail( "null uris are allowed in initializers" );
+ }
+ }
+
+ public void testSetInitializationNullTarget() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setInitialization( new URI( "system:null" ), null );
+ fail( "No NPE." );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationBadTarget() throws Exception
+ {
+ State foo = new State();
+ try
+ {
+ m_root.setInitialization( new URI( "method:null" ), foo );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationInTerminal() throws Exception
+ {
+ State foo = m_root.addTerminalState( "foo" );
+ try
+ {
+ foo.setInitialization( new URI( "method:null" ), m_root );
+ // success
+ }
+ catch( IllegalStateException e )
+ {
+ fail( "Initializations in terminals are allowed." );
+ }
+ }
+
+ public void testTerminatorNullURI() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setTerminator( null, foo );
+ }
+ catch( NullPointerException e )
+ {
+ fail( "null uris are allowed in terminators" );
+ }
+ }
+
+ public void testTerminatorNullTarget() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setTerminator( new URI( "system:null" ), null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetTerminatorBadTarget() throws Exception
+ {
+ State foo = new State();
+ try
+ {
+ m_root.setTerminator( new URI( "method:null" ), foo );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetTerminatorInTerminal() throws Exception
+ {
+ State foo = m_root.addTerminalState( "foo" );
+ foo.setTerminator( m_root );
+ }
+
+ public void testGetTransition() throws Exception
+ {
+ String name = "bar";
+ URI uri = new URI( "method:null" );
+ State foo = m_root.addState( "foo" );
+ m_root.addTransition( name, uri, foo );
+ Transition bar = m_root.getTransition( name );
+ assertEquals( "target", foo, bar.getTargetState() );
+ }
+
+ public void testGetTransitionWithInvalidKey() throws Exception
+ {
+ try
+ {
+ m_root.getTransition( "fred" );
+ fail( "do not throw NSTE" );
+ }
+ catch( NoSuchTransitionException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetTransitionWithNullKey() throws Exception
+ {
+ try
+ {
+ m_root.getTransition( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetNamedTransition() throws Exception
+ {
+ String name = "bar";
+ URI uri = new URI( "method:null" );
+ State foo = m_root.addState( "foo" );
+ m_root.addTransition( name, uri, foo );
+ Transition bar = m_root.getNamedTransition( name );
+ assertEquals( "target", foo, bar.getTargetState() );
+ assertEquals( "handler", uri, bar.getHandlerURI() );
+ }
+
+ public void testGetNamedTransitionWithNullKey() throws Exception
+ {
+ try
+ {
+ m_root.getNamedTransition( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetNamedTransitionWithInvalidKey() throws Exception
+ {
+ try
+ {
+ m_root.getNamedTransition( "fred" );
+ fail( "do not throw NSTE" );
+ }
+ catch( NoSuchTransitionException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddOperationNullKey() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addOperation( null, new URI( "method:null" ) );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddOperationNullURI() throws Exception
+ {
+ State foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addOperation( "key", null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddDuplicateOperation() throws Exception
+ {
+ m_root.addOperation( "aaa", new URI( "method:null" ) );
+ try
+ {
+ m_root.addOperation( "aaa", new URI( "method:null" ) );
+ fail( "do not throw DKE" );
+ }
+ catch( DuplicateKeyException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddDuplicateOperationWithPolicy() throws Exception
+ {
+ m_root.addOperation( "aaa", new URI( "method:null" ) );
+ try
+ {
+ m_root.addOperation( "aaa", new URI( "method:null" ), false );
+ fail( "do not throw DKE" );
+ }
+ catch( DuplicateKeyException e )
+ {
+ // success
+ }
+ }
+
+ public void testReplaceOperation() throws Exception
+ {
+ URI bar = new URI( "method:bar" );
+ m_root.addOperation( "aaa", new URI( "method:foo" ) );
+ m_root.addOperation( "aaa", bar, true );
+ Operation operation = m_root.getNamedOperation( "aaa" );
+ assertEquals( "uri", bar, operation.getHandlerURI() );
+ }
+
+ public void testGetOperationNullKey() throws Exception
+ {
+ try
+ {
+ m_root.getOperation( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetOperationBadKey() throws Exception
+ {
+ try
+ {
+ m_root.getOperation( "xyz" );
+ fail( "do not throw NSOE" );
+ }
+ catch( NoSuchOperationException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetNamedOperationNullKey() throws Exception
+ {
+ try
+ {
+ m_root.getNamedOperation( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetNamedOperationBadKey() throws Exception
+ {
+ try
+ {
+ m_root.getNamedOperation( "xyz" );
+ fail( "do not throw NSOE" );
+ }
+ catch( NoSuchOperationException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetLocalOperationNames() throws Exception
+ {
+ URI uri = new URI( "handler:gizmo" );
+ State foo = m_root.addState( "foo" );
+ foo.addOperation( "widget", uri );
+ foo.addOperation( "gizmo", uri );
+ String[] operations = foo.getLocalOperationNames();
+ assertEquals( "operations", operations.length, 2 );
+ }
+
+ public void testGetNamedOperation() throws Exception
+ {
+ URI uri = new URI( "handler:gizmo" );
+ State foo = m_root.addState( "foo" );
+ foo.addOperation( "widget", uri );
+ Operation operation = foo.getNamedOperation( "widget" );
+ assertNotNull( "operation", operation );
+ assertEquals( "uri", uri, operation.getHandlerURI() );
+ }
+
+ public void testGetOperationNames() throws Exception
+ {
+ URI uri = new URI( "handler:gizmo" );
+ int n = m_root.getOperationNames().length;
+ State foo = m_root.addState( "foo" );
+ foo.addOperation( "widget", uri );
+ int m = m_root.getOperationNames().length;
+ assertEquals( "operation count", m, n ); // we don't see child
operations
+ }
+
+ public void testGetNestedOperationNames() throws Exception
+ {
+ URI uri = new URI( "handler:gizmo" );
+ int n = m_root.getOperationNames().length;
+ State foo = m_root.addState( "foo" );
+ foo.addOperation( "widget", uri );
+ int m = foo.getOperationNames().length;
+ assertEquals( "operation count", m, n+1 ); // we see local plus
parent operations
+ }
+
+ public void testGraphOperationCount() throws Exception
+ {
+ State root = createComplexState();
+ State started = root.getState( "started" );
+ assertEquals( "operations", started.getOperationNames().length, 3 );
+ }
+
+ public void testGraphTransitionCount() throws Exception
+ {
+ State root = createComplexState();
+ State started = root.getState( "started" );
+ assertEquals( "transitions", started.getTransitionNames().length, 1
);
+ }
+
+ public void testList() throws Exception
+ {
+ State root = createComplexState();
+ root.list();
+ }
+
+ public State createComplexState() throws Exception
+ {
+ //
+ // construct a state graph
+ //
+
+ State root = new State();
+ State initialized = root.addState( "initialized" );
+ State available = root.addState( "available" );
+ State started = available.addState( "started" );
+ State stopped = available.addState( "stopped" );
+ State terminated = root.addTerminalState( "terminated" );
+
+ //
+ // add operations and transitions
+ //
+
+ root.setInitialization( new URI( "handler:demo" ), initialized );
+ initialized.setTerminator( new URI( "handler:demo" ), terminated );
+ available.addTransition( "start", new URI( "handler:demo" ), started
);
+ root.addOperation( "foo", new URI( "handler:bar" ) );
+ started.addTransition( "stop", new URI( "handler:demo" ), stopped );
+ started.addOperation( "do-this", new URI( "part:abc" ) );
+ started.addOperation( "do-that", new URI( "method:cde" ) );
+ stopped.addTransition( "start", new URI( "handler:demo" ), started );
+
+ return root;
+ }
+
+}
+
+
+

Added:
development/main/metro/parts/src/test/net/dpml/parts/state/TransitionTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/parts/src/test/net/dpml/parts/state/TransitionTestCase.java
Tue May 10 01:58:07 2005
@@ -0,0 +1,91 @@
+/*
+ * 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.parts.state;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import junit.framework.TestCase;
+
+import net.dpml.parts.model.DuplicateKeyException;
+
+/**
+ * Test creation of a state model.
+ *
+ * @author <a href="mailto:dev-dpml AT lists.ibiblio.org";>The Digital Product
Meta Library</a>
+ * @version $Id: AbstractDescriptorTestCase.java 1556 2005-01-22 12:43:42Z
niclas $
+ */
+public class TransitionTestCase extends TestCase
+{
+ private URI m_uri;
+ private State m_target;
+ private Transition m_transition;
+
+ /**
+ * Test the State as a vehicle for the creation of a state model.
+ */
+ public void setUp() throws Exception
+ {
+ m_uri = new URI( "method:null" );
+ m_target = new State();
+ m_transition = new Transition( m_uri, m_target );
+ }
+
+ public void testURI() throws Exception
+ {
+ assertEquals( "uri", m_uri, m_transition.getHandlerURI() );
+ }
+
+ public void testTargetState() throws Exception
+ {
+ assertEquals( "target", m_target, m_transition.getTargetState() );
+ }
+
+ public void testTransitionTargetState() throws Exception
+ {
+ assertEquals( "target", m_target, m_transition.getTransitionTarget()
);
+ }
+
+ public void testConstructorWithNullURI() throws Exception
+ {
+ try
+ {
+ new Transition( null, m_target );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testConstructorWithNullTarget() throws Exception
+ {
+ try
+ {
+ new Transition( m_uri, null );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+}
+
+
+



  • svn commit: r2481 - in development/main/metro: . composition/control/src/main/net/dpml/composition/control composition/control/src/main/net/dpml/composition/model composition/part/src/main/net/dpml/composition/state composition/part/src/test/net/dpml/composition/state composition/testing/test/src/main/net/dpml/test/state composition/testing/workshop/src/test/net/dpml/test parts/src/main/net/dpml/parts/state parts/src/test parts/src/test/net parts/src/test/net/dpml parts/src/test/net/dpml/parts parts/src/test/net/dpml/parts/state, mcconnell, 05/09/2005

Archive powered by MHonArc 2.6.24.

Top of Page