nextflow.util.ServiceDiscover.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nf-commons Show documentation
Show all versions of nf-commons Show documentation
A DSL modelled around the UNIX pipe concept, that simplifies writing parallel and scalable pipelines in a portable manner
/*
* Copyright 2013-2024, Seqera Labs
*
* Licensed 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 nextflow.util
import groovy.transform.CompileStatic
/**
* A service loader inspired to {@link ServiceLoader}
* that allows to load only service names or classes without instantiating
* the actual instances
*
* @author Paolo Di Tommaso
*/
@CompileStatic
class ServiceDiscover {
private static final String PREFIX = "META-INF/services/";
private Class service
private ClassLoader classLoader
static List> load(Class service) {
new ServiceDiscover(service).load()
}
ServiceDiscover(Class service) {
assert service
this.service = service
this.classLoader = Thread.currentThread().getContextClassLoader()
}
ServiceDiscover(Class service, ClassLoader classLoader) {
assert service
assert classLoader
this.service = service
this.classLoader = classLoader
}
private int parseLine(Class service, URL u, BufferedReader r, int lc, List names)
throws IOException, ServiceConfigurationError
{
String ln = r.readLine();
if (ln == null) {
return -1
}
int ci = ln.indexOf('#')
if (ci >= 0)
ln = ln.substring(0, ci)
ln = ln.trim()
int n = ln.length()
if (n != 0) {
if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
fail(service, u, lc, "Illegal configuration file syntax")
int cp = ln.codePointAt(0)
if (!Character.isJavaIdentifierStart(cp))
fail(service, u, lc, "Illegal provider-class name: " + ln)
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
cp = ln.codePointAt(i)
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
fail(service, u, lc, "Illegal provider-class name: " + ln)
}
if ( !names.contains(ln) )
names.add(ln)
}
return lc + 1
}
private List parse(Class service, URL u) throws ServiceConfigurationError
{
InputStream stream = null;
BufferedReader reader = null;
ArrayList names = new ArrayList<>();
try {
stream = u.openStream();
reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));
int lc = 1;
while ((lc = parseLine(service, u, reader, lc, names)) >= 0) { /*empty*/ }
}
catch (IOException x) {
fail(service, "Error reading configuration file", x);
}
finally {
try {
if (reader != null) reader.close();
if (stream != null) stream.close();
}
catch (IOException y) {
fail(service, "Error closing configuration file", y);
}
}
return names
}
private static void fail(Class service, String msg, Throwable cause)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
private static void fail(Class service, String msg)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
private static void fail(Class service, URL u, int line, String msg)
throws ServiceConfigurationError
{
fail(service, u.toString() + ":" + line + ": " + msg);
}
private Class classForName(String clazzName) {
Class> result = null
try {
result = Class.forName(clazzName, false, classLoader);
}
catch (ClassNotFoundException x) {
fail(service, "Provider $clazzName not found");
}
if (!service.isAssignableFrom(result)) {
fail(service, "Provider $clazzName not a subtype");
}
try {
return (Class)result;
}
catch (Throwable x) {
fail(service, "Provider $clazzName could not be instantiated: " + x, x);
}
throw new Error()
}
List names() {
Enumeration configs = null
try {
configs = classLoader.getResources(PREFIX + service.getName())
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
List result = []
for( URL url : configs ) {
for( String name : parse(service, url) ) {
result << name
}
}
return result
}
List> load() {
names().collect{ classForName(it) }
}
}