
org.openl.rules.ruleservice.loader.RuleServiceLoaderImpl Maven / Gradle / Ivy
package org.openl.rules.ruleservice.loader;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.ProviderNotFoundException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.PreDestroy;
import org.openl.rules.common.CommonVersion;
import org.openl.rules.common.ProjectException;
import org.openl.rules.common.impl.CommonVersionImpl;
import org.openl.rules.deploy.LocalDeployment;
import org.openl.rules.deploy.LocalProject;
import org.openl.rules.deploy.LocalProjectResource;
import org.openl.rules.project.abstraction.Deployment;
import org.openl.rules.project.abstraction.IDeployment;
import org.openl.rules.project.abstraction.IProject;
import org.openl.rules.project.abstraction.IProjectArtefact;
import org.openl.rules.project.model.Module;
import org.openl.rules.project.model.ProjectDescriptor;
import org.openl.rules.project.resolving.ProjectResolver;
import org.openl.rules.project.resolving.ProjectResolvingException;
import org.openl.rules.repository.api.FileData;
import org.openl.rules.repository.api.FolderRepository;
import org.openl.rules.repository.api.Repository;
import org.openl.rules.repository.file.FileSystemRepository;
import org.openl.rules.repository.zip.ZippedLocalRepository;
import org.openl.rules.ruleservice.core.RuleServiceRuntimeException;
import org.openl.util.FileTypeHelper;
import org.openl.util.RuntimeExceptionWrapper;
import org.openl.util.StringUtils;
import org.openl.util.ZipUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileSystemUtils;
/**
* Wrapper on data source that gives access to data source and resolves the OpenL projects/modules inside the projects.
* Contains own storage for all projects that is used in services.
*
* @author Marat Kamalov
*/
public class RuleServiceLoaderImpl implements RuleServiceLoader {
private final Logger log = LoggerFactory.getLogger(RuleServiceLoaderImpl.class);
private final ProjectResolver projectResolver;
private final Repository repository;
private final FileSystemRepository tempRepo;
private final Path tempPath;
private String deployPath = "";
/**
* Construct a new RulesLoader for bean usage.
*/
public RuleServiceLoaderImpl(Repository repository) throws IOException {
tempPath = Files.createTempDirectory("rules-deploy_");
log.info("Local temporary folder location is: {}", tempPath);
tempRepo = new FileSystemRepository();
tempRepo.setUri(tempPath.toString());
tempRepo.initialize();
this.projectResolver = ProjectResolver.getInstance();
this.repository = repository;
}
/**
* {@inheritDoc}
*/
@Override
public Collection resolveModulesForProject(String deploymentName,
CommonVersion deploymentVersion,
String projectName) {
Objects.requireNonNull(deploymentName, "deploymentName cannot be null");
Objects.requireNonNull(deploymentVersion, "deploymentVersion cannot be null");
Objects.requireNonNull(projectName, "projectName cannot be null");
log.debug("Resolving modules for deployment (name='{}', version='{}', projectName='{}')",
deploymentName,
deploymentVersion.getVersionName(),
projectName);
IDeployment localDeployment = getDeployment(deploymentName, deploymentVersion);
IProject project = localDeployment.getProject(projectName);
if (project == null) {
throw new RuleServiceRuntimeException(
String.format("Project '%s' is not found in deployment '%s'.", projectName, deploymentName));
}
Path projectFolder;
if (project instanceof LocalProject) {
projectFolder = ((LocalProject) project).getData().getPath();
if (projectFolder.getFileName() != null && (FileTypeHelper.isZipFile(
projectFolder.getFileName().toString()) || ZippedLocalRepository.zipArchiveFilter(projectFolder))) {
FileSystem fs = FileSystems.getFileSystem(ZipUtils.toJarURI(projectFolder));
projectFolder = fs.getPath("/");
}
} else {
String stringValue = project.getArtefactPath().getStringValue();
projectFolder = tempPath.resolve(stringValue);
}
List result = Collections.emptyList();
try {
ProjectDescriptor projectDescriptor = projectResolver.resolve(projectFolder);
if (projectDescriptor != null) {
List modules = projectDescriptor.getModules();
result = Collections.unmodifiableList(modules);
}
} catch (ProjectResolvingException e) {
log.error("Project resolving has been failed.", e);
}
return result;
}
@Override
public IDeployment getDeployment(String deploymentName, CommonVersion version) {
if (repository.supports().isLocal() && repository.supports().folders()) {
FileData data;
try {
data = repository.check(getDeployPath() + deploymentName);
if (data != null && data.getPath() != null) {
return buildLocalDeployment(version, data, (FolderRepository) repository);
}
} catch (IOException e) {
throw RuntimeExceptionWrapper.wrap(e);
}
}
String versionName = version.getVersionName();
Deployment loadedDeployment = new Deployment(tempRepo,
deploymentName + "_v" + versionName,
deploymentName,
version,
true);
if (loadedDeployment.getProjects().isEmpty()) {
log.debug("Loading deployment with name='{}' and version='{}'", deploymentName, versionName);
String folderPath = getDeployPath() + deploymentName;
boolean folderStructure = isFolderStructure(folderPath);
Deployment deployment = new Deployment(repository, folderPath, deploymentName, version, folderStructure);
try {
loadedDeployment.update(deployment, null);
loadedDeployment.refresh();
} catch (ProjectException e) {
log.warn("Exception occurs on loading deployment with name='{}' and version='{}' from data source.",
deploymentName,
versionName,
e);
throw new RuleServiceRuntimeException(e);
}
}
return loadedDeployment;
}
/**
* {@inheritDoc}
*/
@Override
public Collection getDeployments() {
List fileData;
try {
if (repository.supports().folders()) {
// All deployments
fileData = ((FolderRepository) repository).listFolders(getDeployPath());
} else {
// Projects inside all deployments
fileData = repository.list(getDeployPath());
}
} catch (IOException ex) {
throw RuntimeExceptionWrapper.wrap(ex);
}
ConcurrentMap deployments = new ConcurrentHashMap<>();
for (FileData fd : fileData) {
String name = fd.getName();
String deployFolder = getDeployPath();
String deploymentPath = name.substring(deployFolder.length());
String[] pathEntries = deploymentPath.split("/");
String deploymentFolderName = pathEntries[0];
String version = fd.getVersion();
CommonVersionImpl commonVersion = new CommonVersionImpl(version == null ? "0" : version);
String folderPath = getDeployPath() + deploymentFolderName;
IDeployment deployment;
if (isLocalZipFile(fd)) {
try {
deployment = buildLocalDeployment(commonVersion, fd, (FolderRepository) repository);
} catch (IOException e) {
throw RuntimeExceptionWrapper.wrap(e);
}
} else {
boolean folderStructure = isFolderStructure(folderPath);
deployment = new Deployment(repository,
folderPath,
deploymentFolderName,
commonVersion,
folderStructure);
}
deployments.putIfAbsent(deploymentFolderName, deployment);
}
return deployments.values();
}
private boolean isLocalZipFile(FileData fileData) {
return repository.supports().folders() && repository.supports()
.isLocal() && fileData.getPath() != null && (FileTypeHelper
.isZipFile(fileData.getPath().getFileName().toString()) || ZippedLocalRepository
.zipArchiveFilter(fileData.getPath()));
}
private boolean isSimpleProjectDeployment(FileData fileData) {
URI jarURI = ZipUtils.toJarURI(fileData.getPath());
try {
Path zipRoot = FileSystems.getFileSystem(jarURI).getPath("/");
return projectResolver.isRulesProject(zipRoot) != null;
} catch (FileSystemNotFoundException ignored) {
try (FileSystem fs = FileSystems.newFileSystem(jarURI, Collections.emptyMap())) {
return projectResolver.isRulesProject(fs.getPath("/")) != null;
} catch (IOException | UnsupportedOperationException | ProviderNotFoundException e) {
return false;
}
}
}
private LocalDeployment buildLocalDeployment(CommonVersion commonVersion,
FileData deploymentFolder,
FolderRepository repository) throws IOException {
LocalDeployment deployment;
if (isSimpleProjectDeployment(deploymentFolder)) {
Map resourceMap = gatherProjectResources(deploymentFolder, repository);
LocalProject project = new LocalProject(deploymentFolder, resourceMap);
deployment = new LocalDeployment(deploymentFolder.getName().split("/")[0],
commonVersion,
Collections.singletonMap(project.getName(), project));
} else {
List projectFolders = repository.listFolders(getDeployPath() + deploymentFolder.getName());
Map projectMap = new HashMap<>();
for (FileData projectFolder : projectFolders) {
Map resourceMap = gatherProjectResources(projectFolder, repository);
LocalProject project = new LocalProject(projectFolder, resourceMap);
projectMap.put(project.getName(), project);
}
deployment = new LocalDeployment(deploymentFolder.getName().split("/")[0], commonVersion, projectMap);
}
return deployment;
}
private Map gatherProjectResources(FileData folder,
Repository repository) throws IOException {
List files = repository.list(getDeployPath() + folder.getName());
Map resourceMap = new HashMap<>();
for (FileData file : files) {
String resourceName = file.getName().substring(folder.getName().length() + 1);
LocalProjectResource resource = new LocalProjectResource(resourceName, repository.read(file.getName()));
resourceMap.put(resource.getName(), resource);
}
return resourceMap;
}
@Override
public void setListener(DataSourceListener dataSourceListener) {
if (dataSourceListener == null) {
repository.setListener(null);
} else {
repository.setListener(dataSourceListener::onDeploymentAdded);
}
}
/**
* For Spring framework
*/
@PreDestroy
public void destroy() throws Exception {
log.debug("Data source releasing");
if (repository instanceof Closeable) {
((Closeable) repository).close();
}
tempRepo.close();
try {
FileSystemUtils.deleteRecursively(tempPath);
} catch (Exception e) {
log.error("Cannot delete temporary directory", e);
}
}
public void setDeployPath(String deployPath) {
this.deployPath = deployPath.isEmpty() || deployPath.endsWith("/") ? deployPath : deployPath + "/";
}
private boolean isFolderStructure(String deploymentFolderPath) {
boolean folderStructure;
try {
if (repository.supports().folders()) {
folderStructure = !((FolderRepository) repository).listFolders(deploymentFolderPath + "/").isEmpty();
} else {
folderStructure = false;
}
} catch (IOException e) {
throw RuntimeExceptionWrapper.wrap(e);
}
return folderStructure;
}
private String getDeployPath() {
if (repository.supports().isLocal()) {
// NOTE deployment path isn't required for LocalRepository. It must be specified within URI
return "";
}
return deployPath;
}
@Override
public String getLogicalProjectFolder(String realFolderPath) {
if (StringUtils.isBlank(realFolderPath) || repository.supports().isLocal()) {
return realFolderPath;
}
final String baseDeployFolder = getDeployPath();
if (!realFolderPath.startsWith(baseDeployFolder)) {
return realFolderPath;
}
return realFolderPath.substring(baseDeployFolder.length());
}
@Override
public boolean isReady() {
try {
repository.validateConnection();
return true;
} catch (Exception e) {
log.debug(e.getMessage(), e);
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy