/*
 * Copyright 2005 JBoss Inc
 *
 * 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.drools.modelcompiler;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

import org.drools.compiler.kie.builder.impl.KieProject;
import org.drools.compiler.kie.builder.impl.ResultsImpl;
import org.drools.compiler.kie.builder.impl.ZipKieModule;
import org.drools.compiler.kproject.models.KieBaseModelImpl;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.util.IoUtils;
import org.drools.modelcompiler.builder.KieBaseBuilder;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.model.KieModuleModel;

public class CanonicalKieModule extends ZipKieModule {

    public static final String PACKAGE_LIST = "META-INF/packages";
    public static final String RULES_FILE_NAME = "Rules";
    public static final String VARIABLES_FILE_NAME = "Variables";

    private final Collection<String> ruleClassesNames;

    public CanonicalKieModule( ReleaseId releaseId, KieModuleModel kieProject, File file ) {
        this( releaseId, kieProject, file, null );
    }

    public CanonicalKieModule( ReleaseId releaseId, KieModuleModel kieProject, File file, Collection<String> ruleClassesNames ) {
        super( releaseId, kieProject, file );
        this.ruleClassesNames = ruleClassesNames;
    }

    @Override
    public InternalKnowledgeBase createKieBase( KieBaseModelImpl kBaseModel, KieProject kieProject, ResultsImpl messages, KieBaseConfiguration conf ) {
        KieProjectClassLoader kieProjectCL = new KieProjectClassLoader(kieProject);

        KieBaseBuilder builder = new KieBaseBuilder( kBaseModel, kieProject.getClassLoader(), conf );

        if (ruleClassesNames == null) {
            String packages = null;
            try {
                packages = new String( IoUtils.readBytesFromInputStream( kieProjectCL.getResourceAsStream( PACKAGE_LIST ) ) );
            } catch (IOException e) {
                throw new RuntimeException( e );
            }
            for ( String pkg : packages.split( "\n" ) ) {
                builder.addModel( kieProjectCL.createInstance( pkg + "." + RULES_FILE_NAME ) );
            }
        } else {
            ruleClassesNames.forEach( s -> builder.addModel( kieProjectCL.createInstance( s ) ) );
        }

        return builder.createKieBase();
    }

    class KieProjectClassLoader extends ClassLoader {
        public KieProjectClassLoader(KieProject kieProject) {
            super(kieProject.getClassLoader());
        }

        public Class<?> loadClass(String className) throws ClassNotFoundException {
            try {
                return super.loadClass( className );
            } catch (ClassNotFoundException cnfe) { }

            String fileName = className.replace( '.', '/' ) + ".class";
            byte[] bytes = getBytes(fileName);

            if (bytes == null) {
                throw new ClassNotFoundException(className);
            }

            return defineClass(className, bytes, 0, bytes.length);
        }

        public <T> T createInstance(String className) {
            try {
                return (T) loadClass( className ).newInstance();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                throw new RuntimeException( e );
            }
        }
    }
}

@@ -627,87 +627,8 @@
 r;%0A%0A
-import java.io.File;%0Aimport java.io.IOException;%0Aimport java.util.Collection;%0A%0A
 impo
@@ -1128,16 +1128,117 @@
 Model;%0A%0A
+import java.io.File;%0Aimport java.io.IOException;%0Aimport java.util.Collection;%0Aimport java.util.Map;%0A%0A
 public c
@@ -1913,24 +1913,171 @@
 mes;%0A    %7D%0A%0A
+    @Override%0A    public Map%3CString, byte%5B%5D%3E getClassesMap( boolean includeTypeDeclarations ) %7B%0A        return super.getClassesMap( true );%0A    %7D%0A%0A
     @Overrid
@@ -2238,26 +2238,16 @@
         
-KieProject
 ClassLoa
@@ -2265,21 +2265,17 @@
 ectCL = 
-new K
+k
 ieProjec
@@ -2267,32 +2267,36 @@
 tCL = kieProject
+.get
 ClassLoader(kieP
@@ -2295,22 +2295,11 @@
 der(
-kieProject
 );%0A
-%0A
     
@@ -2369,33 +2369,18 @@
 eProject
-.getClassLoader()
+CL
 , conf )
@@ -2792,37 +2792,24 @@
 r.addModel( 
-kieProjectCL.
 createInstan
@@ -2811,16 +2811,30 @@
 nstance(
+ kieProjectCL,
  pkg + %22
@@ -2951,29 +2951,16 @@
 dModel( 
-kieProjectCL.
 createIn
@@ -2966,16 +2966,30 @@
 nstance(
+ kieProjectCL,
  s ) ) )
@@ -3056,732 +3056,53 @@
     
-class KieProjectClassLoader extends ClassLoader %7B%0A        public KieProjectClassLoader(KieProject kieProject) %7B%0A            super(kieProject.getClassLoader());%0A        %7D%0A%0A        public Class%3C?%3E loadClass(String className) throws ClassNotFoundException %7B%0A            try %7B%0A                return super.loadClass( className );%0A            %7D catch (ClassNotFoundException cnfe) %7B %7D%0A%0A            String fileName = className.replace( '.', '/' ) + %22.class%22;%0A            byte%5B%5D bytes = getBytes(fileName);%0A%0A            if (bytes == null) %7B%0A                throw new ClassNotFoundException(className);%0A            %7D%0A%0A            return defineClass(className, bytes, 0, bytes.length);%0A        %7D%0A%0A        public %3CT%3E T createInstance(
+private %3CT%3E T createInstance(ClassLoader cl, 
 Stri
@@ -3121,38 +3121,30 @@
 ) %7B%0A        
-   
- 
 try %7B%0A
-    
             
@@ -3154,16 +3154,19 @@
 urn (T) 
+cl.
 loadClas
@@ -3191,28 +3191,24 @@
 Instance();%0A
-    
         %7D ca
@@ -3294,36 +3294,32 @@
 ) %7B%0A            
-   
- 
 throw new Runtim
@@ -3331,38 +3331,24 @@
 ption( e );%0A
-            %7D%0A
         %7D%0A  

fix CanonicalKieModule ClassLoader to work with type declarations