1 package org.apache.onami.lifecycle.core;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.google.inject.Key;
23 import com.google.inject.TypeLiteral;
24 import com.google.inject.matcher.Matcher;
25 import com.google.inject.spi.InjectionListener;
26 import com.google.inject.spi.TypeEncounter;
27 import com.google.inject.util.Types;
28
29 import java.lang.annotation.Annotation;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.ParameterizedType;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import static com.google.inject.matcher.Matchers.any;
36 import static java.util.Arrays.asList;
37
38
39
40
41
42
43 public abstract class LifeCycleStageModule
44 extends LifeCycleModule
45 {
46
47 private List<BindingBuilder<?>> bindings;
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public static <A extends Annotation> Key<Stager<A>> key( Class<A> stage )
62 {
63 return Key.get( type( stage ) );
64 }
65
66 private static <A extends Annotation> TypeLiteral<Stager<A>> type( Class<A> stage )
67 {
68 ParameterizedType parameterizedType = Types.newParameterizedTypeWithOwner( null, Stager.class, stage );
69
70 @SuppressWarnings( "unchecked" )
71 TypeLiteral<Stager<A>> stagerType = (TypeLiteral<Stager<A>>) TypeLiteral.get( parameterizedType );
72 return stagerType;
73 }
74
75
76
77
78 @Override
79 protected final void configure()
80 {
81 if ( bindings != null )
82 {
83 throw new IllegalStateException( "Re-entry is not allowed" );
84 }
85 bindings = new ArrayList<BindingBuilder<?>>();
86 try
87 {
88 configureBindings();
89 for ( BindingBuilder<?> binding : bindings )
90 {
91 bind( binding );
92 }
93 }
94 finally
95 {
96 bindings = null;
97 }
98 }
99
100 private <A extends Annotation> void bind( BindingBuilder<A> binding )
101 {
102 final Stager<A> stager = binding.stager;
103 final StageableTypeMapper typeMapper = binding.typeMapper;
104 bind( type( stager.getStage() ) ).toInstance( stager );
105
106 bindListener( binding.typeMatcher, new AbstractMethodTypeListener( asList( stager.getStage() ) )
107 {
108
109 @Override
110 protected <I> void hear( final Method stageMethod, final TypeLiteral<I> parentType,
111 final TypeEncounter<I> encounter,
112 final Class<? extends Annotation> annotationType )
113 {
114 encounter.register( new InjectionListener<I>()
115 {
116
117 @Override
118 public void afterInjection( I injectee )
119 {
120 Stageable stageable = new StageableMethod( stageMethod, injectee );
121 stager.register( stageable );
122 typeMapper.registerType( stageable, parentType );
123 }
124
125 } );
126 }
127
128 } );
129 }
130
131 protected abstract void configureBindings();
132
133 protected final <A extends Annotation> MapperBinding bindStager( Stager<A> stager )
134 {
135 BindingBuilder<A> builder = new BindingBuilder<A>( checkNotNull( stager, "Argument 'stager' must be not null" ) );
136 bindings.add( builder );
137 return builder;
138 }
139
140 protected interface MatcherBinding
141 {
142
143
144
145
146
147 void matching( Matcher<? super TypeLiteral<?>> typeMatcher );
148 }
149
150 protected interface MapperBinding extends MatcherBinding
151 {
152
153
154
155
156
157 MatcherBinding mappingWith( StageableTypeMapper typeMapper );
158 }
159
160
161
162
163 private static class BindingBuilder<A extends Annotation> implements MapperBinding
164 {
165
166 private Matcher<? super TypeLiteral<?>> typeMatcher = any();
167
168 private final Stager<A> stager;
169
170 private StageableTypeMapper typeMapper = new NoOpStageableTypeMapper();
171
172 public BindingBuilder( Stager<A> stager )
173 {
174 this.stager = stager;
175 }
176
177 @Override
178 public MatcherBinding mappingWith( StageableTypeMapper typeMapper )
179 {
180 this.typeMapper = checkNotNull( typeMapper, "Argument 'typeMapper' must be not null." );
181 return this;
182 }
183
184 @Override
185 public void matching( Matcher<? super TypeLiteral<?>> typeMatcher )
186 {
187 this.typeMatcher = checkNotNull( typeMatcher, "Argument 'typeMatcher' must be not null" );
188 }
189
190 }
191
192 private static <T> T checkNotNull( T object, String message )
193 {
194 if ( object == null )
195 {
196 throw new IllegalArgumentException( message );
197 }
198 return object;
199 }
200 }