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