1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.seasar.cubby.internal.util;
17
18 import static org.seasar.cubby.internal.util.LogMessages.format;
19
20 import java.io.BufferedReader;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.Enumeration;
27 import java.util.Iterator;
28 import java.util.LinkedHashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class ServiceLoader<S> implements Iterable<S> {
52
53
54 private static final Logger logger = LoggerFactory
55 .getLogger(ServiceLoader.class);
56
57
58 private static final String PREFIX = "META-INF/services/";
59
60
61 private final Map<String, S> providers = new LinkedHashMap<String, S>();
62
63
64 private final Class<S> service;
65
66
67 private final ClassLoader classLoader;
68
69
70
71
72
73
74
75
76
77 private ServiceLoader(final Class<S> service, final ClassLoader classLoader) {
78 this.service = service;
79 this.classLoader = classLoader;
80 reload();
81 }
82
83
84
85
86 public void reload() {
87 providers.clear();
88
89 final String resourceName = PREFIX + service.getName();
90 try {
91 final Enumeration<URL> urls = classLoader
92 .getResources(resourceName);
93 while (urls.hasMoreElements()) {
94 final URL url = urls.nextElement();
95 for (final String providerClassName : parse(url)) {
96 providers.put(providerClassName, null);
97 }
98 }
99 } catch (final IOException e) {
100 throw new ServiceLoadingException(e);
101 }
102 }
103
104
105
106
107
108
109
110
111
112
113 private List<String> parse(final URL url) throws IOException {
114 if (logger.isDebugEnabled()) {
115 logger.debug(format("DCUB0017", service, url));
116 }
117 final List<String> providerClassNames = new ArrayList<String>();
118 InputStream input = null;
119 BufferedReader reader = null;
120 try {
121 input = url.openStream();
122 reader = new BufferedReader(new InputStreamReader(input, "utf-8"));
123 for (String line; (line = reader.readLine()) != null;) {
124 final String providerClassName = cleanup(line);
125 if (providerClassName != null) {
126 providerClassNames.add(providerClassName);
127 }
128 }
129 } finally {
130 if (reader != null) {
131 reader.close();
132 }
133 if (input != null) {
134 input.close();
135 }
136 }
137 return providerClassNames;
138 }
139
140
141
142
143
144
145
146
147 private String cleanup(String line) {
148 final int commentIndex = line.indexOf('#');
149 if (commentIndex >= 0) {
150 line = line.substring(0, commentIndex);
151 }
152 line = line.trim();
153 if (line.length() == 0) {
154 return null;
155 }
156 return line;
157 }
158
159
160
161
162
163
164 public Iterator<S> iterator() {
165 return new ProviderIterator();
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179 public static <S> ServiceLoader<S> load(final Class<S> service,
180 final ClassLoader classLoader) {
181 return new ServiceLoader<S>(service, classLoader);
182 }
183
184
185
186
187
188
189
190
191
192
193 public static <S> ServiceLoader<S> load(final Class<S> service) {
194 final ClassLoader classLoader = Thread.currentThread()
195 .getContextClassLoader();
196 return load(service, classLoader);
197 }
198
199
200
201
202
203
204
205 private class ProviderIterator implements Iterator<S> {
206
207
208 private final Iterator<Entry<String, S>> providerIterator;
209
210
211
212
213 ProviderIterator() {
214 providerIterator = providers.entrySet().iterator();
215 }
216
217
218
219
220 public boolean hasNext() {
221 return providerIterator.hasNext();
222 }
223
224
225
226
227 public S next() {
228 final Entry<String, S> entry = providerIterator.next();
229 if (entry.getValue() == null) {
230 final String providerClassName = entry.getKey();
231 final S provider = newInstance(providerClassName);
232 entry.setValue(provider);
233 if (logger.isDebugEnabled()) {
234 logger.debug(format("DCUB0018", service, providerClassName,
235 provider));
236 }
237 }
238 return entry.getValue();
239 }
240
241
242
243
244
245
246
247
248 private S newInstance(final String className) {
249 try {
250 final Class<?> providerClass = Class.forName(className, true,
251 classLoader);
252 final Object providerInstance = providerClass.newInstance();
253 final S provider = service.cast(providerInstance);
254 return provider;
255 } catch (final ClassNotFoundException e) {
256 throw new ServiceLoadingException(e);
257 } catch (final InstantiationException e) {
258 throw new ServiceLoadingException(e);
259 } catch (final IllegalAccessException e) {
260 throw new ServiceLoadingException(e);
261 } catch (final ClassCastException e) {
262 throw new ServiceLoadingException(e);
263 }
264 }
265
266
267
268
269 public void remove() {
270 throw new UnsupportedOperationException();
271 }
272
273 }
274
275 }