Skip to Content.
Sympa Menu

notify-dpml - svn commit: r2326 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/testing/activity/src/main/net/dpml/test composition/testing/activity/src/test/net/dpml/test state/api/src/main/net/dpml/state state/impl/src/main/net/dpml/state/impl state/impl/src/test/net/dpml/state/impl

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: r2326 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/testing/activity/src/main/net/dpml/test composition/testing/activity/src/test/net/dpml/test state/api/src/main/net/dpml/state state/impl/src/main/net/dpml/state/impl state/impl/src/test/net/dpml/state/impl
  • Date: Tue, 19 Apr 2005 22:03:37 -0400

Author: mcconnell AT dpml.net
Date: Tue Apr 19 22:03:30 2005
New Revision: 2326

Added:

development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultOperationTestCase.java

development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultTransitionTestCase.java
Modified:

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

development/main/metro/composition/testing/activity/src/main/net/dpml/test/Component.java

development/main/metro/composition/testing/activity/src/test/net/dpml/test/ComponentTestCase.java
development/main/metro/state/api/src/main/net/dpml/state/Transition.java

development/main/metro/state/impl/src/main/net/dpml/state/impl/AbstractStateManager.java

development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultOperation.java

development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultState.java

development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultTransition.java

development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultStateTestCase.java
Log:
housekeeping

Modified:
development/main/metro/composition/control/src/main/net/dpml/composition/control/StateManagerInvocationHandler.java
==============================================================================
---
development/main/metro/composition/control/src/main/net/dpml/composition/control/StateManagerInvocationHandler.java
(original)
+++
development/main/metro/composition/control/src/main/net/dpml/composition/control/StateManagerInvocationHandler.java
Tue Apr 19 22:03:30 2005
@@ -233,14 +233,14 @@
throw new NoSuchTransitionException( key );
}

- public String list()
+ public boolean isTerminal()
{
- return "state:available";
+ return true;
}

- public boolean isTerminal()
+ public String list()
{
- return true;
+ return "state:available";
}
}


Modified:
development/main/metro/composition/testing/activity/src/main/net/dpml/test/Component.java
==============================================================================
---
development/main/metro/composition/testing/activity/src/main/net/dpml/test/Component.java
(original)
+++
development/main/metro/composition/testing/activity/src/main/net/dpml/test/Component.java
Tue Apr 19 22:03:30 2005
@@ -62,7 +62,7 @@
}

// ------------------------------------------------------------------
- // implementation
+ // concerns
// ------------------------------------------------------------------

public class Controller extends AbstractStateManager
@@ -89,13 +89,17 @@
}
}

+ // ------------------------------------------------------------------
+ // implementation
+ // ------------------------------------------------------------------
+
private Logger getLogger()
{
return m_logger;
}

//
- // The following methods are invoked by the state manager based on
+ // The following component methods are invoked by the state manager
based on
// uris assigned to transitions. The state manager locates the method
// from the uri and invokes the operation after constructing arguments
// from the possible set of Logger, Object (component impl), State
(initial),
@@ -174,9 +178,9 @@
// use, and the transitions target state
//

- root.addTerminatingTransition( new URI( "handler:terminate" ),
terminated );
- root.addInitializingTransition( new URI( "method:null" ),
initialized );
- started.addTerminatingTransition( new URI( "method:stop" ),
stopped );
+ root.setTerminator( new URI( "handler:terminate" ), terminated );
+ root.setInitialization( new URI( "method:null" ), initialized );
+ started.setTerminator( new URI( "method:stop" ), stopped );

//
// add user (application) transitions

Modified:
development/main/metro/composition/testing/activity/src/test/net/dpml/test/ComponentTestCase.java
==============================================================================
---
development/main/metro/composition/testing/activity/src/test/net/dpml/test/ComponentTestCase.java
(original)
+++
development/main/metro/composition/testing/activity/src/test/net/dpml/test/ComponentTestCase.java
Tue Apr 19 22:03:30 2005
@@ -61,11 +61,8 @@
{
String name = transitions[i];
Transition transition = state.getTransition( name );
- if( transition.isUserTransition() )
- {
- manager.apply( name );
- break;
- }
+ manager.apply( name );
+ break;
}
}
manager.terminate();

