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