All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.compiler.kie.builder.impl.KieBuilderSetImpl Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * 
 *      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.compiler.kie.builder.impl;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.drools.compiler.builder.impl.KnowledgeBuilderImpl;
import org.drools.core.common.ProjectClassLoader;
import org.drools.core.io.impl.BaseResource;
import org.kie.api.KieServices;
import org.kie.api.builder.model.KieBaseModel;
import org.kie.api.io.Resource;
import org.kie.internal.builder.CompositeKnowledgeBuilder;
import org.kie.internal.builder.IncrementalResults;
import org.kie.internal.builder.KieBuilderSet;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderError;

import static java.util.Arrays.asList;
import static org.drools.compiler.kie.builder.impl.KieBuilderImpl.filterFileInKBase;

public class KieBuilderSetImpl implements KieBuilderSet {

    private final KieBuilderImpl kieBuilder;
    private String[] files;

    private Map> previousErrors;

    private final Map> resourcesWithErrors = new HashMap>();

    public KieBuilderSetImpl(KieBuilderImpl kieBuilder) {
        this.kieBuilder = kieBuilder;
        registerInitialErrors(kieBuilder);
    }

    private void registerInitialErrors(KieBuilderImpl kieBuilder) {
        previousErrors = new HashMap>();
        InternalKieModule kieModule = (InternalKieModule) kieBuilder.getKieModuleIgnoringErrors();
        for (KieBaseModel kBaseModel : kieModule.getKieModuleModel().getKieBaseModels().values()) {
            KnowledgeBuilder kBuilder = kieModule.getKnowledgeBuilderForKieBase( kBaseModel.getName() );
            if (kBuilder != null) {
                previousErrors.put( kBaseModel.getName(), kBuilder.getErrors() );
                resourcesWithErrors.put(kBaseModel.getName(), findResourcesWithErrors(kBuilder));
            }
        }
    }

    KieBuilderSetImpl setFiles(String[] files) {
        this.files = files;
        return this;
    }

    @Override
    public IncrementalResults build() {
        Collection srcFiles = files != null ? asList(files) : kieBuilder.getModifiedResourcesSinceLastMark();
        Collection filesToBuild = new ArrayList();
        if ( srcFiles.isEmpty() ) {
            return new IncrementalResultsImpl();
        }
        kieBuilder.cloneKieModuleForIncrementalCompilation();
        for (String file : srcFiles) {
            if ( !file.endsWith( ".properties" ) ) {
                String trgFile = kieBuilder.copySourceToTarget(file);
                if (trgFile != null) {
                    filesToBuild.add(trgFile);
                }
            }
        }
        IncrementalResults result = buildChanges(filesToBuild);
        files = null;
        kieBuilder.markSource();
        return result;
    }

    private Set findResourcesWithErrors(KnowledgeBuilder kBuilder) {
        if ( kBuilder.hasErrors() ) {
            Set resourcesWithErrors = new HashSet();
            for ( KnowledgeBuilderError error : kBuilder.getErrors() ) {
                resourcesWithErrors.add(error.getResource().getSourcePath());
            }
            return resourcesWithErrors;
        }
        return Collections.emptySet();
    }

