You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by rm...@apache.org on 2016/03/23 10:34:25 UTC
deltaspike git commit: DELTASPIKE-1099 @Locked interceptor
Repository: deltaspike
Updated Branches:
refs/heads/master 4523b5f35 -> 2b630819a
DELTASPIKE-1099 @Locked interceptor
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/2b630819
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/2b630819
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/2b630819
Branch: refs/heads/master
Commit: 2b630819a6392e52b8ff6c5d306c21aa8cd50e90
Parents: 4523b5f
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Wed Mar 23 10:34:04 2016 +0100
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Wed Mar 23 10:34:04 2016 +0100
----------------------------------------------------------------------
.../apache/deltaspike/core/api/lock/Locked.java | 88 ++++++++++
.../core/impl/future/FutureableInterceptor.java | 15 +-
.../core/impl/lock/LockedInterceptor.java | 170 +++++++++++++++++++
.../impl/throttling/ThrottledInterceptor.java | 15 +-
.../core/impl/util/AnnotatedMethods.java | 49 ++++++
.../impl/src/main/resources/META-INF/beans.xml | 1 +
.../test/core/impl/lock/LockedTest.java | 161 ++++++++++++++++++
.../deltaspike/test/core/impl/lock/Service.java | 54 ++++++
8 files changed, 527 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/lock/Locked.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/lock/Locked.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/lock/Locked.java
new file mode 100644
index 0000000..c866327
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/lock/Locked.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.core.api.lock;
+
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.util.Nonbinding;
+import javax.interceptor.InterceptorBinding;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReadWriteLock;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * The access to the method is protected by a read/write lock.
+ */
+@InterceptorBinding
+@Retention(RUNTIME)
+@Target({ TYPE, METHOD })
+public @interface Locked
+{
+ /**
+ * @return if the lock is fair.
+ */
+ @Nonbinding
+ boolean fair() default false;
+
+ /**
+ * @return the operation used on the lock, default to read but you can use write.
+ */
+ @Nonbinding
+ Operation operation() default Operation.READ;
+
+ /**
+ * @return how to retrieve the lock for this method. Default uses a lock per class.
+ */
+ @Nonbinding
+ Class<? extends LockFactory> factory() default LockFactory.class;
+
+ /**
+ * @return the access timeout for this method. Ignored by default since it is 0.
+ */
+ @Nonbinding
+ long timeout() default 0L;
+
+ /**
+ * @return the timeout unit (default ms).
+ */
+ @Nonbinding
+ TimeUnit timeoutUnit() default TimeUnit.MILLISECONDS;
+
+ enum Operation
+ {
+ READ, WRITE
+ }
+
+ /**
+ * Provide a way to switch the ReadWriteLock implementation for @Locked.
+ */
+ interface LockFactory
+ {
+ /**
+ * @param method the intercepted method.
+ * @param fair is the lock fair.
+ * @return a read/write lock used for @Locked implementation.
+ */
+ ReadWriteLock newLock(AnnotatedMethod<?> method, boolean fair);
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/FutureableInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/FutureableInterceptor.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/FutureableInterceptor.java
index a9119ed..6aec388 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/FutureableInterceptor.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/future/FutureableInterceptor.java
@@ -20,6 +20,7 @@ package org.apache.deltaspike.core.impl.future;
import org.apache.deltaspike.core.api.config.ConfigResolver;
import org.apache.deltaspike.core.api.future.Futureable;
+import org.apache.deltaspike.core.impl.util.AnnotatedMethods;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
@@ -174,19 +175,7 @@ public class FutureableInterceptor implements Serializable
if (executorService == null)
{
final AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(method.getDeclaringClass());
- AnnotatedMethod<?> annotatedMethod = null;
- for (final AnnotatedMethod<?> am : annotatedType.getMethods())
- {
- if (am.getJavaMember().equals(method))
- {
- annotatedMethod = am;
- break;
- }
- }
- if (annotatedMethod == null)
- {
- throw new IllegalStateException("No annotated method for " + method);
- }
+ final AnnotatedMethod<?> annotatedMethod = AnnotatedMethods.findMethod(annotatedType, method);
final Futureable methodConfig = annotatedMethod.getAnnotation(Futureable.class);
final ExecutorService instance = manager.find(
(methodConfig == null ? annotatedType.getAnnotation(Futureable.class) : methodConfig).value());
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/lock/LockedInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/lock/LockedInterceptor.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/lock/LockedInterceptor.java
new file mode 100644
index 0000000..aff1efc
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/lock/LockedInterceptor.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.core.impl.lock;
+
+import org.apache.deltaspike.core.api.lock.Locked;
+import org.apache.deltaspike.core.impl.util.AnnotatedMethods;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Typed;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import static org.apache.deltaspike.core.api.lock.Locked.Operation.READ;
+
+@Locked
+@Interceptor
+public class LockedInterceptor implements Serializable
+{
+ @Inject
+ private Locks locks;
+
+ @AroundInvoke
+ public Object invoke(final InvocationContext ic) throws Exception
+ {
+ final Lock l = locks.lockAcquirer(ic).get();
+ try
+ {
+ return ic.proceed();
+ }
+ finally
+ {
+ l.unlock();
+ }
+ }
+
+ @ApplicationScoped
+ @Typed(Locks.class)
+ static class Locks implements Locked.LockFactory
+ {
+ private final ConcurrentMap<String, ReadWriteLock> locks = new ConcurrentHashMap<String, ReadWriteLock>();
+
+ // read or write
+ private final ConcurrentMap<Method, LockSupplier> lockSuppliers = new ConcurrentHashMap<Method, LockSupplier>();
+
+ @Inject
+ private BeanManager beanManager;
+
+ LockSupplier lockAcquirer(final InvocationContext ic)
+ {
+ final Method key = ic.getMethod();
+ LockSupplier operation = lockSuppliers.get(key);
+ if (operation == null)
+ {
+ final Class declaringClass = key.getDeclaringClass();
+ final AnnotatedType<Object> annotatedType = beanManager.createAnnotatedType(declaringClass);
+ final AnnotatedMethod<?> annotatedMethod = AnnotatedMethods.findMethod(annotatedType, key);
+
+ Locked config = annotatedMethod.getAnnotation(Locked.class);
+ if (config == null)
+ {
+ config = annotatedType.getAnnotation(Locked.class);
+ }
+ final Locked.LockFactory factory = config.factory() != Locked.LockFactory.class ?
+ Locked.LockFactory.class.cast(
+ beanManager.getReference(beanManager.resolve(
+ beanManager.getBeans(
+ config.factory())),
+ Locked.LockFactory.class, null)) : this;
+
+ final ReadWriteLock writeLock = factory.newLock(annotatedMethod, config.fair());
+ final long timeout = config.timeoutUnit().toMillis(config.timeout());
+ final Lock lock = config.operation() == READ ? writeLock.readLock() : writeLock.writeLock();
+
+ if (timeout > 0)
+ {
+ operation = new LockSupplier()
+ {
+ @Override
+ public Lock get()
+ {
+ try
+ {
+ if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS))
+ {
+ throw new IllegalStateException("Can't lock for " + key + " in " + timeout + "ms");
+ }
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.interrupted();
+ throw new IllegalStateException("Locking interrupted", e);
+ }
+ return lock;
+ }
+ };
+ }
+ else
+ {
+ operation = new LockSupplier()
+ {
+ @Override
+ public Lock get()
+ {
+ lock.lock();
+ return lock;
+ }
+ };
+ }
+
+ final LockSupplier existing = lockSuppliers.putIfAbsent(key, operation);
+ if (existing != null)
+ {
+ operation = existing;
+ }
+ }
+ return operation;
+ }
+
+ @Override
+ public ReadWriteLock newLock(final AnnotatedMethod<?> method, final boolean fair)
+ {
+ final String name = method.getJavaMember().getDeclaringClass().getName();
+ ReadWriteLock lock = locks.get(name);
+ if (lock == null)
+ {
+ lock = new ReentrantReadWriteLock(fair);
+ final ReadWriteLock existing = locks.putIfAbsent(name, lock);
+ if (existing != null)
+ {
+ lock = existing;
+ }
+ }
+ return lock;
+ }
+ }
+
+ private interface LockSupplier // yes we miss a bit java 8 there
+ {
+ Lock get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/throttling/ThrottledInterceptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/throttling/ThrottledInterceptor.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/throttling/ThrottledInterceptor.java
index 6b9e1f8..f02b14f 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/throttling/ThrottledInterceptor.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/throttling/ThrottledInterceptor.java
@@ -20,6 +20,7 @@ package org.apache.deltaspike.core.impl.throttling;
import org.apache.deltaspike.core.api.throttling.Throttled;
import org.apache.deltaspike.core.api.throttling.Throttling;
+import org.apache.deltaspike.core.impl.util.AnnotatedMethods;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Typed;
@@ -74,19 +75,7 @@ public class ThrottledInterceptor implements Serializable
{
final Class declaringClass = method.getDeclaringClass();
final AnnotatedType<Object> annotatedType = beanManager.createAnnotatedType(declaringClass);
- AnnotatedMethod<?> annotatedMethod = null;
- for (final AnnotatedMethod<?> am : annotatedType.getMethods())
- {
- if (am.getJavaMember().equals(method))
- {
- annotatedMethod = am;
- break;
- }
- }
- if (annotatedMethod == null)
- {
- throw new IllegalStateException("No annotated method for " + method);
- }
+ final AnnotatedMethod<?> annotatedMethod = AnnotatedMethods.findMethod(annotatedType, method);
Throttled config = annotatedMethod.getAnnotation(Throttled.class);
if (config == null)
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/AnnotatedMethods.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/AnnotatedMethods.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/AnnotatedMethods.java
new file mode 100644
index 0000000..fc0c980
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/util/AnnotatedMethods.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.core.impl.util;
+
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import java.lang.reflect.Method;
+
+public final class AnnotatedMethods
+{
+ private AnnotatedMethods()
+ {
+ // no-op
+ }
+
+ public static AnnotatedMethod<?> findMethod(final AnnotatedType<?> type, final Method method)
+ {
+ AnnotatedMethod<?> annotatedMethod = null;
+ for (final AnnotatedMethod<?> am : type.getMethods())
+ {
+ if (am.getJavaMember().equals(method))
+ {
+ annotatedMethod = am;
+ break;
+ }
+ }
+ if (annotatedMethod == null)
+ {
+ throw new IllegalStateException("No annotated method for " + method);
+ }
+ return annotatedMethod;
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/resources/META-INF/beans.xml b/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
index 9994be5..5d96bf1 100644
--- a/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
+++ b/deltaspike/core/impl/src/main/resources/META-INF/beans.xml
@@ -22,6 +22,7 @@
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>org.apache.deltaspike.core.impl.throttling.ThrottledInterceptor</class>
+ <class>org.apache.deltaspike.core.impl.lock.LockedInterceptor</class>
<class>org.apache.deltaspike.core.impl.future.FutureableInterceptor</class>
</interceptors>
</beans>
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/LockedTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/LockedTest.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/LockedTest.java
new file mode 100644
index 0000000..c0f43ce
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/LockedTest.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.test.core.impl.lock;
+
+import org.apache.deltaspike.test.util.ArchiveUtils;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.inject.Inject;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(Arquillian.class)
+public class LockedTest {
+ @Deployment
+ public static WebArchive deploy()
+ {
+ JavaArchive testJar = ShrinkWrap.create(JavaArchive.class, "FutureableTest.jar")
+ .addPackage(Service.class.getPackage().getName())
+ .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+
+ return ShrinkWrap.create(WebArchive.class, "FutureableTest.war")
+ .addAsLibraries(ArchiveUtils.getDeltaSpikeCoreArchive())
+ .addAsLibraries(testJar)
+ .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+ }
+
+ @Inject
+ private Service service;
+
+ @Test
+ public void simpleNotConcurrent()
+ {
+ final CountDownLatch synchro = new CountDownLatch(1);
+ final Thread writer = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ service.write("test", "value");
+ synchro.countDown();
+ }
+ };
+
+ final CountDownLatch end = new CountDownLatch(1);
+ final AtomicReference<String> val = new AtomicReference<String>();
+ final Thread reader = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ synchro.await(1, TimeUnit.MINUTES);
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.interrupted();
+ fail();
+ }
+ val.set(service.read("test"));
+ end.countDown();
+ }
+ };
+
+ reader.start();
+ writer.start();
+ try
+ {
+ end.await(1, TimeUnit.MINUTES);
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.interrupted();
+ fail();
+ }
+ assertEquals("value", val.get());
+ }
+
+ @Test
+ public void concurrentTimeout()
+ {
+ final AtomicBoolean doAgain = new AtomicBoolean(true);
+ final CountDownLatch endWriter = new CountDownLatch(1);
+ final Thread writer = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ while (doAgain.get())
+ {
+ service.write("test", "value");
+ service.force();
+ }
+ endWriter.countDown();
+ }
+ };
+
+ final CountDownLatch endReader = new CountDownLatch(1);
+ final Thread reader = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ while (doAgain.get())
+ {
+ try
+ {
+ service.read("test");
+ }
+ catch (final IllegalStateException e)
+ {
+ doAgain.set(false);
+ }
+ }
+ endReader.countDown();
+ }
+ };
+
+ reader.start();
+ writer.start();
+ try
+ {
+ endReader.await(1, TimeUnit.MINUTES);
+ endWriter.await(1, TimeUnit.MINUTES);
+ }
+ catch (final InterruptedException e)
+ {
+ Thread.interrupted();
+ fail();
+ }
+ assertEquals("value", service.read("test"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2b630819/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/Service.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/Service.java b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/Service.java
new file mode 100644
index 0000000..e2c7894
--- /dev/null
+++ b/deltaspike/core/impl/src/test/java/org/apache/deltaspike/test/core/impl/lock/Service.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.deltaspike.test.core.impl.lock;
+
+import org.apache.deltaspike.core.api.lock.Locked;
+
+import javax.enterprise.context.ApplicationScoped;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.deltaspike.core.api.lock.Locked.Operation.WRITE;
+import static org.junit.Assert.fail;
+
+@ApplicationScoped
+public class Service {
+ private final Map<String, String> entries = new HashMap<String, String>();
+
+ @Locked(timeout = 1, timeoutUnit = TimeUnit.SECONDS)
+ public String read(final String k) {
+ return entries.get(k);
+ }
+
+ @Locked(timeout = 1, timeoutUnit = TimeUnit.SECONDS, operation = WRITE)
+ public void write(final String k, final String v) {
+ entries.put(k, v);
+ }
+
+ @Locked(operation = WRITE)
+ public void force() {
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(5));
+ } catch (final InterruptedException e) {
+ Thread.interrupted();
+ fail();
+ }
+ }
+}