1 package org.apache.maven.surefire.providerapi;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import javax.annotation.Nonnull;
23 import java.io.BufferedReader;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.lang.reflect.InvocationTargetException;
28 import java.net.URL;
29 import java.util.Enumeration;
30 import java.util.HashSet;
31 import java.util.Set;
32
33 import static java.lang.Character.isJavaIdentifierPart;
34 import static java.lang.Character.isJavaIdentifierStart;
35 import static java.util.Collections.emptySet;
36 import static org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
37
38
39
40
41
42
43
44
45
46 public class ServiceLoader
47 {
48
49 @Nonnull
50 @SuppressWarnings( "unchecked" )
51 public <T> Set<T> load( Class<T> clazz, ClassLoader classLoader )
52 {
53 try
54 {
55 Set<T> implementations = new HashSet<T>();
56 for ( String fullyQualifiedClassName : lookup( clazz, classLoader ) )
57 {
58 Class<?> implClass = classLoader.loadClass( fullyQualifiedClassName );
59 implementations.add( (T) getConstructor( implClass ).newInstance() );
60 }
61 return implementations;
62 }
63 catch ( IOException e )
64 {
65 throw new IllegalStateException( e.getLocalizedMessage(), e );
66 }
67 catch ( ClassNotFoundException e )
68 {
69 throw new IllegalStateException( e.getLocalizedMessage(), e );
70 }
71 catch ( InvocationTargetException e )
72 {
73 throw new IllegalStateException( e.getLocalizedMessage(), e );
74 }
75 catch ( InstantiationException e )
76 {
77 throw new IllegalStateException( e.getLocalizedMessage(), e );
78 }
79 catch ( IllegalAccessException e )
80 {
81 throw new IllegalStateException( e.getLocalizedMessage(), e );
82 }
83 }
84
85 @Nonnull
86 public Set<String> lookup( Class<?> clazz, ClassLoader classLoader )
87 throws IOException
88 {
89 final String resourceName = "META-INF/services/" + clazz.getName();
90
91 if ( classLoader == null )
92 {
93 return emptySet();
94 }
95 final Enumeration<URL> urls = classLoader.getResources( resourceName );
96 return lookupSpiImplementations( urls );
97 }
98
99
100
101
102
103
104
105
106
107 @Nonnull
108 @SuppressWarnings( "checkstyle:innerassignment" )
109 private static Set<String> lookupSpiImplementations( final Enumeration<URL> urlEnumeration )
110 throws IOException
111 {
112 final Set<String> names = new HashSet<String>();
113 nextUrl:
114 while ( urlEnumeration.hasMoreElements() )
115 {
116 final URL url = urlEnumeration.nextElement();
117 final BufferedReader reader = getReader( url );
118 try
119 {
120 for ( String line; ( line = reader.readLine() ) != null; )
121 {
122 int ci = line.indexOf( '#' );
123 if ( ci >= 0 )
124 {
125 line = line.substring( 0, ci );
126 }
127 line = line.trim();
128 int n = line.length();
129 if ( n == 0 )
130 {
131 continue;
132 }
133
134 if ( line.indexOf( ' ' ) >= 0 || line.indexOf( '\t' ) >= 0 )
135 {
136 continue nextUrl;
137 }
138 char cp = line.charAt( 0 );
139 if ( !isJavaIdentifierStart( cp ) )
140 {
141 continue nextUrl;
142 }
143 for ( int i = 1; i < n; i++ )
144 {
145 cp = line.charAt( i );
146 if ( !isJavaIdentifierPart( cp ) && cp != '.' )
147 {
148 continue nextUrl;
149 }
150 }
151 if ( !names.contains( line ) )
152 {
153 names.add( line );
154 }
155 }
156 }
157 finally
158 {
159 reader.close();
160 }
161 }
162
163 return names;
164 }
165
166 @Nonnull
167 private static BufferedReader getReader( @Nonnull URL url )
168 throws IOException
169 {
170 final InputStream inputStream = url.openStream();
171 final InputStreamReader inputStreamReader = new InputStreamReader( inputStream );
172 return new BufferedReader( inputStreamReader );
173 }
174 }