    private IncrementalResults buildChanges(Collection filesToBuild) {
        Map> currentErrors = new HashMap>();

        InternalKieModule kieModule = (InternalKieModule) kieBuilder.getKieModuleIgnoringErrors();
        for (KieBaseModel kBaseModel : kieModule.getKieModuleModel().getKieBaseModels().values()) {
            KnowledgeBuilder kBuilder = kieModule.getKnowledgeBuilderForKieBase( kBaseModel.getName() );
            if (kBuilder == null) {
                continue;
            }
            CompositeKnowledgeBuilder ckbuilder = kBuilder.batch();
            boolean useFolders = (( KnowledgeBuilderImpl ) kBuilder).getBuilderConfiguration().isGroupDRLsInKieBasesByFolder();

            KnowledgeBuilderImpl.ResourceRemovalResult removalResult = new KnowledgeBuilderImpl.ResourceRemovalResult();
            KnowledgeBuilderImpl pkgBuilder = ((KnowledgeBuilderImpl)kBuilder);

            Set wrongResources = resourcesWithErrors.get(kBaseModel.getName());
            for ( String resourceName : wrongResources ) {
                removalResult.add( pkgBuilder.removeObjectsGeneratedFromResource(new DummyResource(resourceName)) );
                removalResult.mergeModified( addResource(ckbuilder, kBaseModel, kieModule, resourceName, useFolders) );
            }

            for (String file : filesToBuild) {
                if ( wrongResources.contains(file) ) {
                    removalResult.mergeModified( true );
                } else {
                    // remove the objects generated by the old Resource
                    removalResult.add( pkgBuilder.removeObjectsGeneratedFromResource(new DummyResource(file)) );
                    // add the modified Resource
                    removalResult.mergeModified( addResource(ckbuilder, kBaseModel, kieModule, file, useFolders) );
                }
            }

            if (removalResult.isModified()) {
                if (!removalResult.getRemovedTypes().isEmpty()) {
                    ProjectClassLoader projectClassLoader = (ProjectClassLoader) (( KnowledgeBuilderImpl ) kBuilder).getRootClassLoader();
                    projectClassLoader.reinitTypes();
                    for (String removedType : removalResult.getRemovedTypes()) {
                        projectClassLoader.undefineClass(removedType);
                    }
                }

                ckbuilder.build();
                resourcesWithErrors.put(kBaseModel.getName(), findResourcesWithErrors(kBuilder));
                if ( kBuilder.hasErrors() ) {
                    currentErrors.put( kBaseModel.getName(), kBuilder.getErrors() );
                    kBuilder.undo();
                } else {
                    KieServices.Factory.get().getRepository().addKieModule( kieModule );
                    kieBuilder.updateKieModuleMetaInfo();
                }
            }
        }

        IncrementalResultsImpl results = getIncrementalResults(currentErrors);
        previousErrors = currentErrors;
        return results;
    }

    private IncrementalResultsImpl getIncrementalResults(Map> currentErrors) {
        IncrementalResultsImpl results = new IncrementalResultsImpl();
        for (Map.Entry> entry : currentErrors.entrySet()) {
            Collection previousErrorsInKB = previousErrors.remove(entry.getKey());
            for ( KnowledgeBuilderError error : entry.getValue() ) {
                if ( previousErrorsInKB == null || !previousErrorsInKB.remove( error ) ) {
                    results.addMessage( error, entry.getKey() );
                }
            }
            if (previousErrorsInKB != null) {
                for ( KnowledgeBuilderError error : previousErrorsInKB ) {
                    results.removeMessage( error, entry.getKey() );
                }
            }
        }
        for (Map.Entry> entry : previousErrors.entrySet()) {
            for ( KnowledgeBuilderError error : entry.getValue() ) {
                results.removeMessage( error, entry.getKey() );
            }
        }
        return results;
    }

    private boolean addResource( CompositeKnowledgeBuilder ckbuilder,
                                 KieBaseModel kieBaseModel,
                                 InternalKieModule kieModule,
                                 String resourceName,
                                 boolean useFolders ) {
        return !resourceName.endsWith(".properties") &&
               filterFileInKBase(kieModule, kieBaseModel, resourceName, () -> kieModule.getBytes( resourceName ), useFolders) &&
               kieModule.addResourceToCompiler(ckbuilder, kieBaseModel, resourceName);
    }

    public static class DummyResource extends BaseResource {
        public DummyResource(String resourceName) {
            setSourcePath(decode(resourceName));
        }

        @Override
        public URL getURL() throws IOException {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean hasURL() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isDirectory() {
            throw new UnsupportedOperationException();
        }

        @Override
        public Collection listResources() {
            throw new UnsupportedOperationException();
        }

        @Override
        public long getLastModified() {
            throw new UnsupportedOperationException();
        }

        @Override
        public long getLastRead() {
            throw new UnsupportedOperationException();
        }

        @Override
        public String getEncoding() {
            throw new UnsupportedOperationException();
        }

        @Override
        public InputStream getInputStream() throws IOException {
            throw new UnsupportedOperationException();
        }

        @Override
        public Reader getReader() throws IOException {
            throw new UnsupportedOperationException();
        }

        private String decode(final String resourceName) {
            try {
                return URLDecoder.decode(resourceName, "UTF-8");
            } catch (UnsupportedEncodingException | IllegalArgumentException e) {
                return resourceName;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy