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

ai.h2o.mojos.runtime.api.MojoPipelineService Maven / Gradle / Ivy

There is a newer version: 2.8.7.1
Show newest version
package ai.h2o.mojos.runtime.api;

import ai.h2o.mojos.runtime.MojoPipeline;
import ai.h2o.mojos.runtime.api.backend.DirReaderBackend;
import ai.h2o.mojos.runtime.api.backend.ReaderBackend;
import ai.h2o.mojos.runtime.api.backend.ZipFileReaderBackend;
import ai.h2o.mojos.runtime.lic.LicenseException;
import ai.h2o.mojos.runtime.utils.ClassLoaderUtils;
import ai.h2o.mojos.runtime.utils.Consts;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Primary pipeline service.
 *
 * This class takes care of instantiating pipeline based on what's found in a given backend.
 * And, because one backed can contain multiple pipeline formats, the choice can be configured with property sys.ai.h2o.mojos.pipelineFormats.
 * It contains a comma separated list of format provider names, which are defined by their {@link PipelineLoaderFactory#getName()} method.
 */
public class MojoPipelineService {
    private static final Logger log = LoggerFactory.getLogger(MojoPipelineService.class);
    private final LinkedHashMap registry = new LinkedHashMap<>();

    private MojoPipelineService(String... pipelineFormats) {
        // gather all providers
        final LinkedHashMap factories = new LinkedHashMap<>();
        final ServiceLoader loader = ServiceLoader.load(
            PipelineLoaderFactory.class,
            ClassLoaderUtils.getPreferredSpiClassLoader(PipelineLoaderFactory.class));
        for (PipelineLoaderFactory factory : loader) {
            final String name = factory.getName();
            final PipelineLoaderFactory existing = factories.put(name, factory);
            if (existing != null) {
                throw new IllegalStateException(String.format("Pipeline loader '%s' is already registered with class '%s'", name, existing.getClass().getName()));
            }
        }

        // first, register preferred format providers in the order of preference
        for (String pipelineFormat : pipelineFormats) {
            final PipelineLoaderFactory provider = factories.remove(pipelineFormat);
            if (provider != null) {
                registry.put(pipelineFormat, provider);
            } else {
                log.warn("No pipeline format provider for '{}'", pipelineFormat);
            }
        }
        // then add the rest
        registry.putAll(factories);
    }

    public PipelineLoaderFactory get(ReaderBackend backend) throws IOException {
        if (registry.isEmpty()) {
            throw new IllegalStateException("No pipeline factory is available");
        }
        for (Map.Entry entry : registry.entrySet()) {
            final PipelineLoaderFactory factory = entry.getValue();
            final String rootResource = factory.getRootResource();
            if (backend.exists(rootResource)) {
                return factory;
            }
        }
        throw new IOException(String.format("None of %d available pipeline factories %s can read this mojo.", registry.size(), registry.keySet()));
    }

    /**
     * The global service to provide pipeline service.
     * @see MojoPipelineService
     */
    public static MojoPipelineService INSTANCE = new MojoPipelineService(Consts.getSysProp("pipelineFormats", "pbuf,toml,klime,h2o3").split(","));

    private static ReaderBackend autodetectBackend(File file) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException(file.getAbsolutePath());
        } else if (file.isDirectory()) {
            return DirReaderBackend.open(file);
        } else if (file.isFile()) {
            return ZipFileReaderBackend.open(file);
        } else {
            throw new IOException("Unsupported file type: " + file.getAbsolutePath());
        }
    }

    /**
     * Loads {@link MojoPipeline pipeline} from a file.
     * @param file the file or directory containing pipeline resources
     * @param config -
     * @return pipeline
     */
    public static MojoPipeline loadPipeline(File file, final PipelineConfig config) throws IOException, LicenseException {
        final ReaderBackend backend = autodetectBackend(file);
        return loadPipeline(backend, config);
    }

    /**
     * @deprecated use {@link #loadPipeline(File, PipelineConfig)} instead
     */
    @Deprecated
    public static MojoPipeline loadPipeline(File file) throws IOException, LicenseException {
        return loadPipeline(file, PipelineConfig.DEFAULT);
    }

    /**
     * Loads {@link MojoPipeline pipeline} from a backend.
     * @param backend the backend providing access to pipeline resources
     * @return pipeline
     */
    public static MojoPipeline loadPipeline(ReaderBackend backend, final PipelineConfig config) throws IOException, LicenseException {
        final PipelineLoaderFactory loaderFactory = INSTANCE.get(backend);
        final PipelineLoader loader = loaderFactory.createLoader(backend, null, config);
        try {
            // This check is to ensure that h2o implementations are always protected against simple overriding (and avoiding AccessManager check)
            // It will fail only in our CI; customer will never experience it.
            final Method method = loader.getClass().getMethod("load");
            final int modifiers = method.getModifiers();
            if (!Modifier.isFinal(modifiers)) {
                throw new IllegalStateException(String.format("Internal error: Method %s#%s() is required to be declared final", loader.getClass().getName(), method.getName()));
            }
            // In future, we might also want detect if AccessManager was used during call to load.
            return loader.load();
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * @deprecated use {@link #loadPipeline(ReaderBackend, PipelineConfig)} instead
     */
    @Deprecated
    public static MojoPipeline loadPipeline(ReaderBackend backend) throws IOException, LicenseException {
        return loadPipeline(backend, PipelineConfig.DEFAULT);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy