Package org.drools.io

Source Code of org.drools.io.RuleBaseLoader$ObjectInputStreamWithLoader

package org.drools.io;

/*
* $Id: RuleBaseLoader.java,v 1.11 2006/01/13 07:26:55 michaelneale Exp $
*
* Copyright 2001-2003 (C) The Werken Company. All Rights Reserved.
*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name "drools" must not be used to endorse or promote products derived
* from this Software without prior written permission of The Werken Company.
* For written permission, please contact bob@werken.com.
*
* 4. Products derived from this Software may not be called "drools" nor may
* "drools" appear in their names without prior written permission of The Werken
* Company. "drools" is a trademark of The Werken Company.
*
* 5. Due credit should be given to The Werken Company. (http://werken.com/)
*
* THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE WERKEN COMPANY OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.Reader;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import org.drools.IntegrationException;
import org.drools.RuleBase;
import org.drools.RuleBaseBuilder;
import org.drools.conflict.DefaultConflictResolver;
import org.drools.rule.RuleSet;
import org.drools.smf.RuleSetCompiler;
import org.drools.spi.ConflictResolver;
import org.xml.sax.SAXException;


/**
* Convenience methods for loading a <code>RuleBase</code>, as well as lower level calls
* for building up a rule base from RuleSets.
*
* Note that the loadXXX static helper methods work directly off DRL, building/compiling behind the scenes.
* The addXXX methods generally work with pre compiled rules binaries (DDJ's as they are known).
*
*
*
* <p>
* The <code>RuleBaseLoader</code> provides convenience methods for loading
* <code>RuleBase</code> s from streams. <code>RuleBaseLoader</code> is
* thread-safe and as such may be used to build multiple <code>RuleBase</code> s
* simultaneously by multiple threads.
* </p>
*
* @see RuleSet
* @see RuleBase
* @see RuleSetReader
* @see RuleBaseBuilder
* @see SerializableRuleBaseProxy
*
* @author <a href="mailto:bob@werken.com">bob mcwhirter </a>
* TODO: Move static helper methods into a different class.
*/
public final class RuleBaseLoader
{

    private RuleBaseBuilder builder = new RuleBaseBuilder();

    private List ruleSetBinaries = new ArrayList();
   
   
    /**
     * Default constructor
     */
    public RuleBaseLoader()
    {
        this( DefaultConflictResolver.getInstance() );
    }

    /**
     * Default constructor
     */
    public RuleBaseLoader(ConflictResolver resolver)
    {
        this.builder.setConflictResolver( resolver );
    }

    /**
     * Loads a RuleBase using several URLs, using the DefaultConflictResolver.
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromUrl(URL[] url, ConflictResolver resolver) passing the
     * DefaultConflictResolver
     *
     * @param urls
     * @return RuleBase
     */
    public void addFromRuleSetLoader(RuleSetLoader[] ruleSetLoaders) throws SAXException,
                                                                    IOException,
                                                                    IntegrationException
    {
        for ( int i = 0; i < ruleSetLoaders.length; i++ )
        {
            addFromRuleSetLoader( ruleSetLoaders[i] );
        }
    }

    /**
     * Adds to the rulebase from a RuleSetLoader instance.
     * The binaries from the ruleset loader will be kept for serialization purposes.
     */
    public void addFromRuleSetLoader(RuleSetLoader ruleSetLoader) throws SAXException,
                                                                 IOException,
                                                                 IntegrationException
    {       
        Map map = ruleSetLoader.getRuleSets();
        Iterator it = map.values().iterator();
        RuleSet[] ruleSets = new RuleSet[map.size()];
        int i = 0;
        while ( it.hasNext() )
        {
            RuleSetCompiler compiler = (RuleSetCompiler) it.next();
            ruleSets[i] = (compiler).getRuleSet();
            addRuleSetBinary(compiler.getBinaryDeploymentJar());
            i++;
        }
        addFromRuleSet( ruleSets );
    }

    /**
     * Loads a RuleBase from several URLS, merging them and using the specified
     * ConflictResolver. URLS should be either to compiled DDJ rules, or a configuration file
     * which indicates where to find the DDJs.
     *
     * @param urls
     * @param resolver
     * @return RuleBase
     */
    public void addFromUrl(URL[] urls) throws SAXException,
                                      IOException,
                                      IntegrationException
    {
        for ( int i = 0; i < urls.length; i++ )
        {
            addFromUrl( urls[i] );
        }
    }

