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> + * + * @Concerns( UnitOfWorkConcern.class ) + * public class MyBusinessServiceMixin implements BusinessService + * { + * @Structure UnitOfWorkFactory uowf; + * + * @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 [email protected] + * @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> + * + * @Concerns( UnitOfWorkConcern.class ) + * public class MyBusinessServiceMixin implements BusinessService + * { + * @Structure UnitOfWorkFactory uowf; + * + * @UnitOfWorkPropagation + * @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 [email protected] + * @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> + * + * @Concerns( UnitOfWorkConcern.class ) + * public class MyBusinessServiceMixin implements BusinessService + * { + * @Structure UnitOfWorkFactory uowf; + * + * @UnitOfWorkPropagation + * public void myBusinessMethod() + * { + * // Must invoke current unit of work. + * UnitOfWork uow = uowf.currentUnitOfWork(); + * + * // Perform business logic + * } + * } + * </code> + * </pre> + * + * @author [email protected] + * @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
