├── .gitignore ├── README.adoc ├── microscoped-core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── tomitribe │ │ │ └── microscoped │ │ │ └── core │ │ │ ├── Scope.java │ │ │ └── ScopeContext.java │ └── resources │ │ └── META-INF │ │ └── beans.xml │ └── test │ └── resources │ └── arquillian.xml ├── microscoped-domain ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── tomitribe │ │ │ └── microscoped │ │ │ └── domain │ │ │ ├── Domain.java │ │ │ ├── DomainScoped.java │ │ │ ├── DomainScopedExtension.java │ │ │ └── DomainScopedFilter.java │ └── resources │ │ └── META-INF │ │ ├── beans.xml │ │ └── services │ │ └── javax.enterprise.inject.spi.Extension │ └── test │ ├── java │ └── org │ │ └── supertribe │ │ └── domain │ │ ├── Count.java │ │ ├── DomainScopedTest.java │ │ └── SimpleService.java │ └── resources │ └── arquillian.xml ├── microscoped-header ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── tomitribe │ │ │ └── microscoped │ │ │ └── header │ │ │ ├── Beans.java │ │ │ ├── Header.java │ │ │ ├── HeaderScoped.java │ │ │ ├── HeaderScopedConfig.java │ │ │ ├── HeaderScopedExtension.java │ │ │ └── HeaderScopedFilter.java │ └── resources │ │ └── META-INF │ │ ├── beans.xml │ │ └── services │ │ └── javax.enterprise.inject.spi.Extension │ └── test │ ├── java │ └── org │ │ └── supertribe │ │ └── header │ │ ├── Count.java │ │ ├── HeaderScopedConfigExtension.java │ │ ├── HeaderScopedTest.java │ │ └── SimpleService.java │ └── resources │ ├── META-INF │ ├── beans.xml │ └── services │ │ └── javax.enterprise.inject.spi.Extension │ └── arquillian.xml ├── microscoped-method ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── tomitribe │ │ │ └── microscoped │ │ │ └── method │ │ │ ├── MethodScopeEnabled.java │ │ │ ├── MethodScoped.java │ │ │ ├── MethodScopedExtension.java │ │ │ └── MethodScopedInterceptor.java │ └── resources │ │ └── META-INF │ │ ├── beans.xml │ │ └── services │ │ └── javax.enterprise.inject.spi.Extension │ └── test │ ├── java │ └── org │ │ └── supertribe │ │ ├── ColorService.java │ │ ├── Count.java │ │ └── MethodScopedTest.java │ └── resources │ └── arquillian.xml ├── microscoped-timer ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── tomitribe │ │ │ └── microscoped │ │ │ └── timer │ │ │ ├── TimerScopeEnabled.java │ │ │ ├── TimerScoped.java │ │ │ ├── TimerScopedExtension.java │ │ │ └── TimerScopedInterceptor.java │ └── resources │ │ └── META-INF │ │ ├── beans.xml │ │ └── services │ │ └── javax.enterprise.inject.spi.Extension │ └── test │ ├── java │ └── org │ │ └── supertribe │ │ └── timer │ │ ├── ColorService.java │ │ ├── Count.java │ │ ├── Log.java │ │ └── TimerScopedTest.java │ └── resources │ └── arquillian.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.class 3 | *.jar 4 | *.war 5 | *.ear 6 | *.iml 7 | *.ipr 8 | .idea 9 | *.iws 10 | *~ 11 | *.launch 12 | *.pydevproject 13 | *.swp 14 | .project 15 | *.tmp 16 | *~.nib 17 | .AppleDB 18 | .AppleDesktop 19 | .AppleDouble 20 | .DS_Store 21 | .LSOverride 22 | .Spotlight-V100 23 | .Trashes 24 | ._* 25 | .apdisk 26 | .buildpath 27 | .cproject 28 | .externalToolBuilders/ 29 | .gradle 30 | .idea/ 31 | .idea_modules/ 32 | .loadpath 33 | .metadata 34 | .mtj.tmp/ 35 | .classpath 36 | .checkstyle 37 | .settings/ 38 | .target 39 | .texlipse 40 | /*.iml 41 | data/ 42 | Icon 43 | target 44 | Network Trash Folder 45 | Temporary Items 46 | atlassian-ide-plugin.xml 47 | bin/ 48 | com_crashlytics_export_strings.xml 49 | hs_err_pid* 50 | local.properties 51 | out/ 52 | pom.xml.next 53 | pom.xml.releaseBackup 54 | pom.xml.tag 55 | pom.xml.versionsBackup 56 | release.properties 57 | target/ 58 | dependency-reduced-pom.xml 59 | tmp/ 60 | build/ 61 | *.log 62 | /bin/ 63 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | # Microscoped 2 | 3 | A handful of custom CDI Scopes for your learning and hashmap-killing pleasure. 4 | 5 | While EJB has `@Stateless`, `@Singleton`, `@Stateful` there are near equivalent of all such concepts in CDI such as `@ApplicationScoped` and `@SessionScoped`. 6 | Unlike its predecessor EJB, CDI is not fixed to just these bean types. It is possible for nearly any lifecycle to be supported via adding a custom `@Scope` implementation. 7 | 8 | Despite this awesome power and potential, the use of custom CDI Scopes is rarely found in the wild. This is more due to lack of resources and examples for doing so as well as a truly inspired set of ideas. 9 | 10 | This project attempts to give both. Rest assured, if you're storing objects in a map in your code and hooking that map up to a `ThreadLocal`, that code is begging to be rewritten. 11 | 12 | ## Out of the Box Scopes 13 | 14 | Microscoped provides a handful of real-world and usable scopes out of the box: 15 | 16 | - `@MethodScoped` - track objects based on the currently executing method 17 | - `@DomainScoped` - swap out all your implementations based on what virtual host an HTTP request is targeting 18 | - `@HeaderScoped` - specify a header, such as `version`, to toggle a completely different set of objects to be used to service a request 19 | - `@TimerScoped` - keep state between EJB Timer firing by using a scope to remember where you left off last time the timer fired 20 | 21 | ## Implementing a Custom Scope 22 | 23 | First order of business is to create the scope annotation itself: 24 | 25 | [source,java] 26 | ---- 27 | import javax.enterprise.context.NormalScope; 28 | import java.lang.annotation.Documented; 29 | import java.lang.annotation.ElementType; 30 | import java.lang.annotation.Inherited; 31 | import java.lang.annotation.Retention; 32 | import java.lang.annotation.RetentionPolicy; 33 | import java.lang.annotation.Target; 34 | 35 | @Documented 36 | @NormalScope(passivating = false) 37 | @Inherited 38 | @Retention(RetentionPolicy.RUNTIME) 39 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 40 | public @interface MethodScoped { 41 | } 42 | ---- 43 | 44 | Next we need to register that scope with the `BeanManger` when the application starts. We must specify a `Context` implementation. No worries, 45 | Microscoped comes with one very simple implementation called `ScopeContext` that can hold anything. 46 | 47 | [source,java] 48 | ---- 49 | import org.tomitribe.microscoped.core.ScopeContext; 50 | 51 | import javax.enterprise.event.Observes; 52 | import javax.enterprise.inject.spi.AfterBeanDiscovery; 53 | import javax.enterprise.inject.spi.BeforeBeanDiscovery; 54 | import javax.enterprise.inject.spi.Extension; 55 | 56 | 57 | public class MethodScopedExtension implements Extension { 58 | 59 | public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { 60 | bbd.addScope(MethodScoped.class, true, false); 61 | bbd.addInterceptorBinding(MethodScopeEnabled.class); 62 | } 63 | 64 | public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { 65 | 66 | abd.addContext(new ScopeContext<>(MethodScoped.class)); 67 | 68 | } 69 | } 70 | ---- 71 | 72 | Finally, we do the work of putting boundaries on when the scope should be active and not active. 73 | This is usually done with an interceptor, filter or some other around advice. 74 | 75 | [source,java] 76 | ---- 77 | import org.tomitribe.microscoped.core.ScopeContext; 78 | 79 | import javax.enterprise.inject.spi.BeanManager; 80 | import javax.inject.Inject; 81 | import javax.interceptor.AroundInvoke; 82 | import javax.interceptor.Interceptor; 83 | import javax.interceptor.InvocationContext; 84 | import java.lang.reflect.Method; 85 | 86 | @Interceptor 87 | @MethodScopeEnabled 88 | public class MethodScopedInterceptor { 89 | 90 | @Inject 91 | private BeanManager beanManager; 92 | 93 | @AroundInvoke 94 | public Object invoke(InvocationContext invocation) throws Exception { 95 | final ScopeContext context = (ScopeContext) beanManager.getContext(MethodScoped.class); 96 | 97 | final Method previous = context.enter(invocation.getMethod()); 98 | try { 99 | return invocation.proceed(); 100 | } finally { 101 | context.exit(previous); 102 | } 103 | } 104 | } 105 | ---- 106 | 107 | ## Using a Custom Scope 108 | 109 | To use your newly created custom scope, you simply need to start annotating beans with it. 110 | 111 | The following will effectively give each method its very own `Count` instance. 112 | 113 | [source,java] 114 | ---- 115 | import org.tomitribe.microscoped.method.MethodScoped; 116 | 117 | import java.util.concurrent.atomic.AtomicInteger; 118 | 119 | @MethodScoped 120 | public class Count { 121 | 122 | private final AtomicInteger count = new AtomicInteger(); 123 | 124 | public int get() { 125 | return count.get(); 126 | } 127 | 128 | public int add() { 129 | return count.incrementAndGet(); 130 | } 131 | 132 | public boolean compareAndSet(int expect, int update) { 133 | return count.compareAndSet(expect, update); 134 | } 135 | 136 | public int remove() { 137 | return count.decrementAndGet(); 138 | } 139 | } 140 | ---- 141 | 142 | Then, in complete magic and with no map in the service class at all, we will get one `Count` per method 143 | 144 | [source,java] 145 | ---- 146 | import org.tomitribe.microscoped.method.MethodScopeEnabled; 147 | 148 | import javax.ejb.Lock; 149 | import javax.ejb.Singleton; 150 | import javax.inject.Inject; 151 | import javax.ws.rs.GET; 152 | import javax.ws.rs.Path; 153 | 154 | import static javax.ejb.LockType.READ; 155 | 156 | @Lock(READ) 157 | @Singleton 158 | @Path("/color") 159 | @MethodScopeEnabled 160 | public class ColorService { 161 | 162 | @Inject 163 | private Count count; 164 | 165 | @GET 166 | @Path("/red") 167 | public String red() { 168 | return String.format("red, %s invocations", count.add()); 169 | } 170 | 171 | @GET 172 | @Path("/green") 173 | public String green() { 174 | return String.format("green, %s invocations", count.add()); 175 | } 176 | 177 | @GET 178 | @Path("/blue") 179 | public String blue() { 180 | return String.format("blue, %s invocations", count.add()); 181 | } 182 | 183 | } 184 | ---- 185 | -------------------------------------------------------------------------------- /microscoped-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | 23 | org.tomitribe 24 | microscoped-parent 25 | 0.5-SNAPSHOT 26 | 27 | 28 | microscoped-core 29 | 30 | jar 31 | 32 | 33 | 34 | org.apache.openejb 35 | javaee-api 36 | ${openejb.javaee.api} 37 | provided 38 | 39 | 40 | org.apache.openejb 41 | arquillian-tomee-embedded 42 | ${tomee.version} 43 | test 44 | 45 | 46 | org.apache.openejb 47 | tomee-jaxrs 48 | ${tomee.version} 49 | test 50 | 51 | 52 | junit 53 | junit 54 | 4.12 55 | test 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /microscoped-core/src/main/java/org/tomitribe/microscoped/core/Scope.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.core; 18 | 19 | import javax.enterprise.context.spi.Contextual; 20 | import javax.enterprise.context.spi.CreationalContext; 21 | import java.util.Map; 22 | import java.util.concurrent.ConcurrentHashMap; 23 | 24 | class Scope { 25 | private final Instance NOTHING = new Instance<>(null, null, null); 26 | 27 | private final Map, Instance> instances = new ConcurrentHashMap<>(); 28 | 29 | private final Key key; 30 | 31 | public Scope(final Key key) { 32 | this.key = key; 33 | } 34 | 35 | public Key getKey() { 36 | return key; 37 | } 38 | 39 | /** 40 | * Returns an instance of the Bean (Contextual), creating it if necessary 41 | * @param contextual the Bean type to create 42 | * @param the Java type of the bean instance itself 43 | * @return existing or newly created bean instance, never null 44 | */ 45 | public T get(final Contextual contextual, final CreationalContext creationalContext) { 46 | return (T) instances.computeIfAbsent(contextual, c -> new Instance<>(contextual, creationalContext)).get(); 47 | } 48 | 49 | /** 50 | * Returns the existing instance of the Bean or null if none exists yet 51 | * @param contextual the Bean type to create 52 | * @param the Java type of the bean instance itself 53 | * @return existing the bean instance or null 54 | */ 55 | public T get(final Contextual contextual) { 56 | return (T) instances.getOrDefault(contextual, NOTHING).get(); 57 | } 58 | 59 | /** 60 | * Destroy all the instances in this scope 61 | */ 62 | public void destroy() { 63 | // TODO We really should ensure no more instances can be added during or after this 64 | instances.values().stream().forEach(Instance::destroy); 65 | instances.clear(); 66 | } 67 | 68 | private class Instance { 69 | private final T instance; 70 | private final CreationalContext creationalContext; 71 | private final Contextual contextual; 72 | 73 | public Instance(final Contextual contextual, final CreationalContext creationalContext) { 74 | 75 | this(contextual, creationalContext, contextual.create(creationalContext)); 76 | } 77 | 78 | public Instance(Contextual contextual, CreationalContext creationalContext, T instance) { 79 | this.instance = instance; 80 | this.creationalContext = creationalContext; 81 | this.contextual = contextual; 82 | } 83 | 84 | public T get() { 85 | return instance; 86 | } 87 | 88 | public void destroy() { 89 | contextual.destroy(instance, creationalContext); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /microscoped-core/src/main/java/org/tomitribe/microscoped/core/ScopeContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.core; 18 | 19 | import javax.enterprise.context.spi.Context; 20 | import javax.enterprise.context.spi.Contextual; 21 | import javax.enterprise.context.spi.CreationalContext; 22 | import java.lang.annotation.Annotation; 23 | import java.util.Map; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | import java.util.concurrent.atomic.AtomicReference; 26 | 27 | public class ScopeContext implements Context { 28 | 29 | private final Map scopes = new ConcurrentHashMap<>(); 30 | 31 | /** 32 | * The use of an AtomicReference inside the ThreadLocal is a clever way to be able to 33 | * do several operations against the "slot" for this thread without repeat lookups 34 | * to the ThreadLocal's underlying map. 35 | * 36 | * We use an AtomicReference for the "slot" simply because it has several convenience methods 37 | * for inplace editing such as getAndSet. 38 | * 39 | * Similar to if Map.Entry had a 'setValue(Object)' method 40 | */ 41 | private final ThreadLocal>> active = ThreadLocal.withInitial(this::inactive); 42 | 43 | private final Class scopeAnnotation; 44 | 45 | public ScopeContext(final Class scopeAnnotation) { 46 | this.scopeAnnotation = scopeAnnotation; 47 | } 48 | 49 | /** 50 | * Activate the new Scope and return the old scope for future reassociation 51 | * 52 | * If no scope instance existed associated with this key, a new scope will be lazily created 53 | * 54 | * @param key the key to serve as the "center of the world" of the scope 55 | * @return returns the previous "center of the world" so it can be reassociated when this scope exits 56 | */ 57 | public Key enter(Key key) { 58 | final Scope scope = scopes.computeIfAbsent(key, k -> new Scope(key)); 59 | return scope().getAndSet(scope).getKey(); 60 | } 61 | 62 | /** 63 | * Exits the current scope and connects the thread with the previously associated scope 64 | * 65 | * @param previous the key of the previously active scope or null 66 | */ 67 | public void exit(Key previous) { 68 | final AtomicReference> reference = scope(); 69 | 70 | if (previous == null) { 71 | 72 | reference.set(inactiveScope); 73 | 74 | } else { 75 | 76 | // Can possibly be null of Scope was destroyed 77 | final Scope scope = scopes.get(previous); 78 | reference.set(scope); 79 | } 80 | } 81 | 82 | /** 83 | * Destroys the scope and all instance in that scope 84 | * 85 | * @param key the key of the scope 86 | */ 87 | public void destroy(Key key) { 88 | scopes.computeIfPresent(key, (k, scope) -> { 89 | scope.destroy(); 90 | return null; 91 | }); 92 | } 93 | 94 | public void destroyAll() { 95 | scopes.values().stream().forEach(Scope::destroy); 96 | scopes.clear(); 97 | } 98 | 99 | @Override 100 | public T get(Contextual contextual, CreationalContext creationalContext) { 101 | return scope().get().get(contextual, creationalContext); 102 | } 103 | 104 | @Override 105 | public T get(Contextual contextual) { 106 | return scope().get().get(contextual); 107 | } 108 | 109 | private AtomicReference> scope() { 110 | return active.get(); 111 | } 112 | 113 | @Override 114 | public boolean isActive() { 115 | return scope() != null; 116 | } 117 | 118 | @Override 119 | public Class getScope() { 120 | return scopeAnnotation; 121 | } 122 | 123 | public Key getKey() { 124 | Key key; 125 | if(scope() != null && scope().get() != null) { 126 | key = scope().get().getKey(); 127 | } else { 128 | key = null; 129 | } 130 | return key; 131 | } 132 | 133 | private final Scope inactiveScope = new Scope(null) { 134 | @Override 135 | public T get(Contextual contextual, CreationalContext creationalContext) { 136 | throw new IllegalStateException("Scope Not Active"); 137 | } 138 | 139 | @Override 140 | public T get(Contextual contextual) { 141 | throw new IllegalStateException("Scope Not Active"); 142 | } 143 | 144 | @Override 145 | public void destroy() { 146 | throw new IllegalStateException("Scope Not Active"); 147 | } 148 | }; 149 | 150 | private AtomicReference> inactive() { 151 | return new AtomicReference<>(inactiveScope); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /microscoped-core/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomitribe/microscoped/6e565afc8b7f42b163359e4398e4f2c61158eab7/microscoped-core/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /microscoped-core/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | -1 22 | -1 23 | -1 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /microscoped-domain/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | 23 | org.tomitribe 24 | microscoped-parent 25 | 0.5-SNAPSHOT 26 | 27 | 28 | microscoped-domain 29 | 30 | jar 31 | 32 | 33 | 34 | org.tomitribe 35 | microscoped-core 36 | 0.5-SNAPSHOT 37 | 38 | 39 | org.apache.openejb 40 | javaee-api 41 | ${openejb.javaee.api} 42 | provided 43 | 44 | 45 | org.apache.openejb 46 | arquillian-tomee-embedded 47 | ${tomee.version} 48 | test 49 | 50 | 51 | org.apache.openejb 52 | tomee-jaxrs 53 | ${tomee.version} 54 | test 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /microscoped-domain/src/main/java/org/tomitribe/microscoped/domain/Domain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.domain; 18 | 19 | import javax.enterprise.context.RequestScoped; 20 | 21 | @RequestScoped 22 | public class Domain { 23 | 24 | private String name; 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /microscoped-domain/src/main/java/org/tomitribe/microscoped/domain/DomainScoped.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.domain; 18 | 19 | import javax.enterprise.context.NormalScope; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @Documented 28 | @NormalScope(passivating = false) 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 32 | public @interface DomainScoped { 33 | } -------------------------------------------------------------------------------- /microscoped-domain/src/main/java/org/tomitribe/microscoped/domain/DomainScopedExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.domain; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.event.Observes; 22 | import javax.enterprise.inject.spi.AfterBeanDiscovery; 23 | import javax.enterprise.inject.spi.BeforeBeanDiscovery; 24 | import javax.enterprise.inject.spi.Extension; 25 | 26 | 27 | public class DomainScopedExtension implements Extension { 28 | 29 | public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { 30 | 31 | bbd.addScope(DomainScoped.class, true, false); 32 | } 33 | 34 | public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { 35 | 36 | abd.addContext(new ScopeContext<>(DomainScoped.class)); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /microscoped-domain/src/main/java/org/tomitribe/microscoped/domain/DomainScopedFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.domain; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.context.spi.CreationalContext; 22 | import javax.enterprise.inject.spi.Bean; 23 | import javax.enterprise.inject.spi.BeanManager; 24 | import javax.inject.Inject; 25 | import javax.servlet.FilterChain; 26 | import javax.servlet.FilterConfig; 27 | import javax.servlet.ServletException; 28 | import javax.servlet.ServletRequest; 29 | import javax.servlet.ServletResponse; 30 | import javax.servlet.annotation.WebFilter; 31 | import java.io.IOException; 32 | import java.lang.annotation.Annotation; 33 | import java.util.Arrays; 34 | import java.util.Set; 35 | 36 | @WebFilter(urlPatterns = "/*") 37 | public class DomainScopedFilter implements javax.servlet.Filter { 38 | 39 | @Inject 40 | private BeanManager beanManager; 41 | 42 | @Override 43 | public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { 44 | 45 | final String domain = servletRequest.getServerName(); 46 | 47 | final ScopeContext context = (ScopeContext) beanManager.getContext(DomainScoped.class); 48 | 49 | getContextualReference(Domain.class, beanManager).setName(domain); 50 | 51 | // There won't be a "previous" domain, but doesn't hurt anything to be complete 52 | final String previous = context.enter(domain); 53 | try { 54 | filterChain.doFilter(servletRequest, servletResponse); 55 | } finally { 56 | context.exit(previous); 57 | } 58 | } 59 | 60 | @Override 61 | public void init(FilterConfig filterConfig) throws ServletException { 62 | } 63 | 64 | @Override 65 | public void destroy() { 66 | } 67 | 68 | public static T getContextualReference(Class type, final BeanManager beanManager, Annotation... qualifiers) { 69 | 70 | final Set> beans = beanManager.getBeans(type, qualifiers); 71 | 72 | if (beans == null || beans.isEmpty()) { 73 | throw new IllegalStateException("Could not find beans for Type=" + type 74 | + " and qualifiers:" + Arrays.toString(qualifiers)); 75 | } 76 | 77 | final Bean bean = beanManager.resolve(beans); 78 | 79 | final CreationalContext creationalContext = beanManager.createCreationalContext(bean); 80 | 81 | return (T) beanManager.getReference(bean, type, creationalContext); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /microscoped-domain/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomitribe/microscoped/6e565afc8b7f42b163359e4398e4f2c61158eab7/microscoped-domain/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /microscoped-domain/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension: -------------------------------------------------------------------------------- 1 | org.tomitribe.microscoped.domain.DomainScopedExtension -------------------------------------------------------------------------------- /microscoped-domain/src/test/java/org/supertribe/domain/Count.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.domain; 18 | 19 | import org.tomitribe.microscoped.domain.DomainScoped; 20 | 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | 23 | @DomainScoped 24 | public class Count { 25 | 26 | private final AtomicInteger count = new AtomicInteger(); 27 | 28 | public int get() { 29 | return count.get(); 30 | } 31 | 32 | public int add() { 33 | return count.incrementAndGet(); 34 | } 35 | 36 | public boolean compareAndSet(int expect, int update) { 37 | return count.compareAndSet(expect, update); 38 | } 39 | 40 | public int remove() { 41 | return count.decrementAndGet(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-domain/src/test/java/org/supertribe/domain/DomainScopedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.domain; 18 | 19 | import org.apache.cxf.jaxrs.client.WebClient; 20 | import org.jboss.arquillian.container.test.api.Deployment; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.ShrinkWrap; 24 | import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset; 25 | import org.jboss.shrinkwrap.api.asset.StringAsset; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | import org.junit.Assert; 28 | import org.junit.Ignore; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.tomitribe.microscoped.core.ScopeContext; 32 | import org.tomitribe.microscoped.domain.DomainScopedExtension; 33 | 34 | import javax.enterprise.inject.spi.Extension; 35 | import java.net.URI; 36 | import java.net.URISyntaxException; 37 | import java.net.URL; 38 | 39 | /** 40 | * 41 | * This test requires some DNS hacking. 42 | * Edit your /etc/hosts to contain the following entries: 43 | * 44 | *
 45 |  * $ cat /etc/hosts | egrep 'orange|red'
 46 |  * 127.0.0.1	orange
 47 |  * 127.0.0.1	red
 48 |  * 
49 | * 50 | * Then comment out the @Ignore 51 | */ 52 | @RunWith(Arquillian.class) 53 | public class DomainScopedTest extends Assert { 54 | 55 | @Deployment 56 | public static WebArchive createDeployment() { 57 | 58 | return ShrinkWrap.create(WebArchive.class) 59 | .addPackage(ScopeContext.class.getPackage()) 60 | .addPackage(DomainScopedExtension.class.getPackage()) 61 | .addPackage(SimpleService.class.getPackage()) 62 | .addAsWebInfResource(new ClassLoaderAsset("META-INF/beans.xml"), "classes/META-INF/beans.xml") 63 | .addAsWebInfResource(new StringAsset(DomainScopedExtension.class.getName()), 64 | "classes/META-INF/services/" + Extension.class.getName() 65 | ); 66 | } 67 | 68 | @ArquillianResource 69 | private URL webappUrl; 70 | 71 | @Test 72 | @Ignore("Comment this out to run the test") 73 | public void test() throws Exception { 74 | assertDomain("http://orange/", 1); 75 | assertDomain("http://orange/", 2); 76 | assertDomain("http://red/", 1); 77 | assertDomain("http://red/", 2); 78 | assertDomain("http://red/", 3); 79 | assertDomain("http://orange/", 3); 80 | assertDomain("http://orange/", 4); 81 | assertDomain("http://red/", 4); 82 | } 83 | 84 | private void assertDomain(String orange, int i) throws URISyntaxException { 85 | final URI uri = setDomain(orange, webappUrl.toURI()); 86 | final WebClient webClient = WebClient.create(uri); 87 | 88 | final String result = webClient.path("domain").get(String.class); 89 | assertEquals(orange + " domain, " + i + " invocations", result); 90 | } 91 | 92 | private static URI setDomain(String domain, URI uri) throws URISyntaxException { 93 | final URI target = URI.create(domain); 94 | return new URI( 95 | uri.getScheme(), 96 | uri.getUserInfo(), 97 | target.getHost(), 98 | uri.getPort(), 99 | uri.getPath(), 100 | uri.getQuery(), 101 | uri.getFragment()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /microscoped-domain/src/test/java/org/supertribe/domain/SimpleService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.domain; 18 | 19 | import org.tomitribe.microscoped.domain.Domain; 20 | 21 | import javax.ejb.Lock; 22 | import javax.ejb.Singleton; 23 | import javax.inject.Inject; 24 | import javax.ws.rs.GET; 25 | import javax.ws.rs.Path; 26 | 27 | import static javax.ejb.LockType.READ; 28 | 29 | @Lock(READ) 30 | @Singleton 31 | @Path("/domain") 32 | public class SimpleService { 33 | 34 | @Inject 35 | private Count count; 36 | 37 | @Inject 38 | private Domain domain; 39 | 40 | @GET 41 | public String get() { 42 | final int add = count.add(); 43 | return String.format("%s domain, %s invocations", domain.getName(), add); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /microscoped-domain/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | -1 22 | -1 23 | -1 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /microscoped-header/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | 23 | org.tomitribe 24 | microscoped-parent 25 | 0.5-SNAPSHOT 26 | 27 | 28 | microscoped-header 29 | 30 | jar 31 | 32 | 33 | 34 | org.tomitribe 35 | microscoped-core 36 | 0.5-SNAPSHOT 37 | 38 | 39 | org.apache.openejb 40 | javaee-api 41 | ${openejb.javaee.api} 42 | provided 43 | 44 | 45 | org.apache.openejb 46 | arquillian-tomee-embedded 47 | ${tomee.version} 48 | test 49 | 50 | 51 | org.apache.openejb 52 | tomee-jaxrs 53 | ${tomee.version} 54 | test 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/Beans.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import javax.enterprise.context.spi.CreationalContext; 20 | import javax.enterprise.inject.spi.Bean; 21 | import javax.enterprise.inject.spi.BeanManager; 22 | import java.lang.annotation.Annotation; 23 | import java.util.Arrays; 24 | import java.util.Set; 25 | 26 | public class Beans { 27 | 28 | private Beans() { 29 | } 30 | 31 | public static T getContextualReference(Class type, final BeanManager beanManager, Annotation... qualifiers) { 32 | 33 | final Set> beans = beanManager.getBeans(type, qualifiers); 34 | 35 | if (beans == null || beans.isEmpty()) { 36 | throw new IllegalStateException("Could not find beans for Type=" + type 37 | + " and qualifiers:" + Arrays.toString(qualifiers)); 38 | } 39 | 40 | final Bean bean = beanManager.resolve(beans); 41 | 42 | final CreationalContext creationalContext = beanManager.createCreationalContext(bean); 43 | 44 | return (T) beanManager.getReference(bean, type, creationalContext); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/Header.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import javax.enterprise.context.RequestScoped; 20 | 21 | @RequestScoped 22 | public class Header { 23 | 24 | private String name; 25 | private String value; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public String getValue() { 36 | return value; 37 | } 38 | 39 | public void setValue(String value) { 40 | this.value = value; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/HeaderScoped.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import javax.enterprise.context.NormalScope; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @Documented 28 | @NormalScope(passivating = false) 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 32 | public @interface HeaderScoped { 33 | } -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/HeaderScopedConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import javax.enterprise.context.ApplicationScoped; 20 | 21 | @ApplicationScoped 22 | public class HeaderScopedConfig { 23 | 24 | private String headerName; 25 | private String defaultValue = "unspecified"; 26 | 27 | public String getHeaderName() { 28 | return headerName; 29 | } 30 | 31 | public void setHeaderName(String headerName) { 32 | this.headerName = headerName; 33 | } 34 | 35 | public String getDefaultValue() { 36 | return defaultValue; 37 | } 38 | 39 | public void setDefaultValue(String defaultValue) { 40 | this.defaultValue = defaultValue; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/HeaderScopedExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.event.Observes; 22 | import javax.enterprise.inject.spi.AfterBeanDiscovery; 23 | import javax.enterprise.inject.spi.BeforeBeanDiscovery; 24 | import javax.enterprise.inject.spi.Extension; 25 | 26 | 27 | public class HeaderScopedExtension implements Extension { 28 | 29 | public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { 30 | 31 | bbd.addScope(HeaderScoped.class, true, false); 32 | } 33 | 34 | public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { 35 | 36 | abd.addContext(new ScopeContext<>(HeaderScoped.class)); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /microscoped-header/src/main/java/org/tomitribe/microscoped/header/HeaderScopedFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.header; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.inject.spi.BeanManager; 22 | import javax.inject.Inject; 23 | import javax.servlet.FilterChain; 24 | import javax.servlet.FilterConfig; 25 | import javax.servlet.ServletException; 26 | import javax.servlet.ServletRequest; 27 | import javax.servlet.ServletResponse; 28 | import javax.servlet.annotation.WebFilter; 29 | import javax.servlet.http.HttpServletRequest; 30 | import java.io.IOException; 31 | 32 | @WebFilter(urlPatterns = "/*") 33 | public class HeaderScopedFilter implements javax.servlet.Filter { 34 | 35 | @Inject 36 | private BeanManager beanManager; 37 | 38 | @Inject 39 | private HeaderScopedConfig config; 40 | 41 | @Inject 42 | private Header header; 43 | 44 | @Override 45 | public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { 46 | 47 | final String value = getKey((HttpServletRequest) servletRequest); 48 | 49 | final ScopeContext context = (ScopeContext) beanManager.getContext(HeaderScoped.class); 50 | 51 | // set the name and value in the thread for others to see 52 | header.setName(config.getHeaderName()); 53 | header.setValue(value); 54 | 55 | // There won't be a "previous", but doesn't hurt anything to be complete 56 | final String previous = context.enter(value); 57 | try { 58 | filterChain.doFilter(servletRequest, servletResponse); 59 | } finally { 60 | context.exit(previous); 61 | } 62 | } 63 | 64 | private String getKey(final HttpServletRequest request) { 65 | final String header = request.getHeader(config.getHeaderName()); 66 | 67 | if (header != null) { 68 | return header; 69 | } else { 70 | return config.getDefaultValue(); 71 | } 72 | } 73 | 74 | @Override 75 | public void init(FilterConfig filterConfig) throws ServletException { 76 | } 77 | 78 | @Override 79 | public void destroy() { 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /microscoped-header/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomitribe/microscoped/6e565afc8b7f42b163359e4398e4f2c61158eab7/microscoped-header/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /microscoped-header/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension: -------------------------------------------------------------------------------- 1 | org.tomitribe.microscoped.header.HeaderScopedExtension -------------------------------------------------------------------------------- /microscoped-header/src/test/java/org/supertribe/header/Count.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.header; 18 | 19 | import org.tomitribe.microscoped.header.HeaderScoped; 20 | 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | 23 | @HeaderScoped 24 | public class Count { 25 | 26 | private final AtomicInteger count = new AtomicInteger(); 27 | 28 | public int get() { 29 | return count.get(); 30 | } 31 | 32 | public int add() { 33 | return count.incrementAndGet(); 34 | } 35 | 36 | public boolean compareAndSet(int expect, int update) { 37 | return count.compareAndSet(expect, update); 38 | } 39 | 40 | public int remove() { 41 | return count.decrementAndGet(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-header/src/test/java/org/supertribe/header/HeaderScopedConfigExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.header; 18 | 19 | import org.tomitribe.microscoped.header.Beans; 20 | import org.tomitribe.microscoped.header.HeaderScopedConfig; 21 | 22 | import javax.enterprise.event.Observes; 23 | import javax.enterprise.inject.spi.AfterDeploymentValidation; 24 | import javax.enterprise.inject.spi.BeanManager; 25 | import javax.enterprise.inject.spi.Extension; 26 | 27 | public class HeaderScopedConfigExtension implements Extension { 28 | 29 | public void buildViewConfig(@Observes AfterDeploymentValidation adv, BeanManager beanManager) { 30 | final HeaderScopedConfig config = Beans.getContextualReference(HeaderScopedConfig.class, beanManager); 31 | config.setHeaderName("version"); 32 | config.setDefaultValue("1"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /microscoped-header/src/test/java/org/supertribe/header/HeaderScopedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.header; 18 | 19 | import org.apache.cxf.jaxrs.client.WebClient; 20 | import org.jboss.arquillian.container.test.api.Deployment; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.ShrinkWrap; 24 | import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset; 25 | import org.jboss.shrinkwrap.api.asset.StringAsset; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | import org.junit.Assert; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.tomitribe.microscoped.core.ScopeContext; 31 | import org.tomitribe.microscoped.header.HeaderScopedExtension; 32 | 33 | import javax.enterprise.inject.spi.Extension; 34 | import java.net.URI; 35 | import java.net.URISyntaxException; 36 | import java.net.URL; 37 | 38 | @RunWith(Arquillian.class) 39 | public class HeaderScopedTest extends Assert { 40 | 41 | @Deployment 42 | public static WebArchive createDeployment() { 43 | 44 | return ShrinkWrap.create(WebArchive.class) 45 | .addPackage(ScopeContext.class.getPackage()) 46 | .addPackage(HeaderScopedExtension.class.getPackage()) 47 | .addPackage(SimpleService.class.getPackage()) 48 | .addAsWebInfResource(new ClassLoaderAsset("META-INF/beans.xml"), "classes/META-INF/beans.xml") 49 | .addAsWebInfResource(new StringAsset(HeaderScopedExtension.class.getName()), 50 | "classes/META-INF/services/" + Extension.class.getName() 51 | ) 52 | .addAsWebInfResource(new StringAsset(HeaderScopedConfigExtension.class.getName()), 53 | "classes/META-INF/services/" + Extension.class.getName() 54 | ) 55 | ; 56 | } 57 | 58 | @ArquillianResource 59 | private URL webappUrl; 60 | 61 | @Test 62 | public void test() throws Exception { 63 | assertHeader("1.0", 1); 64 | assertHeader("1.0", 2); 65 | 66 | assertHeader("1.1", 1); 67 | assertHeader("1.1", 2); 68 | assertHeader("1.1", 3); 69 | 70 | assertHeader("1.0", 3); 71 | assertHeader("1.0", 4); 72 | 73 | assertHeader("1.1", 4); 74 | } 75 | 76 | private void assertHeader(String version, int i) throws URISyntaxException { 77 | final URI uri = webappUrl.toURI(); 78 | 79 | final String result = WebClient.create(uri) 80 | .header("version", version) 81 | .path("domain") 82 | .get(String.class); 83 | 84 | final String expected = String.format("version=%s , %s invocations", version, i); 85 | 86 | assertEquals(expected, result); 87 | } 88 | 89 | private static URI setDomain(String domain, URI uri) throws URISyntaxException { 90 | return new URI(uri.getScheme(), uri.getUserInfo(), domain, uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /microscoped-header/src/test/java/org/supertribe/header/SimpleService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.header; 18 | 19 | import org.tomitribe.microscoped.header.Header; 20 | 21 | import javax.ejb.Lock; 22 | import javax.ejb.Singleton; 23 | import javax.inject.Inject; 24 | import javax.ws.rs.GET; 25 | import javax.ws.rs.Path; 26 | 27 | import static javax.ejb.LockType.READ; 28 | 29 | @Lock(READ) 30 | @Singleton 31 | @Path("/domain") 32 | public class SimpleService { 33 | 34 | @Inject 35 | private Count count; 36 | 37 | @Inject 38 | private Header header; 39 | 40 | @GET 41 | public String get() { 42 | 43 | return String.format("%s=%s , %s invocations", header.getName(), header.getValue(), count.add()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /microscoped-header/src/test/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomitribe/microscoped/6e565afc8b7f42b163359e4398e4f2c61158eab7/microscoped-header/src/test/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /microscoped-header/src/test/resources/META-INF/services/javax.enterprise.inject.spi.Extension: -------------------------------------------------------------------------------- 1 | org.supertribe.header.HeaderScopedConfigExtension -------------------------------------------------------------------------------- /microscoped-header/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | -1 22 | -1 23 | -1 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /microscoped-method/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | 23 | org.tomitribe 24 | microscoped-parent 25 | 0.5-SNAPSHOT 26 | 27 | 28 | microscoped-method 29 | 30 | jar 31 | 32 | 33 | 34 | org.tomitribe 35 | microscoped-core 36 | 0.5-SNAPSHOT 37 | 38 | 39 | org.apache.openejb 40 | javaee-api 41 | ${openejb.javaee.api} 42 | provided 43 | 44 | 45 | org.apache.openejb 46 | arquillian-tomee-embedded 47 | ${tomee.version} 48 | test 49 | 50 | 51 | org.apache.openejb 52 | tomee-jaxrs 53 | ${tomee.version} 54 | test 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /microscoped-method/src/main/java/org/tomitribe/microscoped/method/MethodScopeEnabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.method; 18 | 19 | import javax.interceptor.InterceptorBinding; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @InterceptorBinding 28 | @Documented 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD}) 32 | public @interface MethodScopeEnabled { 33 | } 34 | -------------------------------------------------------------------------------- /microscoped-method/src/main/java/org/tomitribe/microscoped/method/MethodScoped.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.method; 18 | 19 | import javax.enterprise.context.NormalScope; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @Documented 28 | @NormalScope(passivating = false) 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 32 | public @interface MethodScoped { 33 | } -------------------------------------------------------------------------------- /microscoped-method/src/main/java/org/tomitribe/microscoped/method/MethodScopedExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.method; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.event.Observes; 22 | import javax.enterprise.inject.spi.AfterBeanDiscovery; 23 | import javax.enterprise.inject.spi.BeforeBeanDiscovery; 24 | import javax.enterprise.inject.spi.Extension; 25 | 26 | 27 | public class MethodScopedExtension implements Extension { 28 | 29 | public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { 30 | bbd.addScope(MethodScoped.class, true, false); 31 | bbd.addInterceptorBinding(MethodScopeEnabled.class); 32 | } 33 | 34 | public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { 35 | 36 | abd.addContext(new ScopeContext<>(MethodScoped.class)); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /microscoped-method/src/main/java/org/tomitribe/microscoped/method/MethodScopedInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.method; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.inject.spi.BeanManager; 22 | import javax.inject.Inject; 23 | import javax.interceptor.AroundInvoke; 24 | import javax.interceptor.Interceptor; 25 | import javax.interceptor.InvocationContext; 26 | import java.lang.reflect.Method; 27 | 28 | @Interceptor 29 | @MethodScopeEnabled 30 | public class MethodScopedInterceptor { 31 | 32 | @Inject 33 | private BeanManager beanManager; 34 | 35 | @AroundInvoke 36 | public Object invoke(InvocationContext invocation) throws Exception { 37 | final ScopeContext context = (ScopeContext) beanManager.getContext(MethodScoped.class); 38 | 39 | final Method previous = context.enter(invocation.getMethod()); 40 | try { 41 | return invocation.proceed(); 42 | } finally { 43 | context.exit(previous); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /microscoped-method/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.tomitribe.microscoped.method.MethodScopedInterceptor 4 | 5 | -------------------------------------------------------------------------------- /microscoped-method/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension: -------------------------------------------------------------------------------- 1 | org.tomitribe.microscoped.method.MethodScopedExtension -------------------------------------------------------------------------------- /microscoped-method/src/test/java/org/supertribe/ColorService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe; 18 | 19 | import org.tomitribe.microscoped.method.MethodScopeEnabled; 20 | 21 | import javax.ejb.Lock; 22 | import javax.ejb.Singleton; 23 | import javax.inject.Inject; 24 | import javax.ws.rs.GET; 25 | import javax.ws.rs.Path; 26 | 27 | import static javax.ejb.LockType.READ; 28 | 29 | @Lock(READ) 30 | @Singleton 31 | @Path("/color") 32 | @MethodScopeEnabled 33 | public class ColorService { 34 | 35 | @Inject 36 | private Count count; 37 | 38 | @GET 39 | @Path("/red") 40 | public String red() { 41 | return String.format("red, %s invocations", count.add()); 42 | } 43 | 44 | @GET 45 | @Path("/green") 46 | public String green() { 47 | return String.format("green, %s invocations", count.add()); 48 | } 49 | 50 | @GET 51 | @Path("/blue") 52 | public String blue() { 53 | return String.format("blue, %s invocations", count.add()); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /microscoped-method/src/test/java/org/supertribe/Count.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe; 18 | 19 | import org.tomitribe.microscoped.method.MethodScoped; 20 | 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | 23 | @MethodScoped 24 | public class Count { 25 | 26 | private final AtomicInteger count = new AtomicInteger(); 27 | 28 | public int get() { 29 | return count.get(); 30 | } 31 | 32 | public int add() { 33 | return count.incrementAndGet(); 34 | } 35 | 36 | public boolean compareAndSet(int expect, int update) { 37 | return count.compareAndSet(expect, update); 38 | } 39 | 40 | public int remove() { 41 | return count.decrementAndGet(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-method/src/test/java/org/supertribe/MethodScopedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe; 18 | 19 | import org.apache.cxf.jaxrs.client.WebClient; 20 | import org.jboss.arquillian.container.test.api.Deployment; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.ShrinkWrap; 24 | import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset; 25 | import org.jboss.shrinkwrap.api.asset.StringAsset; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | import org.junit.Assert; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.tomitribe.microscoped.core.ScopeContext; 31 | import org.tomitribe.microscoped.method.MethodScopedExtension; 32 | 33 | import javax.enterprise.inject.spi.Extension; 34 | import java.net.URISyntaxException; 35 | import java.net.URL; 36 | 37 | @RunWith(Arquillian.class) 38 | public class MethodScopedTest extends Assert { 39 | 40 | @Deployment 41 | public static WebArchive createDeployment() { 42 | 43 | return ShrinkWrap.create(WebArchive.class) 44 | .addPackage(ScopeContext.class.getPackage()) 45 | .addPackage(MethodScopedExtension.class.getPackage()) 46 | .addPackage(ColorService.class.getPackage()) 47 | .addAsWebInfResource(new ClassLoaderAsset("META-INF/beans.xml"), "classes/META-INF/beans.xml") 48 | .addAsWebInfResource(new StringAsset(MethodScopedExtension.class.getName()), 49 | "classes/META-INF/services/" + Extension.class.getName() 50 | ); 51 | } 52 | 53 | @ArquillianResource 54 | private URL webappUrl; 55 | 56 | @Test 57 | public void test() throws Exception { 58 | 59 | assertRequest("color/red", "red, 1 invocations"); 60 | assertRequest("color/red", "red, 2 invocations"); 61 | assertRequest("color/red", "red, 3 invocations"); 62 | assertRequest("color/green", "green, 1 invocations"); 63 | assertRequest("color/green", "green, 2 invocations"); 64 | assertRequest("color/green", "green, 3 invocations"); 65 | assertRequest("color/red", "red, 4 invocations"); 66 | assertRequest("color/blue", "blue, 1 invocations"); 67 | assertRequest("color/blue", "blue, 2 invocations"); 68 | 69 | } 70 | 71 | private void assertRequest(String path, String expected) throws URISyntaxException { 72 | final WebClient webClient = WebClient.create(webappUrl.toURI()); 73 | final String s = webClient.path(path).get(String.class); 74 | assertEquals(expected, s); 75 | } 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /microscoped-method/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | -1 22 | -1 23 | -1 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /microscoped-timer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 4.0.0 20 | 21 | 22 | 23 | org.tomitribe 24 | microscoped-parent 25 | 0.5-SNAPSHOT 26 | 27 | 28 | microscoped-timer 29 | 30 | jar 31 | 32 | 33 | 34 | org.tomitribe 35 | microscoped-core 36 | 0.5-SNAPSHOT 37 | 38 | 39 | org.apache.openejb 40 | javaee-api 41 | ${openejb.javaee.api} 42 | provided 43 | 44 | 45 | org.apache.openejb 46 | arquillian-tomee-embedded 47 | ${tomee.version} 48 | test 49 | 50 | 51 | org.apache.openejb 52 | tomee-jaxrs 53 | ${tomee.version} 54 | test 55 | 56 | 57 | junit 58 | junit 59 | 4.12 60 | test 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /microscoped-timer/src/main/java/org/tomitribe/microscoped/timer/TimerScopeEnabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.timer; 18 | 19 | import javax.interceptor.InterceptorBinding; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @InterceptorBinding 28 | @Documented 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD}) 32 | public @interface TimerScopeEnabled { 33 | } 34 | -------------------------------------------------------------------------------- /microscoped-timer/src/main/java/org/tomitribe/microscoped/timer/TimerScoped.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.timer; 18 | 19 | import javax.enterprise.context.NormalScope; 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Inherited; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | 27 | @Documented 28 | @NormalScope(passivating = false) 29 | @Inherited 30 | @Retention(RetentionPolicy.RUNTIME) 31 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 32 | public @interface TimerScoped { 33 | } -------------------------------------------------------------------------------- /microscoped-timer/src/main/java/org/tomitribe/microscoped/timer/TimerScopedExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.timer; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.enterprise.event.Observes; 22 | import javax.enterprise.inject.spi.AfterBeanDiscovery; 23 | import javax.enterprise.inject.spi.BeforeBeanDiscovery; 24 | import javax.enterprise.inject.spi.Extension; 25 | 26 | 27 | public class TimerScopedExtension implements Extension { 28 | 29 | public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { 30 | bbd.addScope(TimerScoped.class, true, false); 31 | bbd.addInterceptorBinding(TimerScopeEnabled.class); 32 | } 33 | 34 | public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd) { 35 | 36 | abd.addContext(new ScopeContext<>(TimerScoped.class)); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /microscoped-timer/src/main/java/org/tomitribe/microscoped/timer/TimerScopedInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.tomitribe.microscoped.timer; 18 | 19 | import org.tomitribe.microscoped.core.ScopeContext; 20 | 21 | import javax.ejb.ScheduleExpression; 22 | import javax.ejb.Timer; 23 | import javax.enterprise.inject.spi.BeanManager; 24 | import javax.inject.Inject; 25 | import javax.interceptor.AroundTimeout; 26 | import javax.interceptor.Interceptor; 27 | import javax.interceptor.InvocationContext; 28 | import java.io.Serializable; 29 | 30 | @Interceptor 31 | @TimerScopeEnabled 32 | public class TimerScopedInterceptor { 33 | 34 | @Inject 35 | private BeanManager beanManager; 36 | 37 | @AroundTimeout 38 | public Object invoke(final InvocationContext invocation) throws Exception { 39 | final ScopeContext context = (ScopeContext) beanManager.getContext(TimerScoped.class); 40 | 41 | final String key = getKey(invocation); 42 | final String previous = context.enter(key); 43 | try { 44 | return invocation.proceed(); 45 | } finally { 46 | context.exit(previous); 47 | } 48 | } 49 | 50 | private String getKey(InvocationContext invocation) { 51 | final String method = invocation.getMethod().toString(); 52 | 53 | final Object object = invocation.getTimer(); 54 | if (!(object instanceof Timer)) { 55 | return method; 56 | } 57 | 58 | final Timer timer = (Timer) object; 59 | final Serializable info = timer.getInfo(); 60 | if (info == null || info instanceof ScheduleExpression) { 61 | return method; 62 | } else { 63 | return info.toString(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /microscoped-timer/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.tomitribe.microscoped.timer.TimerScopedInterceptor 4 | 5 | -------------------------------------------------------------------------------- /microscoped-timer/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension: -------------------------------------------------------------------------------- 1 | org.tomitribe.microscoped.timer.TimerScopedExtension -------------------------------------------------------------------------------- /microscoped-timer/src/test/java/org/supertribe/timer/ColorService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.timer; 18 | 19 | import org.tomitribe.microscoped.timer.TimerScopedInterceptor; 20 | 21 | import javax.annotation.PostConstruct; 22 | import javax.annotation.Resource; 23 | import javax.ejb.Lock; 24 | import javax.ejb.Schedule; 25 | import javax.ejb.ScheduleExpression; 26 | import javax.ejb.Singleton; 27 | import javax.ejb.Timeout; 28 | import javax.ejb.Timer; 29 | import javax.ejb.TimerConfig; 30 | import javax.ejb.TimerService; 31 | import javax.inject.Inject; 32 | import javax.interceptor.Interceptors; 33 | import javax.ws.rs.GET; 34 | import javax.ws.rs.Path; 35 | 36 | import static javax.ejb.LockType.READ; 37 | 38 | @Lock(READ) 39 | @Singleton 40 | @Path("/color") 41 | //@TimerScopeEnabled 42 | @Interceptors(TimerScopedInterceptor.class) 43 | public class ColorService { 44 | 45 | @Inject 46 | private Count count; 47 | 48 | @Resource 49 | private TimerService timerService; 50 | 51 | private final Log log = new Log(); 52 | 53 | @PostConstruct 54 | public void construct() { 55 | { 56 | final TimerConfig timerConfig = new TimerConfig("red", false); 57 | timerService.createCalendarTimer(new ScheduleExpression().second("*").minute("*").hour("*"), timerConfig); 58 | } 59 | { 60 | final TimerConfig timerConfig = new TimerConfig("green", false); 61 | timerService.createCalendarTimer(new ScheduleExpression().second("*").minute("*").hour("*"), timerConfig); 62 | } 63 | } 64 | 65 | @GET 66 | public Log getLog() { 67 | return log; 68 | } 69 | 70 | @Timeout 71 | public void timeout(Timer timer) { 72 | log.add(String.format("%s, %s", timer.getInfo(), count.add())); 73 | } 74 | 75 | @Schedule(second = "*", minute = "*", hour = "*") 76 | public void blue() { 77 | log.add(String.format("blue, %s", count.add())); 78 | } 79 | 80 | @Schedule(second = "*", minute = "*", hour = "*") 81 | public void orange() { 82 | log.add(String.format("orange, %s", count.add())); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /microscoped-timer/src/test/java/org/supertribe/timer/Count.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.timer; 18 | 19 | import org.tomitribe.microscoped.timer.TimerScoped; 20 | 21 | import java.util.concurrent.atomic.AtomicInteger; 22 | 23 | @TimerScoped 24 | public class Count { 25 | 26 | private final AtomicInteger count = new AtomicInteger(); 27 | 28 | public int get() { 29 | return count.get(); 30 | } 31 | 32 | public int add() { 33 | return count.incrementAndGet(); 34 | } 35 | 36 | public boolean compareAndSet(int expect, int update) { 37 | return count.compareAndSet(expect, update); 38 | } 39 | 40 | public int remove() { 41 | return count.decrementAndGet(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-timer/src/test/java/org/supertribe/timer/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.timer; 18 | 19 | import javax.enterprise.inject.Typed; 20 | import javax.xml.bind.annotation.XmlAccessType; 21 | import javax.xml.bind.annotation.XmlAccessorType; 22 | import javax.xml.bind.annotation.XmlRootElement; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | @Typed 27 | @XmlRootElement 28 | @XmlAccessorType(XmlAccessType.FIELD) 29 | public class Log { 30 | 31 | final List lines = new ArrayList(); 32 | 33 | public Log() { 34 | } 35 | 36 | public List getLines() { 37 | return lines; 38 | } 39 | 40 | public boolean add(String s) { 41 | return lines.add(s); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /microscoped-timer/src/test/java/org/supertribe/timer/TimerScopedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.supertribe.timer; 18 | 19 | import org.apache.cxf.jaxrs.client.WebClient; 20 | import org.jboss.arquillian.container.test.api.Deployment; 21 | import org.jboss.arquillian.junit.Arquillian; 22 | import org.jboss.arquillian.test.api.ArquillianResource; 23 | import org.jboss.shrinkwrap.api.ShrinkWrap; 24 | import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset; 25 | import org.jboss.shrinkwrap.api.asset.StringAsset; 26 | import org.jboss.shrinkwrap.api.spec.WebArchive; 27 | import org.junit.Assert; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.tomitribe.microscoped.core.ScopeContext; 31 | import org.tomitribe.microscoped.timer.TimerScopedExtension; 32 | 33 | import javax.enterprise.inject.spi.Extension; 34 | import javax.ws.rs.core.MediaType; 35 | import java.io.ByteArrayOutputStream; 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.net.URL; 39 | import java.util.Collection; 40 | import java.util.List; 41 | import java.util.concurrent.TimeUnit; 42 | 43 | /** 44 | * Arquillian will start the container, deploy all @Deployment bundles, then run all the @Test methods. 45 | * 46 | * A strong value-add for Arquillian is that the test is abstracted from the server. 47 | * It is possible to rerun the same test against multiple adapters or server configurations. 48 | * 49 | * A second value-add is it is possible to build WebArchives that are slim and trim and therefore 50 | * isolate the functionality being tested. This also makes it easier to swap out one implementation 51 | * of a class for another allowing for easy mocking. 52 | * 53 | */ 54 | @RunWith(Arquillian.class) 55 | public class TimerScopedTest extends Assert { 56 | 57 | /** 58 | * ShrinkWrap is used to create a war file on the fly. 59 | * 60 | * The API is quite expressive and can build any possible 61 | * flavor of war file. It can quite easily return a rebuilt 62 | * war file as well. 63 | * 64 | * More than one @Deployment method is allowed. 65 | */ 66 | @Deployment 67 | public static WebArchive createDeployment() { 68 | 69 | return ShrinkWrap.create(WebArchive.class) 70 | .addPackage(ScopeContext.class.getPackage()) 71 | .addPackage(TimerScopedExtension.class.getPackage()) 72 | .addPackage(ColorService.class.getPackage()) 73 | .addAsWebInfResource(new ClassLoaderAsset("META-INF/beans.xml"), "classes/META-INF/beans.xml") 74 | .addAsWebInfResource(new StringAsset(TimerScopedExtension.class.getName()), 75 | "classes/META-INF/services/" + Extension.class.getName() 76 | ); 77 | } 78 | 79 | /** 80 | * This URL will contain the following URL data 81 | * 82 | * - http://:// 83 | * 84 | * This allows the test itself to be agnostic of server information or even 85 | * the name of the webapp 86 | * 87 | */ 88 | @ArquillianResource 89 | private URL webappUrl; 90 | 91 | 92 | @Test 93 | public void test() throws Exception { 94 | 95 | Thread.sleep(TimeUnit.SECONDS.toMillis(7)); 96 | 97 | final WebClient webClient = WebClient.create(webappUrl.toURI()); 98 | webClient.accept(MediaType.APPLICATION_JSON); 99 | 100 | final List lines = webClient.path("color").get(Log.class).getLines(); 101 | 102 | assertTrue(lines.contains("red, 1")); 103 | assertTrue(lines.contains("red, 2")); 104 | assertTrue(lines.contains("red, 3")); 105 | assertTrue(lines.contains("red, 4")); 106 | assertTrue(lines.contains("green, 1")); 107 | assertTrue(lines.contains("green, 2")); 108 | assertTrue(lines.contains("green, 3")); 109 | assertTrue(lines.contains("green, 4")); 110 | assertTrue(lines.contains("blue, 1")); 111 | assertTrue(lines.contains("blue, 2")); 112 | assertTrue(lines.contains("blue, 3")); 113 | assertTrue(lines.contains("blue, 4")); 114 | assertTrue(lines.contains("orange, 1")); 115 | assertTrue(lines.contains("orange, 2")); 116 | assertTrue(lines.contains("orange, 3")); 117 | assertTrue(lines.contains("orange, 4")); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /microscoped-timer/src/test/resources/arquillian.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | -1 22 | -1 23 | -1 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 4.0.0 21 | 22 | 23 | org.tomitribe 24 | oss-parent 25 | 4 26 | 27 | 28 | microscoped-parent 29 | pom 30 | 0.5-SNAPSHOT 31 | Tomitribe :: Microscoped 32 | 33 | 34 | scm:git:git@github.com:tomitribe/microscoped.git 35 | scm:git:git@github.com:tomitribe/microscoped.git 36 | scm:git:git@github.com:tomitribe/microscoped.git 37 | HEAD 38 | 39 | 40 | 41 | microscoped-core 42 | microscoped-method 43 | microscoped-domain 44 | microscoped-header 45 | microscoped-timer 46 | 47 | 48 | 49 | UTF-8 50 | 1.7.2 51 | 6.0-6 52 | 53 | 54 | 55 | 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-compiler-plugin 60 | 3.2 61 | 62 | 1.8 63 | 1.8 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | snapshots 72 | http://repository.tomitribe.com/content/repositories/snapshots 73 | 74 | true 75 | 76 | 77 | 78 | Sonatype-public 79 | Sonatype snapshot and release 80 | https://oss.sonatype.org/content/groups/public/ 81 | 82 | true 83 | 84 | 85 | true 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | junit 94 | junit 95 | 4.11 96 | test 97 | 98 | 99 | 100 | org.tomitribe 101 | tomitribe-util 102 | 1.2.1 103 | 104 | 105 | 106 | 107 | 108 | 109 | --------------------------------------------------------------------------------