Modified:
development/main/metro/state/api/src/main/net/dpml/state/Transition.java
==============================================================================
--- development/main/metro/state/api/src/main/net/dpml/state/Transition.java
(original)
+++ development/main/metro/state/api/src/main/net/dpml/state/Transition.java
Tue Apr 19 22:03:30 2005
@@ -31,18 +31,4 @@
* @return the transition target
*/
State getTargetState();
-
- /**
- * Returns TRUE if the transition is a system transition.
- *
- * @return TRUE if system transition
- */
- boolean isSystemTransition();
-
- /**
- * Returns TRUE if the transition is a user transition.
- *
- * @return TRUE if user transition
- */
- boolean isUserTransition();
}

Modified:
development/main/metro/state/impl/src/main/net/dpml/state/impl/AbstractStateManager.java
==============================================================================
---
development/main/metro/state/impl/src/main/net/dpml/state/impl/AbstractStateManager.java
(original)
+++
development/main/metro/state/impl/src/main/net/dpml/state/impl/AbstractStateManager.java
Tue Apr 19 22:03:30 2005
@@ -18,20 +18,25 @@

package net.dpml.state.impl;

-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.Hashtable;
import java.util.Map;
-import java.util.logging.Level;
+import java.util.Hashtable;
+import java.util.TreeMap;
+import java.util.ArrayList;
import java.util.logging.Logger;
+import java.util.logging.Level;
+import java.lang.reflect.Method;
+import java.net.URI;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

-import net.dpml.state.DuplicateKeyException;
-import net.dpml.state.NoSuchTransitionException;
import net.dpml.state.State;
+import net.dpml.state.Transition;
import net.dpml.state.StateManager;
+import net.dpml.state.DuplicateKeyException;
+import net.dpml.state.NoSuchTransitionException;
+import net.dpml.state.NoSuchOperationException;
+import net.dpml.state.Operation;

/**
* The State interface is an interface representing an immutable state of
@@ -159,11 +164,12 @@
boolean flag = true;
while( flag )
{
- try
+ DefaultTransition initialization =
getCurrentState().getInitialization();
+ if( null != initialization )
{
- flag = apply( "initialize" );
+ flag = apply( initialization );
}
- catch( NoSuchTransitionException e )
+ else
{
flag = false;
}
@@ -231,6 +237,27 @@
{
DefaultState state = getCurrentState();
DefaultTransition transition = state.getNamedTransition( key );
+ return apply( transition );
+ }
+
+ /**
+ * 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
+ * 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.
+ * If the transition resolved from the supplied key references a target
state
+ * that is the same as the current state the transition will not be
invoked and
+ * the method will return false.
+ *
+ * @param key the transition key
+ * @return TRUE if the transition was executed
+ * @exception if a error occurs in transition execution
+ */
+ public boolean apply( DefaultTransition transition ) throws Exception
+ {
+ DefaultState state = getCurrentState();
URI handler = transition.getHandlerURI();
DefaultState target = transition.getTransitionTarget();
if( state.equals( target ) )
@@ -304,64 +331,85 @@
*/
private void execution( URI uri, State state, State target, Logger
logger ) throws Exception
{
- String scheme = uri.getScheme();
- if( "part".equals( scheme ) )
- {
- //
- // delegate transition execution to an identified part
- //
-
- throw new UnsupportedOperationException( uri.toString() );
- }
- else if( "handler".equals( scheme ) )
- {
- //
- // delegate execution to an registered handler
- //
-
- String spec = uri.getSchemeSpecificPart();
- if( "null".equals( spec ) )
- {
- return;
- }
- else
- {
- Object h = getRegisteredHandler( spec );
- Class c = h.getClass();
- Method method = locateMethod( c, "handle" );
- Class[] parameters = method.getParameterTypes();
- Object[] args = resolveArguments( parameters, state,
target, logger );
- method.invoke( h, args );
- }
- }
- else if( "method".equals( scheme ) )
- {
- //
- // invoke the named method on the component instance
- //
-
- String spec = uri.getSchemeSpecificPart();
- if( "null".equals( spec ) )
- {
- return;
- }
- else
- {
- Class c = m_instance.getClass();
- Method method = locateMethod( c, spec );
- Class[] parameters = method.getParameterTypes();
- Object[] args = resolveArguments( parameters, state,
target, logger );
- method.invoke( m_instance, args );
- }
- }
- else
- {
- final String error =
- "Scheme not recognized."
- + "\nScheme: " + scheme
- + "\nURI: " + uri;
- throw new IllegalArgumentException( error );
- }
+ String scheme = uri.getScheme();
+ if( "part".equals( scheme ) )
+ {
+ //
+ // Delegate transition execution to an identified part. The
supplied
+ // uri argument contains the key of the part in the scheme
specific
+ // element of the uri. If the reference is to an identifiable
instance
+ // the instance identity is encoded in the uri fragment. In
order to
+ // resolve the part in the form of an instance we need to
convert the
+ // part refernece to a form that is consitent with the
operations exposed
+ // on the part interface.
+ //
+
+ Object object = getPartObjectFromURI( uri ); // ain't ready yet
+ Class c = object.getClass();
+ Method method = locateMethod( c, "handle" );
+ Class[] parameters = method.getParameterTypes();
+ Object[] args = resolveArguments( parameters, state, target,
logger );
+ method.invoke( object, args );
+ }
+ else if( "handler".equals( scheme ) )
+ {
+ //
+ // delegate execution to an registered handler
+ //
+
+ String spec = uri.getSchemeSpecificPart();
+ if( "null".equals( spec ) )
+ {
+ return;
+ }
+ else
+ {
+ Object h = getRegisteredHandler( spec );
+ Class c = h.getClass();
+ Method method = locateMethod( c, "handle" );
+ Class[] parameters = method.getParameterTypes();
+ Object[] args = resolveArguments( parameters, state, target,
logger );
+ method.invoke( h, args );
+ }
+ }
+ else if( "method".equals( scheme ) )
+ {
+ //
+ // invoke the named method on the component instance
+ //
+
+ String spec = uri.getSchemeSpecificPart();
+ if( "null".equals( spec ) )
+ {
+ return;
+ }
+ else
+ {
+ Class c = m_instance.getClass();
+ Method method = locateMethod( c, spec );
+ Class[] parameters = method.getParameterTypes();
+ Object[] args = resolveArguments( parameters, state, target,
logger );
+ method.invoke( m_instance, args );
+ }
+ }
+ else
+ {
+ final String error =
+ "Scheme not recognized."
+ + "\nScheme: " + scheme
+ + "\nURI: " + uri;
+ throw new IllegalArgumentException( error );
+ }
+ }
+
+ /**
+ * This utiity method is charged with the potentially impossibble tasks
of resolving
+ * an object from a uri that refers to a part within the collection of
parts managed
+ * the component that this state manager is managing.
+ */
+ private Object getPartObjectFromURI( URI uri )
+ {
+ throw new UnsupportedOperationException( "getPartObjectFromURI/1" );
}

/**
@@ -448,26 +496,31 @@
*/
public synchronized void terminate()
{
- DefaultState state = getCurrentState();
- if( state.isTerminal() )
- {
- return;
- }
- try
+ boolean flag = true;
+ while( flag )
{
- boolean flag = true;
- while( flag )
+ DefaultState state = getCurrentState();
+ if( state.isTerminal() )
{
- flag = apply( "terminate" );
+ return;
+ }
+ DefaultTransition terminator = state.getTerminator();
+ if( null == terminator )
+ {
+ return;
+ }
+ else
+ {
+ try
+ {
+ flag = apply( terminator );
+ }
+ catch( Exception e )
+ {
+ flag = false;
+ getLogger().log( Level.WARNING, "Ignoring termination
transtion error", e );
+ }
}
- }
- catch( NoSuchTransitionException e )
- {
- // no default termination transition registered
- }
- catch( Exception e )
- {
- getLogger().log( Level.WARNING, "Ignoring termination transtion
error", e );
}
}


Modified:
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultOperation.java
==============================================================================
---
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultOperation.java
(original)
+++
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultOperation.java
Tue Apr 19 22:03:30 2005
@@ -33,10 +33,10 @@

/**
* Internal utility to construct a new operation instance. This
constructor
- * is used by the DefaultState state implmentation class as part of it's
operation
+ * is used by the DefaultState implementation class as part of it's
operation
* factory service.
*
- * @param handler the uri identifying the handler
+ * @param handler the uri identifying the operation handler
*/
protected DefaultOperation( URI handler )
{
@@ -48,8 +48,8 @@
}

/**
- * Return the handler uri identifier associated with this transition.
- * @return the transition handler identfier
+ * Return the handler uri identifier associated with this operation.
+ * @return the uri identiifying the handler
*/
public URI getHandlerURI()
{

Modified:
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultState.java
==============================================================================
---
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultState.java
(original)
+++
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultState.java
Tue Apr 19 22:03:30 2005
@@ -21,6 +21,8 @@
import java.util.Map;
import java.util.Hashtable;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.URI;
@@ -49,9 +51,13 @@

private final Map m_operations = new Hashtable();
private final Map m_transitions = new Hashtable();
- private final Map m_states = new Hashtable();
private final State m_proxy;

+ private DefaultTransition m_initialization;
+ private DefaultTransition m_terminator;
+
+ private final Map m_states = new Hashtable();
+
/**
* Creation of a new top-level non-terminal state.
*/
@@ -160,37 +166,29 @@
{
String[] keys = m_parent.getTransitionNames();
String[] local = getLocalTransitionNames();
- 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;
+ 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] );
}
}

/**
- * 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()
+ * Return the list of transition names local to this state.
+ * @return the array of transition names
+ */
+ protected String[] getLocalTransitionNames()
{
- 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 (String[]) m_transitions.keySet().toArray( new String[0] );
}

/**
@@ -270,7 +268,6 @@
/**
* Return an array of all states within the state graph. This includes
* all substates of the root state and all substates of substates, etc.
- * It does not include the root state itself.
*
* @return the state array
*/
@@ -282,8 +279,13 @@
}
else
{
- ArrayList list = new ArrayList();
- return (DefaultState[]) m_states.values().toArray( new
DefaultState[0] );
+ ArrayList list = new ArrayList( );
+ DefaultState[] nested =
+ (DefaultState[]) m_states.values().toArray( new
DefaultState[0] );
+ DefaultState[] states = new DefaultState[ nested.length + 1 ];
+ states[0] = this;
+ System.arraycopy( nested, 0, states, 1, nested.length );
+ return states;
}
}

@@ -353,139 +355,97 @@
}

/**
- * A terminating transition is transition with the reserver name
'terminate'.
- * Terminating transitions are the same as classic transition and subject
to
- * the same restrictions concenring name scoping (i.e. at most one
transition
- * named 'terminate' may be assigned to a particular state). A
terminating
- * transition within the scope of the current state chain will be fired
automatically
- * in the event of a request to the state manager for manager
termination. If the
- * result of the application of the teerminal transition is a state
change to a
- * non-terminal state, the state manager will attempt to locate and apply
terminal
- * transitions until either no terminating traistion is found or a
terminal state
- * is reached.
+ * 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
+ * selcting 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 addTerminatingTransition( URI uri, DefaultState target )
+ public void addTransition( String key, URI uri, DefaultState target )
{
- addTransition( "terminate", uri, target, true );
+ if( null == key )
+ {
+ throw new NullPointerException( "key" );
+ }
+ if( m_transitions.containsKey( key ) )
+ {
+ throw new DuplicateKeyException( key );
+ }
+ validateTransition( "transition", key, uri, target );
+ DefaultTransition transition = new DefaultTransition( uri, target );
+ m_transitions.put( key, transition );
}

/**
- * A initializing transition is transition with the reserver name
'initialize'.
- * Initializing transitions are the same as classic transition and
subject to
- * the same restrictions concerning name scoping (i.e. at most one
transition
- * named 'initialize' may be assigned to a particular state). An
initializing
- * transition within the scope of the current state chain will be fired
automatically
- * in the event of a request to the state manager for manager
initialization. If the
- * result of the application of the initialization transition is a state
change to a
- * non-terminal state, the state manager will attempt to locate and apply
initiazation
- * transitions until no further initilizations transitions are reachable.
+ * 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 transition action
- * @param target the transition target state
+ * of the initialization action
+ * @param target the target initialization state
*/
- public void addInitializingTransition( URI uri, DefaultState target )
+ public void setInitialization( URI uri, DefaultState target )
{
- addTransition( "initialize", uri, target, true );
+ if( null != m_initialization )
+ {
+ final String error =
+ "Initilization already set."
+ + "\nState: " + getName();
+ throw new IllegalStateException( error );
+ }
+ validateTransition( "initializer", null, uri, target );
+ m_initialization = new DefaultTransition( uri, 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
- * selcting 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
+ * Return the initialization transition assigned to the state.
+ * @return the initialization transition (possibly null)
*/
- public void addTransition( String key, URI uri, DefaultState target )
+ public DefaultTransition getInitialization()
{
- addTransition( key, uri, target, false );
+ return m_initialization;
}

/**
- * Internal function to add a transition to the state.
+ * 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 key the transition key
- * @param uri the uri identifying the handler to be assingned as the
- * handler of the transition action
+ * @param uri the uri identifying the handler to be assigned as the
handler
+ * of the transition action
* @param target the transition target state
*/
- private void addTransition( String key, URI uri, DefaultState target,
boolean system )
+ public void setTerminator( URI uri, DefaultState target )
{
- if( null == key )
- {
- throw new NullPointerException( "key" );
- }
- if( null == uri )
- {
- throw new NullPointerException( "uri" );
- }
- if( null == target )
- {
- throw new NullPointerException( "target" );
- }
- if( isTerminal() )
+ if( null != m_terminator )
{
final String error =
- "Cannot add a transtion to a terminal state.";
+ "Terminator already set."
+ + "\nState: " + getName();
throw new IllegalStateException( error );
}
- if( m_transitions.containsKey( key ) )
- {
- throw new DuplicateKeyException( key );
- }
- if( false == system )
- {
- if( "initialize".equals( key ) || "terminate".equals( key ) )
- {
- final String error =
- "The supplied key is a reserved transition name."
- + "\nKey: " + key
- + "\nHandler URI: " + uri;
- throw new IllegalArgumentException( error );
- }
- }
- DefaultTransition transition = new DefaultTransition( uri, target,
system );
- m_transitions.put( key, transition );
+ validateTransition( "terminator", null, uri, target );
+ m_terminator = new DefaultTransition( uri, target );
}

/**
- * 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
operaiton 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 assinged. If the an operation
with the
- * same name is assigned to a parent or higher state then this operation
will
- * override that operation.
- *
- * @param key the operation key
- * @param uri the uri identifying the operation handler
+ * Return the terminator transition assigned to the state.
+ * @return the terminator transition (possibly null)
*/
- public void addOperation( String key, URI uri )
+ public DefaultTransition getTerminator()
{
- if( null == key )
- {
- throw new NullPointerException( "key" );
- }
- if( null == uri )
- {
- throw new NullPointerException( "uri" );
- }
- if( m_operations.containsKey( key ) )
- {
- throw new DuplicateKeyException( key );
- }
- DefaultOperation operation = new DefaultOperation( uri );
- m_operations.put( key, operation );
+ return m_terminator;
}

/**
@@ -503,20 +463,6 @@
}

/**
- * 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
- */
- public Operation getOperation( String key )
- {
- return getNamedOperation( key );
- }
-
- /**
* 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.
@@ -550,6 +496,82 @@
}

/**
+ * 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 );
+ }
+ }
+ DefaultOperation operation = new DefaultOperation( 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
+ */
+ 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.
@@ -583,12 +605,29 @@
}

/**
- * Return the list of transition names local to this state.
- * @return the array of transition names
- */
- protected String[] getLocalTransitionNames()
+ * 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()
{
- return (String[]) m_transitions.keySet().toArray( new String[0] );
+ 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;
+ }
}

/**
@@ -682,6 +721,20 @@
{
buffer.append( " (terminal)" );
}
+ DefaultTransition initializer = state.getInitialization();
+ if( initializer != null )
+ {
+ buffer.append(
+ "\n " + offset + "initializer:" + name + " --> state:"
+ + initializer.getTargetState().getName() );
+ }
+ DefaultTransition 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++ )
{
@@ -689,14 +742,6 @@
DefaultTransition transition = state.getNamedTransition( t );
State target = transition.getTargetState();
buffer.append( "\n " + offset + "transition:" + t + " -->
state:" + target.getName() );
- if( "initialize".equals( t ) )
- {
- buffer.append( " (system initializer)" );
- }
- else if( "terminate".equals( t ) )
- {
- buffer.append( " (system terminator)" );
- }
}
String[] operations = state.getLocalOperationNames();
for( int i=0; i<operations.length; i++ )
@@ -713,4 +758,73 @@
graph( buffer, s, offset + " " );
}
}
+
+ /**
+ * 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( DefaultState state )
+ {
+ DefaultState[] states = getAllStates();
+ for( int i=0; i<states.length; i++ )
+ {
+ DefaultState s = states[i];
+ if( s == state ) return true;
+ }
+ return false;
+ }
+
+ private void validateTransition( String role, String key, URI uri,
DefaultState target )
+ {
+ if( null == uri )
+ {
+ throw new NullPointerException( "uri" );
+ }
+ if( null == target )
+ {
+ throw new NullPointerException( "target" );
+ }
+ String line = "";
+ if( null != key )
+ {
+ line = "\nKey: " + key;
+ }
+ if( isTerminal() )
+ {
+ final String error =
+ "Cannot add " + role + " to a terminal state."
+ + "\nState: " + getName()
+ + "\nTarget: " + target.getName()
+ + "\nURI: " + uri
+ + line;
+ throw new IllegalStateException( error );
+ }
+ 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()
+ + "\nURI: " + uri
+ + line;
+ throw new IllegalArgumentException( error );
+ }
+ if( this == target )
+ {
+ final String error =
+ "Cannot add " + role
+ + " because "
+ + "the containing state and target state are the same."
+ + "\nState: " + getName()
+ + "\nTarget: " + target.getName()
+ + "\nURI: " + uri
+ + line;
+ throw new IllegalArgumentException( error );
+ }
+ }
}

Modified:
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultTransition.java
==============================================================================
---
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultTransition.java
(original)
+++
development/main/metro/state/impl/src/main/net/dpml/state/impl/DefaultTransition.java
Tue Apr 19 22:03:30 2005
@@ -33,7 +33,6 @@
{
private final DefaultState m_target;
private final URI m_handler;
- private final boolean m_system;

/**
* Internal utility to construct a new transition instance. This
constructor
@@ -45,7 +44,7 @@
* @param system if TRUE this is a system transition otherwise the
transition
* is a user (application) transition
*/
- protected DefaultTransition( URI handler, DefaultState target, boolean
system )
+ protected DefaultTransition( URI handler, DefaultState target )
{
if( null == handler )
{
@@ -57,7 +56,6 @@
}
m_handler = handler;
m_target = target;
- m_system = system;
}

/**
@@ -79,26 +77,6 @@
}

/**
- * Returns TRUE if the transition is a system transition.
- *
- * @return TRUE if system transition
- */
- public boolean isSystemTransition()
- {
- return m_system;
- }
-
- /**
- * Returns TRUE if the transition is a user transition.
- *
- * @return TRUE if user transition
- */
- public boolean isUserTransition()
- {
- return !isSystemTransition();
- }
-
- /**
* Return the target of this transition.
* @return the transition target
*/

Added:
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultOperationTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultOperationTestCase.java
Tue Apr 19 22:03:30 2005
@@ -0,0 +1,87 @@
+/*
+ * 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.impl;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import junit.framework.TestCase;
+
+import net.dpml.state.State;
+import net.dpml.state.DuplicateKeyException;
+import net.dpml.state.NoSuchStateException;
+import net.dpml.state.NoSuchTransitionException;
+import net.dpml.state.NoSuchOperationException;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+
+/**
+ * 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 DefaultOperationTestCase extends TestCase
+{
+ private URI m_uri;
+ private DefaultOperation m_operation;
+
+ /**
+ * Setup the DefaultOperation
+ */
+ public void setUp() throws Exception
+ {
+ m_uri = new URI( "method:null" );
+ m_operation = new DefaultOperation( m_uri );
+ }
+
+ public void testURI() throws Exception
+ {
+ assertEquals( "uri", m_uri, m_operation.getHandlerURI() );
+ }
+
+ public void testConstructorWithNullURI() throws Exception
+ {
+ try
+ {
+ new DefaultOperation( null );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testImplementsOperation() throws Exception
+ {
+ try
+ {
+ Operation o = (Operation) m_operation;
+ }
+ catch( ClassCastException e )
+ {
+ fail( "DefaultOperation not castable to Operation" );
+ }
+ }
+
+
+}
+
+
+

Modified:
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultStateTestCase.java
==============================================================================
---
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultStateTestCase.java
(original)
+++
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultStateTestCase.java
Tue Apr 19 22:03:30 2005
@@ -25,6 +25,12 @@

import junit.framework.TestCase;

+import net.dpml.state.DuplicateKeyException;
+import net.dpml.state.NoSuchStateException;
+import net.dpml.state.NoSuchTransitionException;
+import net.dpml.state.NoSuchOperationException;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;

/**
* Test creation of a state model.
@@ -34,10 +40,720 @@
*/
public class DefaultStateTestCase extends TestCase
{
+ private DefaultState m_root = null;
+
/**
* Test the DefaultState as a vehicle for the creation of a state model.
*/
- public void testModelCreation() throws Exception
+ public void setUp() throws Exception
+ {
+ DefaultState root = new DefaultState();
+ 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
+ {
+ DefaultState parent = m_root.getParent();
+ assertNull( "root parent", parent );
+ }
+
+ public void testRootProxy() throws Exception
+ {
+ State state = m_root.getProxy();
+ try
+ {
+ DefaultState s = (DefaultState) state;
+ fail( "casting proxied state object to implementation succeeded"
);
+ }
+ catch( ClassCastException e )
+ {
+ // success
+ }
+ }
+
+ public void testRootNotTerminal() throws Exception
+ {
+ assertFalse( "root is terminal", m_root.isTerminal() );
+ }
+
+ public void testRootTerminal() throws Exception
+ {
+ DefaultState root = new DefaultState( 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++ )
+ {
+ DefaultState s = m_root.addState( "" + i );
+ n++;
+ }
+ DefaultState[] states = m_root.getStates( m_root );
+ for( int i=0; i<states.length; i++ )
+ {
+ DefaultState 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;
+ DefaultState foo = m_root.addState( "foo" );
+ for( int i=0; i<10; i++ )
+ {
+ DefaultState s = foo.addState( "" + i );
+ n++;
+ }
+ DefaultState[] states = foo.getStates();
+ if( states.length != n )
+ {
+ fail( "sub-state count " + states.length + " != " + n );
+ }
+ }
+
+ public void testStatesCountInSuppliedTarget() throws Exception
+ {
+ int n = 0;
+ DefaultState foo = m_root.addState( "foo" );
+ for( int i=0; i<10; i++ )
+ {
+ DefaultState s = foo.addState( "" + i );
+ n++;
+ }
+ DefaultState[] states = m_root.getStates( foo );
+ if( states.length != n )
+ {
+ fail( "sub-state count " + states.length + " != " + n );
+ }
+ }
+
+ public void testGetStateWithNull() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.getState( null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetInvalidState() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.getState( "bar" );
+ fail( "do not throw NSSE" );
+ }
+ catch( NoSuchStateException e )
+ {
+ // success
+ }
+ }
+
+ public void testRootStateRetrieval() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ DefaultState s = m_root.getState( "foo" );
+ assertEquals( "testing created is retrieved", foo, s );
+ }
+
+ public void testSubStateRetrieval() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ DefaultState s = foo.getState( "foo" );
+ assertEquals( "testing created is retrieved", foo, s );
+ }
+
+ public void testAddTransitionNullKey() throws Exception
+ {
+ DefaultState 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
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.addTransition( "to-foo", null, foo );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testAddTransitionNullTarget() throws Exception
+ {
+ DefaultState 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
+ {
+ DefaultState foo = new DefaultState();
+ 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
+ {
+ DefaultState 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
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setInitialization( null, foo );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationNullTarget() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setInitialization( new URI( "system:null" ), null );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationBadTarget() throws Exception
+ {
+ DefaultState foo = new DefaultState();
+ try
+ {
+ m_root.setInitialization( new URI( "method:null" ), foo );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetInitializationInTerminal() throws Exception
+ {
+ DefaultState foo = m_root.addTerminalState( "foo" );
+ try
+ {
+ foo.setInitialization( new URI( "method:null" ), m_root );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalStateException e )
+ {
+ // success
+ }
+ }
+
+ public void testTerminatorNullURI() throws Exception
+ {
+ DefaultState foo = m_root.addState( "foo" );
+ try
+ {
+ m_root.setTerminator( null, foo );
+ fail( "do not throw NPE" );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testTerminatorNullTarget() throws Exception
+ {
+ DefaultState 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
+ {
+ DefaultState foo = new DefaultState();
+ try
+ {
+ m_root.setTerminator( new URI( "method:null" ), foo );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalArgumentException e )
+ {
+ // success
+ }
+ }
+
+ public void testSetTerminatorInTerminal() throws Exception
+ {
+ DefaultState foo = m_root.addTerminalState( "foo" );
+ try
+ {
+ foo.setTerminator( new URI( "method:null" ), m_root );
+ fail( "do not throw ISE" );
+ }
+ catch( IllegalStateException e )
+ {
+ // success
+ }
+ }
+
+ public void testGetTransition() throws Exception
+ {
+ String name = "bar";
+ URI uri = new URI( "method:null" );
+ DefaultState 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" );
+ DefaultState foo = m_root.addState( "foo" );
+ m_root.addTransition( name, uri, foo );
+ DefaultTransition 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
+ {
+ DefaultState 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
+ {
+ DefaultState 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 );
+ DefaultOperation 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" );
+ DefaultState 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" );
+ DefaultState foo = m_root.addState( "foo" );
+ foo.addOperation( "widget", uri );
+ DefaultOperation 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;
+ DefaultState 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;
+ DefaultState 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 testList() throws Exception
+ {
+ DefaultState root = createComplexState();
+ System.out.println( root.list() );
+ }
+
+ public void testGraphOperationCount() throws Exception
+ {
+ DefaultState root = createComplexState();
+ DefaultState started = root.getState( "started" );
+ assertEquals( "operations", started.getOperationNames().length, 3 );
+ }
+
+ public void testGraphTransitionCount() throws Exception
+ {
+ DefaultState root = createComplexState();
+ DefaultState started = root.getState( "started" );
+ assertEquals( "transitions", started.getTransitionNames().length, 1
);
+ }
+
+ public DefaultState createComplexState() throws Exception
{
//
// construct a state graph
@@ -51,28 +767,22 @@
DefaultState terminated = root.addTerminalState( "terminated" );

//
- // create the operations and add then under transitions
+ // add operations and transitions
//

- root.addInitializingTransition( new URI( "handler:demo" ),
initialized );
- initialized.addTerminatingTransition( new URI( "handler:demo" ),
terminated );
+ 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 );

- String audit = root.list();
- System.out.println( audit );
+ return root;
}

- public static Operation demo = new Operation();
-
- private static class Operation
- {
- public void handle( Logger logger, State state, State target )
- {
- System.out.println( "transitioning to " + target );
- }
- }
}


+

Added:
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultTransitionTestCase.java
==============================================================================
--- (empty file)
+++
development/main/metro/state/impl/src/test/net/dpml/state/impl/DefaultTransitionTestCase.java
Tue Apr 19 22:03:30 2005
@@ -0,0 +1,111 @@
+/*
+ * 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.impl;
+
+import java.net.URI;
+import java.util.logging.Logger;
+
+import junit.framework.TestCase;
+
+import net.dpml.state.State;
+import net.dpml.state.DuplicateKeyException;
+import net.dpml.state.NoSuchStateException;
+import net.dpml.state.NoSuchTransitionException;
+import net.dpml.state.NoSuchOperationException;
+import net.dpml.state.Transition;
+import net.dpml.state.Operation;
+
+/**
+ * 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 DefaultTransitionTestCase extends TestCase
+{
+ private URI m_uri;
+ private DefaultState m_target;
+ private DefaultTransition m_transition;
+
+ /**
+ * Test the DefaultState as a vehicle for the creation of a state model.
+ */
+ public void setUp() throws Exception
+ {
+ m_uri = new URI( "method:null" );
+ m_target = new DefaultState();
+ m_transition = new DefaultTransition( 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 DefaultTransition( null, m_target );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testConstructorWithNullTarget() throws Exception
+ {
+ try
+ {
+ new DefaultTransition( m_uri, null );
+ }
+ catch( NullPointerException e )
+ {
+ // success
+ }
+ }
+
+ public void testImplementsTransition() throws Exception
+ {
+ try
+ {
+ Transition transition = (Transition) m_transition;
+ }
+ catch( ClassCastException e )
+ {
+ fail( "DefaultTransition not castable to Transition" );
+ }
+ }
+
+
+}
+
+
+



  • svn commit: r2326 - in development/main/metro: composition/control/src/main/net/dpml/composition/control composition/testing/activity/src/main/net/dpml/test composition/testing/activity/src/test/net/dpml/test state/api/src/main/net/dpml/state state/impl/src/main/net/dpml/state/impl state/impl/src/test/net/dpml/state/impl, mcconnell, 04/19/2005

Archive powered by MHonArc 2.6.24.

Top of Page