Package org.kie.api.builder.helper

Source Code of org.kie.api.builder.helper.KieModuleDeploymentHelperImpl

package org.kie.api.builder.helper;

import static org.kie.scanner.MavenRepository.getMavenRepository;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import org.drools.compiler.kie.builder.impl.InternalKieModule;
import org.drools.compiler.kproject.ReleaseIdImpl;
import org.drools.core.util.IoUtils;
import org.kie.api.KieBase;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.Message;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieModuleModel;
import org.kie.api.runtime.KieSession;
import org.kie.scanner.MavenRepository;

/**
* This is the main class where all interfaces and code comes together.
*/
final class KieModuleDeploymentHelperImpl extends FluentKieModuleDeploymentHelper implements SingleKieModuleDeploymentHelper {
   
    /**
     * package scope: Because users will do very unexpected things.
     */

    private KieModuleDeploymentConfig config;
   
    KieModuleDeploymentHelperImpl() {
        config = new KieModuleDeploymentConfig();
    }

    /**
     * Fluent API
     */
   
    @Override
    public FluentKieModuleDeploymentHelper setGroupId(String groupId) {
        assertNotNull( groupId, "groupId");
        this.config.setGroupId(groupId);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper setArtifactId(String artifactId) {
        assertNotNull( artifactId, "artifactId");
        this.config.setArtifactId(artifactId);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper setVersion(String version) {
        assertNotNull( version, "version");
        this.config.setVersion(version);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper setKBaseName(String kbaseName) {
        assertNotNull(kbaseName, "kbase name");
        this.config.setKbaseName(kbaseName);
        return this;
    }

    @Override
    public FluentKieModuleDeploymentHelper setKieSessionname(String ksessionName) {
        assertNotNull(ksessionName, "ksession name");
        this.config.setKsessionName(ksessionName);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper setResourceFilePaths(List<String> resourceFilePaths) {
        assertNotNull( resourceFilePaths, "resourceFilePaths");
        this.config.resourceFilePaths.addAll(resourceFilePaths);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper addResourceFilePath(String... resourceFilePath) {
        assertNotNull( resourceFilePath, "resourceFilePath");
        for( int i = 0; i < resourceFilePath.length; ++i ) {
            assertNotNull( resourceFilePath[i], "resourceFilePath[" + i + "]");
            this.config.resourceFilePaths.add(resourceFilePath[i]);
        }
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper setClasses(List<Class<?>> classesForKjar) {
        assertNotNull( classesForKjar, "classesForKjar");
        this.config.classes.addAll(classesForKjar);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper addClass(Class<?>... classForKjar) {
        assertNotNull( classForKjar, "classForKjar");
        for( int i = 0; i < classForKjar.length; ++i ) {
            assertNotNull( classForKjar[i], "classForKjar[" + i + "]");
            this.config.classes.add(classForKjar[i]);
        }
        return this;
    }

    @Override
    public FluentKieModuleDeploymentHelper setDependencies(List<String> dependencies) {
        assertNotNull( dependencies, "dependencies");
        this.config.dependencies.addAll(dependencies);
        return this;
    }
   
    @Override
    public FluentKieModuleDeploymentHelper addDependencies(String... dependency) {
        assertNotNull( dependency, "dependency");
        for( int i = 0; i < dependency.length; ++i ) {
            assertNotNull( dependency[i], "dependency[" + i + "]");
            this.config.dependencies.add(dependency[i]);
        }
        return this;
    }
   
    @Override
    public KieModuleModel getKieModuleModel() {
        return config.getKieProject();
    }

    @Override
    public FluentKieModuleDeploymentHelper resetHelper() {
        this.config = new KieModuleDeploymentConfig();
        return this;
    }

    @Override
    public KieModule createKieJar() {
        config.checkComplete();
        return internalCreateKieJar(config.getReleaseId(), config.getKbaseName(), config.getKsessionName(),
                config.resourceFilePaths, config.classes, config.dependencies);
    }

    @Override
    public void createKieJarAndDeployToMaven() {
        config.checkComplete();
        internalCreateAndDeployKjarToMaven(config.getReleaseId(), config.getKbaseName(), config.getKsessionName(),
                config.resourceFilePaths, config.classes,
                config.dependencies);
    }
   
    private static void assertNotNull(Object obj, String name) {
        if( obj == null ) {
            throw new IllegalArgumentException("Null " + name + " arguments are not accepted!");
        }
    }
   
    /**
     * General/Single API
     */
   
    @Override
    public KieModule createKieJar(String groupId, String artifactId, String version,
            String kbaseName,
            String ksessionName,
            List<String> resourceFilePaths ) {
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        return internalCreateKieJar(releaseId, kbaseName, ksessionName, resourceFilePaths, null, null);
    }
   
    @Override
    public KieModule createKieJar(String groupId, String artifactId, String version,
            String kbaseName,
            String ksessionName,
            List<String> bpmnFilePaths,
            List<Class<?>> classes) {
       
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        return internalCreateKieJar(releaseId, kbaseName, ksessionName, bpmnFilePaths, classes, null);
    }
   
    @Override
    public KieModule createKieJar(String groupId, String artifactId, String version,
            String kbaseName,
            String ksessionName,
            List<String> bpmnFilePaths,
            List<Class<?>> classes,
            List<String> dependencies) {
       
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        return internalCreateKieJar(releaseId, kbaseName, ksessionName, bpmnFilePaths, classes, dependencies);
    }
   
    @Override
    public void createKieJarAndDeployToMaven(String groupId, String artifactId, String version, String kbaseName,
            String ksessionName, List<String> resourceFilePaths) {
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        internalCreateAndDeployKjarToMaven(releaseId, kbaseName, ksessionName, resourceFilePaths, null, null);
    }

    @Override
    public void createKieJarAndDeployToMaven(String groupId, String artifactId, String version, String kbaseName,
            String ksessionName, List<String> resourceFilePaths, List<Class<?>> classesForKjar) {
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        internalCreateAndDeployKjarToMaven(releaseId, kbaseName, ksessionName, resourceFilePaths, classesForKjar, null);
    }

    @Override
    public void createKieJarAndDeployToMaven(String groupId, String artifactId, String version, String kbaseName,
            String ksessionName, List<String> resourceFilePaths, List<Class<?>> classesForKjar, List<String> dependencies) {
        ReleaseId releaseId = new ReleaseIdImpl(groupId, artifactId, version);
        internalCreateAndDeployKjarToMaven(releaseId, kbaseName, ksessionName, resourceFilePaths, classesForKjar, dependencies);
    }
   
    /**
     * Internal methods
     */

    /**
     * Create a KJar and deploy it to maven.
     *
     * @param releaseId The {@link ReleaseId} of the jar.
     * @param kbaseName The name to use for the (default) {@link KieBase} in the kmodule.xml.
     * @param ksessionName The name to use for the (default) {@link KieSession} in the kmodule.xml.
     * @param resourceFilePaths A (possibly null) list of files to be added to the kjar.
     * @param classes
     * @param dependencies
     */
    private synchronized void internalCreateAndDeployKjarToMaven(ReleaseId releaseId,
            String kbaseName,
            String ksessionName,
            List<String> resourceFilePaths,
            List<Class<?>> classes,
            List<String> dependencies) {
       
        InternalKieModule kjar = (InternalKieModule) internalCreateKieJar(releaseId,
                kbaseName, ksessionName,
                resourceFilePaths, classes,
                dependencies);
       
        String pomFileName = MavenRepository.toFileName(releaseId, null) + ".pom";
        File pomFile = new File(System.getProperty("java.io.tmpdir"), pomFileName);
        try {
            FileOutputStream fos = new FileOutputStream(pomFile);
            fos.write(config.pomText.getBytes(IoUtils.UTF8_CHARSET));
            fos.flush();
            fos.close();
        } catch (IOException ioe) {
            throw new RuntimeException("Unable to write pom.xml to temporary file : " + ioe.getMessage(), ioe);
        }
   
        MavenRepository repository = getMavenRepository();
        repository.deployArtifact(releaseId, kjar, pomFile);
    }

    /**
     * Create a KJar for deployment;
     *
     * @param releaseId Release (deployment) id.
     * @param resourceFilePaths List of resource file paths
     * @param kbaseName The name of the {@link KieBase}
     * @param ksessionName The name of the {@link KieSession}.
     * @param dependencies List of dependencies to add
     *
     * @return The {@link InternalKieModule} which represents the KJar.
     */
    private synchronized KieModule internalCreateKieJar(ReleaseId releaseId,
            String kbaseName,
            String ksessionName,
            List<String> resourceFilePaths,
            List<Class<?>> classes,
            List<String> dependencies) {
       
       
        ReleaseId [] releaseIds = { };
        if( dependencies != null && dependencies.size() > 0 ) {
            List<ReleaseId> depReleaseIds = new ArrayList<ReleaseId>();
            for( String dep : dependencies ) {
                String [] gav = dep.split(":");
                if( gav.length != 3 ) {
                    throw new IllegalArgumentException("Dependendency id '" + dep  + "' does not conform to the format <groupId>:<artifactId>:<version> (Classifiers are not accepted).");
                }
                depReleaseIds.add(new ReleaseIdImpl(gav[0], gav[1], gav[2]));
            }
            releaseIds = depReleaseIds.toArray(new ReleaseId[depReleaseIds.size()]);
        }
        config.pomText = getPomText(releaseId, releaseIds);
       
        KieFileSystem kfs = createKieFileSystemWithKProject(kbaseName, ksessionName);
        kfs.writePomXML(this.config.pomText);
   
        List<KJarResource> resourceFiles = loadResources(resourceFilePaths);
        for (KJarResource resource : resourceFiles) {
            kfs.write("src/main/resources/" + kbaseName + "/" + resource.name, resource.content);
        }
   
        if( classes != null ) {
            for( Class<?> userClass : classes ) {
                addClass(userClass, kfs);
            }
        }
   
        KieBuilder kieBuilder = config.getKieServicesInstance().newKieBuilder(kfs);
        int buildMsgs = 0;
        for( Message buildMsg : kieBuilder.buildAll().getResults().getMessages() ) {
           System.out.println( buildMsg.getPath() + " : " + buildMsg.getText() );
           ++buildMsgs;
        }
        if( buildMsgs > 0 ) {
            throw new RuntimeException("Unable to build KieModule, see the " + buildMsgs + " messages above.");
        }
       
        return (InternalKieModule) kieBuilder.getKieModule();
    }

    /**
     * Create the {@link KieFileSystem} instance to store the content going into the KJar.
     *
     * @param kbaseName
     * @param ksessionName
     * @return
     */
    private KieFileSystem createKieFileSystemWithKProject(String kbaseName, String ksessionName) {
        KieModuleModel kproj = config.getKieProject();
        KieFileSystem kfs = config.getKieServicesInstance().newKieFileSystem();
        kfs.writeKModuleXML(kproj.toXML());
        return kfs;
    }

    /**
     * Create the pom that will be placed in the KJar.
     *
     * @param releaseId The release (deployment) id.
     * @param dependencies The list of dependendencies to be added to the pom
     * @return A string representation of the pom.
     */
    private static String getPomText(ReleaseId releaseId, ReleaseId... dependencies) {
        String pom = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
                + "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
                + "  <modelVersion>4.0.0</modelVersion>\n"
                + "\n"
                + "  <groupId>" + releaseId.getGroupId() + "</groupId>\n"
                + "  <artifactId>" + releaseId.getArtifactId() + "</artifactId>\n"
                + "  <version>" + releaseId.getVersion() + "</version>\n" + "\n";
       
        if (dependencies != null && dependencies.length > 0) {
            pom += "<dependencies>\n";
            for (ReleaseId dep : dependencies) {
                pom += "<dependency>\n";
                pom += "  <groupId>" + dep.getGroupId() + "</groupId>\n";
                pom += "  <artifactId>" + dep.getArtifactId() + "</artifactId>\n";
                pom += "  <version>" + dep.getVersion() + "</version>\n";
                pom += "</dependency>\n";
            }
            pom += "</dependencies>\n";
        }
       
        pom += "</project>";
       
        return pom;
    }

    /**
     * Create a list of {@link KJarResource} instances with the process files to be included in the KJar.
     *
     * @return The list of {@link KJarResource} instances.
     * @throws Exception
     */
    static List<KJarResource> internalLoadResources(String path, boolean fromDir) throws Exception {
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        List<KJarResource> output = new ArrayList<KJarResource>();
        URL url = KieModuleDeploymentHelperImpl.class.getResource(path);
        if (fromDir) {
            if (url == null) {
                File folder = new File(path);
                if (folder.exists()) {
                    for (File folderFile : folder.listFiles()) {
                        if (folderFile.isDirectory()) {
                            continue;
                        }
                        String content = convertFileToString(new FileInputStream(folderFile));
                        output.add(new KJarResource(folderFile.getName(), content));
                    }
                } else {
                    throw new IllegalArgumentException("Directory + '" + path + "' does not exist.");
                }
            } else if ("file".equals(url.getProtocol())) {
                File folder = new File(url.toURI());
                if (folder.isDirectory()) {
                    for (File folderFile : folder.listFiles()) {
                        if (folderFile.getName().endsWith(".class")
                                || folderFile.isDirectory() ) {
                            continue;
                        }
                        String content = convertFileToString(new FileInputStream(folderFile));
                        output.add(new KJarResource(folderFile.getName(), content));
                    }
                } else {
                    throw new IllegalStateException("'" + path + "' is not an existing directory.");
                }
            } else if ("jar".equals(url.getProtocol())) {
                String urlString = url.toExternalForm();
                int jarPathIndex = urlString.lastIndexOf(".jar!") + 4;
                String resourcePath = urlString.substring(jarPathIndex + 1);
                if (resourcePath.startsWith("/")) {
                    resourcePath = resourcePath.substring(1);
                }
                int depth = resourcePath.split("/").length + 1;

                String jarUrlString = urlString.substring("jar:".length(), jarPathIndex);
                url = new URL(jarUrlString);
                ZipInputStream zip = new ZipInputStream(url.openStream());

                ZipEntry ze = zip.getNextEntry();
                while (ze != null) {
                    String name = ze.getName();
                    if (name.startsWith(resourcePath) && !name.endsWith("/")
                            && (name.split("/").length == depth)) {
                        String shortName = name.substring(name.lastIndexOf("/") + 1);
                        String content = convertFileToString(zip);
                        output.add(new KJarResource(shortName, content));
                    }
                    ze = zip.getNextEntry();
                }
            } else {
                throw new IllegalArgumentException("Unable to find resource directory '" + path + "'");
            }
        } else {
            InputStream is = KieModuleDeploymentHelperImpl.class.getResourceAsStream(path);
            if (is == null) {
                is = new FileInputStream(new File(path));
            }
            String content = convertFileToString(is);
            String name = path.substring(path.lastIndexOf("/") + 1);
            output.add(new KJarResource(name, content));
        }
        return output;
    }
  
    /**
     * Find the resource files specified and create {@link KJarResource} instances from them.
     *
     * @param resourceFilePaths A list of resource files or directories containing resource files
     * @return A List of {@link KJarResource} instances representing the given list of resource files
     */
    private static List<KJarResource> loadResources(List<String> resourceFilePaths) {
        List<KJarResource> kjarResources = new ArrayList<KieModuleDeploymentHelperImpl.KJarResource>();
        for( String filePath : resourceFilePaths ) {
            if( filePath.endsWith("/") ) {
                try {
                    kjarResources.addAll(internalLoadResources(filePath, true));
                } catch (Exception e) {
                    throw new RuntimeException("Unable to load resources from " + filePath + ": " + e.getMessage(), e);
                }
            } else {
                try {
                    kjarResources.addAll(internalLoadResources(filePath, false));
                } catch (FileNotFoundException fnfe) {
                    throw new RuntimeException("No file found at '" + filePath + "' -- if it's a directory, please add a " + File.separator + " to the end of the path.");
                } catch (Exception e) {
                    throw new RuntimeException("Unable to load resource from '" + filePath + "'", e);
                }
            }
        }
       
        return kjarResources;
    }
   
    private static String convertFileToString(InputStream in) {
        InputStreamReader input = new InputStreamReader(in, IoUtils.UTF8_CHARSET);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OutputStreamWriter output = new OutputStreamWriter(baos, IoUtils.UTF8_CHARSET);
        char[] buffer = new char[4096];
        int n = 0;
        try {
            while (-1 != (n = input.read(buffer))) {
                output.write(buffer, 0, n);
            }
            output.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return new String(baos.toByteArray(), IoUtils.UTF8_CHARSET);
    }

    /**
     * Add class to the {@link KieFileSystem}.
     *
     * @param userClass The class to be added.
     * @param kfs The {@link KieFileSystem}
     */
    private static void addClass(Class<?> userClass, KieFileSystem kfs) {
        String classSimpleName = userClass.getSimpleName();
       
        URL classFileUrl = userClass.getResource(classSimpleName + ".class");
        if( classFileUrl == null ) {
            throw new RuntimeException("Class " + userClass.getCanonicalName() + " can not be found on the classpath." );
        }
   
        byte[] classByteCode = null;
        if ("file".equalsIgnoreCase(classFileUrl.getProtocol())) {
            File classFile = new File(classFileUrl.getPath());
            if( ! classFile.exists() ) {
                throw new RuntimeException("Unable to find path for class " + userClass.getCanonicalName()
                        + " that should be here: " + classFileUrl.toExternalForm());
            }
   
            try {
                classByteCode = readStream(new FileInputStream(classFile));
            } catch (Exception e) {
                throw new RuntimeException("Unable to read in " + classFile.getAbsolutePath(), e);
            }
            if( classByteCode.length == 0 ) {
                throw new RuntimeException("No bytes retrieved from " + classFile.getAbsolutePath() );
            }
        } else if ("jar".equalsIgnoreCase(classFileUrl.getProtocol())) {
            // file:/opt/mavenRepository/org/kie/tests/kie-wb-tests-base/6.0.0-SNAPSHOT/kie-wb-tests-base-6.0.0-SNAPSHOT.jar!/org/kie/tests/wb/base/test/MyType.class
            String path = classFileUrl.getPath();
            int bangIndex = path.indexOf('!');
            String jarPath = path.substring("file:".length(), bangIndex);
            String classPath = path.substring(bangIndex+2); // no base /
           
            try {
                ZipFile zip = new ZipFile(new File(jarPath));
                ZipEntry entry = zip.getEntry(classPath);
                InputStream zipStream = zip.getInputStream(entry);
                classByteCode = readStream(zipStream);
            } catch (Exception e) {
                throw new RuntimeException("Unable to read from " + jarPath, e);
            }
        }

        String pkgFolder = userClass.getPackage().toString();

        // @#$%ing Eclipe classloader!! The following 2 lines "normalize" the package name from what Eclipse (and other IDE's?) do with it
        pkgFolder = pkgFolder.replace("package ", "");
        pkgFolder = pkgFolder.replaceAll(",.+$", "");
        pkgFolder = pkgFolder.replaceAll("\\.", "/" );
        String classFilePath = pkgFolder + "/" + classSimpleName + ".class";

        if( classFilePath.contains(" " ) ) {
            throw new RuntimeException("Invalid class name ('" + classFilePath + "'), contact the developers.");
        }
   
        kfs.write(classFilePath, classByteCode);
    }

    private static byte[] readStream(InputStream ios) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = ios.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
        } finally {
            try {
                if (baos != null) {
                    baos.close();
                }
                if (ios != null) {
                    ios.close();
                }
            } catch (IOException e) {
                // do nothing
            }
        }
        return baos.toByteArray();
    }

    static class KJarResource {
        public String name;
        public String content;
   
        public KJarResource(String name, String content) {
            this.content = content;
            this.name = name;
        }
    }





}
TOP

Related Classes of org.kie.api.builder.helper.KieModuleDeploymentHelperImpl

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.