    /**
     * Loads a RuleBase from a URL using the given ConflictResolver
     * The URL must be to a DDJ compiled resource, or a conf file pointing to
     * the DDJ compiled rules.
     * If you do not use pre compiled rulesets, use one of the static helper methods instead.
     * @param url
     * @param resolver
     * @return RuleBase
     */
    public void addFromUrl(URL url) throws SAXException,
                                   IOException,
                                   IntegrationException
    {
        if ( url.toExternalForm().toLowerCase().endsWith( ".ddj" ) )
        {
            addFromDDJInputStream(url.openStream());
            //its url to drools deployment jar
            //addFromRuleSet( getRuleSet(url) );
        }
        else
        {
            // the url should reference a RuleBase coniguration text file
            // which contains a list of URLs to .ddj files or to more RuleBase
            // configurations
            InputStream config = url.openStream();
            BufferedReader in = new BufferedReader( new InputStreamReader( config ) );
            try
            {
                String line;

                while ( (line = in.readLine( )) != null )
                {
                    line = line.trim( );

                    if ( line.equals( "" ) || line.startsWith( "#" ) )
                    {
                        continue;
                    }

                    addFromUrl( new URL(line) );
                }
            }
            finally
            {
                in.close( );
            }
        }
    }
   
    /** This will add multiple rulesets. Bytes should be for DDJ compiled rules
     *
     * @param bytes
     * @throws IntegrationException
     * @throws IOException
     * @throws SAXException
     */
    public void addFromByteArray(byte[][] bytes) throws IntegrationException, IOException, SAXException
    {
        for(int i = 0; i < bytes.length; i++)
        {
            addFromByteArray(bytes[i]);
        }
    }
   
   

   
    /**
     * Creates a JarInputStream and defines each .class in custom classLoader
     * The RuleSet is serialised out using the custom classLoader
     * Loads a ruleset from the DDJ bytes.
     * @param bytes
     * @throws IOException
     * @throws IntegrationException
     * @throws SAXException
     */   
    public void addFromByteArray(byte[] bytes)throws IOException,
    IntegrationException, SAXException {
       
        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
        addFromDDJInputStream(stream);
    }
   
    /**
     * The input stream here should be to a DDJ compiled rules "jar" only.
     * NOT source.
     */
    private void addFromDDJInputStream(InputStream jarInputStream) throws IOException,
        IntegrationException, SAXException
    {
        JarInputStream jos = new JarInputStream( jarInputStream );
       
        Map functions = new HashMap();
        Map others = new HashMap();
        Map invokers = new HashMap();
       
        ByteArrayClassLoader classLoader = new ByteArrayClassLoader(Thread.currentThread().getContextClassLoader());
       
        byte[] ruleSetBytes = null;
        for ( JarEntry entry = jos.getNextJarEntry( ); entry != null; entry = jos.getNextJarEntry( ) )
        {
            String name = entry.getName();           
            if ( !name.endsWith(".conf") )
            {
                //We should only read in .class files and the serialised RuleSet
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] data = new byte[1024];
                int byteCount;
                while ( (byteCount = jos.read( data,
                                     0,
                                     1024 )) > -1 )
                {                   
                    bos.write(data, 0, byteCount);
                }
               
                if ( name.endsWith( ".class") )
                {
                    //We need to add to the classloader in a certain order...
                    name = entry.getName().replace('/', '.').substring(0, name.length() - 6);
                    if (name.indexOf("Invoker") > 0) {
                        invokers.put(name, bos.toByteArray());
                    } else if (name.indexOf("Function_") > 0) {
                        functions.put(name, bos.toByteArray());
                    } else {
                        others.put(name, bos.toByteArray());
                    }
                  
                }
                else
                {
                    ruleSetBytes = bos.toByteArray();
                }
            }    
       
        }
       
        addToClassLoader(functions, classLoader);
        addToClassLoader(others, classLoader);
        addToClassLoader(invokers, classLoader);
       
