org.apache.maven.surefire.providerapi.ServiceLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-surefire-common Show documentation
Show all versions of maven-surefire-common Show documentation
API used in Surefire and Failsafe MOJO.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.surefire.providerapi;
import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import org.codehaus.plexus.component.annotations.Component;
import static java.lang.Character.isJavaIdentifierPart;
import static java.lang.Character.isJavaIdentifierStart;
import static java.util.Collections.emptySet;
import static org.apache.maven.surefire.api.util.ReflectionUtils.getConstructor;
/**
* SPI loader for Surefire/Failsafe should use {@link Thread#getContextClassLoader() current ClassLoader}.
*
* The {@link java.util.ServiceLoader} embedded in JVM uses
* {@link ClassLoader#getSystemClassLoader() System ClassLoader} and cannot be used in Surefire/Failsafe.
*
* @since 2.20
*/
@Component(role = ServiceLoader.class)
public class ServiceLoader {
@Nonnull
@SuppressWarnings("unchecked")
public Set load(Class clazz, ClassLoader classLoader) {
try {
Set implementations = new HashSet<>();
for (String fullyQualifiedClassName : lookup(clazz, classLoader)) {
Class> implClass = classLoader.loadClass(fullyQualifiedClassName);
implementations.add((T) getConstructor(implClass).newInstance());
}
return implementations;
} catch (IOException | ReflectiveOperationException e) {
throw new IllegalStateException(e.getLocalizedMessage(), e);
}
}
@Nonnull
public Set lookup(Class> clazz, ClassLoader classLoader) throws IOException {
final String resourceName = "META-INF/services/" + clazz.getName();
if (classLoader == null) {
return emptySet();
}
final Enumeration urls = classLoader.getResources(resourceName);
return lookupSpiImplementations(urls);
}
/**
* Method loadServices loads the services of a class that are
* defined using the SPI mechanism.
*
* @param urlEnumeration The urls from the resource
* @return The set of service provider names
* @throws IOException When reading the streams fails
*/
@Nonnull
@SuppressWarnings("checkstyle:innerassignment")
private static Set lookupSpiImplementations(final Enumeration urlEnumeration) throws IOException {
final Set names = new HashSet<>();
nextUrl:
while (urlEnumeration.hasMoreElements()) {
final URL url = urlEnumeration.nextElement();
try (BufferedReader reader = getReader(url)) {
for (String line; (line = reader.readLine()) != null; ) {
int ci = line.indexOf('#');
if (ci >= 0) {
line = line.substring(0, ci);
}
line = line.trim();
int n = line.length();
if (n == 0) {
continue; // next line
}
if (line.indexOf(' ') >= 0 || line.indexOf('\t') >= 0) {
continue nextUrl; // next url
}
char cp = line.charAt(0); // should use codePointAt but this was JDK1.3
if (!isJavaIdentifierStart(cp)) {
continue nextUrl; // next url
}
for (int i = 1; i < n; i++) {
cp = line.charAt(i); // should use codePointAt but this was JDK1.3
if (!isJavaIdentifierPart(cp) && cp != '.') {
continue nextUrl; // next url
}
}
if (!names.contains(line)) {
names.add(line);
}
}
}
}
return names;
}
@Nonnull
private static BufferedReader getReader(@Nonnull URL url) throws IOException {
final InputStream inputStream = url.openStream();
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
return new BufferedReader(inputStreamReader);
}
}