1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.seasar.cubby.internal.util;
18
19 import static org.seasar.cubby.internal.util.LogMessages.format;
20
21 import java.io.BufferedReader;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.Iterator;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Map.Entry;
33
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
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 private class ProviderIterator implements Iterator<S> {
205
206
207 private final Iterator<Entry<String, S>> providerIterator;
208
209
210
211
212 ProviderIterator() {
213 providerIterator = providers.entrySet().iterator();
214 }
215
216
217
218
219 public boolean hasNext() {
220 return providerIterator.hasNext();
221 }
222
223
224
225
226 public S next() {
227 final Entry<String, S> entry = providerIterator.next();
228 if (entry.getValue() == null) {
229 final String providerClassName = entry.getKey();
230 final S provider = newInstance(providerClassName);
231 entry.setValue(provider);
232 if (logger.isDebugEnabled()) {
233 logger.debug(format("DCUB0018", service, providerClassName,
234 provider));
235 }
236 }
237 return entry.getValue();
238 }
239
240
241
242
243
244
245
246
247 private S newInstance(final String className) {
248 try {
249 final Class<?> providerClass = Class.forName(className, true,
250 classLoader);
251 final Object providerInstance = providerClass.newInstance();
252 final S provider = service.cast(providerInstance);
253 return provider;
254 } catch (final ClassNotFoundException e) {
255 throw new ServiceLoadingException(e);
256 } catch (final InstantiationException e) {
257 throw new ServiceLoadingException(e);
258 } catch (final IllegalAccessException e) {
259 throw new ServiceLoadingException(e);
260 } catch (final ClassCastException e) {
261 throw new ServiceLoadingException(e);
262 }
263 }
264
265
266
267
268 public void remove() {
269 throw new UnsupportedOperationException();
270 }
271
272 }
273
274 }