        ByteArrayInputStream bis = new ByteArrayInputStream( ruleSetBytes );
        ObjectInput in = new ObjectInputStreamWithLoader( bis,
          
                                                          classLoader );
        addRuleSetBinary( ruleSetBytes );
        try
        {
            RuleSet ruleSet = (RuleSet) in.readObject();
            addFromRuleSet( ruleSet );
        }
        catch ( ClassNotFoundException e )
        {
            throw new IntegrationException( "Rule Set jar is not correctly formed." );
        }
        catch ( IOException e )
        {
            throw new IntegrationException( "Rule Set jar is not correctly formed." );
       
        finally
        {
            if ( bis != null )
            {
                bis.close();
            }
            if ( in != null )
            {
                in.close();
            }
        }
                       
    }

    private void addRuleSetBinary(byte[] ruleSetBytes)
    {
        this.ruleSetBinaries.add(ruleSetBytes);
    }  

   


    /**
     * this adds to the classloader.
     * @param classes
     * @param classLoader
     */
    private void addToClassLoader(Map classes,
                                  ByteArrayClassLoader classLoader)
    {
        for ( Iterator iter = classes.keySet().iterator( ); iter.hasNext( ); )
        {
            String name = (String) iter.next( );
            byte[] data = (byte[]) classes.get(name);
            classLoader.addByteArray( name, data );
           
        }
    }

    public void addFromRuleSet(RuleSet ruleSet) throws SAXException,
                                               IOException,
                                               IntegrationException
    {
        this.builder.addRuleSet( ruleSet );
    }

    public void addFromRuleSet(RuleSet[] ruleSets) throws SAXException,
                                                  IOException,
                                                  IntegrationException
    {
        for ( int i = 0; i < ruleSets.length; i++ )
        {
            addFromRuleSet( ruleSets[i] );
        }
    }
   
 
   
    /**
     * This will return a rulebase based on the added rulesets.
     * The rulebase should be serializable by default.
     * @return
     */
    public RuleBase buildRuleBase() {
       RuleBase ruleBase = this.builder.build();
       if (this.ruleSetBinaries.size() > 0) {
           SerializableRuleBaseProxy proxy = new SerializableRuleBaseProxy(ruleBase, this.ruleSetBinaries);
           return proxy;
       } else {
           return ruleBase;
       }
    }
   
    class ByteArrayClassLoader extends  ClassLoader
    {
        ByteArrayClassLoader(ClassLoader parent) {
          super(parent);
        }
        public void addByteArray(String name, byte[] bytes)
        {
            defineClass(name, bytes, 0, bytes.length);
        }
    }  

    private static class ObjectInputStreamWithLoader extends ObjectInputStream
    {
        private final ClassLoader classLoader;

        public ObjectInputStreamWithLoader(InputStream in,
                                           ClassLoader classLoader) throws IOException
        {
            super( in );
            this.classLoader = classLoader;
            enableResolveObject( true );
        }

        protected Class resolveClass(ObjectStreamClass desc) throws IOException,
                                                            ClassNotFoundException
        {
            if ( this.classLoader == null )
            {
                return super.resolveClass( desc );
            }
            else
            {
                String name = desc.getName();
                return this.classLoader.loadClass( name );
            }
        }
    }

   
    //-------------------------------------------------------
    // Added old static api methods back in for compatability
    //-------------------------------------------------------
   
    /**
     * Loads a RuleBase from a URL using the default ConflictResolver
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromUrl(URL url, ConflictResolver resolver) passing the
     * DefaultConflictResolver
     *
     *
     * @param url A URL to the DRL to compile and load.
     * @return RuleBase
     */
    public static RuleBase loadFromUrl( URL url )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromUrl( url, DefaultConflictResolver.getInstance( ) );
    }

    /**
     * Loads a RuleBase from a URL using the given ConflictResolver
     *
     * @param url
     * @param resolver
     * @return RuleBase
     */
    public static RuleBase loadFromUrl( URL url, ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromUrl( new URL[]{url}, resolver );
    }

    /**
     * Loads a RuleBase using several URLs, using the DefaultConflictResolver.
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromUrl(URL[] url, ConflictResolver resolver) passing the
     * DefaultConflictResolver
     *
     * @param urls
     * @return RuleBase
     */
    public static RuleBase loadFromUrl( URL[] urls )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromUrl( urls, DefaultConflictResolver.getInstance( ) );
    }

    /**
     * Loads a RuleBase from several URLS, merging them and using the specified
     * ConflictResolver
     *
     * @param urls
     * @param resolver
     * @return RuleBase
     */
    public static RuleBase loadFromUrl( URL[] urls, ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {             
      RuleSetLoader ruleSetLoader = new RuleSetLoader();
      ruleSetLoader.addFromUrl(urls);
     
      return buildFromLoader( resolver,
                              ruleSetLoader );     
    }

    /**
     * Loads a RuleBase from an InputStream using the default ConflictResolver
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromInputStream(InputStream in, ConflictResolver resolver) passing
     * the DefaultConflictResolver
     *
     * @param in
     * @return ruleBase
     */
    public static RuleBase loadFromInputStream( InputStream in )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromInputStream( in, DefaultConflictResolver.getInstance( ) );

    }

    /**
     * Loads a RuleBase from an InputStream using the default ConflictResolver
     *
     * @param in
     * @param resolver
     * @return ruleBase
     */
    public static RuleBase loadFromInputStream( InputStream in,
                                                ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromInputStream( new InputStream[]{in}, resolver );
    }

    /**
     * Loads a RuleBase from an InputStream using the default ConflictResolver
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromInputStream(InputStream[] ins, ConflictResolver resolver)
     * passing the DefaultConflictResolver
     *
     * @param ins
     * @return ruleBase
     */
    public static RuleBase loadFromInputStream( InputStream[] ins )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromInputStream( ins, DefaultConflictResolver.getInstance( ) );
    }

    /**
     * Loads a RuleBase from an InputStream using the default ConflictResolver
     *
     * @param ins
     * @param resolver
     * @return ruleBase
     */
    public static RuleBase loadFromInputStream( InputStream[] ins,
                                                ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {
        RuleSetLoader ruleSetLoader = new RuleSetLoader();
        ruleSetLoader.addFromInputStream(ins);
       
        return buildFromLoader( resolver,
                                  ruleSetLoader );                 
    }



    /**
     * Loads a RuleBase from a Reader using the default ConflictResolver
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromReader(Reader in, ConflictResolver resolver) passing the
     * DefaultConflictResolver
     *
     * @param in
     * @return ruleBase
     */
    public static RuleBase loadFromReader( Reader in )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromReader( in, DefaultConflictResolver.getInstance( ) );
    }

    /**
     * Loads a RuleBase from a Reader using the given ConflictResolver
     *
     * @param in
     * @param resolver
     * @return ruleBase
     */
    public static RuleBase loadFromReader( Reader in, ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromReader( new Reader[]{in}, resolver );
    }

    /**
     * Loads a RuleBase from a Reader using the default ConflictResolver
     *
     * This is a convenience method and calls public static RuleBase
     * loadFromReader(Reader[] ins, ConflictResolver resolver) passing the
     * DefaultConflictResolver
     *
     * @param ins
     * @return ruleBase
     */
    public static RuleBase loadFromReader( Reader[] ins )
        throws SAXException,
               IOException,
               IntegrationException
    {
        return loadFromReader( ins, DefaultConflictResolver.getInstance( ) );
    }

    /**
     * Loads a RuleBase from a Reader using the given ConflictResolver
     *
     * @param ins
     * @param resolver
     * @return ruleBase
     */
    public static RuleBase loadFromReader( Reader[] ins,
                                             ConflictResolver resolver )
        throws SAXException,
               IOException,
               IntegrationException
    {
        RuleSetLoader ruleSetLoader = new RuleSetLoader();
        ruleSetLoader.addFromReader(ins);
       
        return buildFromLoader( resolver,
                                  ruleSetLoader )
    }

    private static RuleBase buildFromLoader(ConflictResolver resolver,
                                              RuleSetLoader ruleSetLoader) throws SAXException,
                                                                          IOException,
                                                                          IntegrationException
    {
        RuleBaseLoader ruleBaseLoader = new RuleBaseLoader(resolver);
        ruleBaseLoader.addFromRuleSetLoader(ruleSetLoader);

        return ruleBaseLoader.buildRuleBase();
    }   

}
TOP

Related Classes of org.drools.io.RuleBaseLoader$ObjectInputStreamWithLoader

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.