1 package org.apache.onami.spi.services;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static java.lang.String.format;
23 import static java.lang.Thread.currentThread;
24 import static org.apache.onami.spi.core.ServiceLoader.load;
25
26 import java.lang.annotation.Annotation;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30
31 import javax.inject.Qualifier;
32
33 import com.google.inject.AbstractModule;
34 import com.google.inject.BindingAnnotation;
35 import com.google.inject.ProvisionException;
36 import com.google.inject.binder.AnnotatedBindingBuilder;
37 import com.google.inject.binder.LinkedBindingBuilder;
38
39
40
41
42
43 public abstract class ServiceLoaderModule
44 extends AbstractModule
45 {
46
47 private List<ServiceInfo<?>> services = new LinkedList<ServiceInfo<?>>();
48
49 @Override
50 protected final void configure()
51 {
52 if ( !services.isEmpty() )
53 {
54 throw new IllegalStateException( "Re-entry is not allowed." );
55 }
56
57 configureServices();
58
59 try
60 {
61 for ( ServiceInfo<?> builder : services )
62 {
63 bindService( builder );
64 }
65 }
66 finally
67 {
68 services.clear();
69 }
70 }
71
72 private <S> void bindService( ServiceInfo<S> serviceInfo )
73 {
74 Class<S> serviceType = serviceInfo.getServiceType();
75
76 Iterator<Class<? extends S>> servicesIterator = load( serviceType, serviceInfo.getClassLoader() )
77 .iterator();
78 boolean found = false;
79 while ( servicesIterator.hasNext() )
80 {
81 if ( !found )
82 {
83 found = true;
84 }
85
86 Class<? extends S> serviceImplType = servicesIterator.next();
87
88 bindService( serviceType, serviceImplType );
89 }
90
91 if ( !found )
92 {
93 throw new ProvisionException( format( "No Provider found for Service %s", serviceType.getName() ) );
94 }
95 }
96
97 private <S> void bindService( Class<S> serviceType, Class<? extends S> serviceImplType )
98 {
99 AnnotatedBindingBuilder<S> annotatedBindingBuilder = bind( serviceType );
100 LinkedBindingBuilder<S> linkedBindingBuilder = annotatedBindingBuilder;
101
102 dance: for ( Annotation annotation : serviceImplType.getAnnotations() )
103 {
104 Class<? extends Annotation> annotationType = annotation.annotationType();
105
106
107
108
109
110
111 if ( annotationType.isAnnotationPresent( Qualifier.class )
112 || annotationType.isAnnotationPresent( BindingAnnotation.class ) )
113 {
114 linkedBindingBuilder = annotatedBindingBuilder.annotatedWith( annotation );
115 break dance;
116 }
117 }
118
119 linkedBindingBuilder.to( serviceImplType );
120 }
121
122 protected abstract void configureServices();
123
124
125
126
127
128
129
130 protected final <S> FromClassLoaderBuilder discover( Class<S> service )
131 {
132 checkArgument( service != null, "Impossible to bind null service class!" );
133 ServiceInfo<S> builder = new ServiceInfo<S>( service );
134 services.add( builder );
135 return builder;
136 }
137
138
139
140
141
142
143 private static final class ServiceInfo<S>
144 implements FromClassLoaderBuilder
145 {
146
147 private final Class<S> serviceType;
148
149 private ClassLoader classLoader;
150
151 public ServiceInfo( Class<S> serviceType )
152 {
153 this.serviceType = serviceType;
154 classLoader = currentThread().getContextClassLoader();
155 }
156
157
158
159
160 public void fromClassLoader( ClassLoader classLoader )
161 {
162 checkArgument( classLoader != null,
163 "Impossible to load Service %s with a null ClassLoader", serviceType.getName() );
164 this.classLoader = classLoader;
165 }
166
167 public Class<S> getServiceType()
168 {
169 return serviceType;
170 }
171
172 public ClassLoader getClassLoader()
173 {
174 return classLoader;
175 }
176
177 }
178
179 private static void checkArgument( boolean expression, String errorMessagePattern, Object...args )
180 {
181 if ( !expression )
182 {
183 throw new IllegalArgumentException( format( errorMessagePattern, args ) );
184 }
185 }
186
187 }