/* * 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.kie.workbench.common.services.datamodel.backend.server.cache; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.inject.Named; import org.drools.workbench.models.datamodel.oracle.PackageDataModelOracle; import org.drools.workbench.models.datamodel.oracle.ProjectDataModelOracle; import org.guvnor.common.services.backend.cache.LRUCache; import org.guvnor.common.services.backend.file.FileDiscoveryService; import org.guvnor.common.services.project.builder.events.InvalidateDMOPackageCacheEvent; import org.guvnor.common.services.project.builder.events.InvalidateDMOProjectCacheEvent; import org.guvnor.common.services.project.builder.model.BuildMessage; import org.guvnor.common.services.project.model.Package; import org.guvnor.common.services.shared.message.Level; import org.kie.api.builder.KieModule; import org.kie.scanner.KieModuleMetaData; import org.kie.workbench.common.services.backend.builder.service.BuildInfoService; import org.kie.workbench.common.services.backend.file.DSLFileFilter; import org.kie.workbench.common.services.backend.file.EnumerationsFileFilter; import org.kie.workbench.common.services.backend.file.GlobalsFileFilter; import org.kie.workbench.common.services.datamodel.backend.server.builder.packages.PackageDataModelOracleBuilder; import org.kie.workbench.common.services.shared.project.KieProject; import org.kie.workbench.common.services.shared.project.KieProjectService; import org.uberfire.backend.server.util.Paths; import org.uberfire.backend.vfs.Path; import org.uberfire.commons.validation.PortablePreconditions; import org.uberfire.io.IOService; import org.uberfire.java.nio.file.DirectoryStream; /** * A simple LRU cache for Package DataModelOracles */ @ApplicationScoped @Named("PackageDataModelOracleCache") public class LRUDataModelOracleCache extends LRUCache<Package, PackageDataModelOracle> { private static final DirectoryStream.Filter<org.uberfire.java.nio.file.Path> FILTER_ENUMERATIONS = new EnumerationsFileFilter(); private static final DirectoryStream.Filter<org.uberfire.java.nio.file.Path> FILTER_GLOBALS = new GlobalsFileFilter(); private static final DirectoryStream.Filter<org.uberfire.java.nio.file.Path> FILTER_DSLS = new DSLFileFilter(); private IOService ioService; private FileDiscoveryService fileDiscoveryService; private LRUProjectDataModelOracleCache cacheProjects; private KieProjectService projectService; private BuildInfoService buildInfoService; public LRUDataModelOracleCache() { //CDI proxy } @Inject public LRUDataModelOracleCache(final @Named("ioStrategy") IOService ioService, final FileDiscoveryService fileDiscoveryService, final @Named("ProjectDataModelOracleCache") LRUProjectDataModelOracleCache cacheProjects, final KieProjectService projectService, final BuildInfoService buildInfoService) { this.ioService = ioService; this.fileDiscoveryService = fileDiscoveryService; this.cacheProjects = cacheProjects; this.projectService = projectService; this.buildInfoService = buildInfoService; } public synchronized void invalidatePackageCache(@Observes final InvalidateDMOPackageCacheEvent event) { PortablePreconditions.checkNotNull("event", event); final Path resourcePath = event.getResourcePath(); final Package pkg = projectService.resolvePackage(resourcePath); //If resource was not within a Package there's nothing to invalidate if (pkg != null) { invalidateCache(pkg); } } public synchronized void invalidateProjectPackagesCache(@Observes final InvalidateDMOProjectCacheEvent event) { PortablePreconditions.checkNotNull("event", event); final Path resourcePath = event.getResourcePath(); final KieProject project = projectService.resolveProject(resourcePath); //If resource was not within a Project there's nothing to invalidate if (project == null) { return; } final String projectUri = project.getRootPath().toURI(); final List<Package> cacheEntriesToInvalidate = new ArrayList<Package>(); for (final Package pkg : getKeys()) { final Path packageMainSrcPath = pkg.getPackageMainSrcPath(); final Path packageTestSrcPath = pkg.getPackageTestSrcPath(); final Path packageMainResourcesPath = pkg.getPackageMainResourcesPath(); final Path packageTestResourcesPath = pkg.getPackageTestResourcesPath(); if (packageMainSrcPath != null && packageMainSrcPath.toURI().startsWith(projectUri)) { cacheEntriesToInvalidate.add(pkg); } else if (packageTestSrcPath != null && packageTestSrcPath.toURI().startsWith(projectUri)) { cacheEntriesToInvalidate.add(pkg); } else if (packageMainResourcesPath != null && packageMainResourcesPath.toURI().startsWith(projectUri)) { cacheEntriesToInvalidate.add(pkg); } else if (packageTestResourcesPath != null && packageTestResourcesPath.toURI().startsWith(projectUri)) { cacheEntriesToInvalidate.add(pkg); } } for (final Package pkg : cacheEntriesToInvalidate) { invalidateCache(pkg); } } //Check the DataModelOracle for the Package has been created, otherwise create one! public synchronized PackageDataModelOracle assertPackageDataModelOracle(final KieProject project, final Package pkg) { PackageDataModelOracle oracle = getEntry(pkg); if (oracle == null) { oracle = makePackageDataModelOracle(project, pkg); setEntry(pkg, oracle); } return oracle; } private PackageDataModelOracle makePackageDataModelOracle(final KieProject project, final Package pkg) { final String packageName = pkg.getPackageName(); final PackageDataModelOracleBuilder dmoBuilder = PackageDataModelOracleBuilder.newPackageOracleBuilder(packageName); final ProjectDataModelOracle projectOracle = cacheProjects.assertProjectDataModelOracle(project); dmoBuilder.setProjectOracle(projectOracle); //Add Guvnor enumerations loadEnumsForPackage(dmoBuilder, project, pkg); //Add DSLs loadDslsForPackage(dmoBuilder, pkg); //Add Globals loadGlobalsForPackage(dmoBuilder, pkg); return dmoBuilder.build(); } private BuildMessage makeMessage(final String msg) { final BuildMessage buildMessage = new BuildMessage(); buildMessage.setLevel(Level.ERROR); buildMessage.setText(msg); return buildMessage; } private void loadEnumsForPackage(final PackageDataModelOracleBuilder dmoBuilder, final KieProject project, final Package pkg) { final KieModule module = buildInfoService.getBuildInfo( project ).getKieModuleIgnoringErrors(); final ClassLoader classLoader = KieModuleMetaData.Factory.newKieModuleMetaData(module).getClassLoader(); final org.uberfire.java.nio.file.Path nioPackagePath = Paths.convert(pkg.getPackageMainResourcesPath()); final Collection<org.uberfire.java.nio.file.Path> enumFiles = fileDiscoveryService.discoverFiles(nioPackagePath, FILTER_ENUMERATIONS); for (final org.uberfire.java.nio.file.Path path : enumFiles) { final String enumDefinition = ioService.readAllString(path); dmoBuilder.addEnum(enumDefinition, classLoader); } } private void loadDslsForPackage(final PackageDataModelOracleBuilder dmoBuilder, final Package pkg) { final org.uberfire.java.nio.file.Path nioPackagePath = Paths.convert(pkg.getPackageMainResourcesPath()); final Collection<org.uberfire.java.nio.file.Path> dslFiles = fileDiscoveryService.discoverFiles(nioPackagePath, FILTER_DSLS); for (final org.uberfire.java.nio.file.Path path : dslFiles) { final String dslDefinition = ioService.readAllString(path); dmoBuilder.addDsl(dslDefinition); } } private void loadGlobalsForPackage(final PackageDataModelOracleBuilder dmoBuilder, final Package pkg) { final org.uberfire.java.nio.file.Path nioPackagePath = Paths.convert(pkg.getPackageMainResourcesPath()); final Collection<org.uberfire.java.nio.file.Path> globalFiles = fileDiscoveryService.discoverFiles(nioPackagePath, FILTER_GLOBALS); for (final org.uberfire.java.nio.file.Path path : globalFiles) { final String definition = ioService.readAllString(path); dmoBuilder.addGlobals(definition); } } }