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

org.kie.api.internal.utils.ServiceDiscoveryImpl Maven / Gradle / Ivy

Go to download

The Kogito public API which is backwards compatible between releases.

There is a newer version: 10.0.0
Show newest version
/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *      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.kie.api.internal.utils;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ServiceDiscoveryImpl {
    private static final Logger log = LoggerFactory.getLogger( ServiceDiscoveryImpl.class );

    private final String fileName = "kie.conf";

    private final String path =  "META-INF/" + fileName;

    private ClassLoader classloader;

    private ServiceDiscoveryImpl() {}

    private static class LazyHolder {
        static final ServiceDiscoveryImpl INSTANCE = new ServiceDiscoveryImpl();
    }

    public static ServiceDiscoveryImpl getInstance() {
        return LazyHolder.INSTANCE;
    }

    private Map     services   = new HashMap<>();
    private Map>    childServices = new HashMap<>();
    private boolean                 sealed     = false;
    private boolean                 kiecConfDiscoveryAllowed = true;
    private Map     cachedServices = new HashMap();

    public synchronized boolean isKiecConfDiscoveryAllowed() {
        return kiecConfDiscoveryAllowed;
    }

    public synchronized void setKiecConfDiscoveryAllowed(boolean kiecConfDiscoveryAllowed) {
        this.kiecConfDiscoveryAllowed = kiecConfDiscoveryAllowed;
    }

    public  void addService(Class serviceClass, T service) {
        addService( serviceClass.getCanonicalName(), service );
    }

    public synchronized void addService(String serviceName, Object object) {
        if (!sealed) {
            cachedServices.put(serviceName, object);
        } else {
            throw new IllegalStateException("Unable to add service '" + serviceName + "'. Services cannot be added once the ServiceDiscoverys is sealed");
        }
    }

    public synchronized void reset() {
        cachedServices = new HashMap();
        sealed = false;
    }

    public synchronized Map getServices() {
        if (!sealed) {
            if (kiecConfDiscoveryAllowed) {
                Enumeration confResources = null;
                try {
                    confResources = getClassLoader().getResources(path);
                } catch (Exception e) {
                    throw new IllegalStateException("Discovery started, but no kie.conf's found");
                }
                if (confResources != null) {
                    while (confResources.hasMoreElements()) {
                        registerConfs( getClassLoader(), confResources.nextElement() );
                    }
                }
                buildMap();
            }

            cachedServices = Collections.unmodifiableMap( cachedServices );
            sealed = true;
        }
        return cachedServices;
    }

    public void registerConfs( ClassLoader classLoader, URL url ) {
        log.debug("Loading kie.conf from  " + url + " in classloader " + classLoader);

        try ( BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream())) ) {
            for (String line = br.readLine(); line != null; line = br.readLine()) {
                // DROOLS-2122: parsing with Properties.load a Drools version 6 kie.conf, hence skipping this entry
                if (line.contains( "=" ) && !line.contains( "[" )) {
                    String[] entry = line.split( "=" );
                    processKieService( classLoader, entry[0].trim(), entry[1].trim() );
                }
            }
        } catch (Exception exc) {
            throw new RuntimeException( "Unable to build kie service url = " + url.toExternalForm(), exc );
        }
    }

    private void processKieService(ClassLoader classLoader, String key, String values) {
        for (String value : values.split( "," )) {
            boolean optional = key.startsWith( "?" );
            String serviceName = optional ? key.substring( 1 ) : key;
            try {
                if ( value.startsWith( "+" ) ) {
                    childServices.computeIfAbsent( serviceName, k -> new ArrayList<>() )
                            .add( newInstance( classLoader, value.substring( 1 ) ) );
                } else {
                    services.put( serviceName, newInstance( classLoader, value ) );
                }
            } catch (RuntimeException e) {
                if (optional) {
                    log.info("Cannot load service: " + serviceName);
                } else {
                    System.out.println("Loading failed because " + e.getMessage());
                    throw e;
                }
            }
            log.debug( "Adding Service {}\n", value );
        }
    }

    @FunctionalInterface
    private interface ServiceProcessor {
        boolean process(ClassLoader classLoader, String key, String value);
    }

    private  T newInstance( ClassLoader classLoader, String className ) {
        try {
            return (T) Class.forName( className, true, classLoader ).newInstance();
        } catch (Throwable t) {
            throw new RuntimeException( "Cannot create instance of class: " + className, t );
        }
    }

    private ClassLoader getClassLoader() {
        if (classloader == null) {
            classloader = Thread.currentThread().getContextClassLoader();
            if (classloader == null) {
                classloader = ClassLoader.getSystemClassLoader();
            }
        }
        return classloader;
    }

    private void buildMap() {
        for (Map.Entry serviceEntry : services.entrySet()) {
            cachedServices.put(serviceEntry.getKey(), serviceEntry.getValue());
            List children = childServices.remove( serviceEntry.getKey() );
            if (children != null) {
                for (Object child : children) {
                    ( (Consumer) serviceEntry.getValue() ).accept( child );
                }
            }
        }

        if (!childServices.isEmpty()) {
            throw new RuntimeException("Child services " + childServices.keySet() + " have no parent");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy