Revision: 1284
Author: plorenz
Date: Tue Feb 26 19:49:07 2013
Log: First pass at fixing token set AND behavior. Works for mem
engine, still need to test hib implementation.
http://code.google.com/p/sarasvati/source/detail?r=1284
Added:
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64InputStream.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64OutputStream.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/LongArrayAttributeConverter.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/mem/TokenSetDeadEndListener.java
/java/trunk/sarasvati-core/src/test/java/com/googlecode/sarasvati/env
/java/trunk/sarasvati-core/src/test/java/com/googlecode/sarasvati/env/Base64Test.java
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/TokenSetDeadEndListener.java
Modified:
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/Engine.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/AttributeConverters.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ArcTokenEvent.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ExecutionEventType.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/impl/BaseEngine.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/join/TokenSetJoinStrategy.java
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/mem/MemEngine.java
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibEngine.java
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibGraphRepository.java
/java/trunk/sarasvati-test/src/test/java/com/googlecode/sarasvati/test/execution/TokenSetTest.java
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,88 @@
+package com.googlecode.sarasvati.env;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+class Base64
+{
+ public static char[] BYTE_TO_CHAR = {
+ 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b',
+ 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', '=', '/' };
+
+ public static byte[] CHAR_TO_BYTE = new byte[128];
+
+ static
+ {
+ for (int i = 0; i < BYTE_TO_CHAR.length; i++)
+ {
+ CHAR_TO_BYTE[BYTE_TO_CHAR[i]] = (byte)i;
+ }
+ }
+
+ public static String encode(final byte[] bytes)
+ {
+ try
+ {
+ final StringWriter stringWriter = new StringWriter();
+ final Base64OutputStream out = new Base64OutputStream(stringWriter);
+ out.write(bytes);
+ out.close();
+ stringWriter.close();
+ return stringWriter.toString();
+ }
+ catch(final IOException ioe)
+ {
+ throw new RuntimeException("Unexpected failure while encoding bytes
to base64", ioe);
+ }
+ }
+
+ public static byte[] decode(final String base64)
+ {
+ try
+ {
+ final StringReader stringReader = new StringReader(base64);
+ final Base64InputStream in = new Base64InputStream(stringReader);
+ final int length = ((base64.length() / 4) * 3) + Math.max(0,
((base64.length() % 4) - 1));
+ byte[] bytes = new byte[length];
+ in.read(bytes);
+ in.close();
+ stringReader.close();
+ return bytes;
+ }
+ catch(final IOException ioe)
+ {
+ throw new RuntimeException("Unexpected failure while decoding bytes
from base64", ioe);
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ for (int i = 0; i < BYTE_TO_CHAR.length; i++)
+ {
+ System.out.println(i + ". " + BYTE_TO_CHAR[i] + ": " +
(int)BYTE_TO_CHAR[i]);
+ }
+
+ for (int i = 0; i < CHAR_TO_BYTE.length; i++)
+ {
+ if (CHAR_TO_BYTE[i] != 0)
+ {
+ System.out.println(i + ": " + CHAR_TO_BYTE[i] + " " + (i ==
BYTE_TO_CHAR[CHAR_TO_BYTE[i]]));
+ }
+ }
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64InputStream.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,81 @@
+package com.googlecode.sarasvati.env;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+public class Base64InputStream extends InputStream
+{
+ private final Reader reader;
+
+ int current = 0;
+ int index = 0;
+ int available = 0;
+
+ public Base64InputStream(final Reader reader)
+ {
+ this.reader = reader;
+ }
+
+ @Override
+ public int read() throws IOException
+ {
+ if (available == 0)
+ {
+ index = 0;
+ current = reader.read();
+ if (current == -1)
+ {
+ return -1;
+ }
+
+ current = Base64.CHAR_TO_BYTE[current];
+
+ int next = reader.read();
+ if (next == -1)
+ {
+ throw new IOException("Unexpected end of stream");
+ }
+ current = current << 6 | Base64.CHAR_TO_BYTE[next];
+
+ available = 1;
+
+ next = reader.read();
+ if (next != -1)
+ {
+ current = current << 6 | Base64.CHAR_TO_BYTE[next];
+ available = 2;
+
+ next = reader.read();
+ if (next != -1)
+ {
+ current = current << 6 | Base64.CHAR_TO_BYTE[next];
+ available = 3;
+ }
+ else
+ {
+ current = current << 6;
+ }
+ }
+ else
+ {
+ current = current << 12;
+ }
+ }
+
+ available--;
+ index++;
+
+ if (index == 1)
+ {
+ return (current >> 16) & 255;
+ }
+
+ if (index == 2)
+ {
+ return (current >> 8) & 255;
+ }
+
+ return current & 255;
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/Base64OutputStream.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,73 @@
+package com.googlecode.sarasvati.env;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+public class Base64OutputStream extends OutputStream
+{
+ private static final int MASK_6_BITS = 63;
+ private final Writer writer;
+
+ int current = 0;
+ int index = 0;
+
+ public Base64OutputStream(final Writer writer)
+ {
+ this.writer = writer;
+ }
+
+ @Override
+ public void write(final int b) throws IOException
+ {
+ current |= b & 0xFF;
+ index++;
+ if (index == 3)
+ {
+ int charIdx = (current >> 18) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ charIdx = (current >> 12) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ charIdx = (current >> 6) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ charIdx = current & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ current = 0;
+ index = 0;
+ }
+ else
+ {
+ current = current << 8;
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ if (index == 0)
+ {
+ return;
+ }
+
+ if (index == 1)
+ {
+ current = current << 8;
+ }
+
+ int charIdx = (current >> 18) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ charIdx = (current >> 12) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+
+ if (index == 2)
+ {
+ charIdx = (current >> 6) & MASK_6_BITS;
+ writer.write(Base64.BYTE_TO_CHAR[charIdx]);
+ }
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/LongArrayAttributeConverter.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,76 @@
+/*
+ This file is part of Sarasvati.
+
+ Sarasvati is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ Sarasvati is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Sarasvati. If not, see
<
http://www.gnu.org/licenses/>.
+
+ Copyright 2009 Paul Lorenz
+*/
+package com.googlecode.sarasvati.env;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Attribute converter for String <--> Integer
+ *
+ * @author Paul Lorenz
+ */
+public final class LongArrayAttributeConverter implements
AttributeConverter
+{
+ @Override
+ public String objectToString (final Object object)
+ {
+ if (object == null)
+ {
+ return null;
+ }
+
+ final long[] array = (long[]) object;
+
+ final ByteBuffer byteBuffer = ByteBuffer.allocate(4 + (8 *
array.length));
+ byteBuffer.putInt(array.length);
+ for (final long value : array)
+ {
+ byteBuffer.putLong(value);
+ }
+
+ return Base64.encode(byteBuffer.array());
+ }
+
+ /**
+ * Converts the given string to an Integer
+ *
+ * @see
com.googlecode.sarasvati.env.AttributeConverter#stringToObject(java.lang.String,
java.lang.Class)
+ */
+ @Override
+ public Object stringToObject (final String string, final Class<?> object)
+ {
+ if (string == null)
+ {
+ return null;
+ }
+
+ final byte[] bytes = Base64.decode(string);
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ final int length = byteBuffer.getInt();
+
+ final long[] array = new long[length];
+
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = byteBuffer.getLong();
+ }
+
+ return array;
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/mem/TokenSetDeadEndListener.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,83 @@
+/*
+ This file is part of Sarasvati.
+
+ Sarasvati is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ Sarasvati is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Sarasvati. If not, see
<
http://www.gnu.org/licenses/>.
+
+ Copyright 2008 Paul Lorenz
+*/
+package com.googlecode.sarasvati.mem;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import com.googlecode.sarasvati.ArcToken;
+import com.googlecode.sarasvati.JoinType;
+import com.googlecode.sarasvati.NodeToken;
+import com.googlecode.sarasvati.NodeTokenSetMember;
+import com.googlecode.sarasvati.TokenSetMember;
+import com.googlecode.sarasvati.env.Env;
+import com.googlecode.sarasvati.event.EventActions;
+import com.googlecode.sarasvati.event.ExecutionEvent;
+import com.googlecode.sarasvati.event.ExecutionEventType;
+import com.googlecode.sarasvati.event.ExecutionListener;
+import com.googlecode.sarasvati.event.NodeTokenEvent;
+
+public class TokenSetDeadEndListener implements ExecutionListener
+{
+ private static final String KEY
= "com.googlecode.sarasvati.tokenset.tokens_waiting_for_tokenset";
+
+ @Override
+ public EventActions notify (final ExecutionEvent event)
+ {
+ if ( event.getEventType() ==
ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN &&
+ event.getArcToken().getArc().getEndNode().getJoinType() ==
JoinType.TOKEN_SET )
+ {
+ for ( TokenSetMember setMember :
event.getArcToken().getTokenSetMemberships() )
+ {
+ final Env tsEnv = setMember.getTokenSet().getEnv();
+ @SuppressWarnings("unchecked")
+ List<ArcToken> checkNodes = (List<ArcToken>)
tsEnv.getTransientAttribute(KEY);
+ if (checkNodes == null)
+ {
+ checkNodes = new LinkedList<ArcToken>();
+ tsEnv.setTransientAttribute(KEY, checkNodes);
+ }
+ checkNodes.add(event.getArcToken());
+ }
+ }
+ else if ( event.getEventType() ==
ExecutionEventType.NODE_TOKEN_COMPLETED )
+ {
+ final NodeToken token = event.getNodeToken();
+ final NodeTokenEvent nodeTokenEvent = (NodeTokenEvent) event;
+ if (nodeTokenEvent.getExitArcs().isEmpty())
+ {
+ for ( NodeTokenSetMember setMember :
token.getTokenSetMemberships() )
+ {
+ final Env tsEnv = setMember.getTokenSet().getEnv();
+ @SuppressWarnings("unchecked")
+ final List<ArcToken> checkNodes = (List<ArcToken>)
tsEnv.getTransientAttribute(KEY);
+ if (checkNodes != null)
+ {
+ for (final ArcToken arcToken : checkNodes)
+ {
+ event.getEngine().retryIncompleteArcToken(arcToken);
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-core/src/test/java/com/googlecode/sarasvati/env/Base64Test.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,38 @@
+package com.googlecode.sarasvati.env;
+
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Base64Test
+{
+ @Test
+ public void test()
+ {
+ SecureRandom rand = new SecureRandom();
+
+ for (int i = 1; i < 1024; i++)
+ {
+ byte[] array = new byte[i];
+ rand.nextBytes(array);
+
+ final String encoded = Base64.encode(array);
+
+ byte[] decoded = Base64.decode(encoded);
+ Assert.assertTrue(Arrays.equals(array, decoded));
+ }
+
+ for (int i = 1024; i < 1024 * 1024; i += rand.nextInt(1024))
+ {
+ byte[] array = new byte[i];
+ rand.nextBytes(array);
+
+ final String encoded = Base64.encode(array);
+
+ byte[] decoded = Base64.decode(encoded);
+ Assert.assertTrue(Arrays.equals(array, decoded));
+ }
+ }
+}
=======================================
--- /dev/null
+++
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/TokenSetDeadEndListener.java
Tue Feb 26 19:49:07 2013
@@ -0,0 +1,82 @@
+/*
+ This file is part of Sarasvati.
+
+ Sarasvati is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ Sarasvati is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Sarasvati. If not, see
<
http://www.gnu.org/licenses/>.
+
+ Copyright 2008 Paul Lorenz
+*/
+package com.googlecode.sarasvati.hib;
+
+import com.googlecode.sarasvati.ArcToken;
+import com.googlecode.sarasvati.JoinType;
+import com.googlecode.sarasvati.NodeToken;
+import com.googlecode.sarasvati.NodeTokenSetMember;
+import com.googlecode.sarasvati.TokenSetMember;
+import com.googlecode.sarasvati.env.Env;
+import com.googlecode.sarasvati.event.EventActions;
+import com.googlecode.sarasvati.event.ExecutionEvent;
+import com.googlecode.sarasvati.event.ExecutionEventType;
+import com.googlecode.sarasvati.event.ExecutionListener;
+import com.googlecode.sarasvati.event.NodeTokenEvent;
+
+public class TokenSetDeadEndListener implements ExecutionListener
+{
+ private static final String KEY
= "com.googlecode.sarasvati.tokenset.tokens_waiting_for_tokenset";
+
+ @Override
+ public EventActions notify (final ExecutionEvent event)
+ {
+ if ( event.getEventType() ==
ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN &&
+ event.getArcToken().getArc().getEndNode().getJoinType() ==
JoinType.TOKEN_SET )
+ {
+ for ( TokenSetMember setMember :
event.getArcToken().getTokenSetMemberships() )
+ {
+ final Env tsEnv = setMember.getTokenSet().getEnv();
+ long[] checkNodes = tsEnv.getAttribute(KEY, long[].class);
+ if (checkNodes == null)
+ {
+ checkNodes = new long[] { event.getArcToken().getId() };
+ }
+ else
+ {
+ final long[] newCheckNodes = new long[checkNodes.length + 1];
+ System.arraycopy(checkNodes, 0, newCheckNodes, 0,
checkNodes.length);
+ newCheckNodes[checkNodes.length] = event.getArcToken().getId();
+ }
+ tsEnv.setAttribute(KEY, checkNodes);
+ }
+ }
+ else if ( event.getEventType() ==
ExecutionEventType.NODE_TOKEN_COMPLETED )
+ {
+ final NodeToken token = event.getNodeToken();
+ final NodeTokenEvent nodeTokenEvent = (NodeTokenEvent) event;
+ if (nodeTokenEvent.getExitArcs().isEmpty())
+ {
+ final HibEngine hibEngine = (HibEngine)event.getEngine();
+ for ( NodeTokenSetMember setMember :
token.getTokenSetMemberships() )
+ {
+ final Env tsEnv = setMember.getTokenSet().getEnv();
+ long[] checkNodes = tsEnv.getAttribute(KEY, long[].class);
+ for (final long arcTokenId : checkNodes)
+ {
+ final ArcToken arcToken =
hibEngine.getRepository().loadArcToken(arcTokenId);
+ event.getEngine().retryIncompleteArcToken(arcToken);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/Engine.java
Sun Nov 25 13:35:50 2012
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/Engine.java
Tue Feb 26 19:49:07 2013
@@ -467,6 +467,16 @@
*/
GuardResult evaluateGuard (NodeToken token, String guard);
+ /**
+ * Allows retrying an arc token, to see if the conditions have changed
and
+ * its execution can now be completed.
+ *
+ * @param token The token to retry
+ * @return The resulting join action
+ */
+ JoinAction retryIncompleteArcToken (final ArcToken token);
+
+
/**
* Since an Engine can have state specific to the currently executing
process,
* there are times we want to create a new engine (such as when
executing a
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/AttributeConverters.java
Tue Dec 13 07:27:51 2011
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/env/AttributeConverters.java
Tue Feb 26 19:49:07 2013
@@ -61,6 +61,8 @@
converters.put( Double.class, new DoubleAttributeConverter() );
converters.put( Double.TYPE, new DoubleAttributeConverter() );
+
+ converters.put( long[].class, new LongArrayAttributeConverter() );
}
private static AttributeConverter defaultConverter = new
AttributeConverter()
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ArcTokenEvent.java
Thu Nov 19 14:45:21 2009
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ArcTokenEvent.java
Tue Feb 26 19:49:07 2013
@@ -43,6 +43,11 @@
{
return engine.fireEvent( new ArcTokenEvent( engine,
ExecutionEventType.ARC_TOKEN_BACKTRACKED, arcToken ) );
}
+
+ public static final EventActions fireIncompleteJoinEvent (final Engine
engine, final ArcToken arcToken)
+ {
+ return engine.fireEvent( new ArcTokenEvent( engine,
ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN, arcToken ) );
+ }
public static final EventActions fireMergedEvent (final Engine engine,
final ArcToken arcToken)
{
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ExecutionEventType.java
Sun Nov 25 13:35:50 2012
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/event/ExecutionEventType.java
Tue Feb 26 19:49:07 2013
@@ -26,27 +26,28 @@
* stable. If adding a new event type, it must be assigned the next
* highest power of 2.
*/
- PROCESS_CREATED ( 1 << 0 ),
- PROCESS_STARTED ( 1 << 1 ),
- PROCESS_PENDING_COMPLETE ( 1 << 2 ),
- PROCESS_COMPLETED ( 1 << 3 ),
- PROCESS_PENDING_CANCEL ( 1 << 4 ),
- PROCESS_CANCELED ( 1 << 5 ),
+ PROCESS_CREATED ( 1 << 0 ),
+ PROCESS_STARTED ( 1 << 1 ),
+ PROCESS_PENDING_COMPLETE ( 1 << 2 ),
+ PROCESS_COMPLETED ( 1 << 3 ),
+ PROCESS_PENDING_CANCEL ( 1 << 4 ),
+ PROCESS_CANCELED ( 1 << 5 ),
- NODE_TOKEN_CREATED ( 1 << 6 ),
- NODE_TOKEN_ACCEPTED ( 1 << 7 ),
- NODE_TOKEN_EXECUTED ( 1 << 8 ),
- NODE_TOKEN_DISCARDED ( 1 << 9 ),
- NODE_TOKEN_SKIPPED ( 1 << 10 ),
- NODE_TOKEN_COMPLETED ( 1 << 11 ),
- NODE_TOKEN_BACKTRACKED ( 1 << 12 ),
- NODE_TOKEN_DELAYED ( 1 << 18 ),
+ NODE_TOKEN_CREATED ( 1 << 6 ),
+ NODE_TOKEN_ACCEPTED ( 1 << 7 ),
+ NODE_TOKEN_EXECUTED ( 1 << 8 ),
+ NODE_TOKEN_DISCARDED ( 1 << 9 ),
+ NODE_TOKEN_SKIPPED ( 1 << 10 ),
+ NODE_TOKEN_COMPLETED ( 1 << 11 ),
+ NODE_TOKEN_BACKTRACKED ( 1 << 12 ),
+ NODE_TOKEN_DELAYED ( 1 << 18 ),
- ARC_TOKEN_CREATED ( 1 << 13 ),
- ARC_TOKEN_PROCESSED ( 1 << 14 ),
- ARC_TOKEN_COMPLETED ( 1 << 15 ),
- ARC_TOKEN_BACKTRACKED ( 1 << 16 ),
- ARC_TOKEN_MERGED ( 1 << 17 );
+ ARC_TOKEN_CREATED ( 1 << 13 ),
+ ARC_TOKEN_PROCESSED ( 1 << 14 ),
+ ARC_TOKEN_COMPLETED ( 1 << 15 ),
+ ARC_TOKEN_BACKTRACKED ( 1 << 16 ),
+ ARC_TOKEN_MERGED ( 1 << 17 ),
+ ARC_TOKEN_INCOMPLETE_JOIN ( 1 << 18 );
private static final int INVERSE_MASK = 0xFFFFFFFF;
@@ -92,7 +93,8 @@
this == ARC_TOKEN_PROCESSED ||
this == ARC_TOKEN_COMPLETED ||
this == ARC_TOKEN_MERGED ||
- this == ARC_TOKEN_BACKTRACKED;
+ this == ARC_TOKEN_BACKTRACKED ||
+ this == ARC_TOKEN_INCOMPLETE_JOIN;
}
public static int toMask (final ExecutionEventType...eventTypes)
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/impl/BaseEngine.java
Mon Nov 26 16:01:20 2012
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/impl/BaseEngine.java
Tue Feb 26 19:49:07 2013
@@ -135,6 +135,7 @@
{
queue.addListener( new TokenSetCompletionListener(),
ExecutionEventType.ARC_TOKEN_COMPLETED,
+ ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN,
ExecutionEventType.NODE_TOKEN_COMPLETED );
queue.addListener( new GraphDefinedEventListenerInvoker() );
queue.addListener( new ProcessDefinedEventListenerInvoker() );
@@ -265,8 +266,7 @@
ProcessEvent.fireCanceledEvent( this, process );
}
- private void executeArc (final GraphProcess process,
- final ArcToken token)
+ private void executeArc (final GraphProcess process, final ArcToken
token)
{
if ( token.isPending() )
{
@@ -275,6 +275,20 @@
process.addActiveArcToken( token );
+ final JoinAction joinAction = retryIncompleteArcToken(token);
+ if ( JoinAction.Nothing == joinAction )
+ {
+ ArcTokenEvent.fireIncompleteJoinEvent( this, token );
+ }
+ }
+ }
+
+ @Override
+ public JoinAction retryIncompleteArcToken (final ArcToken token)
+ {
+ if ( !token.isComplete() )
+ {
+ final GraphProcess process = token.getProcess();
final Node targetNode = token.getArc().getEndNode();
final JoinResult result = targetNode.getJoinStrategy( token.getArc()
).performJoin( this, token );
@@ -291,7 +305,9 @@
ArcTokenEvent.fireMergedEvent( this, arcToken );
}
}
+ return result.getJoinAction();
}
+ return null;
}
private void completeExecuteArc (final GraphProcess process,
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/join/TokenSetJoinStrategy.java
Sun Nov 4 19:28:44 2012
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/join/TokenSetJoinStrategy.java
Tue Feb 26 19:49:07 2013
@@ -19,13 +19,13 @@
package com.googlecode.sarasvati.join;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import com.googlecode.sarasvati.ArcToken;
import com.googlecode.sarasvati.ArcTokenSetMember;
import com.googlecode.sarasvati.Engine;
import com.googlecode.sarasvati.GraphProcess;
-import com.googlecode.sarasvati.JoinAction;
import com.googlecode.sarasvati.JoinResult;
import com.googlecode.sarasvati.JoinStrategy;
import com.googlecode.sarasvati.TokenSet;
@@ -118,22 +118,24 @@
final List<TokenSet> tokenSets = getTokenSet( token );
final List<ArcToken> resultTokens = new ArrayList<ArcToken>();
- final AndJoinStrategy strategy = new AndJoinStrategy();
-
for (final TokenSet tokenSet : tokenSets)
{
- for (int idx=0; idx <= tokenSet.getMaxMemberIndex(); idx++)
+ if (!tokenSet.getActiveNodeTokens(engine).isEmpty())
{
- JoinResult result = strategy.performJoin(token, new
TokenSetGroupFilter(tokenSet, idx));
- if (result.getJoinAction() == JoinAction.Complete)
- {
- resultTokens.addAll(result.getArcTokensCompletingJoin());
- }
- else
+ return IncompleteJoinResult.INSTANCE;
+ }
+
+ final Collection<ArcToken> members =
tokenSet.getActiveArcTokens(engine);
+
+ for (final ArcToken member : members)
+ {
+ if
(!member.getArc().getEndNode().equals(token.getArc().getEndNode()))
{
return IncompleteJoinResult.INSTANCE;
}
}
+
+ resultTokens.addAll(members);
}
return new CompleteJoinResult( resultTokens, tokenSets );
=======================================
---
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/mem/MemEngine.java
Mon Nov 26 16:01:20 2012
+++
/java/trunk/sarasvati-core/src/main/java/com/googlecode/sarasvati/mem/MemEngine.java
Tue Feb 26 19:49:07 2013
@@ -21,6 +21,8 @@
import com.googlecode.sarasvati.DelayedTokenScheduler;
import com.googlecode.sarasvati.EngineFactory;
+import com.googlecode.sarasvati.event.DefaultExecutionEventQueue;
+import com.googlecode.sarasvati.event.ExecutionEventType;
import com.googlecode.sarasvati.impl.BaseEngine;
import com.googlecode.sarasvati.impl.TimerBasedDelayedTokenScheduler;
import com.googlecode.sarasvati.load.GraphLoader;
@@ -151,6 +153,25 @@
return
TimerBasedDelayedTokenScheduler.newDelayedTokenScheduler(newEngineFactory());
}
+ /**
+ * Provides a subclass to override which execution event listeners are
added to
+ * new global queues. By default this adds the listeners from {@link
BaseEngine}
+ * as well as the following listeners:
+ * <ul>
+ * <li>{@link TokenSetDeadEndListener}</li>
+ * </ul>
+ *
+ * @param queue The new global queue
+ */
+ @Override
+ protected void contributeGlobalListeners (final
DefaultExecutionEventQueue queue)
+ {
+ super.contributeGlobalListeners(queue);
+ queue.addListener( new TokenSetDeadEndListener(),
+ ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN,
+ ExecutionEventType.NODE_TOKEN_COMPLETED );
+ }
+
private EngineFactory<MemEngine> newEngineFactory()
{
return new EngineFactory<MemEngine>()
=======================================
---
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibEngine.java
Mon Nov 26 16:01:20 2012
+++
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibEngine.java
Tue Feb 26 19:49:07 2013
@@ -29,6 +29,7 @@
import com.googlecode.sarasvati.DelayedTokenScheduler;
import com.googlecode.sarasvati.GraphProcess;
import com.googlecode.sarasvati.NodeToken;
+import com.googlecode.sarasvati.event.DefaultExecutionEventQueue;
import com.googlecode.sarasvati.event.ExecutionEventType;
import com.googlecode.sarasvati.event.ExecutionListener;
import com.googlecode.sarasvati.impl.BaseEngine;
@@ -334,4 +335,23 @@
config.setCacheConcurrencyStrategy(
HibArcToken.class.getName(),"read-write" );
}
}
+
+ /**
+ * Provides a subclass to override which execution event listeners are
added to
+ * new global queues. By default this adds the listeners from {@link
BaseEngine}
+ * as well as the following listeners:
+ * <ul>
+ * <li>{@link TokenSetDeadEndListener}</li>
+ * </ul>
+ *
+ * @param queue The new global queue
+ */
+ @Override
+ protected void contributeGlobalListeners (final
DefaultExecutionEventQueue queue)
+ {
+ super.contributeGlobalListeners(queue);
+ queue.addListener( new TokenSetDeadEndListener(),
+ ExecutionEventType.ARC_TOKEN_INCOMPLETE_JOIN,
+ ExecutionEventType.NODE_TOKEN_COMPLETED );
+ }
}
=======================================
---
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibGraphRepository.java
Sun Oct 21 15:56:14 2012
+++
/java/trunk/sarasvati-hibernate/src/main/java/com/googlecode/sarasvati/hib/HibGraphRepository.java
Tue Feb 26 19:49:07 2013
@@ -108,6 +108,11 @@
{
return (HibNodeToken)session.load( HibNodeToken.class, tokenId );
}
+
+ public HibArcToken loadArcToken (final long tokenId)
+ {
+ return (HibArcToken)session.load( HibArcToken.class, tokenId );
+ }
public HibNodeToken findNodeToken (final long tokenId)
{
=======================================
---
/java/trunk/sarasvati-test/src/test/java/com/googlecode/sarasvati/test/execution/TokenSetTest.java
Sun Nov 4 19:28:44 2012
+++
/java/trunk/sarasvati-test/src/test/java/com/googlecode/sarasvati/test/execution/TokenSetTest.java
Tue Feb 26 19:49:07 2013
@@ -226,11 +226,10 @@
"[5 N3 C F ts 1]" +
" (C F 8)" +
"[6 N4 C F ts 0]" +
- " (C F 9)" +
+ " (I F N6)" +
"[7 N4 C F ts 1]" +
- " (C F 9)" +
- "[8 N5 C F ts 1]" +
- "[9 N6 I F]";
+ " (I F N6)" +
+ "[8 N5 C F ts 1]";
TestProcess.validate( p, state );
token = getActiveToken(p, "N3", "ts", 0);
@@ -243,21 +242,20 @@
" (C F 5)" +
"[2 N2 C F ts 0]" +
" (C F 6)" +
- " (C F 10)" +
+ " (C F 9)" +
"[3 N3 C F ts 0]" +
- " (C F 10)" +
+ " (C F 9)" +
"[4 N2 C F ts 1]" +
" (C F 7)" +
" (C F 8)" +
"[5 N3 C F ts 1]" +
" (C F 8)" +
"[6 N4 C F ts 0]" +
- " (C F 9)" +
+ " (I F N6)" +
"[7 N4 C F ts 1]" +
- " (C F 9)" +
+ " (I F N6)" +
"[8 N5 C F ts 1]" +
- "[9 N6 I F]" +
- "[10 N5 I F ts 0]";
+ "[9 N5 I F ts 0]";
TestProcess.validate( p, state );
token = getActiveToken(p, "N5", "ts", 0);
@@ -270,21 +268,21 @@
" (C F 5)" +
"[2 N2 C F ts 0]" +
" (C F 6)" +
- " (C F 10)" +
+ " (C F 9)" +
"[3 N3 C F ts 0]" +
- " (C F 10)" +
+ " (C F 9)" +
"[4 N2 C F ts 1]" +
" (C F 7)" +
" (C F 8)" +
"[5 N3 C F ts 1]" +
" (C F 8)" +
"[6 N4 C F ts 0]" +
- " (C F 9)" +
+ " (C F 10)" +
"[7 N4 C F ts 1]" +
- " (C F 9)" +
+ " (C F 10)" +
"[8 N5 C F ts 1]" +
- "[9 N6 I F]" +
- "[10 N5 C F ts 0]";
+ "[9 N5 C F ts 0]" +
+ "[10 N6 I F]";
TestProcess.validate( p, state );
token = getActiveToken(p, "N6");