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

org.kevoree.MavenRuntimeService Maven / Gradle / Ivy

package org.kevoree;

import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
import org.kevoree.api.ChannelContext;
import org.kevoree.api.ChannelContextImpl;
import org.kevoree.api.Context;
import org.kevoree.api.InstanceContext;
import org.kevoree.core.KevoreeCore;
import org.kevoree.log.Log;
import org.kevoree.modeling.api.KMFContainer;
import org.kevoree.reflect.Injector;
import org.kevoree.resolver.MavenResolver;
import org.kevoree.resolver.MavenResolverException;
import org.kevoree.service.ContextAwareModelServiceAdapter;
import org.kevoree.service.ModelService;
import org.kevoree.service.RuntimeService;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * Created by leiko on 6/7/17.
 */
public class MavenRuntimeService implements RuntimeService {

    private static final URL[] URL_ARRAY = new URL[] {};

    private KevoreeCore core;
    private Injector injector;
    private Map classLoaders;
    private MavenResolver resolver;

    public MavenRuntimeService(KevoreeCore core, Injector injector) throws MavenResolverException {
        this.core = core;
        this.injector = injector;
        this.classLoaders = new HashMap<>();
        this.resolver = new MavenResolver.Builder().build();
    }

    @Override
    public ClassLoader get(String key) {
        return this.classLoaders.get(key);
    }

    @Override
    public ClassLoader get(DeployUnit du) {
        return this.classLoaders.get(du.getUrl());
    }

    @Override
    public ClassLoader installDeployUnit(DeployUnit du) throws KevoreeCoreException {
        Value kevVersion = du.findFiltersByID("kevoree_version");
        if (kevVersion == null || kevVersion.getValue() == null) {
            throw new KevoreeCoreException("DeployUnit " + du.getName() + ":" + du.getVersion() + " is incompatible with current runtime v" + core.getFactory().getVersion());
        } else if (!kevVersion.getValue().equals(core.getFactory().getVersion())) {
            throw new KevoreeCoreException("DeployUnit " + du.getName() + ":" + du.getVersion() + " targets v" + kevVersion.getValue() + " which is incompatible with current runtime v" + core.getFactory().getVersion());
        }

        final String KEVOREE_API_ARTIFACT = "org" + File.separator + "kevoree" + File.separator + "org.kevoree.api" + File.separator + "org.kevoree.api-" + core.getFactory().getVersion() + ".jar";
        final List repos = new ArrayList<>();
        getRepositories(du)
                .forEach((id, url) -> repos.add(new RemoteRepository.Builder(id, "default", url).build()));

        ClassLoader classLoader = this.classLoaders.get(du.getUrl());

        if (classLoader != null) {
            return classLoader;
        }

        try {
            Log.info("Resolving ............. {}", du.getUrl());
            long before = System.currentTimeMillis();
            PreorderNodeListGenerator nlg = resolver
                    .resolve(du.getUrl(), repos);
            Log.info("Resolved in {}ms", (System.currentTimeMillis() - before));

            URL[] jars = nlg.getFiles()
                    .stream()
                    .map(f -> {
                        try {
                            return f.toURI().toURL();
                        } catch (MalformedURLException e) {
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .filter(f -> !f.toString().endsWith(KEVOREE_API_ARTIFACT))
                    .collect(Collectors.toList()).toArray(URL_ARRAY);

            Log.trace("ClassLoader content for {}:{}:", du.getName(), du.getVersion());
            for (URL url : jars) {
                Log.trace(" - {}", url.toString());
            }

            classLoader = new URLClassLoader(jars, core.getClass().getClassLoader());
            this.classLoaders.put(du.getUrl(), classLoader);
            return classLoader;
        } catch (MavenResolverException e) {
            throw new KevoreeCoreException("Unable to resolve DeployUnit " + du.getName() + ":" + du.getVersion(), e);
        }
    }

    @Override
    public ClassLoader installTypeDefinition(Instance instance) throws KevoreeCoreException {
        TypeDefinition td = instance.getTypeDefinition();
        DeployUnit du = validateFilters(instance, td.select("deployUnits[]/filters[name=platform,value=java]"));
        return installDeployUnit(du);
    }

    @Override
    public void removeDeployUnit(DeployUnit du) {

    }

    @Override
    public  T getService(Class serviceClass) {
        return this.injector.get(serviceClass);
    }

    @Override
    public synchronized Object createInstance(final Instance instance, final ClassLoader classLoader)
            throws KevoreeCoreException {
        final DeployUnit du = getJavaDeployUnit(instance);
        try {
            final String mainClassName = searchMainClassName(instance);
            final Class clazz = classLoader.loadClass(mainClassName);
            final Object newInstance = clazz.newInstance();

            final InstanceContext instanceContext = new InstanceContext(instance.path(), core.getNodeName(), instance.getName());
            injector.register(Context.class, instanceContext);
            injector.register(ModelService.class, new ContextAwareModelServiceAdapter(core, instance.path()));
            // TODO there should be a GroupContext also that gives attached nodes etc..
            injector.register(ChannelContext.class, new ChannelContextImpl(instanceContext));
            injector.inject(newInstance);

            return newInstance;
        } catch (NoClassDefFoundError e) {
            throw new KevoreeCoreException("@KevoreeInject failed (is " + du.getName() + ":" + du.getVersion() + ":"+du.getHashcode().substring(0, 6)+" up-to-date?)", e);
        } catch (Throwable e) {
            throw new KevoreeCoreException("Unable to create instance " + instance.getName(), e);
        }
    }

    private DeployUnit getJavaDeployUnit(Instance instance) {
        TypeDefinition tdef = instance.getTypeDefinition();
        if (tdef != null) {
            return tdef.getDeployUnits().stream().filter(du -> {
                Value filter = du.findFiltersByID("platform");
                return filter != null && filter.getValue() != null && filter.getValue().equals("java");
            }).findFirst().orElse(null);
        }
        return null;
    }

    private String searchMainClassName(final Instance instance) throws KevoreeCoreException {
        TypeDefinition td = instance.getTypeDefinition();
        DeployUnit du = validateFilters(instance, td.select("deployUnits[]/filters[name=platform,value=java]"));
        String tag = "class:" + td.getName() + ":" + td.getVersion();
        Value tdefClassName = du.findFiltersByID(tag);
        if (tdefClassName != null) {
            return tdefClassName.getValue();
        } else {
            throw new RuntimeException("Cannot find meta-data \"" + tag + "\" in DeployUnit " + du.getHashcode() + "/" + du.getName() + "/" + du.getVersion());
        }
    }

    private DeployUnit validateFilters(Instance instance, List filters) throws KevoreeCoreException {
        if (filters.isEmpty()) {
            throw new KevoreeCoreException("Instance " + instance2fqn(instance) + " has no DeployUnit for \"java\" platform");
        } else if (filters.size() > 1) {
            StringBuilder filtersStr = new StringBuilder();
            for (int i=0; i < filters.size(); i++) {
                filtersStr.append(filters.get(i).eContainer().path());
                if (i < filters.size() - 1) {
                    filtersStr.append(", ");
                }
            }
            throw new RuntimeException("Instance " + instance2fqn(instance) + " has " + filters.size() + " deployUnits ("+filtersStr+") that matches platform \"java\" (must only be one)");
        }

        return (DeployUnit) filters.get(0).eContainer();
    }

    private Map getRepositories(DeployUnit deployUnit) {
        Map repositories = new HashMap<>();
        // hacky way to treat Maven repositories as I don't want to change the Kevoree MM
        for (Value val : deployUnit.getFilters()) {
            if (val.getName().startsWith("repo_")) {
                repositories.put(val.getName().substring(5), val.getValue());
            }
        }

        return repositories;
    }

    private String instance2fqn(Instance instance) {
        if (instance instanceof ContainerNode || instance instanceof Group || instance instanceof Channel) {
            return instance.getName() + ": " + instance.getTypeDefinition().getName() + "/" + instance.getTypeDefinition().getVersion();
        } else {
            return ((NamedElement) instance.eContainer()).getName() + "." + instance.getName() + ": " + instance.getTypeDefinition().getName() + "/" + instance.getTypeDefinition().getVersion();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy