Package org.rioproject.gnostic.service

Source Code of org.rioproject.gnostic.service.GnosticImpl$RuleMapWorker

/*
* Copyright to the original author or authors.
*
* 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 org.rioproject.gnostic.service;

import edu.emory.mathcs.util.classloader.URIClassLoader;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import org.drools.agent.KnowledgeAgent;
import org.drools.io.ResourceFactory;
import org.drools.io.impl.ResourceChangeScannerImpl;
import org.rioproject.associations.Association;
import org.rioproject.associations.AssociationDescriptor;
import org.rioproject.impl.associations.DefaultAssociationManagement;
import org.rioproject.associations.AssociationType;
import org.rioproject.annotation.Initialized;
import org.rioproject.annotation.Started;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.gnostic.Gnostic;
import org.rioproject.monitor.ProvisionMonitor;
import org.rioproject.resolver.Artifact;
import org.rioproject.resolver.ResolverException;
import org.rioproject.resolver.ResolverHelper;
import org.rioproject.impl.client.JiniClient;
import org.rioproject.sla.RuleMap;
import org.rioproject.impl.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* Gnostic provides support for Complex Event Processing, associating
* distributed metrics of associated services to rules that in turn
* provide decisions based on the temporal data accumulated in a knowledge base.
*
* @author Dennis Reedy
*/
public class GnosticImpl implements Gnostic {
    private KnowledgeAgent kAgent;
    //private KnowledgeBase kBase;
    private ServiceBeanContext context;
    //private ProvisionMonitor monitor;
    Future<ProvisionMonitor> monitorFuture;
    private ExecutorService execService;
    private final List<RuleMap> managedRuleMaps = new ArrayList<RuleMap>();
    private final List<RuleMap> ruleMapsInProcess = new ArrayList<RuleMap>();
    private static BlockingQueue<RuleMap> addRuleMapQ = new LinkedBlockingQueue<RuleMap>();
    private final List<RuleMapAssociationController> controllers = new ArrayList<RuleMapAssociationController>();
    private static final Logger logger = LoggerFactory.getLogger(Gnostic.class.getName());
    private final AtomicBoolean droolsInitialized = new AtomicBoolean(false);

    /*
     * Set the configuration and wire up the Monitor association.
     */
    @SuppressWarnings("unused")
    public void setServiceBeanContext(ServiceBeanContext context) {
        this.context = context;
        DefaultAssociationManagement associationMgmt =
            (DefaultAssociationManagement) context.getAssociationManagement();
        boolean createCoreAssociations = true;
        String s = (String)context.getInitParameter("create-core-associations");
        if(s!=null && s.equals("no"))
            createCoreAssociations = false;
        if(createCoreAssociations) {
            AssociationDescriptor monitor =
                createAssociationDescriptor("Monitor", context.getServiceBeanConfig().getGroups());
            Association<ProvisionMonitor> monitorAssociation = associationMgmt.addAssociationDescriptor(monitor);
            monitorFuture = monitorAssociation.getServiceFuture();
        }
    }

    @Initialized
    @SuppressWarnings({"unchecked", "unused"})
    public void setupDrools() {
        try {
            execService = Executors.newSingleThreadExecutor();
            execService.submit(new RuleMapWorker());
            int scannerInterval = 60;
            try {
                scannerInterval =(Integer) context.getConfiguration().getEntry("org.rioproject.gnostic",
                                                                               "scannerInterval",
                                                                               int.class,
                                                                               scannerInterval);
            } catch (ConfigurationException e) {
                logger.warn("Non-fatal error, unable to obtain scannerInterval from configuration, defaulting to 30 seconds",
                           e);
            }
            kAgent = DroolsFactory.createKnowledgeAgent(scannerInterval);
        } finally {
            droolsInitialized.set(true);
        }
        List<RuleMap> ruleMappings = context.getServiceElement().getRuleMaps();
        List<RuleMap> otherMappings = null;
        try {
            /* Add from configuration as well? */
            Configuration config = context.getConfiguration();
            otherMappings = (List<RuleMap>)config.getEntry("org.rioproject.gnostic",
                                                           "ruleMappings",
                                                           List.class,
                                                           null);
        } catch(ConfigurationException e) {
            logger.warn("Non-fatal error, unable to obtain ruleMappings from configuration", e);
        }
        if(otherMappings!=null)
            ruleMappings.addAll(otherMappings);
        if(ruleMappings!=null) {
            for(RuleMap ruleMap : ruleMappings) {
                add(ruleMap);
            }
        }

    }

    @Started
    @SuppressWarnings("unused")
    public void started() {
        logger.info("{}: started [{}]",
                    context.getServiceBeanConfig().getName(), JiniClient.getDiscoveryAttributes(context));
    }

    private void checkDroolsHasInitialized() {
        long t0 = System.currentTimeMillis();
        while(!droolsInitialized.get()) {
            logger.info("Waiting for Drools to initialize ... {}", (System.currentTimeMillis()-t0));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                logger.warn("Interrupted while waiting for Drools to initialize", e);
            }
        }
    }

    public int getScannerInterval() {
        checkDroolsHasInitialized();
        return ((ResourceChangeScannerImpl)ResourceFactory.getResourceChangeScannerService()).getInterval();
    }

    public void setScannerInterval(int interval) {
        if(interval<=0)
            throw new IllegalArgumentException("The scannerInterval must be > 0");
        checkDroolsHasInitialized();
        ResourceFactory.getResourceChangeScannerService().setInterval(interval);
    }

    public boolean add(RuleMap ruleMap) {
        checkDroolsHasInitialized();
        verify(ruleMap);
        synchronized(managedRuleMaps) {
            if(managedRuleMaps.contains(ruleMap))
                return false;
        }
        synchronized(ruleMapsInProcess) {
            if(ruleMapsInProcess.contains(ruleMap)) {
                return false;
            }
            ruleMapsInProcess.add(ruleMap);
        }
        logger.info("Adding {}", ruleMap);
        addRuleMapQ.add(ruleMap);
        return true;
    }

    public boolean remove(RuleMap ruleMap) {
        verify(ruleMap);
        synchronized(managedRuleMaps) {
            if(!managedRuleMaps.contains(ruleMap)) {
                logger.debug("RuleMap not found in collection of managed RuleMaps. {}", ruleMap);
                return false;
            }
        }       
        RuleMapAssociationController controller = null;
        synchronized(controllers) {
            for(RuleMapAssociationController c : controllers) {
                if(c.getRuleMap().equals(ruleMap)) {
                    controller = c;
                    break;
                }
            }
        }
        boolean removed = false;
        if(controller!=null) {
            controller.close();
            synchronized(controllers) {
                removed = controllers.remove(controller);
            }
            synchronized(managedRuleMaps) {
                managedRuleMaps.remove(ruleMap);
            }
            logger.info("Removed {}", ruleMap);
        } else {
            logger.debug("RuleMap not managed by any controllers. {}", ruleMap);
        }
        return removed;
    }

    public List<RuleMap> get() {
        List<RuleMap> ruleMaps;
        synchronized(managedRuleMaps) {
            ruleMaps = Collections.unmodifiableList(managedRuleMaps);
        }
        return ruleMaps;
    }

    private void verify(RuleMap ruleMap) {
        if(ruleMap==null)
            throw new IllegalArgumentException("ruleMap is null");
        if(ruleMap.getRuleDefinition()==null)
            throw new IllegalArgumentException("ruleMap has null rules");
        if(ruleMap.getRuleDefinition()==null)
            throw new IllegalArgumentException("ruleMap has no rules");
        if(ruleMap.getServiceDefinitions()==null)
            throw new IllegalArgumentException("ruleMap has null services");
        if(ruleMap.getServiceDefinitions().size()==0)
            throw new IllegalArgumentException("ruleMap has no services");
    }

    @PreDestroy
    @SuppressWarnings("unused")
    public void cleanup() {
        logger.info("Gnostic shutting down");
        try {
            context.getAssociationManagement().terminate();
            ResourceFactory.getResourceChangeNotifierService().stop();
            ResourceFactory.getResourceChangeScannerService().stop();
            if(execService!=null)
                execService.shutdownNow();
            for (RuleMapAssociationController controller : controllers) {
                controller.close();
            }
        } catch(Throwable t) {
            t.printStackTrace();
        } finally {
            logger.info("Gnostic shutdown complete");
        }
    }

    private AssociationDescriptor createAssociationDescriptor(String name, String[] groups) {
        /*
         * Create the Association as a REQUIRES, we always require these associations
         * to be resolved. If for some reason we do not resolve these associations,
         * this service will never be advertised.
         */
        AssociationDescriptor ad = new AssociationDescriptor(AssociationType.REQUIRES, name);
        ad.setInterfaceNames(ProvisionMonitor.class.getName());
        //ad.setPropertyName("service");
        ad.setGroups(groups);
        ad.setMatchOnName(false);
        return ad;
    }

    class RuleMapWorker implements Runnable {
        ProvisionMonitor monitor;

        public void run() {
            while (true) {
                waitForMonitor();
                RuleMap ruleMap;
                try {
                    ruleMap = addRuleMapQ.take();
                } catch (InterruptedException e) {
                    logger.debug("RuleMapWorker breaking out of main loop");
                    break;
                }
                if (ruleMap != null) {
                    RuleMapAssociationController controller;
                    ClassLoader ruleLoader;
                    ClassLoader currentCL = null;
                    try {
                        ruleLoader = getRuleClassLoader(ruleMap);
                        if(ruleLoader!=null) {
                            currentCL = Thread.currentThread().getContextClassLoader();
                            Thread.currentThread().setContextClassLoader(ruleLoader);
                        }
                        controller = new RuleMapAssociationController(ruleMap,
                                                                      kAgent,
                                                                      //kBase,
                                                                      monitor,
                                                                      context.getServiceBeanConfig().getGroups(),
                                                                      ruleLoader);
                        controller.addRuleMapListener(new RuleMapNotificationListener());
                        controllers.add(controller);
                        controller.process();
                    } catch (ResolverException e) {
                        logger.warn("Unable to provision artifact [{}] for RuleMap {}",
                                   ruleMap.getRuleDefinition().getRuleClassPath(), ruleMap, e);
                    } catch (MalformedURLException e) {
                        logger.warn("Unable to create URL from rule classpath [{}], cannot set classpath for rule classpath jars",
                                   ruleMap.getRuleDefinition().getRuleClassPath(), e);
                    } catch (URISyntaxException e) {
                        logger.warn("Unable to create URI from rule classpath [{}], cannot set classpath for rule classpath jars",
                                    ruleMap.getRuleDefinition().getRuleClassPath(), e);
                    } catch (IllegalArgumentException e) {
                        logger.warn("Unable to create RuleMapAssociationController", e);
                    } finally {
                        if(currentCL!=null)
                            Thread.currentThread().setContextClassLoader(currentCL);
                    }
                }
            }
        }

        private void waitForMonitor() {
            if (monitor == null) {
                try {
                    monitor = monitorFuture.get(30, TimeUnit.SECONDS);
                } catch (Exception e) {
                    logger.warn("Problem waiting for the ProvisionMonitor", e);
                }
            }
        }

        private ClassLoader getRuleClassLoader(RuleMap ruleMap) throws
                                                                ResolverException,
                                                                MalformedURLException,
                                                                URISyntaxException {
            String ruleClassPath = ruleMap.getRuleDefinition().getRuleClassPath();
            if (ruleClassPath != null) {
                String[] classPath;
                if (Artifact.isArtifact(ruleClassPath)) {
                    String[] cp = ResolverHelper.getResolver().getClassPathFor(ruleClassPath,
                                                                               context.getServiceElement().getRemoteRepositories());
                    classPath = new String[cp.length];
                    for (int i = 0; i < classPath.length; i++) {
                        String s =
                            cp[i].startsWith("file:") ? cp[i] : "file:" + cp[i];
                        classPath[i] = ResolverHelper.handleWindows(s);
                    }
                    if(logger.isDebugEnabled()) {
                        StringBuilder sb = new StringBuilder();
                        for(String s : classPath) {
                            if(sb.length()>0)
                                sb.append(", ");
                            sb.append(s);
                        }
                        logger.debug("Resolved classpath for rule artifact [{}]: {}", ruleClassPath, sb.toString());
                    }
                } else {
                    classPath = StringUtil.toArray(ruleClassPath, " ,");
                }
                URI[] uris = new URI[classPath.length];
                for (int i = 0; i < classPath.length; i++) {
                    uris[i] = new URL(classPath[i]).toURI();
                }

                return new RulesClassLoader(new URIClassLoader(uris,
                                                               Thread.currentThread().getContextClassLoader()));
            } else {
                return null;
            }
        }

    }

    class RuleMapNotificationListener implements RuleMapListener {

        public void added(RuleMap ruleMap) {
            synchronized(managedRuleMaps) {
                managedRuleMaps.add(ruleMap);
            }
            remove(ruleMap);
            logger.info("Added {}", ruleMap);
        }

        public void failed(RuleMap ruleMap) {
            logger.info("Failed to add {}", ruleMap);
            remove(ruleMap);
        }

        private void remove(RuleMap ruleMap) {
            synchronized(ruleMapsInProcess) {
                ruleMapsInProcess.remove(ruleMap);
            }
        }
    }

    class RulesClassLoader extends ClassLoader /*implements DroolsClassLoader*/ {

        RulesClassLoader(ClassLoader parent) {
            super(parent);
        }

        public InputStream getResourceAsStream(String name) {
            return getParent().getResourceAsStream(name);
        }

        /*public Class<?> fastFindClass(String name) {
            Class<?> cl = null;
            try {
                cl = loadClass(name, false);
            } catch (ClassNotFoundException e) {
                //
            }
            return cl;
        }*/

        public Class<?> loadClass(String name, boolean resolve) throws
                                                                ClassNotFoundException {
            Class<?> cl = null;
            try {
                cl = Class.forName(name, true, getParent());
            } catch(ClassNotFoundException e) {
                //
            }
            return cl;
        }
    }

}
TOP

Related Classes of org.rioproject.gnostic.service.GnosticImpl$RuleMapWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
script>