polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From paulmer...@apache.org
Subject [02/18] zest-sandbox git commit: Move Qi4j related projects in a `qi4j/` subfolder
Date Tue, 21 Apr 2015 11:50:14 GMT
http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryAssembler.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryAssembler.java b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryAssembler.java
new file mode 100644
index 0000000..7de4d9c
--- /dev/null
+++ b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryAssembler.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.registry;
+
+import org.qi4j.bootstrap.Assembler;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+
+public class RegistryAssembler
+    implements Assembler
+{
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.addServices( RegistryService.class );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryMixin.java b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryMixin.java
new file mode 100644
index 0000000..80ee8cf
--- /dev/null
+++ b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryMixin.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.registry;
+
+import org.qi4j.api.common.Optional;
+import org.qi4j.api.injection.scope.Service;
+import org.qi4j.library.exception.ExceptionHandling;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+public class RegistryMixin<K, V>
+    implements Registry<K, V>
+{
+    @Optional @Service private ExceptionHandling exceptionHandling;
+
+    private final HashMap<K, V> registrations;
+    private LinkedList<RegistryObserver<K, V>> observers;
+
+    public RegistryMixin()
+    {
+        this.registrations = new HashMap<K, V>();
+    }
+
+    public V lookup( K key )
+    {
+        V compositeType;
+        synchronized( registrations )
+        {
+            compositeType = registrations.get( key );
+        }
+        return compositeType;
+    }
+
+    public void register( K key, V value )
+    {
+        synchronized( registrations )
+        {
+            registrations.put( key, value );
+            for( RegistryObserver<K, V> observer : observers )
+            {
+                sendNotification( key, value, observer );
+            }
+        }
+    }
+
+    public void unregister( K key )
+    {
+        synchronized( registrations )
+        {
+            registrations.remove( key );
+        }
+    }
+
+    public void addRegistryObserver( RegistryObserver<K, V> observer )
+    {
+        synchronized( this )
+        {
+            LinkedList<RegistryObserver<K, V>> clone;
+            clone = new LinkedList<RegistryObserver<K, V>>();
+            if( observers != null )
+            {
+                clone.addAll( observers );
+            }
+            clone.add( observer );
+            observers = clone;
+        }
+    }
+
+    public void removeRegistryObserver( RegistryObserver<K, V> observer )
+    {
+        synchronized( this )
+        {
+            if( observers == null )
+            {
+                return;
+            }
+            if( observers.contains( observer ) )
+            {
+                if( observers.size() == 1 )
+                {
+                    observers = null;
+                    return;
+                }
+                LinkedList<RegistryObserver<K, V>> clone = new LinkedList<RegistryObserver<K, V>>();
+                clone.addAll( observers );
+                observers = clone;
+            }
+        }
+    }
+
+    private void sendNotification( K key, V value, RegistryObserver<K, V> observer )
+    {
+        try
+        {
+            observer.registration( this, key, value );
+        }
+        catch( Exception e )
+        {
+            if( exceptionHandling != null )
+            {
+                exceptionHandling.exceptionOccurred( "Observer " + observer + " threw an exception", this, e );
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryObserver.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryObserver.java b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryObserver.java
new file mode 100644
index 0000000..1af9336
--- /dev/null
+++ b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryObserver.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.registry;
+
+
+public interface RegistryObserver<K, V>
+{
+    void registration( Registry<K, V> source, K key, V value );
+
+    void deregistration( Registry<K, V> source, K key, V value );
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryService.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryService.java b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryService.java
new file mode 100644
index 0000000..9f9a75c
--- /dev/null
+++ b/qi4j/libraries/registry/src/main/java/org/qi4j/library/registry/RegistryService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.registry;
+
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.api.service.ServiceComposite;
+
+@Mixins( RegistryMixin.class )
+public interface RegistryService extends Registry, ServiceComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/dev-status.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/dev-status.xml b/qi4j/libraries/rmi/dev-status.xml
new file mode 100644
index 0000000..0c93156
--- /dev/null
+++ b/qi4j/libraries/rmi/dev-status.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<module xmlns="http://www.qi4j.org/schemas/2008/dev-status/1">
+  <status>
+    <codebase>early</codebase>
+    <!--none,early,beta,stable,mature-->
+    <documentation>none</documentation>
+    <!-- none, brief, good, complete -->
+    <unittests>some</unittests>
+    <!-- none, some, good, complete -->
+  </status>
+  <licenses>
+    <license>ALv2</license>
+  </licenses>
+</module>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/pom.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/pom.xml b/qi4j/libraries/rmi/pom.xml
new file mode 100644
index 0000000..e3caafe
--- /dev/null
+++ b/qi4j/libraries/rmi/pom.xml
@@ -0,0 +1,42 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.qi4j.sandbox</groupId>
+    <artifactId>qi4j-sandbox-libraries</artifactId>
+    <version>0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.qi4j.library</groupId>
+  <artifactId>org.qi4j.library.rmi</artifactId>
+  <name>Qi4j Library - RMI</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.bootstrap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.runtime</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.testsupport</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.library</groupId>
+      <artifactId>org.qi4j.library.cache</artifactId>
+      <version>${version.qi4j}</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/src/main/java/org/qi4j/library/rmi/RMIMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/src/main/java/org/qi4j/library/rmi/RMIMixin.java b/qi4j/libraries/rmi/src/main/java/org/qi4j/library/rmi/RMIMixin.java
new file mode 100644
index 0000000..add281c
--- /dev/null
+++ b/qi4j/libraries/rmi/src/main/java/org/qi4j/library/rmi/RMIMixin.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007 Rickard Öberg
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+*/
+package org.qi4j.library.rmi;
+
+import org.qi4j.api.common.AppliesTo;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.rmi.Remote;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+/**
+ * Generic mixin that looks up and invokes an object through RMI
+ */
+@AppliesTo( Remote.class )
+public class RMIMixin
+    implements InvocationHandler
+{
+    private Object remote;
+
+    public Object invoke( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        if( remote == null )
+        {
+            Registry registry = LocateRegistry.getRegistry( "localhost" );
+            remote = registry.lookup( method.getDeclaringClass().getSimpleName() );
+        }
+
+        try
+        {
+            return method.invoke( remote, args );
+        }
+        catch( InvocationTargetException e )
+        {
+            remote = null;
+            throw e.getTargetException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/RMIMixinTest.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/RMIMixinTest.java b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/RMIMixinTest.java
new file mode 100644
index 0000000..5eeb948
--- /dev/null
+++ b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/RMIMixinTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2007 Rickard Öberg
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+*/
+package org.qi4j.library.rmi;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.library.rmi.remote.RemoteInterface;
+import org.qi4j.library.rmi.remote.RemoteInterfaceComposite;
+import org.qi4j.library.rmi.remote.RemoteInterfaceImpl;
+import org.qi4j.test.AbstractQi4jTest;
+
+import java.io.IOException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ * JAVADOC
+ */
+public class RMIMixinTest
+    extends AbstractQi4jTest
+{
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.transients( RemoteInterfaceComposite.class );
+    }
+
+    @Test
+    public void testRMIMixin()
+        throws Exception
+    {
+        // Instantiate, export, and bind server object
+        RemoteInterfaceImpl remoteObject = new RemoteInterfaceImpl();
+        RemoteInterface stub = (RemoteInterface) UnicastRemoteObject.exportObject( remoteObject, 0 );
+        Registry registry = LocateRegistry.createRegistry( 1099 );
+        registry.rebind( RemoteInterface.class.getSimpleName(), stub );
+
+        RemoteInterface remote = module.newTransient( RemoteInterfaceComposite.class );
+
+        // MethodCallExpression remote interface
+        System.out.println( remote.foo( "Bar" ) );
+//        System.out.println( remote.foo( "Bar" ) );
+//        System.out.println( remote.foo( "Xyz" ) );
+
+        try
+        {
+            System.out.println( remote.foo( "Zyx" ) );
+            Assert.fail( "Should have thrown IOException " );
+        }
+        catch( IOException e )
+        {
+            // Ok!
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterface.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterface.java b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterface.java
new file mode 100644
index 0000000..1698113
--- /dev/null
+++ b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterface.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2007 Rickard Öberg
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.qi4j.library.rmi.remote;
+
+import org.qi4j.library.cache.Cached;
+
+import java.io.IOException;
+import java.rmi.Remote;
+
+/**
+ * JAVADOC
+ */
+@Cached
+public interface RemoteInterface
+    extends Remote
+{
+    String foo( String aBar )
+        throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceComposite.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceComposite.java b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceComposite.java
new file mode 100644
index 0000000..29e1d57
--- /dev/null
+++ b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceComposite.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2007 Rickard Öberg
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.qi4j.library.rmi.remote;
+
+import org.qi4j.api.composite.Composite;
+import org.qi4j.api.composite.TransientComposite;
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.library.cache.InvocationCacheAbstractComposite;
+import org.qi4j.library.rmi.RMIMixin;
+
+/**
+ * Implement the RemoteInterface by using RMI.
+ * Results of RMI calls are cached, so if an
+ * IOException occurs we can reuse a previous result
+ * if possible.
+ */
+@Mixins( RMIMixin.class )
+public interface RemoteInterfaceComposite
+    extends RemoteInterface, InvocationCacheAbstractComposite, TransientComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceImpl.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceImpl.java b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceImpl.java
new file mode 100644
index 0000000..a379b55
--- /dev/null
+++ b/qi4j/libraries/rmi/src/test/java/org/qi4j/library/rmi/remote/RemoteInterfaceImpl.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2007 Rickard Öberg
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+*/
+package org.qi4j.library.rmi.remote;
+
+import java.io.IOException;
+
+/**
+ * Implementation of RemoteInterface.
+ */
+public class RemoteInterfaceImpl
+    implements RemoteInterface
+{
+    int count = 0;
+
+    // RemoteInterface implementation --------------------------------
+    public String foo( String aBar )
+        throws IOException
+    {
+        count++;
+
+        if( count % 2 == 0 )
+        {
+            throw new IOException( "Something went wrong" );
+        }
+
+        return "Foo:" + aBar;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/dev-status.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/dev-status.xml b/qi4j/libraries/thread/dev-status.xml
new file mode 100644
index 0000000..4d9940b
--- /dev/null
+++ b/qi4j/libraries/thread/dev-status.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<module xmlns="http://www.qi4j.org/schemas/2008/dev-status/1">
+  <status>
+    <codebase>none</codebase>
+    <!--none,early,beta,stable,mature-->
+    <documentation>none</documentation>
+    <!-- none, brief, good, complete -->
+    <unittests>none</unittests>
+    <!-- none, some, good, complete -->
+  </status>
+  <licenses>
+    <license>ALv2</license>
+  </licenses>
+</module>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/pom.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/pom.xml b/qi4j/libraries/thread/pom.xml
new file mode 100644
index 0000000..e166576
--- /dev/null
+++ b/qi4j/libraries/thread/pom.xml
@@ -0,0 +1,43 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.qi4j.sandbox</groupId>
+    <artifactId>qi4j-sandbox-libraries</artifactId>
+    <version>0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.qi4j.library</groupId>
+  <artifactId>org.qi4j.library.thread</artifactId>
+  <name>Qi4j Library - Thread</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.bootstrap</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.testsupport</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.runtime</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.library</groupId>
+      <artifactId>org.qi4j.library.constraints</artifactId>
+      <version>${version.qi4j}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.qi4j.library</groupId>
+      <artifactId>org.qi4j.library.uid</artifactId>
+      <version>${version.qi4j}</version>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/MaximumThreadsException.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/MaximumThreadsException.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/MaximumThreadsException.java
new file mode 100644
index 0000000..6a5fa89
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/MaximumThreadsException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+public class MaximumThreadsException extends RuntimeException
+{
+    private final int limit;
+
+    public MaximumThreadsException( int limit )
+    {
+        super( "Maximum number of threads has been created: " + limit );
+        this.limit = limit;
+    }
+
+    public int limit()
+    {
+        return limit;
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceComposite.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceComposite.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceComposite.java
new file mode 100644
index 0000000..ac050a7
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceComposite.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.api.service.ServiceComposite;
+
+@Mixins( NewThreadServiceMixin.class )
+public interface NewThreadServiceComposite extends ThreadService, ServiceComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceMixin.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceMixin.java
new file mode 100644
index 0000000..00455d1
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/NewThreadServiceMixin.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.configuration.Configuration;
+import org.qi4j.api.injection.scope.Service;
+import org.qi4j.api.injection.scope.This;
+import org.qi4j.library.uid.sequence.Sequencing;
+
+public class NewThreadServiceMixin
+    implements ThreadService
+{
+    private @This Configuration<ThreadServiceConfiguration> config;
+    private int threadCount;
+    @Service private Sequencing sequence;
+    @Service private ThreadGroupService threadGroupService;
+
+    public Thread newThread( Runnable runnable )
+    {
+        synchronized( this )
+        {
+            Integer max = config.get().maxThreads().get();
+            if( threadCount >= max )
+            {
+                throw new MaximumThreadsException( max );
+            }
+            ThreadServiceConfiguration configuration = config.get();
+            String name = configuration.threadBaseName().get() + sequence.newSequenceValue();
+            String tgName = configuration.threadGroupName().get();
+            ThreadGroup threadGroup = threadGroupService.getThreadGroup( tgName );
+            return new Thread( threadGroup, new RunnableWrapper( runnable ), name );
+        }
+    }
+
+    public ThreadServiceConfiguration configuration()
+    {
+        return config.get();
+    }
+
+    public class RunnableWrapper
+        implements Runnable
+    {
+        private Runnable runnable;
+
+        public RunnableWrapper( Runnable runnable )
+        {
+            this.runnable = runnable;
+            threadCount++;
+        }
+
+        public void run()
+        {
+            runnable.run();
+            threadCount--;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceComposite.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceComposite.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceComposite.java
new file mode 100644
index 0000000..e6c498e
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceComposite.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.api.service.ServiceActivation;
+
+@Mixins( PooledThreadServiceMixin.class )
+public interface PooledThreadServiceComposite extends ThreadService, ServiceActivation
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceMixin.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceMixin.java
new file mode 100644
index 0000000..3c05bcf
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/PooledThreadServiceMixin.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import java.util.LinkedList;
+import org.qi4j.api.configuration.Configuration;
+import org.qi4j.api.injection.scope.Service;
+import org.qi4j.api.injection.scope.This;
+import org.qi4j.api.service.ServiceActivation;
+import org.qi4j.library.uid.sequence.Sequencing;
+
+public class PooledThreadServiceMixin
+    implements ThreadService, ServiceActivation
+{
+    @This private Configuration<ThreadServiceConfiguration> config;
+    @Service private Sequencing sequence;
+    @Service private ThreadGroupService threadGroupService;
+    private LinkedList<RunnableThread> pool;
+    private int threadCount;
+
+    public PooledThreadServiceMixin()
+    {
+        pool = new LinkedList<RunnableThread>();
+        threadCount = 0;
+    }
+
+    public Thread newThread( Runnable runnable )
+    {
+        synchronized( this )
+        {
+            if( pool.isEmpty() )
+            {
+                Integer max = config.get().maxThreads().get();
+                if( threadCount >= max )
+                {
+                    throw new MaximumThreadsException( max );
+                }
+                createNewThread();
+            }
+            RunnableThread rt = pool.removeFirst();
+            rt.runnable.currentRunnable( runnable );
+            return rt.thread;
+        }
+    }
+
+    public ThreadServiceConfiguration configuration()
+    {
+        return config.get();
+    }
+
+    public void activateService()
+        throws Exception
+    {
+        pool = new LinkedList<RunnableThread>();
+        int prefered = config.get().preferedNumberOfThreads().get();
+        for( int i = 0; i < prefered; i++ )
+        {
+            createNewThread();
+        }
+    }
+
+    private void createNewThread()
+    {
+        ThreadServiceConfiguration configuration = config.get();
+        String tgName = configuration.threadGroupName().get();
+        ThreadGroup group = threadGroupService.getThreadGroup( tgName );
+        String name = configuration.threadBaseName().get() + "-" + sequence.newSequenceValue();
+        PooledRunnableWrapper runnable = new PooledRunnableWrapper();
+        Thread t = new Thread( group, runnable, name );
+        RunnableThread runnableThread = new RunnableThread( t, runnable );
+        runnable.poolInstance = runnableThread;
+        threadCount++;
+        pool.add( runnableThread );
+    }
+
+    public void passivateService()
+        throws Exception
+    {
+        for( RunnableThread thread : pool )
+        {
+            threadCount = 0;
+            thread.runnable.run = false;
+            thread.thread.interrupt();
+        }
+    }
+
+    public static class RunnableThread
+    {
+        private final Thread thread;
+        private final PooledRunnableWrapper runnable;
+
+        public RunnableThread( Thread thread, PooledRunnableWrapper runnable )
+        {
+            this.thread = thread;
+            this.runnable = runnable;
+        }
+    }
+
+    public class PooledRunnableWrapper
+        implements Runnable
+    {
+        private boolean run;
+        private Runnable current;
+        private RunnableThread poolInstance;
+
+        public void currentRunnable( Runnable current )
+        {
+            this.current = current;
+            synchronized( this )
+            {
+                notifyAll();
+            }
+        }
+
+        public void run()
+        {
+            run = true;
+            while( run )
+            {
+                try
+                {
+                    synchronized( this )
+                    {
+                        while( current == null )
+                        {
+                            wait( 1000 );
+                        }
+                    }
+                    current.run();
+                    pool.addLast( poolInstance );
+                }
+                catch( InterruptedException e )
+                {
+                    run = false;
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfiguration.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfiguration.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfiguration.java
new file mode 100644
index 0000000..7db1086
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfiguration.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.property.Property;
+
+/**
+ * JAVADOC Add JavaDoc
+ */
+public interface ThreadGroupConfiguration
+{
+    Property<String> rootGroupName();
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfigurationEntity.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfigurationEntity.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfigurationEntity.java
new file mode 100644
index 0000000..8fda462
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupConfigurationEntity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.configuration.ConfigurationComposite;
+
+public interface ThreadGroupConfigurationEntity extends ThreadGroupConfiguration, ConfigurationComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupService.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupService.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupService.java
new file mode 100644
index 0000000..ad2ac95
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupService.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+public interface ThreadGroupService
+{
+    ThreadGroup getThreadGroup( String name );
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceComposite.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceComposite.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceComposite.java
new file mode 100644
index 0000000..0f6afb9
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceComposite.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.api.service.ServiceComposite;
+
+@Mixins( ThreadGroupServiceMixin.class )
+public interface ThreadGroupServiceComposite extends ThreadGroupService, ServiceComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceMixin.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceMixin.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceMixin.java
new file mode 100644
index 0000000..88a9372
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadGroupServiceMixin.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.configuration.Configuration;
+import org.qi4j.api.injection.scope.This;
+import org.qi4j.api.property.Property;
+
+import java.util.HashMap;
+
+public class ThreadGroupServiceMixin
+    implements ThreadGroupService
+{
+    private ThreadGroup rootGroup;
+    private HashMap<String, ThreadGroup> groups;
+
+    public ThreadGroupServiceMixin( @This Configuration<ThreadGroupConfiguration> config )
+    {
+        ThreadGroupConfiguration configuration = config.get();
+        Property<String> rootName = configuration.rootGroupName();
+        String name = rootName.get();
+        groups = new HashMap<String, ThreadGroup>();
+        rootGroup = new ThreadGroup( name );
+    }
+
+    public ThreadGroup getThreadGroup( String name )
+    {
+        synchronized( this )
+        {
+            ThreadGroup tg = groups.get( name );
+            if( tg == null )
+            {
+                tg = new ThreadGroup( rootGroup, name );
+                groups.put( name, tg );
+            }
+            return tg;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadService.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadService.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadService.java
new file mode 100644
index 0000000..0574dc1
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadService.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+public interface ThreadService
+{
+    Thread newThread( Runnable runnable );
+
+    ThreadServiceConfiguration configuration();
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfiguration.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfiguration.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfiguration.java
new file mode 100644
index 0000000..90d209c
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfiguration.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.property.Property;
+
+/**
+ * JAVADOC Add JavaDoc
+ */
+public interface ThreadServiceConfiguration
+{
+    Property<String> threadGroupName();
+
+    Property<String> threadBaseName();
+
+    Property<Integer> maxThreads();
+
+    //  Should probably have a Constraint  @Range( min = 1, max = 100 )
+    Property<Integer> preferedNumberOfThreads();
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfigurationEntity.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfigurationEntity.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfigurationEntity.java
new file mode 100644
index 0000000..c24a4ea
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/ThreadServiceConfigurationEntity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.qi4j.api.configuration.ConfigurationComposite;
+
+public interface ThreadServiceConfigurationEntity extends ThreadServiceConfiguration, ConfigurationComposite
+{
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/NewThreadServiceAssembler.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/NewThreadServiceAssembler.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/NewThreadServiceAssembler.java
new file mode 100644
index 0000000..e969a86
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/NewThreadServiceAssembler.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread.assembly;
+
+import org.qi4j.bootstrap.Assembler;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.library.thread.NewThreadServiceComposite;
+import org.qi4j.library.thread.ThreadGroupConfigurationEntity;
+import org.qi4j.library.thread.ThreadGroupServiceComposite;
+import org.qi4j.library.thread.ThreadServiceConfigurationEntity;
+import org.qi4j.library.uid.sequence.assembly.TransientSequencingAssembler;
+
+public class NewThreadServiceAssembler
+    implements Assembler
+{
+    public void assemble( ModuleAssembly module ) throws AssemblyException
+    {
+        module.services( NewThreadServiceComposite.class );
+        module.services( ThreadGroupServiceComposite.class );
+        module.entities( ThreadServiceConfigurationEntity.class );
+        module.entities( ThreadGroupConfigurationEntity.class );
+        new TransientSequencingAssembler().assemble( module );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/PooledThreadServiceAssembler.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/PooledThreadServiceAssembler.java b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/PooledThreadServiceAssembler.java
new file mode 100644
index 0000000..07131eb
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/java/org/qi4j/library/thread/assembly/PooledThreadServiceAssembler.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread.assembly;
+
+import org.qi4j.bootstrap.Assembler;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.library.thread.PooledThreadServiceComposite;
+import org.qi4j.library.thread.ThreadGroupConfigurationEntity;
+import org.qi4j.library.thread.ThreadGroupServiceComposite;
+import org.qi4j.library.thread.ThreadServiceConfigurationEntity;
+import org.qi4j.library.uid.sequence.assembly.TransientSequencingAssembler;
+
+public class PooledThreadServiceAssembler
+    implements Assembler
+{
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.services( PooledThreadServiceComposite.class );
+        module.services( ThreadGroupServiceComposite.class );
+        module.entities( ThreadServiceConfigurationEntity.class );
+        module.entities( ThreadGroupConfigurationEntity.class );
+        new TransientSequencingAssembler().assemble( module );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/NewThreadServiceComposite.properties
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/NewThreadServiceComposite.properties b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/NewThreadServiceComposite.properties
new file mode 100644
index 0000000..e6da438
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/NewThreadServiceComposite.properties
@@ -0,0 +1,10 @@
+#Default Values for the NewThreadService in the Qi4j Thread Library
+
+threadGroupName=org.qi4j
+
+threadBaseName=org.qi4j.thread
+
+maxThreads=50
+
+# Following is not used.
+preferedNumberOfThreads=2

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/PooledThreadServiceComposite.properties
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/PooledThreadServiceComposite.properties b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/PooledThreadServiceComposite.properties
new file mode 100644
index 0000000..056ad3a
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/PooledThreadServiceComposite.properties
@@ -0,0 +1,9 @@
+#Default Values for the PooledThreadService in the Qi4j Thread Library
+
+threadGroupName=org.qi4j
+
+threadBaseName=org.qi4j.thread.pooled
+
+maxThreads=20
+
+preferedNumberOfThreads=2

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/ThreadGroupServiceComposite.properties
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/ThreadGroupServiceComposite.properties b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/ThreadGroupServiceComposite.properties
new file mode 100644
index 0000000..22fb455
--- /dev/null
+++ b/qi4j/libraries/thread/src/main/resources/org/qi4j/library/thread/ThreadGroupServiceComposite.properties
@@ -0,0 +1,2 @@
+
+rootGroupName=org.qi4j
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/NewThreadServiceTest.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/NewThreadServiceTest.java b/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/NewThreadServiceTest.java
new file mode 100644
index 0000000..52bd44b
--- /dev/null
+++ b/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/NewThreadServiceTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+import org.qi4j.api.composite.TransientComposite;
+import org.qi4j.api.injection.scope.Service;
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.library.thread.assembly.NewThreadServiceAssembler;
+import org.qi4j.test.AbstractQi4jTest;
+import org.qi4j.test.EntityTestAssembler;
+
+public class NewThreadServiceTest extends AbstractQi4jTest
+{
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.transients( UnderTestComposite.class );
+        new EntityTestAssembler().assemble( module );
+        new NewThreadServiceAssembler().assemble( module );
+    }
+
+    @Test
+    public void whenUsingNewThreadProviderThenNewThreadsAreHandedBack()
+        throws Exception
+    {
+        TestRunnable r1 = new TestRunnable();
+        TestRunnable r2 = new TestRunnable();
+        UnderTest underTest = module.newTransient( UnderTest.class );
+        Thread t1 = underTest.fetchThread( r1 );
+        Thread t2 = underTest.fetchThread( r2 );
+        assertFalse( t1.equals( t2 ) );
+        t1.start();
+        t2.start();
+        Thread.sleep( 20 );
+        // Clean up
+        r1.run = false;
+        r2.run = false;
+        t1.interrupt();
+        t2.interrupt();
+    }
+
+    public interface UnderTest
+    {
+        Thread fetchThread( Runnable runnable );
+    }
+
+    @Mixins( UnderTestMixin.class )
+    public interface UnderTestComposite extends UnderTest, TransientComposite
+    {
+    }
+
+    public static class UnderTestMixin
+        implements UnderTest
+    {
+        @Service private ThreadService service;
+
+        public Thread fetchThread( Runnable runnable )
+        {
+            return service.newThread( runnable );
+        }
+    }
+
+    public static class TestRunnable
+        implements Runnable
+    {
+        private Thread thread;
+        private boolean run;
+
+        public Thread getThread()
+        {
+            return thread;
+        }
+
+        public void stop()
+        {
+            run = false;
+        }
+
+        public void run()
+        {
+            run = true;
+            thread = Thread.currentThread();
+            while( run )
+            {
+                try
+                {
+                    Thread.sleep( 10 );
+                }
+                catch( InterruptedException e )
+                {
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/PooledThreadServiceTest.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/PooledThreadServiceTest.java b/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/PooledThreadServiceTest.java
new file mode 100644
index 0000000..5637671
--- /dev/null
+++ b/qi4j/libraries/thread/src/test/java/org/qi4j/library/thread/PooledThreadServiceTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2008 Niclas Hedhman. All rights Reserved.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License. 
+ */
+package org.qi4j.library.thread;
+
+import org.junit.Assert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+import org.qi4j.api.composite.TransientComposite;
+import org.qi4j.api.injection.scope.Service;
+import org.qi4j.api.mixin.Mixins;
+import org.qi4j.bootstrap.AssemblyException;
+import org.qi4j.bootstrap.ModuleAssembly;
+import org.qi4j.library.thread.assembly.PooledThreadServiceAssembler;
+import org.qi4j.test.AbstractQi4jTest;
+
+import java.util.ArrayList;
+import org.qi4j.test.EntityTestAssembler;
+
+public class PooledThreadServiceTest extends AbstractQi4jTest
+{
+    public void assemble( ModuleAssembly module )
+        throws AssemblyException
+    {
+        module.transients( UnderTestComposite.class );
+        new EntityTestAssembler().assemble( module );
+        new PooledThreadServiceAssembler().assemble( module );
+    }
+
+    @Test
+    public void whenUsingPooledThreadProviderThenSameThreadsAreHandedBack()
+        throws Exception
+    {
+        UnderTest underTest = module.newTransient( UnderTest.class );
+        ArrayList<Thread> threads = new ArrayList<Thread>();
+        int poolsize = underTest.maxThreads();
+        TestRunnable r1 = new TestRunnable();
+        threads.add( underTest.fetchThread( r1 ) );
+        for( int i = 1; i < poolsize; i++ )
+        {
+            TestRunnable r2 = new TestRunnable();
+            threads.add( underTest.fetchThread( r2 ) );
+        }
+        try
+        {
+            TestRunnable r2 = new TestRunnable();
+            underTest.fetchThread( r2 );
+            Assert.fail( "Should have thrown a MaxixmumThreadsException." );
+        }
+        catch( MaximumThreadsException e )
+        { // ignore
+        }
+        for( int i = 0; i < poolsize; i++ )
+        {
+            Thread t1 = threads.get( i );
+
+            for( int j = 0; j < poolsize; j++ )
+            {
+                Thread t2 = threads.get( j );
+                assertFalse( ( i != j ) && t1.equals( t2 ) );
+            }
+            t1.start();
+        }
+        Thread.sleep( 100 );
+        Thread t1 = threads.get( 0 );
+        r1.stop();
+        Thread.sleep( 100 );
+        TestRunnable r3 = new TestRunnable();
+        Thread t3 = underTest.fetchThread( r3 );
+        assertEquals( t1, t3 );
+    }
+
+    public interface UnderTest
+    {
+        Thread fetchThread( Runnable runnable );
+
+        int maxThreads();
+    }
+
+    @Mixins( UnderTestMixin.class )
+    public interface UnderTestComposite extends UnderTest, TransientComposite
+    {
+    }
+
+    public static class UnderTestMixin
+        implements UnderTest
+    {
+        @Service private ThreadService service;
+
+        public Thread fetchThread( Runnable runnable )
+        {
+            return service.newThread( runnable );
+        }
+
+        public int maxThreads()
+        {
+            return service.configuration().maxThreads().get();
+        }
+    }
+
+    public static class TestRunnable
+        implements Runnable
+    {
+        private Thread thread;
+        private boolean run;
+
+        public Thread getThread()
+        {
+            return thread;
+        }
+
+        public void stop()
+        {
+            run = false;
+        }
+
+        public void run()
+        {
+            run = true;
+            thread = Thread.currentThread();
+            int count = 0;
+            while( run )
+            {
+                try
+                {
+                    Thread.sleep( 10 );
+                }
+                catch( InterruptedException e )
+                {
+                }
+                count++;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/dev-status.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/dev-status.xml b/qi4j/libraries/unitofwork/dev-status.xml
new file mode 100644
index 0000000..dc92d29
--- /dev/null
+++ b/qi4j/libraries/unitofwork/dev-status.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<module xmlns="http://www.qi4j.org/schemas/2008/dev-status/1">
+  <status>
+    <codebase>early</codebase>
+    <!--none,early,beta,stable,mature-->
+    <documentation>brief</documentation>
+    <!-- none, brief, good, complete -->
+    <unittests>some</unittests>
+    <!-- none, some, good, complete -->
+  </status>
+  <licenses>
+    <license>ALv2</license>
+  </licenses>
+</module>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/pom.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/pom.xml b/qi4j/libraries/unitofwork/pom.xml
new file mode 100644
index 0000000..9749a0b
--- /dev/null
+++ b/qi4j/libraries/unitofwork/pom.xml
@@ -0,0 +1,23 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.qi4j.sandbox</groupId>
+    <artifactId>qi4j-sandbox-libraries</artifactId>
+    <version>0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.qi4j.library</groupId>
+  <artifactId>org.qi4j.library.unitofwork</artifactId>
+  <name>Qi4j Library - UnitOfWork</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.qi4j.core</groupId>
+      <artifactId>org.qi4j.core.api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkConcern.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkConcern.java b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkConcern.java
new file mode 100644
index 0000000..771644b
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkConcern.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2008 Edward Yakop.
+ * Copyright 2009 Niclas Hedhman.
+ * Copyright 2009 Michael Hunger.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.qi4j.library.unitofwork;
+
+import java.lang.reflect.Method;
+import org.qi4j.api.common.AppliesTo;
+import org.qi4j.api.concern.GenericConcern;
+import org.qi4j.api.injection.scope.Invocation;
+import org.qi4j.api.injection.scope.Structure;
+import org.qi4j.api.unitofwork.UnitOfWork;
+import org.qi4j.api.unitofwork.UnitOfWorkCompletionException;
+import org.qi4j.api.unitofwork.UnitOfWorkFactory;
+
+/**
+ * {@code UnitOfWorkConcern} manages the unit of work complete and discard policy.
+ *
+ * @see org.qi4j.api.unitofwork.UnitOfWorkPropagation
+ * @see org.qi4j.api.unitofwork.UnitOfWorkDiscardOn
+ */
+@AppliesTo( UnitOfWorkPropagation.class )
+public class UnitOfWorkConcern
+    extends GenericConcern
+{
+    @Structure
+    private UnitOfWorkFactory uowf;
+    @Invocation
+    private UnitOfWorkPropagation propagation;
+
+    /**
+     * Handles method with {@code UnitOfWorkPropagation} annotation.
+     *
+     * @param proxy  The object.
+     * @param method The invoked method.
+     * @param args   The method arguments.
+     *
+     * @return The returned value of method invocation.
+     *
+     * @throws Throwable Thrown if the method invocation throw exception.
+     */
+    public Object invoke( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        UnitOfWorkPropagation.Propagation propagationPolicy = propagation.value();
+        if( propagationPolicy == UnitOfWorkPropagation.Propagation.REQUIRED )
+        {
+            return requiredStrategy( proxy, method, args );
+        }
+        else if( propagationPolicy == UnitOfWorkPropagation.Propagation.MANDATORY )
+        {
+            return mandatoryStrategy( proxy, method, args );
+        }
+        else if( propagationPolicy == UnitOfWorkPropagation.Propagation.REQUIRES_NEW )
+        {
+            return requiresNewRequires( proxy, method, args );
+        }
+        throw new UnitOfWorkPropagationException( "'null' is not allowed as propagation strategy." );
+    }
+
+    /**
+     * Discard unit of work if the discard policy match.
+     *
+     * @param aMethod         The invoked method. This argument must not be {@code null}.
+     * @param aUnitOfWork     The current unit of work. This argument must not be {@code null}.
+     * @param exceptionThrown The exception thrown. This argument must not be {@code null}.
+     *
+     * @throws org.qi4j.api.unitofwork.UnitOfWorkCompletionException
+     *          If the complete() method fails.
+     */
+    private void discardIfRequired( Method aMethod, UnitOfWork aUnitOfWork, Throwable exceptionThrown )
+        throws UnitOfWorkCompletionException
+    {
+        UnitOfWorkDiscardOn discardPolicy = aMethod.getAnnotation( UnitOfWorkDiscardOn.class );
+        UnitOfWorkNoDiscardOn noDiscardPolicy = aMethod.getAnnotation( UnitOfWorkNoDiscardOn.class );
+        if( null == discardPolicy && noDiscardPolicy == null )
+        {
+            aUnitOfWork.discard();
+            return;
+        }
+        Class<?>[] discardClasses;
+        if( discardPolicy == null )
+        {
+            discardClasses = new Class[]{ Throwable.class };
+        }
+        else
+        {
+            discardClasses = discardPolicy.value();
+        }
+        Class<?>[] noDiscardClasses;
+        if( noDiscardPolicy == null )
+        {
+            noDiscardClasses = new Class[0];
+        }
+        else
+        {
+            noDiscardClasses = noDiscardPolicy.value();
+        }
+
+        Class<? extends Throwable> thrownClass = exceptionThrown.getClass();
+
+        next:
+        for( Class<?> discardClass : discardClasses )
+        {
+            if( discardClass.isAssignableFrom( thrownClass ) )
+            {
+                for( Class<?> noDiscardClass : noDiscardClasses )
+                {
+                    if( noDiscardClass.isAssignableFrom( thrownClass ) )
+                    {
+                        continue next;
+                    }
+                }
+                aUnitOfWork.discard();
+                return;
+            }
+        }
+        aUnitOfWork.complete();
+    }
+
+    private UnitOfWork createNewUnitOfWork()
+    {
+        return uowf.newUnitOfWork();
+    }
+
+    private Object requiresNewRequires( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        UnitOfWork currentUnitOfWork = createNewUnitOfWork();
+        try
+        {
+            Object result = next.invoke( proxy, method, args );
+            currentUnitOfWork.complete();
+            return result;
+        }
+        catch( Throwable throwable )
+        {
+            discardIfRequired( method, currentUnitOfWork, throwable );
+            throw throwable;
+        }
+    }
+
+    private Object mandatoryStrategy( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        UnitOfWork currentUnitOfWork = uowf.currentUnitOfWork();
+        if( currentUnitOfWork == null )
+        {
+            throw new UnitOfWorkPropagationException( "[UnitOfWork] was required but there is no available unit of work." );
+        }
+        return next.invoke( proxy, method, args );
+    }
+
+    private Object requiredStrategy( Object proxy, Method method, Object[] args )
+        throws Throwable
+    {
+        UnitOfWork currentUnitOfWork = uowf.currentUnitOfWork();
+        boolean created = false;
+        if( currentUnitOfWork == null )
+        {
+            currentUnitOfWork = createNewUnitOfWork();
+            created = true;
+        }
+
+        try
+        {
+            Object result = next.invoke( proxy, method, args );
+            if( created )
+            {
+                currentUnitOfWork.complete();
+            }
+            return result;
+        }
+        catch( Throwable throwable )
+        {
+            // Discard only if this concern create a unit of work
+            if( created )
+            {
+                discardIfRequired( method, currentUnitOfWork, throwable );
+            }
+            throw throwable;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkDiscardOn.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkDiscardOn.java b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkDiscardOn.java
new file mode 100644
index 0000000..6d759bf
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkDiscardOn.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, Edward Yakop. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.qi4j.library.unitofwork;
+
+/**
+ * Annotation to denote the unit of work discard policy.
+ * By default, discard is applied on any method that has {@link UnitOfWorkPropagation} and any exception is thrown.
+ * <p/>
+ * Apply {@code UnitOfWorkDiscardOn} to override the default settings.
+ *
+ * <p/>
+ * Usage example:
+ * <pre>
+ * <code>
+ *
+ * &#64;Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ *   &#64;Structure UnitOfWorkFactory uowf;
+ *
+ *   &#64;UnitOfWorkDiscardOn( MyBusinessException.class )
+ *   public void myBusinessMethod()
+ *   {
+ *     // Must invoke current unit of work.
+ *     UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ *     // Perform business logic
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * <p/>
+ * The unit of work will be discarded iff {@code MyBusinessException} exceptions or its subclass is thrown from within
+ * {@code myBusinessMethod} method.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.2.0
+ */
+public @interface UnitOfWorkDiscardOn
+{
+    Class<? extends Throwable>[] value() default { Throwable.class };
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkNoDiscardOn.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkNoDiscardOn.java b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkNoDiscardOn.java
new file mode 100644
index 0000000..2710f65
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkNoDiscardOn.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009 Niclas Hedhman.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.qi4j.library.unitofwork;
+
+/**
+ * Annotation to denote the unit of work discard policy.
+ * By default, discard is applied on any method that has {@link UnitOfWorkPropagation} and any exception is thrown.
+ * <p/>
+ * Apply {@code UnitOfWorkDiscardOn} to override the default settings.
+ *
+ * <p/>
+ * Usage example:
+ * <pre>
+ * <code>
+ *
+ * &#64;Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ *   &#64;Structure UnitOfWorkFactory uowf;
+ *
+ *   &#64;UnitOfWorkPropagation
+ *   &#64;UnitOfWorkNoDiscardOn( MyBusinessException.class )
+ *   public void myBusinessMethod()
+ *   {
+ *     // Must invoke current unit of work.
+ *     UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ *     // Perform business logic
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * <p/>
+ * The unit of work will be discarded iff {@code MyBusinessException} exceptions or its subclass is NOT thrown from
+ * within {@code myBusinessMethod} method.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.2.0
+ */
+public @interface UnitOfWorkNoDiscardOn
+{
+    Class<? extends Throwable>[] value();
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagation.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagation.java b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagation.java
new file mode 100644
index 0000000..332b510
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagation.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2008, Edward Yakop. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.qi4j.library.unitofwork;
+
+import java.lang.annotation.Documented;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to denote the unit of work propagation.
+ *
+ * <p/>
+ * Usage example:
+ * <pre>
+ * <code>
+ *
+ * &#64;Concerns( UnitOfWorkConcern.class )
+ * public class MyBusinessServiceMixin implements BusinessService
+ * {
+ *   &#64;Structure UnitOfWorkFactory uowf;
+ *
+ *   &#64;UnitOfWorkPropagation
+ *   public void myBusinessMethod()
+ *   {
+ *     // Must invoke current unit of work.
+ *     UnitOfWork uow = uowf.currentUnitOfWork();
+ *
+ *     // Perform business logic
+ *   }
+ * }
+ * </code>
+ * </pre>
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.2.0
+ */
+@Retention( RUNTIME )
+@Target( METHOD )
+@Inherited
+@Documented
+public @interface UnitOfWorkPropagation
+{
+    Propagation value() default Propagation.REQUIRED;
+
+    UsecasePropagation usecasePropagation() default UsecasePropagation.PROPAGATE;
+
+    enum UsecasePropagation
+    {
+        PROPAGATE,
+        DEFAULT
+    }
+
+    enum Propagation
+    {
+        /**
+         * Default propagation behavior.
+         * Behavior: <br>
+         * If no current transaction: creates a new transaction <br>
+         * If there is a current transaction: use the current transaction.
+         */
+        REQUIRED,
+
+        /**
+         * Behavior: <br>
+         * If no current transaction: throw an exception <br>
+         * If there is a current transaction: use the current transaction.
+         */
+        MANDATORY,
+
+        /**
+         * Behavior: <br>
+         * If no current transaction: creates a new transaction <br>
+         * If there is a current transaction: suspend the current transaction and create a new transaction.
+         */
+        REQUIRES_NEW,
+
+        /**
+         * Behavior: <br>
+         * If no current transaction: creates a new transaction <br>
+         * If there is a current transaction: create a nested transaction.
+         */
+        REQUIRES_NESTED,
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagationException.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagationException.java b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagationException.java
new file mode 100644
index 0000000..f81b82f
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/main/java/org/qi4j/library/unitofwork/UnitOfWorkPropagationException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 Niclas Hedhman.
+ *
+ * Licensed  under the  Apache License,  Version 2.0  (the "License");
+ * you may not use  this file  except in  compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed  under the  License is distributed on an "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+ * implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.qi4j.library.unitofwork;
+
+public class UnitOfWorkPropagationException extends RuntimeException
+{
+    public UnitOfWorkPropagationException( String message )
+    {
+        super( message );
+    }
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/PropagationTest.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/PropagationTest.java b/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/PropagationTest.java
new file mode 100644
index 0000000..4a2fe82
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/PropagationTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 Niclas Hedhman. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.qi4j.library.unitofwork;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PropagationTest
+{
+
+    @Test
+    public void ensurePublicApi()
+    {
+        // if an enum value is changed or removed the test wont compile
+        // if a value is added will fail
+        for( UnitOfWorkPropagation.Propagation propagation : UnitOfWorkPropagation.Propagation.values() )
+        {
+            switch( propagation )
+            {
+            case MANDATORY:
+            case REQUIRED:
+            case REQUIRES_NEW:
+            case REQUIRES_NESTED:
+                break;
+            default:
+                Assert.fail( "unsupported type: " + propagation );
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/TransactionalTest.java
----------------------------------------------------------------------
diff --git a/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/TransactionalTest.java b/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/TransactionalTest.java
new file mode 100644
index 0000000..640b04f
--- /dev/null
+++ b/qi4j/libraries/unitofwork/src/test/java/org/qi4j/library/unitofwork/TransactionalTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007 Alin Dreghiciu. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.qi4j.library.unitofwork;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+public class TransactionalTest
+{
+
+    @Test
+    public void defaultValue() throws NoSuchMethodException
+    {
+        Method method = TransactionalTest.class.getMethod( "transactionalMethod" );
+        assertEquals( "default value",
+                      UnitOfWorkPropagation.Propagation.REQUIRED,
+                      method.getAnnotation( UnitOfWorkPropagation.class ).value() );
+    }
+
+    @UnitOfWorkPropagation
+    public void transactionalMethod()
+    {
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/validation/dev-status.xml
----------------------------------------------------------------------
diff --git a/qi4j/libraries/validation/dev-status.xml b/qi4j/libraries/validation/dev-status.xml
new file mode 100644
index 0000000..1e523b4
--- /dev/null
+++ b/qi4j/libraries/validation/dev-status.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<module xmlns="http://www.qi4j.org/schemas/2008/dev-status/1">
+  <status>
+    <codebase>early</codebase>
+    <!--none,early,beta,stable,mature-->
+    <documentation>none</documentation>
+    <!-- none, brief, good, complete -->
+    <unittests>none</unittests>
+    <!-- none, some, good, complete -->
+  </status>
+  <licenses>
+    <license>ALv2</license>
+  </licenses>
+</module>
\ No newline at end of file


Mime
View raw message