set = EnumSet.of(featured[0], featured);
52 | return bundleOrModule -> {
53 | F f = featured[0].featureOf(bundleOrModule);
54 | return f == null || set.contains(f);
55 | };
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/se.jbee.inject.api/main/java/se/jbee/inject/Extends.java:
--------------------------------------------------------------------------------
1 | package se.jbee.inject;
2 |
3 | import java.lang.annotation.Target;
4 | import java.lang.annotation.*;
5 | import java.util.ServiceLoader;
6 |
7 | import static java.lang.annotation.ElementType.TYPE;
8 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
9 |
10 | /**
11 | * {@link Annotation} used in connection with {@link ServiceLoader} mechanism to
12 | * annotate service classes to point out the role they implement in cases where
13 | * this is ambiguous for the service interface they implement.
14 | *
15 | * Usages
16 | *
17 | * Providing Annotation Templet via ServiceLoader
18 | *
19 | * Annotate a {@code se.jbee.inject.bind.ModuleWith} implementation that should
20 | * load via {@link ServiceLoader} to implement the effects of an type level
21 | * {@link Annotation} and have {@link Extends#value()} point to the
22 | * {@link Annotation} type that triggers the implementation
23 | * {@code se.jbee.inject.bind.ModuleWith}. If the provided {@link Class} is not
24 | * an {@link Annotation} type the module is ignored.
25 | *
26 | *
27 | * Providing Bundles via ServiceLoader
28 | *
29 | * Annotate a {@code se.jbee.inject.bind.Bundle} implementation that should load
30 | * via {@link ServiceLoader} have {@link Extends#value()} be {@link Env}
31 | * {@link Class} to add the bundle to those that should be loaded as part of the
32 | * {@link Env} instead of the {@link Injector} context. To add
33 | * {@code se.jbee.inject.bind.Bundle}s to the {@link Injector} context don't
34 | * annotate them with {@link Extends} or use {@link Injector} {@link Class} as
35 | * {@link Extends#value()}.
36 | *
37 | *
38 | * @since 8.1
39 | */
40 | @Inherited
41 | @Documented
42 | @Retention(RUNTIME)
43 | @Target(TYPE)
44 | public @interface Extends {
45 |
46 | /**
47 | * @return refers to a type in the context of the annotated extension. The
48 | * semantic depends on the annotated type. See class level
49 | * documentation for details.
50 | */
51 | Class> value();
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/se.jbee.inject.bind/main/java/se/jbee/inject/binder/spi/ParentLocalBinder.java:
--------------------------------------------------------------------------------
1 | package se.jbee.inject.binder.spi;
2 |
3 | import se.jbee.inject.Instance;
4 | import se.jbee.inject.Name;
5 | import se.jbee.lang.Type;
6 |
7 | import static se.jbee.inject.Instance.anyOf;
8 | import static se.jbee.inject.Instance.instance;
9 | import static se.jbee.inject.Name.named;
10 | import static se.jbee.lang.Type.raw;
11 |
12 | /**
13 | * Make a binding local to the parent {@link Instance} of the currently injected
14 | * bean.
15 | *
16 | * Multiple calls to {@link #within(Instance)} (and its variants) can be used
17 | * to make the binding to a parent hierarchy.
18 | *
19 | * @since 8.1
20 | *
21 | * @param return type of the binder step following a {@code within} step
22 | */
23 | @FunctionalInterface
24 | public interface ParentLocalBinder {
25 |
26 | /**
27 | * Makes all bindings made with the returned binder local to the provided
28 | * parent instance.
29 | *
30 | * @param parent the parent {@link Instance} to match
31 | * @return next step in fluent API
32 | */
33 | B within(Instance> parent);
34 |
35 | /**
36 | * @see #within(Instance)
37 | */
38 | default B within(String name, Class> parent) {
39 | return within(instance(named(name), raw(parent)));
40 | }
41 |
42 | /**
43 | * @see #within(Instance)
44 | */
45 | default B within(Name name, Type> parent) {
46 | return within(instance(name, parent));
47 | }
48 |
49 | /**
50 | * Makes all bindings made with the returned binder local to any parent
51 | * having the provided type.
52 | *
53 | * @param parent the type of parent instances to match
54 | * @return next step in fluent API
55 | */
56 | default B within(Class> parent) {
57 | return within(raw(parent));
58 | }
59 |
60 | /**
61 | * Makes all bindings made with the returned binder local to any parent
62 | * having the provided type.
63 | *
64 | * @param parent the type of parent instances to match
65 | * @return next step in fluent API
66 | */
67 | default B within(Type> parent) {
68 | return within(anyOf(parent));
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/se.jbee.inject.bootstrap/main/java/se/jbee/inject/defaults/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Contains {@link se.jbee.inject.bind.Bundle}s and {@link
3 | * se.jbee.inject.bind.Module}s that declare the {@link
4 | * se.jbee.inject.defaults.DefaultFeature}s of the library that are build in top of
5 | * the general container mechanism itself.
6 | *
7 | * Defaults
8 | *
9 | * This also includes default implementations for {@link
10 | * se.jbee.inject.bind.ValueBinder}s (see {@link se.jbee.inject.defaults.DefaultValueBinders})
11 | * and the {@link se.jbee.inject.Supplier} implementations they use (see {@link
12 | * se.jbee.inject.binder.Supply}) as well as source value types expended by the
13 | * default {@link se.jbee.inject.bind.ValueBinder}s:
14 | *
15 | *
16 | * - {@link se.jbee.inject.binder.Constructs}
17 | * - {@link se.jbee.inject.binder.Constant}
18 | * - {@link se.jbee.inject.binder.Produces}
19 | *
20 | *
21 | * The base classes mentioned in usage section all install the
22 | * {@link se.jbee.inject.defaults.DefaultsBundle} which binds defaults for
23 | * {@link se.jbee.inject.Scope}s, {@link se.jbee.inject.AnnotatedWith} and
24 | * {@link se.jbee.inject.config.Extension}. As always this can be uninstalled or
25 | * overridden using explicit binds.
26 | *
27 | *
28 | * Utilities
29 | *
30 | * The {@link se.jbee.inject.defaults.AnnotatedWithModule} provides the default
31 | * implementation of the {@link se.jbee.inject.AnnotatedWith} utility type.
32 | *
33 | *
34 | * The {@link se.jbee.inject.defaults.ExtensionModule} provides the default
35 | * implementation for {@link se.jbee.inject.config.Extension} concept.
36 | *
37 | *
38 | * The {@link se.jbee.inject.defaults.DefaultFeature} basic adapters that extend
39 | * the range of types available based on other bound instances.
40 | * {@link se.jbee.inject.defaults.DefaultFeature#ENV} and
41 | * {@link se.jbee.inject.defaults.DefaultFeature#SUB_CONTEXT} are installed by
42 | * default.
43 | *
44 | **/
45 | package se.jbee.inject.defaults;
46 |
--------------------------------------------------------------------------------
/se.jbee.inject.event/main/java/se/jbee/inject/schedule/Scheduled.java:
--------------------------------------------------------------------------------
1 | package se.jbee.inject.schedule;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.Target;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | import static java.lang.annotation.ElementType.METHOD;
9 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
10 |
11 | @Documented
12 | @Retention(RUNTIME)
13 | @Target(METHOD)
14 | public @interface Scheduled {
15 |
16 | /**
17 | * Marker interface to be implemented by managed instances that use the
18 | * {@link Scheduled} annotation to mark methods that should be scheduled.
19 | *
20 | * There is nothing special about this interface except that the {@link
21 | * SchedulerModule} connects it to the {@link Scheduled} annotation so
22 | * instances of implementing classes get connected via {@link
23 | * se.jbee.inject.Lift}.
24 | */
25 | interface Aware {}
26 |
27 | /**
28 | * @return The {@link TimeUnit} used for the {@link #every()} and {@link #starting()} property.
29 | */
30 | TimeUnit unit() default TimeUnit.SECONDS;
31 |
32 | /**
33 | * @return length of the scheduled interval in millis, seconds, minutes (depending on {@link #unit()})
34 | */
35 | int every() default 1;
36 |
37 | /**
38 | * @return
39 | */
40 | int starting() default -1;
41 |
42 | /**
43 | * @return name of the {@link se.jbee.inject.config.Config} property in case
44 | * the time is not given directly by {@link #every()} and {@link #unit()}.
45 | *
46 | * The annotated type is used as context for the {@link
47 | * se.jbee.inject.config.Config}.
48 | *
49 | * If this property is defined the time defined by {@link #every()} and
50 | * {@link #unit()} acts as a default or fallback in case the configuration
51 | * is not defined.
52 | */
53 | String by() default "";
54 |
55 | /**
56 | * @return maximum number of consecutive execution failures after which
57 | * scheduling is cancelled. If zero or negative execution is never
58 | * cancelled.
59 | */
60 | int maxFails() default 1;
61 | }
62 |
--------------------------------------------------------------------------------
/test.integration/test/java/test/integration/bind/TestBasicMultiInstallBinds.java:
--------------------------------------------------------------------------------
1 | package test.integration.bind;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import se.jbee.inject.Injector;
5 | import se.jbee.inject.binder.BinderModule;
6 | import se.jbee.inject.binder.BootstrapperBundle;
7 | import se.jbee.inject.bootstrap.Bootstrap;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 |
11 | /**
12 | * A very small example showing that stateless {@link se.jbee.inject.bind.Module}
13 | * classes can be installed multiple times using different actual instances
14 | * without causing errors because of duplicate (clashing) bindings.
15 | *
16 | * This is because they are recognised as stateless and only the first install
17 | * does have an effect. Further installs are ignored.
18 | *
19 | * The situation would be different if the installed {@link
20 | * se.jbee.inject.bind.Module} has state. In such case is must be assumed that
21 | * this is intentional reuse of the same code to create different bindings based
22 | * on the internal state. Such {@link se.jbee.inject.bind.Module} are all
23 | * installed. Should these lead to clashing bindings this causes the
24 | * bootstrapping to fail with an exception.
25 | */
26 | class TestBasicMultiInstallBinds {
27 |
28 | private static class TwiceInstalledModule extends BinderModule {
29 |
30 | @Override
31 | protected void declare() {
32 | bind(Integer.class).to(42);
33 | }
34 |
35 | }
36 |
37 | private static class TestMultiInstallBundle extends BootstrapperBundle {
38 |
39 | @Override
40 | protected void bootstrap() {
41 | installDefaults();
42 | install(new TwiceInstalledModule());
43 | install(new TwiceInstalledModule());
44 | }
45 | }
46 |
47 | /**
48 | * A stateless module that just has one initial state (or no state) can be
49 | * installed multiple times without causing an error.
50 | */
51 | @Test
52 | void statelessModulesCanBeInstalledTwice() {
53 | Injector injector = Bootstrap.injector(TestMultiInstallBundle.class);
54 | assertEquals(42, injector.resolve(Integer.class).intValue());
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/se.jbee.inject.contract/main/java/se/jbee/inject/contract/Event.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012-2019, Jan Bernitt
3 | *
4 | * Licensed under the Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
5 | */
6 | package se.jbee.inject.contract;
7 |
8 | import se.jbee.lang.Type;
9 |
10 | import java.lang.reflect.Method;
11 | import java.util.function.BinaryOperator;
12 |
13 | import static java.lang.System.currentTimeMillis;
14 |
15 | /**
16 | * The message describing the handler interface method invocation as data.
17 | *
18 | * @since 8.1
19 | *
20 | * @param type of the event handler interface
21 | * @param return type of the {@link #target} method
22 | */
23 | public final class Event {
24 |
25 | /**
26 | * The timestamp used to compute if a events TTL has expired or not.
27 | */
28 | public final long created;
29 | public final Class handlerType;
30 | public final EventPolicy policy;
31 | public final Type result;
32 | public final Method target;
33 | public final Object[] args;
34 | /**
35 | * The function used to aggregate multiple values if a computation is
36 | * dispatched to more then one handler using
37 | * {@link EventPolicy#isAggregatedMultiDispatch()}.
38 | */
39 | public final BinaryOperator aggregator;
40 |
41 | public Event(Class handlerType, EventPolicy policy, Type result,
42 | Method target, Object[] args, BinaryOperator aggregator) {
43 | this.handlerType = handlerType;
44 | this.policy = policy;
45 | this.result = result;
46 | this.target = target;
47 | this.args = args;
48 | this.aggregator = aggregator;
49 | this.created = currentTimeMillis();
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return "[" + handlerType.getSimpleName() + "]:" + target.getName();
55 | }
56 |
57 | public boolean isNonConcurrent() {
58 | return policy.maxConcurrency == 1;
59 | }
60 |
61 | public boolean isExpired() {
62 | return policy.ttl > 0 && currentTimeMillis() > created + policy.ttl;
63 | }
64 |
65 | public boolean returnsVoid() {
66 | return result.rawType == void.class || result.rawType == Void.class;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/test.integration/test/java/test/integration/bind/TestExampleAnnotatedScopeBinds.java:
--------------------------------------------------------------------------------
1 | package test.integration.bind;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import se.jbee.inject.*;
5 | import se.jbee.inject.binder.BinderModule;
6 | import se.jbee.inject.bootstrap.Bootstrap;
7 | import se.jbee.inject.config.ScopesBy;
8 | import test.integration.util.Scoped;
9 |
10 | import static org.junit.jupiter.api.Assertions.assertEquals;
11 | import static org.junit.jupiter.api.Assertions.assertNotSame;
12 |
13 | /**
14 | * This test show how to override the default {@link ScopesBy} in the {@link
15 | * Env} to allow explicitly setting the {@link Scope} of bound instances using
16 | * {@link java.lang.annotation.Annotation}s.
17 | *
18 | * This build upon that the default {@link Scope} is {@link Scope#auto} which is
19 | * a "virtual" scope indicating that {@link ScopesBy} should be used to
20 | * determine the used {@link Scope}. Should a binding explicitly set a {@link
21 | * Scope} using {@link se.jbee.inject.binder.Binder.RootBinder#per(Name)} this
22 | * still is honoured and the custom {@link ScopesBy} strategy is not used for
23 | * such a binding.
24 | */
25 | class TestExampleAnnotatedScopeBinds {
26 |
27 | private static class TestExampleAnnotatedScopeBindsModule extends BinderModule {
28 |
29 | @Override
30 | public Env configure(Env env) {
31 | return env.with(ScopesBy.class, //
32 | ScopesBy.annotatedWith(Scoped.class, Scoped::value));
33 | }
34 |
35 | @Override
36 | protected void declare() {
37 | bind(InjectionScoped.class).toConstructor();
38 | }
39 | }
40 |
41 | @Scoped("injection")
42 | public static final class InjectionScoped {
43 |
44 | }
45 |
46 | private final Injector injector = Bootstrap.injector(
47 | TestExampleAnnotatedScopeBindsModule.class);
48 |
49 | @Test
50 | void annotatedScopeIsUsed() {
51 | assertNotSame(injector.resolve(InjectionScoped.class),
52 | injector.resolve(InjectionScoped.class));
53 | Resource resource = injector.resolve(
54 | Resource.resourceTypeOf(InjectionScoped.class));
55 | assertEquals(Scope.injection, resource.lifeCycle.scope);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/test.integration/test/java/test/integration/bind/TestExampleDependencyAsHintBinds.java:
--------------------------------------------------------------------------------
1 | package test.integration.bind;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import se.jbee.inject.Dependency;
5 | import se.jbee.inject.Injector;
6 | import se.jbee.inject.Instance;
7 | import se.jbee.inject.binder.BinderModule;
8 | import se.jbee.inject.binder.Installs;
9 | import se.jbee.inject.bootstrap.Bootstrap;
10 | import se.jbee.inject.defaults.DefaultFeature;
11 | import se.jbee.inject.defaults.DefaultFeatures;
12 |
13 | import java.util.logging.Logger;
14 |
15 | import static org.junit.jupiter.api.Assertions.assertSame;
16 | import static se.jbee.inject.Dependency.dependency;
17 |
18 | /**
19 | * This test demonstrates the most powerful {@link se.jbee.inject.Hint}: a
20 | * {@link Dependency}.
21 | *
22 | * It allows to also describe what {@link Instance} should be used dependent on
23 | * its parent(s) it would be {@link Dependency#injectingInto(Class)}. Though
24 | * this we can tell to inject the {@link Logger} that would be injected into the
25 | * {@link BinderModule} class into our test object {@link Bean}.
26 | *
27 | * @see TestBasicHintsBinds
28 | */
29 | class TestExampleDependencyAsHintBinds {
30 |
31 | @Installs(features = DefaultFeature.class, by = DefaultFeatures.class)
32 | @DefaultFeatures(DefaultFeature.LOGGER)
33 | private static class TestExampleDependencyAsHintBindsModule
34 | extends BinderModule {
35 |
36 | @Override
37 | protected void declare() {
38 | bind(Bean.class).toConstructor(
39 | dependency(Logger.class).injectingInto(BinderModule.class).asHint());
40 | }
41 | }
42 |
43 | public static class Bean {
44 |
45 | final Logger logger;
46 |
47 | @SuppressWarnings("unused")
48 | public Bean(Logger logger) {
49 | this.logger = logger;
50 | }
51 | }
52 |
53 | @Test
54 | void dependencyHintAffectsInjection() {
55 | Injector resolver = Bootstrap.injector(
56 | TestExampleDependencyAsHintBindsModule.class);
57 | Bean bean = resolver.resolve(Bean.class);
58 | Logger expected = Logger.getLogger(
59 | BinderModule.class.getCanonicalName());
60 | assertSame(expected.getName(), bean.logger.getName());
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/test.integration/test/java/test/integration/container/Decorate.java:
--------------------------------------------------------------------------------
1 | package test.integration.container;
2 |
3 | import se.jbee.inject.Dependency;
4 | import se.jbee.inject.Injector;
5 | import se.jbee.inject.UnresolvableDependency;
6 | import se.jbee.inject.UnresolvableDependency.NoMethodForDependency;
7 |
8 | import java.lang.reflect.Array;
9 |
10 | public class Decorate {
11 |
12 | private Decorate() {
13 | throw new UnsupportedOperationException("util");
14 | }
15 |
16 | /**
17 | * Chains {@link Injector}s similar to a {@link ClassLoader} hierarchy.
18 | *
19 | * @since 8.1
20 | * @param root context acting as fallback
21 | * @param branch context that is tried first when resolving dependencies
22 | * @return An {@link Injector} with both contexts where root acts as
23 | * fallback
24 | */
25 | public static Injector hierarchy(Injector root, Injector branch) {
26 | return new Injector() {
27 |
28 | @Override
29 | public T resolve(Dependency dep)
30 | throws UnresolvableDependency {
31 | if (dep.type().arrayDimensions() == 1)
32 | return Decorate.resolveArray(dep, root, branch);
33 | try {
34 | return branch.resolve(dep);
35 | } catch (UnresolvableDependency.ResourceResolutionFailed | NoMethodForDependency e) {
36 | return root.resolve(dep);
37 | }
38 | }
39 |
40 | };
41 | }
42 |
43 | @SuppressWarnings("unchecked")
44 | static T resolveArray(Dependency dep, Injector root,
45 | Injector branch) {
46 | T branchInstance = null;
47 | try {
48 | branchInstance = branch.resolve(dep);
49 | } catch (UnresolvableDependency e) {
50 | return root.resolve(dep);
51 | }
52 | T rootInstance = null;
53 | try {
54 | rootInstance = root.resolve(dep);
55 | } catch (UnresolvableDependency e) {
56 | return branchInstance;
57 | }
58 | int rootLength = Array.getLength(rootInstance);
59 | int branchLength = Array.getLength(branchInstance);
60 | Object arr = Array.newInstance(dep.type().baseType().rawType,
61 | rootLength + branchLength);
62 | System.arraycopy(rootInstance, 0, arr, 0, rootLength);
63 | System.arraycopy(branchInstance, 0, arr, rootLength, branchLength);
64 | return (T) arr;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/test.integration/test/java/test/integration/contract/TestRoundRobinComputeEvents.java:
--------------------------------------------------------------------------------
1 | package test.integration.contract;
2 |
3 | import org.junit.jupiter.api.Disabled;
4 | import org.junit.jupiter.api.Test;
5 | import se.jbee.inject.Injector;
6 | import se.jbee.inject.bootstrap.Bootstrap;
7 | import se.jbee.inject.contract.ContractModule;
8 |
9 | import static org.junit.jupiter.api.Assertions.*;
10 | import static se.jbee.inject.Name.named;
11 |
12 | class TestRoundRobinComputeEvents {
13 |
14 | private interface Handler {
15 |
16 | int compute(int x);
17 | }
18 |
19 | private static final class Service implements Handler {
20 |
21 | private final int inc;
22 |
23 | public Service(int inc) {
24 | this.inc = inc;
25 | }
26 |
27 | @Override
28 | public int compute(int x) {
29 | return x + inc;
30 | }
31 |
32 | }
33 |
34 | private static final class TestRoundRobinComputeEventsModule
35 | extends ContractModule {
36 |
37 | @Override
38 | protected void declare() {
39 | handle(Handler.class);
40 | bind(named("a"), Service.class).to(new Service(5));
41 | bind(named("b"), Service.class).to(new Service(7));
42 | bind(named("c"), Service.class).to(new Service(3));
43 | }
44 | }
45 |
46 | private final Injector injector = Bootstrap.injector(
47 | TestRoundRobinComputeEventsModule.class);
48 |
49 | @Test
50 | @Disabled("TODO #80 // TestRoundRobinComputeEvents.computationUsesAllAvailableServices()")
51 | void computationUsesAllAvailableServices() {
52 | Handler h = injector.resolve(Handler.class);
53 | Service a = injector.resolve("a", Service.class);
54 | Service b = injector.resolve("b", Service.class);
55 | Service c = injector.resolve("c", Service.class);
56 |
57 | assertNotNull(a);
58 | assertNotNull(b);
59 | assertNotNull(c);
60 | assertNotSame(a, b);
61 | assertNotSame(b, c);
62 | assertNotSame(a, c);
63 |
64 | int sum = 0;
65 | sum += h.compute(1);
66 | sum += h.compute(1);
67 | sum += h.compute(1);
68 | assertEquals(18, sum); // 5+1 + 7+1 + 3+1 = 18 (no guarantee for order)
69 |
70 | // next round
71 | sum += h.compute(3);
72 | sum += h.compute(3);
73 | sum += h.compute(3); // 5+3 + 7+3 + 3+3 = 24 (no guarantee for order)
74 | assertEquals(42, sum); // 18 + 24 = 42
75 | }
76 | }
77 |
--------------------------------------------------------------------------------