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