<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/ConversationService.cfc</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -29,6 +29,8 @@
 	
 	&lt;cffunction name=&quot;fire&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfargument name=&quot;obj&quot; type=&quot;any&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceObject&quot; required=&quot;false&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceMethod&quot; required=&quot;false&quot; /&gt;
 		&lt;cfset var i = 1 /&gt;
 		&lt;cfset var transitions = instance.transitions.getTransitionsFromState(arguments.obj.getCurrentState()) /&gt;
 		&lt;cfset transition = 0 /&gt;
@@ -36,7 +38,7 @@
 		&lt;cfset transitions.reset() /&gt;
 		&lt;cfloop condition=&quot;transitions.hasNext()&quot;&gt;
 			&lt;cfset transition = transitions.next() /&gt;
-			&lt;cfif transition.perform(obj)&gt;
+			&lt;cfif transition.perform(obj, arguments.persistenceObject, arguments.persistenceMethod)&gt;
 				&lt;cfreturn true /&gt;
 			&lt;/cfif&gt;
 		&lt;/cfloop&gt;	</diff>
      <filename>Event.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -19,6 +19,11 @@
 		&lt;cfset invokeCallback('beforeAction', arguments.obj) /&gt;
 		&lt;cfreturn invokeCallback('before#getName()#Action', arguments.obj) /&gt;
 	&lt;/cffunction&gt;
+
+	&lt;cffunction name=&quot;fail&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
+		&lt;cfargument name=&quot;obj&quot; required=&quot;true&quot; /&gt;
+		&lt;cfset invokeCallback('failedAction', arguments.obj) /&gt;
+	&lt;/cffunction&gt;
 	
 	&lt;cffunction name=&quot;after&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfargument name=&quot;obj&quot; required=&quot;true&quot; /&gt;		
@@ -35,6 +40,7 @@
 	&lt;cffunction name=&quot;invokeCallback&quot; returntype=&quot;boolean&quot; access=&quot;private&quot; output=&quot;false&quot;&gt;
 		&lt;cfargument name=&quot;callback&quot; type=&quot;string&quot; required=&quot;true&quot; /&gt;
 		&lt;cfargument name=&quot;obj&quot; required=&quot;true&quot; /&gt;
+		&lt;cftrace text=&quot;#callback#: #obj.getMyState()#&quot; /&gt;
 		&lt;cfif structKeyExists(arguments.obj, arguments.callback)&gt;
 			&lt;cfinvoke component=&quot;#arguments.obj#&quot; method=&quot;#arguments.callback#&quot; returnvariable=&quot;result&quot; /&gt;
 			&lt;cfif isDefined('result') and isBoolean(result)&gt;</diff>
      <filename>State.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -3,16 +3,20 @@
 	&lt;cfset instance = structNew() /&gt;
 	
 	&lt;cffunction name=&quot;init&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
-		&lt;cfargument name=&quot;OriginalObject&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;originalObject&quot; required=&quot;true&quot; /&gt;
 		&lt;cfargument name=&quot;initialState&quot; type=&quot;string&quot; required=&quot;true&quot; /&gt;
 		&lt;cfargument name=&quot;stateMethod&quot; type=&quot;string&quot; required=&quot;false&quot; default=&quot;state&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceObject&quot; required=&quot;false&quot; default=&quot;&quot; hint=&quot;a service that persist the business object&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceMethod&quot; required=&quot;false&quot; default=&quot;save&quot; /&gt;
 		&lt;cfscript&gt;
 			setOriginalObject(arguments.OriginalObject);
 			instance.states = structNew();
 			instance.transitionTable = structNew();
 			instance.eventTable = structNew();
 			instance.stateMethod = arguments.stateMethod;			
