All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.thundra.swark.instance.InstanceDiscovery Maven / Gradle / Ivy

There is a newer version: 0.0.10
Show newest version
package io.thundra.swark.instance;

import com.opsgenie.core.entity.Ordered;
import com.opsgenie.core.instance.InstanceCreator;
import com.opsgenie.core.instance.InstanceDefinitionPathProvider;
import com.opsgenie.core.instance.InstanceProvider;
import com.opsgenie.core.instance.InstanceScope;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public final class InstanceDiscovery {

    private static final String PREFIX;
    private static final Logger LOGGER = LogManager.getLogger(InstanceDiscovery.class);

    static {
        String prefix = "META-INF/services/";
        List> pathProviderClasses =
                typesOf(prefix, InstanceDefinitionPathProvider.class, null);
        if (pathProviderClasses != null && !pathProviderClasses.isEmpty()) {
            if (pathProviderClasses.size() > 1) {
                LOGGER.warn(String.format(
                        "There are multiple instance definition path providers: %s. " +
                                "The one with lowest order will be used", pathProviderClasses));
            }
            Class pathProviderClass =
                    pathProviderClasses.get(0);
            try {
                InstanceDefinitionPathProvider instanceDefinitionPathProvider =
                        InstanceProvider.getInstance(pathProviderClass, InstanceScope.GLOBAL);
                String path = instanceDefinitionPathProvider.getPath();
                if (path != null) {
                    prefix = path;
                }
            } catch (Throwable t) {
                LOGGER.error("Error occurred while getting instance definition path. " +
                        "So going on with default one: " + prefix, t);
            }
        }
        if (!prefix.endsWith("/")) {
            prefix = prefix + "/";
        }
        PREFIX = prefix;
    }

    private InstanceDiscovery() {
    }

    private static void fail(Class type, String msg, Throwable cause) {
        throw new RuntimeException(type.getName() + ": " + msg, cause);
    }

    private static void fail(Class type, String msg) {
        throw new RuntimeException(type.getName() + ": " + msg);
    }

    private static void fail(Class type, URL url, int line, String msg) {
        fail(type, url + ":" + line + ": " + msg);
    }

    private static int parseLine(Class type, URL url, BufferedReader reader, int lc,
                                 Set typeNames) throws IOException {
        String ln = reader.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(type, url, lc, "Illegal configuration-file syntax");
            }
            int cp = ln.codePointAt(0);
            if (!Character.isJavaIdentifierStart(cp)) {
                fail(type, url, lc, "Illegal instance-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(type, url, lc, "Illegal instance-class name: " + ln);
                }
            }
            typeNames.add(ln);
        }
        return lc + 1;
    }

    private static Set parse(Class service, URL url) {
        InputStream in = null;
        BufferedReader reader = null;
        Set typeNames = new HashSet();
        try {
            in = url.openStream();
            reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            int lc = 1;
            //CHECKSTYLE:OFF
            while ((lc = parseLine(service, url, reader, lc, typeNames)) >= 0) ;
            //CHECKSTYLE:ON
        } catch (IOException x) {
            fail(service, "Error reading configuration file", x);
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException y) {
                fail(service, "Error closing configuration file", y);
            }
        }
        return typeNames;
    }

    /////////////////////////////////////////////////////////////////////////////////

    public static  List> typesOf(Class type) {
        return typesOf(type, null);
    }

    public static  List> typesOf(Class type, ClassLoader loader) {
        return typesOf(PREFIX, type, loader);
    }

    private static  List> typesOf(String prefix, Class type, ClassLoader loader) {
        List> types = new ArrayList>();
        try {
            Enumeration configs;
            String fullName = prefix + type.getName();
            if (loader == null) {
                configs = com.opsgenie.core.instance.InstanceDiscovery.class.getClassLoader().getResources(fullName);
            } else {
                configs = loader.getResources(fullName);
            }

            Set allTypeNames = new HashSet();
            if (configs != null) {
                while (configs.hasMoreElements()) {
                    Set typeNames = parse(type, configs.nextElement());
                    allTypeNames.addAll(typeNames);
                }
            }

            for (String typeName : allTypeNames) {
                try {
                    Class instanceType;
                    if (loader == null) {
                        instanceType = (Class) Class.forName(typeName, false,
                                InstanceDiscovery.class.getClassLoader());
                    } else {
                        instanceType = (Class) loader.loadClass(typeName);
                    }
                    if (!type.isAssignableFrom(instanceType)) {
                        fail(type, "Instance type " + typeName + " not a subtype");
                    }
                    types.add(instanceType);
                } catch (ClassNotFoundException e) {
                    fail(type, "Instance class " + typeName + " not found");
                }
            }
        } catch (IOException e) {
            fail(type, "Error locating configuration files", e);
        }
        return types;
    }

    public static  Class typeOf(Class type, ClassLoader loader) {
        List> types = typesOf(type, loader);
        if (types.isEmpty()) {
            return null;
        }
        if (types.size() > 1) {
            throw new IllegalStateException("Multiple type of " + type + " have been found: " + types);
        }
        return types.get(0);
    }

    public static  Class typeOf(Class type) {
        return typeOf(type, null);
    }

    /////////////////////////////////////////////////////////////////////////////////

    private static  List returnInstances(Class type, List instances) {
        if (Ordered.class.isAssignableFrom(type)) {
            Collections.sort(instances, new Comparator() {
                @Override
                public int compare(T o1, T o2) {
                    return Integer.compare(((Ordered) o1).order(), ((Ordered) o2).order());
                }
            });
        }
        return instances;
    }

    public static  List instancesOf(Class type) {
        return instancesOf(type, null);
    }

    public static  List instancesOf(Class type, ClassLoader loader) {
        return instancesOf(type, loader, InstanceScope.GLOBAL);
    }

    public static  List instancesOf(Class type, ClassLoader loader,
                                          InstanceScope scope) {
        return instancesOf(type, loader, scope, null);
    }

    public static  List instancesOf(Class type, ClassLoader loader,
                                          InstanceScope scope, InstanceCreator creator) {
        List instances = new ArrayList();
        List> types = typesOf(type, loader);
        for (Class instanceType : types) {
            try {
                T instance = InstanceProvider.getInstance(instanceType, scope, creator);
                instances.add(instance);
            } catch (Exception e) {
                fail(type, "Instance class " + instanceType.getName() + " could not be instantiated", e);
            }
        }
        return returnInstances(type, instances);
    }

    public static  T instanceOf(Class type) {
        return instanceOf(type, null);
    }

    public static  T instanceOf(Class type, ClassLoader loader) {
        return instanceOf(type, loader, InstanceScope.GLOBAL);
    }

    public static  T instanceOf(Class type, ClassLoader loader, InstanceScope scope) {
        return instanceOf(type, loader, scope, null);
    }

    public static  T instanceOf(Class type, ClassLoader loader,
                                   InstanceScope scope, InstanceCreator creator) {
        List instances = instancesOf(type, loader, scope, creator);
        if (instances.isEmpty()) {
            return null;
        }
        if (instances.size() > 1) {
            throw new IllegalStateException("Multiple instance of " + type + " have been found: " + instances);
        }
        return instances.get(0);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy