Package org.drools.compiler.kie.builder.impl

Source Code of org.drools.compiler.kie.builder.impl.KieRepositoryImpl

package org.drools.compiler.kie.builder.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;

import org.drools.compiler.compiler.io.memory.MemoryFileSystem;
import org.drools.compiler.kproject.ReleaseIdImpl;
import org.drools.compiler.kproject.models.KieModuleModelImpl;
import org.drools.core.io.internal.InternalResource;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.KieRepository;
import org.kie.api.builder.KieScanner;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.io.Resource;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.utils.ServiceRegistryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.drools.compiler.kie.builder.impl.KieBuilderImpl.setDefaultsforEmptyKieModule;

public class KieRepositoryImpl
    implements
    KieRepository {
    private static final Logger        log              = LoggerFactory.getLogger( KieRepositoryImpl.class );

    private static final String        DEFAULT_VERSION  = "1.0.0-SNAPSHOT";
    private static final String        DEFAULT_ARTIFACT = "artifact";
    private static final String        DEFAULT_GROUP    = "org.default";

    public static final KieRepository  INSTANCE         = new KieRepositoryImpl();

    private final KieModuleRepo        kieModuleRepo    = new KieModuleRepo();

    private final AtomicReference<ReleaseId> defaultGAV       = new AtomicReference( new ReleaseIdImpl( DEFAULT_GROUP,
                                                                                            DEFAULT_ARTIFACT,
                                                                                            DEFAULT_VERSION ) );

    private InternalKieScanner         internalKieScanner;

    public void setDefaultGAV(ReleaseId releaseId) {
        this.defaultGAV.set(releaseId);
    }

    public ReleaseId getDefaultReleaseId() {
        return this.defaultGAV.get();
    }

    public void addKieModule(KieModule kieModule) {
        kieModuleRepo.store(kieModule);
        log.info( "KieModule was added:" + kieModule);
    }
   
    public KieModule getKieModule(ReleaseId releaseId) {
        return getKieModule(releaseId, null);
    }

    public KieModule getKieModule(ReleaseId releaseId, byte[] pomXml) {
        VersionRange versionRange = new VersionRange(releaseId.getVersion());

        KieModule kieModule = kieModuleRepo.load(releaseId, versionRange);
        if ( kieModule == null ) {
            log.debug( "KieModule Lookup. ReleaseId {} was not in cache, checking classpath",
                    releaseId.toExternalForm() );
            kieModule = checkClasspathForKieModule(releaseId);
        }

        if ( kieModule == null ) {
            log.debug( "KieModule Lookup. ReleaseId {} was not in cache, checking maven repository",
                    releaseId.toExternalForm() );
            kieModule = loadKieModuleFromMavenRepo(releaseId, pomXml);
        }

        return kieModule;
    }

    private KieModule checkClasspathForKieModule(ReleaseId releaseId) {
        // TODO
        // ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // URL url = classLoader.getResource( ((ReleaseIdImpl)releaseId).getPomPropertiesPath() );
        return null;
    }

    private KieModule loadKieModuleFromMavenRepo(ReleaseId releaseId, byte[] pomXml) {
        return pomXml != null ?
                getInternalKieScanner().loadArtifact(releaseId, new ByteArrayInputStream( pomXml ) ) :
                getInternalKieScanner().loadArtifact(releaseId);
    }

    private InternalKieScanner getInternalKieScanner() {
        if ( internalKieScanner == null ) {
            try {
                internalKieScanner = (InternalKieScanner) ServiceRegistryImpl.getInstance().get( KieScanner.class );
            } catch ( Exception e ) {
                // kie-ci is not on the classpath
                internalKieScanner = new DummyKieScanner();
            }
        }
        return internalKieScanner;
    }

    private static class DummyKieScanner
        implements
        InternalKieScanner {

        public KieModule loadArtifact(ReleaseId releaseId) {
            return null;
        }

        public void start(long pollingInterval) { }

        public void stop() { }

        public void scanNow() { }

        public void setKieContainer(KieContainer kieContainer) { }

        public KieModule loadArtifact(ReleaseId releaseId, InputStream pomXML) {
            return null;
        }
    }


    public KieModule addKieModule(Resource resource, Resource... dependencies) {
        log.info( "Adding KieModule from resource :" + resource  );
        KieModule kModule = getKieModule( resource );
       
        if ( dependencies != null && dependencies.length > 0 ) {
            for ( Resource depRes : dependencies ) {
                InternalKieModule depKModule = ( InternalKieModule ) getKieModule( depRes );
                ((InternalKieModule)kModule).addDependency(depKModule);
                log.info( "Adding KieModule dependency from resource :" + resource  );
            }
        }
        addKieModule( kModule );
        return kModule;
    }
   
    public KieModule getKieModule(Resource resource) {
        InternalResource res = (InternalResource) resource;
        try {
            KieModule kModule;
            // find kmodule.xml
            if( res.hasURL() ) {
                String urlPath = res.getURL().toExternalForm();
                if (res.isDirectory() ) {
                    if ( !urlPath.endsWith( "/" ) ) {
                        urlPath = urlPath + "/";
                    }
                    urlPath = urlPath  + KieModuleModelImpl.KMODULE_JAR_PATH;
                   
                } else {
                    urlPath = "jar:"+ urlPath  + "!/" + KieModuleModelImpl.KMODULE_JAR_PATH;             
                }
                kModule = ClasspathKieProject.fetchKModule( new URL( urlPath )  );
                log.debug( "fetched KieModule from resource :" + resource  );
            } else {
                // might be a byte[] resource
                MemoryFileSystem mfs = MemoryFileSystem.readFromJar( res.getInputStream() );
                byte[] bytes = mfs.getBytes( KieModuleModelImpl.KMODULE_JAR_PATH );
                KieModuleModel kieProject = KieModuleModelImpl.fromXML( new ByteArrayInputStream( bytes ) );
                setDefaultsforEmptyKieModule(kieProject);

                String pomProperties = mfs.findPomProperties();
                ReleaseId releaseId = ReleaseIdImpl.fromPropertiesString(pomProperties);
                kModule = new MemoryKieModule( releaseId, kieProject, mfs );
            }
            return kModule;
        } catch ( Exception e ) {
            throw new RuntimeException("Unable to fetch module from resource :" + res, e);
        }         
    }

    private static class KieModuleRepo {
        private final Map<String, TreeMap<ComparableVersion, KieModule>> kieModules = new HashMap<String, TreeMap<ComparableVersion, KieModule>>();

        void store(KieModule kieModule) {
            ReleaseId releaseId = kieModule.getReleaseId();
            String ga = releaseId.getGroupId() + ":" + releaseId.getArtifactId();

            TreeMap<ComparableVersion, KieModule> artifactMap = kieModules.get(ga);
            if (artifactMap == null) {
                artifactMap = new TreeMap<ComparableVersion, KieModule>();
                kieModules.put(ga, artifactMap);
            }
            artifactMap.put(new ComparableVersion(releaseId.getVersion()), kieModule);
        }

        KieModule load(ReleaseId releaseId, VersionRange versionRange) {
            String ga = releaseId.getGroupId() + ":" + releaseId.getArtifactId();
            TreeMap<ComparableVersion, KieModule> artifactMap = kieModules.get(ga);
            if (artifactMap == null) {
                return null;
            }

            if (versionRange.fixed) {
                return artifactMap.get(new ComparableVersion(releaseId.getVersion()));
            }

            if (versionRange.upperBound == null) {
                return artifactMap.lastEntry().getValue();
            }

            Map.Entry<ComparableVersion, KieModule> entry = versionRange.upperInclusive ?
                    artifactMap.ceilingEntry(new ComparableVersion(versionRange.upperBound)) :
                    artifactMap.lowerEntry(new ComparableVersion(versionRange.upperBound));

            if (entry == null) {
                return null;
            }

            if (versionRange.lowerBound == null) {
                return entry.getValue();
            }

            int versionComparison = entry.getKey().compareTo(new ComparableVersion(versionRange.lowerBound));
            return versionComparison > 0 || (versionComparison == 0 && versionRange.lowerInclusive) ? entry.getValue() : null;
        }
    }

    private static class VersionRange {
        private String lowerBound;
        private String upperBound;
        private boolean lowerInclusive;
        private boolean upperInclusive;
        private boolean fixed;

        private VersionRange(String version) {
            parse(version);
        }

        private void parse(String version) {
            if ("LATEST".equals(version) || "RELEASE".equals(version)) {
                fixed = false;
                lowerBound = "1.0";
                upperBound = null;
                lowerInclusive = true;
                upperInclusive = false;
                return;
            }

            if (version.charAt(0) != '(' && version.charAt(0) != '[') {
                fixed = true;
                lowerBound = version;
                upperBound = version;
                lowerInclusive = true;
                upperInclusive = true;
                return;
            }

            lowerInclusive = version.charAt(0) == '[';
            upperInclusive = version.charAt(version.length()-1) == ']';

            int commaPos = version.indexOf(',');
            if (commaPos < 0) {
                fixed = true;
                lowerBound = version.substring(1, version.length() - 1);
                upperBound = lowerBound;
            } else {
                if (commaPos > 1) {
                    lowerBound = version.substring(1, commaPos);
                }
                if (commaPos < version.length()-2) {
                    upperBound = version.substring(commaPos + 1, version.length() - 1);
                }
            }
        }
    }

    public static class ComparableVersion implements Comparable<ComparableVersion> {
        private String value;

        private String canonical;

        private ListItem items;

        private interface Item {
            final int INTEGER_ITEM = 0;
            final int STRING_ITEM = 1;
            final int LIST_ITEM = 2;

            int compareTo( Item item );

            int getType();

            boolean isNull();
        }

        private static class IntegerItem implements Item {
            private static final BigInteger BigInteger_ZERO = new BigInteger( "0" );

            private final BigInteger value;

            public static final IntegerItem ZERO = new IntegerItem();

            private IntegerItem() {
                this.value = BigInteger_ZERO;
            }

            public IntegerItem( String str ) {
                this.value = new BigInteger( str );
            }

            public int getType() {
                return INTEGER_ITEM;
            }

            public boolean isNull() {
                return BigInteger_ZERO.equals( value );
            }

            public int compareTo( Item item ) {
                if ( item == null )
                {
                    return BigInteger_ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
                }

                switch ( item.getType() )
                {
                    case INTEGER_ITEM:
                        return value.compareTo( ( (IntegerItem) item ).value );

                    case STRING_ITEM:
                        return 1; // 1.1 > 1-sp

                    case LIST_ITEM:
                        return 1; // 1.1 > 1-1

                    default:
                        throw new RuntimeException( "invalid item: " + item.getClass() );
                }
            }

            public String toString() {
                return value.toString();
            }
        }

        /**
         * Represents a string in the version item list, usually a qualifier.
         */
        private static class StringItem implements Item {
            private static final String[] QUALIFIERS = { "alpha", "beta", "milestone", "rc", "snapshot", "", "sp" };

            private static final List<String> _QUALIFIERS = Arrays.asList(QUALIFIERS);

            private static final Properties ALIASES = new Properties();

            static {
                ALIASES.put( "ga", "" );
                ALIASES.put( "final", "" );
                ALIASES.put( "cr", "rc" );
            }

            /**
             * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
             * the version older than one without a qualifier, or more recent.
             */
            private static final String RELEASE_VERSION_INDEX = String.valueOf( _QUALIFIERS.indexOf( "" ) );

            private String value;

            public StringItem( String value, boolean followedByDigit ) {
                if ( followedByDigit && value.length() == 1 ) {
                    // a1 = alpha-1, b1 = beta-1, m1 = milestone-1
                    switch ( value.charAt( 0 ) ) {
                        case 'a':
                            value = "alpha";
                            break;
                        case 'b':
                            value = "beta";
                            break;
                        case 'm':
                            value = "milestone";
                            break;
                    }
                }
                this.value = ALIASES.getProperty( value , value );
            }

            public int getType() {
                return STRING_ITEM;
            }

            public boolean isNull() {
                return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
            }

            /**
             * Returns a comparable value for a qualifier.
             *
             * This method both takes into account the ordering of known qualifiers as well as lexical ordering for unknown
             * qualifiers.
             *
             * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
             * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
             * so this is still fast. If more characters are needed then it requires a lexical sort anyway.
             *
             * @param qualifier
             * @return an equivalent value that can be used with lexical comparison
             */
            public static String comparableQualifier( String qualifier ) {
                int i = _QUALIFIERS.indexOf( qualifier );

                return i == -1 ? _QUALIFIERS.size() + "-" + qualifier : String.valueOf( i );
            }

            public int compareTo( Item item ) {
                if ( item == null ) {
                    // 1-rc < 1, 1-ga > 1
                    return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
                }
                switch ( item.getType() ) {
                    case INTEGER_ITEM:
                        return -1; // 1.any < 1.1 ?

                    case STRING_ITEM:
                        return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );

                    case LIST_ITEM:
                        return -1; // 1.any < 1-1

                    default:
                        throw new RuntimeException( "invalid item: " + item.getClass() );
                }
            }

            public String toString() {
                return value;
            }
        }

        /**
         * Represents a version list item. This class is used both for the global item list and for sub-lists (which start
         * with '-(number)' in the version specification).
         */
        private static class ListItem extends ArrayList<Item> implements Item {
            public int getType() {
                return LIST_ITEM;
            }

            public boolean isNull() {
                return ( size() == 0 );
            }

            void normalize() {
                for( ListIterator<Item> iterator = listIterator( size() ); iterator.hasPrevious(); ) {
                    Item item = iterator.previous();
                    if ( item.isNull() ) {
                        iterator.remove(); // remove null trailing items: 0, "", empty list
                    } else {
                        break;
                    }
                }
            }

            public int compareTo( Item item ) {
                if ( item == null ) {
                    if ( size() == 0 ) {
                        return 0; // 1-0 = 1- (normalize) = 1
                    }
                    Item first = get( 0 );
                    return first.compareTo( null );
                }
                switch ( item.getType() ) {
                    case INTEGER_ITEM:
                        return -1; // 1-1 < 1.0.x

                    case STRING_ITEM:
                        return 1; // 1-1 > 1-sp

                    case LIST_ITEM:
                        Iterator<Item> left = iterator();
                        Iterator<Item> right = ( (ListItem) item ).iterator();

                        while ( left.hasNext() || right.hasNext() ) {
                            Item l = left.hasNext() ? left.next() : null;
                            Item r = right.hasNext() ? right.next() : null;

                            // if this is shorter, then invert the compare and mul with -1
                            int result = l == null ? -1 * r.compareTo( l ) : l.compareTo( r );

                            if ( result != 0 ) {
                                return result;
                            }
                        }

                        return 0;

                    default:
                        throw new RuntimeException( "invalid item: " + item.getClass() );
                }
            }

            public String toString() {
                StringBuilder buffer = new StringBuilder( "(" );
                for( Iterator<Item> iter = iterator(); iter.hasNext(); )
                {
                    buffer.append( iter.next() );
                    if ( iter.hasNext() )
                    {
                        buffer.append( ',' );
                    }
                }
                buffer.append( ')' );
                return buffer.toString();
            }
        }

        public ComparableVersion( String version ) {
            parseVersion( version );
        }

        public final void parseVersion( String version ) {
            this.value = version;

            items = new ListItem();

            version = version.toLowerCase( Locale.ENGLISH );

            ListItem list = items;

            Stack<Item> stack = new Stack<Item>();
            stack.push( list );

            boolean isDigit = false;

            int startIndex = 0;

            for ( int i = 0; i < version.length(); i++ ) {
                char c = version.charAt( i );

                if ( c == '.' ) {
                    if ( i == startIndex ) {
                        list.add( IntegerItem.ZERO );
                    } else {
                        list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
                    }
                    startIndex = i + 1;
                } else if ( c == '-' ) {
                    if ( i == startIndex ) {
                        list.add( IntegerItem.ZERO );
                    } else {
                        list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
                    }
                    startIndex = i + 1;

                    if ( isDigit ) {
                        list.normalize(); // 1.0-* = 1-*

                        if ( ( i + 1 < version.length() ) && Character.isDigit( version.charAt( i + 1 ) ) ) {
                            // new ListItem only if previous were digits and new char is a digit,
                            // ie need to differentiate only 1.1 from 1-1
                            list.add( list = new ListItem() );

                            stack.push( list );
                        }
                    }
                }
                else if ( Character.isDigit( c ) ) {
                    if ( !isDigit && i > startIndex ) {
                        list.add( new StringItem( version.substring( startIndex, i ), true ) );
                        startIndex = i;
                    }

                    isDigit = true;
                } else {
                    if ( isDigit && i > startIndex ) {
                        list.add( parseItem( true, version.substring( startIndex, i ) ) );
                        startIndex = i;
                    }

                    isDigit = false;
                }
            }

            if ( version.length() > startIndex ) {
                list.add( parseItem( isDigit, version.substring( startIndex ) ) );
            }

            while ( !stack.isEmpty() ) {
                list = (ListItem) stack.pop();
                list.normalize();
            }

            canonical = items.toString();
        }

        private static Item parseItem( boolean isDigit, String buf ) {
            return isDigit ? new IntegerItem( buf ) : new StringItem( buf, false );
        }

        public int compareTo( ComparableVersion o ) {
            return items.compareTo( o.items );
        }

        public String toString() {
            return value;
        }

        public boolean equals( Object o ) {
            return ( o instanceof ComparableVersion ) && canonical.equals( ( (ComparableVersion) o ).canonical );
        }

        public int hashCode() {
            return canonical.hashCode();
        }
    }
}
TOP

Related Classes of org.drools.compiler.kie.builder.impl.KieRepositoryImpl

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.