-			instance.initialState = arguments.initialState;
+			instance.initialState = arguments.initialState;			
+			instance.persistenceObject = arguments.persistenceObject;
+			instance.persistenceMethod = arguments.persistenceMethod;
 						
 			configureState();
 			if(getState() eq '') {
@@ -44,7 +48,7 @@
 	&lt;cffunction name=&quot;fireEvent&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfargument name=&quot;name&quot; type=&quot;string&quot; required=&quot;true&quot; /&gt;
 		&lt;cfif structKeyExists(instance.eventTable, arguments.name)&gt;
-			&lt;cfreturn instance.eventTable[arguments.name].fire(this) /&gt;
+			&lt;cfreturn instance.eventTable[arguments.name].fire(this, instance.persistenceObject, instance.persistenceMethod) /&gt;
 		&lt;/cfif&gt;
 		&lt;cfreturn false /&gt;
 	&lt;/cffunction&gt;</diff>
      <filename>StateMachine.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;cfcomponent displayname=&quot;Transition&quot; output=&quot;false&quot;&gt;
+&lt;cfcomponent displayname=&quot;StateTransition&quot; output=&quot;false&quot;&gt;
 	
 	&lt;cfset instance = structNew() /&gt;
 	
@@ -36,6 +36,9 @@
 	
 	&lt;cffunction name=&quot;perform&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfargument name=&quot;obj&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceObject&quot; required=&quot;false&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceMethod&quot; required=&quot;false&quot; default=&quot;save&quot; /&gt;
+		
 		&lt;cfscript&gt;
 			var local = structNew();
 		
@@ -49,8 +52,16 @@
 			local.oldState = local.states[obj.getCurrentState()];
 			
 			if(not local.isLoopback) {
-				if(local.nextState.before(obj)) {	
+				if(local.nextState.before(obj)) {
+					// Set the state
 					obj.setInternalState(getToState());
+					// Do the update if we have an updater reference
+					if(structKeyExists(arguments, 'persistenceObject') and isObject(arguments.persistenceObject)) {
+						if(not persist(arguments.persistenceObject, arguments.persistenceMethod, obj)) {
+							local.nextState.fail(obj);
+							return false;
+						}
+					}
 					local.nextState.after(obj);	
 					local.oldState.exit(obj);	
 				} else {
@@ -69,5 +80,18 @@
 	&lt;cffunction name=&quot;getToState&quot; access=&quot;public&quot; returntype=&quot;string&quot; output=&quot;false&quot;&gt;
 		&lt;cfreturn instance.to /&gt;
 	&lt;/cffunction&gt;
+
+	&lt;cffunction name=&quot;persist&quot; access=&quot;private&quot; returntype=&quot;boolean&quot; output=&quot;false&quot;&gt;
+		&lt;cfargument name=&quot;component&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;method&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;obj&quot; required=&quot;true&quot; /&gt;
+		&lt;cfinvoke component=&quot;#arguments.component#&quot; method=&quot;#arguments.method#&quot; returnvariable=&quot;success&quot;&gt;
+			&lt;cfinvokeargument name=&quot;1&quot; value=&quot;#arguments.obj#&quot; /&gt;
+		&lt;/cfinvoke&gt;
+		&lt;!--- If the method returns void, assume it succeeded ---&gt;
+		&lt;cfparam name=&quot;success&quot; default=&quot;true&quot; type=&quot;boolean&quot; /&gt;
+		&lt;cfreturn success /&gt;
+	&lt;/cffunction&gt;	
+	
 	
 &lt;/cfcomponent&gt;
\ No newline at end of file</diff>
      <filename>StateTransition.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -72,7 +72,7 @@
 		&lt;cfset instance.NeedingAttentionEnter = arguments.value /&gt;
 	&lt;/cffunction&gt;	
 	
-		&lt;cffunction name=&quot;getNeedingAttentionAfter&quot; access=&quot;public&quot; returntype=&quot;string&quot; output=&quot;false&quot;&gt;
+	&lt;cffunction name=&quot;getNeedingAttentionAfter&quot; access=&quot;public&quot; returntype=&quot;string&quot; output=&quot;false&quot;&gt;
 		&lt;cfreturn instance.NeedingAttentionAfter /&gt;
 	&lt;/cffunction&gt;
 	
@@ -97,5 +97,23 @@
 	&lt;cffunction name=&quot;getBeforeActionCount&quot; access=&quot;public&quot; returntype=&quot;Numeric&quot; output=&quot;false&quot;&gt;
 		&lt;cfreturn instance.beforeActionCount /&gt;
 	&lt;/cffunction&gt;	
+	
+	&lt;cffunction name=&quot;getFailed&quot; access=&quot;public&quot; returntype=&quot;boolean&quot; output=&quot;false&quot;&gt;
+		&lt;cfreturn instance.Failed /&gt;
+	&lt;/cffunction&gt;
+	
+	&lt;cffunction name=&quot;setFailed&quot; access=&quot;public&quot; returntype=&quot;void&quot; output=&quot;false&quot;&gt;
+		&lt;cfargument name=&quot;Failed&quot; type=&quot;boolean&quot; required=&quot;true&quot; /&gt;
+		&lt;cfset instance.Failed = arguments.Failed /&gt;
+	&lt;/cffunction&gt;
+
+	&lt;cffunction name=&quot;getFailedForAwaitingResponse&quot; access=&quot;public&quot; returntype=&quot;boolean&quot; output=&quot;false&quot;&gt;
+		&lt;cfreturn instance.FailedForAwaitingResponse /&gt;
+	&lt;/cffunction&gt;
+	
+	&lt;cffunction name=&quot;setFailedForAwaitingResponse&quot; access=&quot;public&quot; returntype=&quot;void&quot; output=&quot;false&quot;&gt;
+		&lt;cfargument name=&quot;FailedForAwaitingResponse&quot; type=&quot;boolean&quot; required=&quot;true&quot; /&gt;
+		&lt;cfset instance.FailedForAwaitingResponse = arguments.FailedForAwaitingResponse /&gt;
+	&lt;/cffunction&gt;
 
 &lt;/cfcomponent&gt;
\ No newline at end of file</diff>
      <filename>test/Conversation.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -2,8 +2,9 @@
 	&lt;cfset instance = structNew() /&gt;
 	
 	&lt;cffunction name=&quot;init&quot; access=&quot;public&quot; returntype=&quot;any&quot; output=&quot;false&quot;&gt;
-		&lt;cfargument name=&quot;conversation&quot; type=&quot;shade.test.Conversation&quot; required=&quot;true&quot; /&gt;		
-		&lt;cfset super.init(arguments.conversation, 'needingAttention', 'MyState') /&gt;
+		&lt;cfargument name=&quot;conversation&quot; type=&quot;shade.test.Conversation&quot; required=&quot;true&quot; /&gt;
+		&lt;cfargument name=&quot;persistenceObject&quot; required=&quot;false&quot; /&gt;	
+		&lt;cfset super.init(arguments.conversation, 'needingAttention', 'MyState', arguments.persistenceObject, 'save') /&gt;
 		&lt;cfreturn this /&gt;
 	&lt;/cffunction&gt;
 		
@@ -62,4 +63,8 @@
 		&lt;cfset getOriginalObject().incrementBeforeActionCount() /&gt;
 	&lt;/cffunction&gt;
 
+	&lt;cffunction name=&quot;failedAction&quot; access=&quot;public&quot; returntype=&quot;void&quot; output=&quot;false&quot;&gt;
+		&lt;cfset getOriginalObject().setFailed(true) /&gt;
+	&lt;/cffunction&gt;
+
 &lt;/cfcomponent&gt;
\ No newline at end of file</diff>
      <filename>test/ConversationState.cfc</filename>
    </modified>
    <modified>
      <diff>@@ -2,8 +2,8 @@
 
 	&lt;cffunction name=&quot;setup&quot; returntype=&quot;void&quot; access=&quot;public&quot;&gt;
 		&lt;cfscript&gt;
-			original = createObject(&quot;component&quot;, &quot;shade.test.Conversation&quot;).init();
-			conversation = createObject( &quot;component&quot;, &quot;shade.test.ConversationState&quot; ).init(original);
+			service = createObject(&quot;component&quot;, &quot;shade.test.ConversationService&quot;).init();
+			conversation = service.new();
 		&lt;/cfscript&gt;
 	&lt;/cffunction&gt;
 	
@@ -72,10 +72,10 @@
 		&lt;cfscript&gt;
 			conversation.view();
 			assertTrue(conversation.isInState('read'));
-			assertTrue(conversation.isRead());
+			assertTrue(conversation.isRead());			
 		&lt;/cfscript&gt;
 	&lt;/cffunction&gt;
-
+	
 	&lt;cffunction name=&quot;testCanGoFromReadToClosedBecauseGuardPasses&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfscript&gt;
 			conversation.setCanClose(true);
@@ -155,13 +155,12 @@
 		&lt;cfscript&gt;
 			conversation.setReadExit(false);
 			conversation.view();
-			conversation.junk();
-			
+			conversation.junk();			
 			assertTrue(conversation.getReadExit());
 		&lt;/cfscript&gt;
 	&lt;/cffunction&gt;
 	
-	&lt;cffunction name=&quot;testEntryAndExitNotRunOnLoopbackTransation&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
+	&lt;cffunction name=&quot;testEntryAndExitNotRunOnLoopbackTransition&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
 		&lt;cfscript&gt;
 			conversation.view();
 			conversation.setReadEnter(false);
@@ -231,5 +230,33 @@
 			assertEquals(3, conversation.getBeforeActionCount());
 		&lt;/cfscript&gt;
 	&lt;/cffunction&gt;
+
+	&lt;cffunction name=&quot;testRecordIsPersistedOnStateChange&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
+		&lt;cfscript&gt;
+			assertFalse(service.recordSaved());
+			conversation.view();
+			assertTrue(service.recordSaved());
+			assertTrue(conversation.isRead());			
+		&lt;/cfscript&gt;
+	&lt;/cffunction&gt;	
 	
+	&lt;cffunction name=&quot;testAfterAndExitNotRunOnPersistenceFailed&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
+		&lt;cfscript&gt;
+			service.setSaveShouldFail(true);			
+			conversation.setReadAfterFirstAction(false);
+			assertFalse(conversation.view());
+			assertFalse(service.recordSaved());
+			assertFalse(conversation.getReadAfterFirstAction());
+		&lt;/cfscript&gt;
+	&lt;/cffunction&gt;
+
+	&lt;cffunction name=&quot;testFailedActionExecuted&quot; returntype=&quot;void&quot; access=&quot;public&quot; output=&quot;false&quot;&gt;
+		&lt;cfscript&gt;
+			service.setSaveShouldFail(true);
+			conversation.setFailed(false);			
+			assertFalse(conversation.view());		
+			assertTrue(conversation.getFailed());
+		&lt;/cfscript&gt;
+	&lt;/cffunction&gt;
+		
 &lt;/cfcomponent&gt;
\ No newline at end of file</diff>
      <filename>test/StateMachineTest.cfc</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>4c22d15ff9d74cfaf15153438ed0b4bb6ca7af08</id>
    </parent>
  </parents>
  <author>
    <name>Ryan Wood</name>
    <email>ryan.wood@gmail.com</email>
  </author>
  <url>http://github.com/ryanwood/shade/commit/0bdacba1386989f5809b763877b67038f0bf609a</url>
  <id>0bdacba1386989f5809b763877b67038f0bf609a</id>
  <committed-date>2008-10-13T06:52:34-07:00</committed-date>
  <authored-date>2008-10-13T06:52:34-07:00</authored-date>
  <message>Added persistence object for saving which creates more accurate events</message>
  <tree>fad87858025708f2f463ba9f617b29a9ab69e189</tree>
  <committer>
    <name>Ryan Wood</name>
    <email>ryan.wood@gmail.com</email>
  </committer>
</commit>
