Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.openl.rules.webstudio.web.ProjectBean Maven / Gradle / Ivy
package org.openl.rules.webstudio.web;
import static org.openl.rules.webstudio.util.NameChecker.BAD_NAME_MSG;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.xml.bind.JAXBException;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.Yaml;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.annotation.RequestScope;
import org.openl.CompiledOpenClass;
import org.openl.rules.cloner.Cloner;
import org.openl.rules.common.ProjectException;
import org.openl.rules.common.impl.ArtefactPathImpl;
import org.openl.rules.model.scaffolding.ProjectModel;
import org.openl.rules.model.scaffolding.environment.EnvironmentModel;
import org.openl.rules.openapi.OpenAPIModelConverter;
import org.openl.rules.openapi.impl.GroovyScriptFile;
import org.openl.rules.openapi.impl.OpenAPIGeneratedClasses;
import org.openl.rules.openapi.impl.OpenAPIJavaClassGenerator;
import org.openl.rules.openapi.impl.OpenAPIScaffoldingConverter;
import org.openl.rules.project.IProjectDescriptorSerializer;
import org.openl.rules.project.IRulesDeploySerializer;
import org.openl.rules.project.ProjectDescriptorManager;
import org.openl.rules.project.abstraction.AProjectArtefact;
import org.openl.rules.project.abstraction.AProjectResource;
import org.openl.rules.project.abstraction.RulesProject;
import org.openl.rules.project.instantiation.RulesInstantiationException;
import org.openl.rules.project.model.MethodFilter;
import org.openl.rules.project.model.Module;
import org.openl.rules.project.model.OpenAPI;
import org.openl.rules.project.model.PathEntry;
import org.openl.rules.project.model.ProjectDependencyDescriptor;
import org.openl.rules.project.model.ProjectDescriptor;
import org.openl.rules.project.model.RulesDeploy;
import org.openl.rules.project.model.WebstudioConfiguration;
import org.openl.rules.project.model.validation.ValidationException;
import org.openl.rules.project.openapi.OpenApiGenerationException;
import org.openl.rules.project.openapi.OpenApiGenerator;
import org.openl.rules.project.resolving.InvalidFileNamePatternException;
import org.openl.rules.project.resolving.InvalidFileNameProcessorException;
import org.openl.rules.project.resolving.NoMatchFileNameException;
import org.openl.rules.project.resolving.ProjectDescriptorBasedResolvingStrategy;
import org.openl.rules.project.resolving.PropertiesFileNameProcessorBuilder;
import org.openl.rules.project.xml.ProjectDescriptorSerializerFactory;
import org.openl.rules.project.xml.RulesDeploySerializerFactory;
import org.openl.rules.project.xml.SupportedVersion;
import org.openl.rules.repository.api.FileData;
import org.openl.rules.repository.api.Repository;
import org.openl.rules.table.formatters.Formats;
import org.openl.rules.ui.Message;
import org.openl.rules.ui.WebStudio;
import org.openl.rules.ui.util.ListItem;
import org.openl.rules.webstudio.WebStudioFormats;
import org.openl.rules.webstudio.service.OpenAPIHelper;
import org.openl.rules.webstudio.util.NameChecker;
import org.openl.rules.webstudio.web.repository.RepositoryTreeState;
import org.openl.rules.webstudio.web.repository.tree.TreeProject;
import org.openl.rules.webstudio.web.util.ProjectArtifactUtils;
import org.openl.rules.webstudio.web.util.WebStudioUtils;
import org.openl.security.acl.permission.AclPermission;
import org.openl.security.acl.permission.AclPermissionsSets;
import org.openl.security.acl.repository.RepositoryAclService;
import org.openl.util.CollectionUtils;
import org.openl.util.FileTypeHelper;
import org.openl.util.FileUtils;
import org.openl.util.IOUtils;
import org.openl.util.StringTool;
import org.openl.util.StringUtils;
import org.openl.util.formatters.FileNameFormatter;
import org.openl.validation.ValidatedCompiledOpenClass;
@Service
@RequestScope
public class ProjectBean {
private static final String RULES_DEPLOY_XML = "rules-deploy.xml";
public static final String CANNOT_BE_EMPTY_MESSAGE = "Cannot be empty";
public static final String RECONCILIATION = "reconciliation";
private final ProjectDescriptorManager projectDescriptorManager = new ProjectDescriptorManager();
private final RepositoryTreeState repositoryTreeState;
private final ProjectDescriptorSerializerFactory projectDescriptorSerializerFactory;
private final RulesDeploySerializerFactory rulesDeploySerializerFactory;
private final WebStudio studio = WebStudioUtils.getWebStudio();
private final Logger log = LoggerFactory.getLogger(ProjectBean.class);
private List> dependencies;
private String sources;
private String[] propertiesFileNamePatterns;
private final Formats formats = WebStudioFormats.getInstance();
private List modulesInfoList = new ArrayList<>();
private UIInput propertiesFileNameProcessorInput;
private String currentModuleName;
private SupportedVersion supportedVersion;
private String newFileName;
private String currentPathPattern;
private Integer currentModuleIndex;
private IRulesDeploySerializer rulesDeploySerializer;
private final RepositoryAclService designRepositoryAclService;
private final OpenAPIHelper openAPIHelper = new OpenAPIHelper();
public ProjectBean(RepositoryTreeState repositoryTreeState,
ProjectDescriptorSerializerFactory projectDescriptorSerializerFactory,
RulesDeploySerializerFactory rulesDeploySerializerFactory,
@Qualifier("designRepositoryAclService") RepositoryAclService designRepositoryAclService) {
this.repositoryTreeState = repositoryTreeState;
this.projectDescriptorSerializerFactory = projectDescriptorSerializerFactory;
this.rulesDeploySerializerFactory = rulesDeploySerializerFactory;
this.designRepositoryAclService = designRepositoryAclService;
}
public String getModulePath(Module module) {
PathEntry modulePath = module == null ? null : module.getRulesRootPath();
if (modulePath == null) {
return null;
}
return modulePath.getPath();
}
public List> getDependencies() {
dependencies = new ArrayList<>();
ProjectDescriptor currentProject = studio.getCurrentProjectDescriptor();
List projects = studio.getAllProjects();
for (ProjectDescriptor project : projects) {
String name = project.getName();
if (!name.equals(currentProject.getName())) {
ProjectDependencyDescriptor dependency = new ProjectDependencyDescriptor();
ProjectDependencyDescriptor projectDependency = studio.getProjectDependency(name);
dependency.setName(name);
dependency.setAutoIncluded(projectDependency != null && projectDependency.isAutoIncluded());
dependencies.add(new ListItem<>(projectDependency != null, dependency));
}
}
return dependencies;
}
public String getSources() {
ProjectDescriptor currentProject = studio.getCurrentProjectDescriptor();
List sourceList = currentProject.getClasspath();
if (sourceList != null) {
StringBuilder sb = new StringBuilder();
for (PathEntry source : sourceList) {
sb.append(source.getPath()).append(StringTool.NEW_LINE);
}
sources = sb.toString();
}
return sources;
}
public void setSources(String sources) {
this.sources = sources;
}
public String getOpenAPIPath() {
ProjectDescriptor currentProject = studio.getCurrentProjectDescriptor();
final OpenAPI openapi = currentProject.getOpenapi();
if (openapi == null || openapi.getPath() == null) {
return "";
}
return openapi.getPath();
}
public String getLastOpenAPIFileUploadDate() {
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
final OpenAPI openapi = projectDescriptor.getOpenapi();
if (openapi == null) {
return null;
}
String path = openapi.getPath();
if (path == null) {
return null;
}
AProjectArtefact openAPIFile;
try {
openAPIFile = studio.getCurrentProject().getArtefactByPath(new ArtefactPathImpl(path));
} catch (ProjectException e) {
log.debug("Error on reading OpenAPI file.", e);
return null;
}
FileData fileData = openAPIFile.getFileData();
if (fileData != null && fileData.getModifiedAt() != null) {
return formats.formatDateOrDateTime(fileData.getModifiedAt());
}
return null;
}
public String getModelModuleName() {
ProjectDescriptor currentProject = studio.getCurrentProjectDescriptor();
final OpenAPI openapi = currentProject.getOpenapi();
if (openapi == null || openapi.getModelModuleName() == null) {
return null;
}
return openapi.getModelModuleName();
}
public String getAlgorithmModuleName() {
ProjectDescriptor currentProject = studio.getCurrentProjectDescriptor();
final OpenAPI openapi = currentProject.getOpenapi();
if (openapi == null || openapi.getAlgorithmModuleName() == null) {
return null;
}
return openapi.getAlgorithmModuleName();
}
public String getPropertiesFileNamePatterns() {
propertiesFileNamePatterns = studio.getCurrentProjectDescriptor().getPropertiesFileNamePatterns();
return StringUtils.join(propertiesFileNamePatterns, "\n");
}
public void setPropertiesFileNamePatterns(String propertiesFileNamePatterns) {
this.propertiesFileNamePatterns = StringUtils.toLines(propertiesFileNamePatterns);
}
// TODO Move messages to ValidationMessages.properties
public void validateProjectName(FacesContext context, UIComponent toValidate, Object value) {
String name = (String) value;
WebStudioUtils.validate(StringUtils.isNotBlank(name), "Cannot be empty");
if (!studio.getCurrentProjectDescriptor().getName().equals(name)) {
WebStudioUtils.validate(NameChecker.checkName(name), NameChecker.BAD_PROJECT_NAME_MSG);
WebStudioUtils.validate(!NameChecker.isReservedName(name), String.format("'%s' is a reserved word.", name));
WebStudioUtils.validate(!studio.isProjectExists(name), "Project with such name already exists");
}
}
public void validatePropertiesFileNameProcessor(FacesContext context, UIComponent toValidate, Object value) {
String className = (String) value;
if (!StringUtils.isBlank(className)) {
WebStudioUtils.validate(className.matches("([\\w$]+\\.)*[\\w$]+"), "Invalid class name");
ProjectDescriptor projectDescriptor = cloneProjectDescriptor(studio.getCurrentProjectDescriptor());
projectDescriptor.setPropertiesFileNameProcessor(className);
PropertiesFileNameProcessorBuilder propertiesFileNameProcessorBuilder = new PropertiesFileNameProcessorBuilder();
try {
propertiesFileNameProcessorBuilder.build(projectDescriptor);
} catch (InvalidFileNameProcessorException e) {
WebStudioUtils.throwValidationError(e.getMessage());
} catch (InvalidFileNamePatternException ignore) {
// Ignore
} finally {
propertiesFileNameProcessorBuilder.destroy();
}
}
}
// TODO Move messages to ValidationMessages.properties
public void validatePropertiesFileNamePattern(FacesContext context, UIComponent toValidate, Object value) {
String[] patterns = StringUtils.toLines((String) value);
if (patterns != null) {
PropertiesFileNameProcessorBuilder propertiesFileNameProcessorBuilder = new PropertiesFileNameProcessorBuilder();
try {
ProjectDescriptor projectDescriptor = cloneProjectDescriptor(studio.getCurrentProjectDescriptor());
projectDescriptor.setPropertiesFileNameProcessor((String) propertiesFileNameProcessorInput.getValue());
projectDescriptor.setPropertiesFileNamePatterns(patterns);
propertiesFileNameProcessorBuilder.build(projectDescriptor);
} catch (InvalidFileNamePatternException e) {
WebStudioUtils.throwValidationError(e.getMessage());
} catch (InvalidFileNameProcessorException ignored) {
// Processed in other validator
} finally {
propertiesFileNameProcessorBuilder.destroy();
}
}
}
// TODO Move messages to ValidationMessages.properties
public void validateModuleName(FacesContext context, UIComponent toValidate, Object value) {
String newName = (String) value;
String oldName = WebStudioUtils.getRequestParameter("moduleNameOld");
String modulePath = WebStudioUtils.getRequestParameter("modulePath");
Module toCheck = new Module();
toCheck.setRulesRootPath(new PathEntry(modulePath));
boolean withWildcard = isModuleWithWildcard(toCheck);
if (!withWildcard) {
WebStudioUtils.validate(StringUtils.isNotBlank(newName), CANNOT_BE_EMPTY_MESSAGE);
}
if (StringUtils.isBlank(oldName) // Add new Module
|| !oldName.equals(newName)) { // Edit current Module
if (!withWildcard || StringUtils.isNotBlank(newName)) {
WebStudioUtils.validate(NameChecker.checkName(newName), BAD_NAME_MSG);
Module module = studio.getModule(studio.getCurrentProjectDescriptor(), newName);
WebStudioUtils.validate(module == null, "Module with such name already exists");
}
}
}
public void validateModuleNameForCopy(FacesContext context, UIComponent toValidate, Object value) {
String newName = (String) value;
String oldName = WebStudioUtils.getRequestParameter("copyModuleForm:moduleNameOld");
String modulePath = WebStudioUtils.getRequestParameter("copyModuleForm:modulePath");
Module toCheck = new Module();
toCheck.setRulesRootPath(new PathEntry(modulePath));
boolean withWildcard = isModuleWithWildcard(toCheck);
if (!withWildcard) {
WebStudioUtils.validate(StringUtils.isNotBlank(newName), CANNOT_BE_EMPTY_MESSAGE);
}
if (StringUtils.isBlank(oldName) // Add new Module
|| !oldName.equals(newName)) { // Edit current Module
if (!withWildcard || StringUtils.isNotBlank(newName)) {
WebStudioUtils.validate(NameChecker.checkName(newName), BAD_NAME_MSG);
Module module = studio.getModule(studio.getCurrentProjectDescriptor(), newName);
WebStudioUtils.validate(module == null, "Module with such name already exists");
}
}
}
// TODO Move messages to ValidationMessages.properties
public void validateModulePath(FacesContext context, UIComponent toValidate, Object value) {
final String path = (String) value;
WebStudioUtils.validate(StringUtils.isNotBlank(path), CANNOT_BE_EMPTY_MESSAGE);
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
if (!(path.contains("*") || path.contains("?"))) {
Path moduleFile = projectDescriptor.getProjectFolder().resolve(path);
WebStudioUtils.validate(Files.exists(moduleFile), "File with the specified path is not found");
}
final String oldName = Optional.ofNullable(WebStudioUtils.getRequestParameter("moduleNameOld"))
.filter(StringUtils::isNotBlank)
.orElseGet(() -> WebStudioUtils.getRequestParameter("copyModuleForm:moduleNameOld"));
final String index = WebStudioUtils.getRequestParameter("moduleIndex");
final String relativePath = path.replace("\\", "/");
final boolean isNewModule = StringUtils.isBlank(oldName) && StringUtils.isBlank(index);
final Predicate isEditedModule = m -> !isNewModule && Objects.equals(oldName, m.getName());
final PathMatcher pathMatcher = projectDescriptorManager.getPathMatcher();
final Predicate wildcardPathMatch = m -> pathMatcher.match(m.getRulesRootPath().getPath(),
relativePath);
final Predicate strictPathMatch = m -> Objects.equals(m.getRulesRootPath().getPath(), relativePath);
final Predicate checkDuplicatePath = strictPathMatch
.or(wildcardPathMatch.and(this::isModuleWithWildcard));
if (projectDescriptor.getModules().stream().filter(isEditedModule.negate()).anyMatch(checkDuplicatePath)) {
WebStudioUtils.throwValidationError("Path is already covered with existing module.");
}
}
public void validateModulePathForCopy(FacesContext context, UIComponent toValidate, Object value) {
String path = WebStudioUtils.getRequestParameter("copyModuleForm:modulePath");
WebStudioUtils.validate(StringUtils.isNotBlank(path), CANNOT_BE_EMPTY_MESSAGE);
WebStudioUtils.validate(!(path.contains("*") || path.contains("?")), "Path cannot contain wildcard symbols");
try {
NameChecker.validatePath(path);
} catch (IOException e) {
WebStudioUtils.throwValidationError(String.format("Invalid path \"%s\". %s", path, e.getMessage()));
}
Path moduleFile = studio.getCurrentProjectDescriptor().getProjectFolder().resolve(path);
WebStudioUtils.validate(!Files.exists(moduleFile), "File with such name already exists");
}
public void validateOpenAPIPath(FacesContext context, UIComponent uiComponent, Object value) {
String pathToOpenAPIFile = (String) value;
WebStudioUtils.validate(StringUtils.isNotBlank(pathToOpenAPIFile), "Path to openAPI file cannot be empty.");
WebStudioUtils.validate(FileTypeHelper.isPossibleOpenAPIFile(pathToOpenAPIFile),
"The OpenAPI file must have JSON, YAML(YML) extension.");
boolean fileExists;
try {
studio.getCurrentProject().getArtefactByPath(new ArtefactPathImpl(pathToOpenAPIFile));
fileExists = true;
} catch (ProjectException e) {
fileExists = false;
}
WebStudioUtils.validate(fileExists, "OpenAPI file with path: " + pathToOpenAPIFile + " was not found.");
}
public void validateAlgorithmPath(FacesContext context, UIComponent component, Object value) {
String algoPath = WebStudioUtils.getRequestParameter("generateOpenAPIForm:algorithmModulePath");
String modelPath = WebStudioUtils.getRequestParameter("generateOpenAPIForm:modelModulePath");
String algorithmModuleNameParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:algorithmModuleName");
WebStudioUtils.validate(StringUtils.isNotBlank(algoPath), "Algorithm Module Path cannot be empty.");
WebStudioUtils.validate(!algoPath.equalsIgnoreCase(modelPath), "Module paths cannot be the same");
validatePath(algoPath, algorithmModuleNameParam);
}
private void validatePath(String path, String moduleName) {
try {
NameChecker.validatePath(path);
} catch (IOException e) {
WebStudioUtils.throwValidationError(String.format("Invalid path \"%s\". %s", path, e.getMessage()));
}
String fileName = FileUtils.getBaseName(path);
WebStudioUtils.validate(NameChecker.checkName(fileName),
"File name contains illegal characters " + BAD_NAME_MSG);
WebStudioUtils.validate(StringUtils.isNotBlank(fileName), "File name is not defined.");
String fileNameWithExtension = FileUtils.getName(path);
WebStudioUtils.validate(FileTypeHelper.isExcelFile(fileNameWithExtension),
"The generated file must have an Excel format.");
ProjectDescriptor currentProjectDescriptor = studio.getCurrentProjectDescriptor();
Module module = studio.getModule(currentProjectDescriptor, moduleName);
String folderPath = studio.getCurrentProject().getFolderPath();
if (module == null || (module
.getRulesRootPath() != null && !getArtefactPath(module.getRulesRootPath().getPath(), folderPath)
.equals(path))) {
Path moduleFile = currentProjectDescriptor.getProjectFolder().resolve(path);
WebStudioUtils.validate(!Files.exists(moduleFile), "File with such name already exists.");
}
}
public void validateDataPath(FacesContext context, UIComponent component, Object value) {
String path = WebStudioUtils.getRequestParameter("generateOpenAPIForm:modelModulePath");
String algoPath = WebStudioUtils.getRequestParameter("generateOpenAPIForm:algorithmModulePath");
String modelModuleNameParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:modelModuleName");
WebStudioUtils.validate(StringUtils.isNotBlank(path), "Data Module Path cannot be empty.");
WebStudioUtils.validate(!algoPath.equalsIgnoreCase(path), "Module paths cannot be the same");
validatePath(path, modelModuleNameParam);
}
public void validateAlgorithmModuleName(FacesContext context, UIComponent component, Object value) {
if (isReconciliationMode())
return;
final String possibleAlgorithmModuleName = (String) value;
final String currentModelModuleName = WebStudioUtils.getRequestParameter("importOpenAPIForm:modelModuleName");
if (currentModelModuleName != null) {
WebStudioUtils.validate(!currentModelModuleName.equalsIgnoreCase(possibleAlgorithmModuleName),
"Module names cannot be the same.");
}
WebStudioUtils.validate(StringUtils.isNotBlank(possibleAlgorithmModuleName),
"Module Name for Rules must not be empty.");
WebStudioUtils.validate(NameChecker.checkName(possibleAlgorithmModuleName),
"Rules Module name contains illegal characters.");
}
public void validateModelModuleName(FacesContext context, UIComponent component, Object value) {
if (isReconciliationMode())
return;
final String possibleModelModuleName = (String) value;
final String currentAlgorithmModuleName = WebStudioUtils
.getRequestParameter("importOpenAPIForm:algorithmModuleName");
if (currentAlgorithmModuleName != null) {
WebStudioUtils.validate(!currentAlgorithmModuleName.equalsIgnoreCase(possibleModelModuleName),
"Module names cannot be the same.");
}
WebStudioUtils.validate(StringUtils.isNotBlank(possibleModelModuleName),
"Module Name for Data Types must not be empty.");
WebStudioUtils.validate(NameChecker.checkName(possibleModelModuleName),
"Data Module name contains illegal characters.");
}
private boolean isReconciliationMode() {
String mode = WebStudioUtils.getRequestParameter("mode");
return mode.equals(RECONCILIATION);
}
public void editName() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
projectDescriptor.setPropertiesFileNamePatterns(propertiesFileNamePatterns);
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
Repository designRepository = currentProject.getDesignRepository();
boolean supportsMappedFolders = designRepository != null && designRepository.supports().mappedFolders();
if (!supportsMappedFolders && studio.isRenamed(currentProject)) {
// Restore physical project name
newProjectDescriptor.setName(currentProject.getName());
}
clean(newProjectDescriptor);
save(newProjectDescriptor);
try {
String repositoryId = currentProject.getRepository().getId();
String branch = currentProject.getBranch();
studio.init(repositoryId, branch, newProjectDescriptor.getName(), null);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new Message("Error while project renaming");
}
}
private void validatePermissionsForDescriptorFile(RulesProject currentProject, boolean append) {
if (currentProject.hasArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME)) {
try {
AProjectArtefact projectArtefact = currentProject
.getArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
validatePermissionForEditing(projectArtefact);
} catch (ProjectException ignored) {
}
} else {
if (append) {
validatePermissionForCreating(currentProject,
ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
}
}
}
public void editModule() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
ProjectDescriptor projectDescriptor = getOriginalProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
String index = WebStudioUtils.getRequestParameter("moduleIndex");
String oldName = WebStudioUtils.getRequestParameter("moduleNameOld");
String name = WebStudioUtils.getRequestParameter("moduleName");
String path = WebStudioUtils.getRequestParameter("modulePath");
String includes = WebStudioUtils.getRequestParameter("moduleIncludes");
String excludes = WebStudioUtils.getRequestParameter("moduleExcludes");
String compileThisModuleOnly = WebStudioUtils.getRequestParameter("compileThisModuleOnly");
Module module;
boolean moduleWasRenamed = false;
if (StringUtils.isBlank(oldName) && StringUtils.isBlank(index)) {
// Add new Module
module = new Module();
module.setProject(newProjectDescriptor);
newProjectDescriptor.getModules().add(module);
} else {
// Edit current Module
if (!StringUtils.isBlank(oldName)) {
module = studio.getModule(newProjectDescriptor, oldName);
if (!oldName.equals(name)) {
moduleWasRenamed = true;
}
} else {
module = newProjectDescriptor.getModules().get(Integer.parseInt(index));
}
}
if (module != null) {
module.setName(name);
PathEntry pathEntry = module.getRulesRootPath();
if (pathEntry == null) {
pathEntry = new PathEntry();
module.setRulesRootPath(pathEntry);
}
pathEntry.setPath(path);
MethodFilter filter = module.getMethodFilter();
if (filter == null) {
filter = new MethodFilter();
module.setMethodFilter(filter);
}
filter.setIncludes(null);
filter.setExcludes(null);
if (StringUtils.isNotBlank(includes)) {
filter.addIncludePattern(StringUtils.toLines(includes));
}
if (StringUtils.isNotBlank(excludes)) {
filter.addExcludePattern(StringUtils.toLines(excludes));
}
if (moduleWasRenamed) {
OpenAPI descriptorOpenAPI = newProjectDescriptor.getOpenapi();
if (descriptorOpenAPI != null) {
String algorithmsModuleName = descriptorOpenAPI.getAlgorithmModuleName();
String modelsModuleName = descriptorOpenAPI.getModelModuleName();
boolean moduleNamesExists = StringUtils.isNotBlank(algorithmsModuleName) || StringUtils
.isNotBlank(modelsModuleName);
if (moduleNamesExists) {
if (oldName.equals(algorithmsModuleName)) {
descriptorOpenAPI.setAlgorithmModuleName(name);
} else if (oldName.equals(modelsModuleName)) {
descriptorOpenAPI.setModelModuleName(name);
}
}
}
}
WebstudioConfiguration webstudioConfiguration = new WebstudioConfiguration();
if ("on".equals(compileThisModuleOnly)) {
webstudioConfiguration.setCompileThisModuleOnly(true);
}
module.setWebstudioConfiguration(webstudioConfiguration);
clean(newProjectDescriptor);
save(newProjectDescriptor);
}
}
public void copyModule() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
ProjectDescriptor projectDescriptor = getOriginalProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
String name = WebStudioUtils.getRequestParameter("copyModuleForm:moduleName");
String oldPath = WebStudioUtils.getRequestParameter("copyModuleForm:modulePathOld");
String path = WebStudioUtils.getRequestParameter("copyModuleForm:modulePath");
PathEntry pathEntry = new PathEntry();
pathEntry.setPath(path);
Module newModule = new Module();
newModule.setName(name);
newModule.setRulesRootPath(pathEntry);
boolean moduleMatchesSomePathPattern = isModuleMatchesSomePathPattern(newModule);
if (!moduleMatchesSomePathPattern) {
validatePermissionsForDescriptorFile(currentProject, false);
}
AProjectResource oldProjectResource;
try {
oldProjectResource = (AProjectResource) currentProject.getArtefact(oldPath);
} catch (ProjectException e) {
throw new Message("Error while module copying.");
}
validatePermissionForCreating(currentProject, path);
try {
AProjectResource newProjectResource = currentProject.addResource(path, oldProjectResource.getContent());
if (!designRepositoryAclService.hasAcl(newProjectResource) && !designRepositoryAclService
.createAcl(newProjectResource, AclPermissionsSets.NEW_FILE_PERMISSIONS, true)) {
String message = String.format("Granting permissions to a new file '%s' is failed.",
ProjectArtifactUtils.extractResourceName(newProjectResource));
WebStudioUtils.addErrorMessage(message);
}
} catch (ProjectException e) {
throw new Message("Error while module copying.");
}
currentProject.setModified();
if (!moduleMatchesSomePathPattern) {
// Add new Module
newModule.setProject(newProjectDescriptor);
newProjectDescriptor.getModules().add(newModule);
clean(newProjectDescriptor);
save(newProjectDescriptor);
} else {
refreshProject(currentProject.getRepository().getId(), currentProject.getName());
}
}
private void refreshProject(String repoId, String name) {
studio.getModel().clearModuleInfo();
ProjectDescriptor oldProjectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = studio.resolveProject(oldProjectDescriptor);
studio.forceUpdateProjectDescriptor(repoId, newProjectDescriptor, oldProjectDescriptor);
TreeProject projectNode = repositoryTreeState.getProjectNodeByPhysicalName(repoId, name);
if (projectNode != null) {
// For example, repository wasn't refreshed yet
projectNode.refresh();
}
}
public void removeModule() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, false);
ProjectDescriptor projectDescriptor = getOriginalProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
String toRemove = WebStudioUtils.getRequestParameter("moduleToRemove");
String leaveExcelFile = WebStudioUtils.getRequestParameter("leaveExcelFile");
List modules = newProjectDescriptor.getModules();
Module removed = modules.remove(Integer.parseInt(toRemove));
if (StringUtils.isEmpty(leaveExcelFile)) {
ProjectDescriptor currentProjectDescriptor = studio.getCurrentProjectDescriptor();
List modulesForRemoving = new ArrayList<>();
if (projectDescriptorManager.isModuleWithWildcard(removed)) {
for (Module module : currentProjectDescriptor.getModules()) {
if (module.getWildcardRulesRootPath() == null) {
// Module not included in wildcard
continue;
}
if (module.getWildcardRulesRootPath().equals(removed.getRulesRootPath().getPath())) {
checkPermissionsForDeletingModule(currentProject, module);
modulesForRemoving.add(module);
}
}
} else {
checkPermissionsForDeletingModule(currentProject, removed);
modulesForRemoving.add(removed);
}
modulesForRemoving.forEach(e -> deleteModule(currentProject, e));
File projectFolder = currentProjectDescriptor.getProjectFolder().toFile();
File rulesXmlFile = new File(projectFolder,
ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
if (rulesXmlFile.exists()) {
String removedModuleName = removed.getName();
clean(newProjectDescriptor);
OpenAPI openAPI = newProjectDescriptor.getOpenapi();
if (openAPI != null) {
String definedAlgoModuleName = openAPI.getAlgorithmModuleName();
String definedModelsName = openAPI.getModelModuleName();
if (definedAlgoModuleName != null && definedAlgoModuleName.equalsIgnoreCase(removedModuleName)) {
openAPI.setAlgorithmModuleName(null);
} else if (definedModelsName != null && definedModelsName.equalsIgnoreCase(removedModuleName)) {
openAPI.setModelModuleName(null);
}
}
save(newProjectDescriptor);
} else {
currentProject.setModified();
refreshProject(currentProject.getRepository().getId(), currentProject.getName());
}
} else {
clean(newProjectDescriptor);
save(newProjectDescriptor);
}
studio.resetProjects();
}
private void checkPermissionsForDeletingModule(RulesProject currentProject, Module module) {
try {
AProjectArtefact projectArtefact = currentProject.getArtefact(module.getRulesRootPath().getPath());
if (!designRepositoryAclService.isGranted(projectArtefact, List.of(AclPermission.DELETE))) {
throw new Message(String.format("There is no permission for deleting '%s' file.",
ProjectArtifactUtils.extractResourceName(projectArtefact)));
}
} catch (ProjectException ignored) {
}
}
private void deleteModule(RulesProject currentProject, Module module) {
try {
AProjectArtefact projectArtefact = currentProject.getArtefact(module.getRulesRootPath().getPath());
projectArtefact.delete();
} catch (ProjectException e) {
throw new Message(String.format("Cannot delete '%s' module.", module.getName()), e);
}
}
public boolean canCopyModule(Module module) {
if (studio.getModel().isEditableProject()) {
RulesProject currentProject = studio.getCurrentProject();
String path = module.getRulesRootPath().getPath();
boolean originalPathWithWildcards = path.contains("?") || path.contains("*");
path = path.replace("\\", "/");
int d = path.lastIndexOf("/");
path = d >= 0 ? path.substring(0, d) : StringUtils.EMPTY;
if (path.contains("?") || path.contains("*")) {
return true;
} else {
if (!originalPathWithWildcards && !studio.getModel().isEditableProjectDescriptor()) {
return false;
}
if (path.startsWith("./")) {
path = path.substring(2);
}
path = designRepositoryAclService
.getPath(currentProject) + (StringUtils.isNotBlank(path) ? "/" + path : StringUtils.EMPTY);
return designRepositoryAclService
.isGranted(currentProject.getRepository().getId(), path, List.of(AclPermission.ADD));
}
}
return false;
}
public boolean canDeleteModule(Module module) {
if (studio.getModel().isEditableProject()) {
RulesProject currentProject = studio.getCurrentProject();
if (currentProject.hasArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME)) {
try {
return designRepositoryAclService.isGranted(
currentProject
.getArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME),
List.of(AclPermission.EDIT));
} catch (ProjectException ignored) {
return false;
}
} else {
return designRepositoryAclService.isGranted(currentProject, List.of(AclPermission.ADD));
}
}
return false;
}
public boolean isOnlySafeModuleRemove(Module module) {
if (module == null) {
return true;
}
RulesProject currentProject = studio.getCurrentProject();
if (currentProject != null) {
try {
if (isModuleWithWildcard(module)) {
for (Module m : getModulesMatchingPathPattern(module)) {
AProjectArtefact projectArtefact = currentProject.getArtefact(m.getRulesRootPath().getPath());
if (!designRepositoryAclService.isGranted(projectArtefact, List.of(AclPermission.DELETE))) {
return true;
}
}
return false;
} else {
AProjectArtefact projectArtefact = currentProject.getArtefact(module.getRulesRootPath().getPath());
return !designRepositoryAclService.isGranted(projectArtefact, List.of(AclPermission.DELETE));
}
} catch (ProjectException e) {
return true;
}
}
return true;
}
public void removeDependency(String name) {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, false);
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
clean(newProjectDescriptor);
List resultDependencies = newProjectDescriptor.getDependencies();
resultDependencies.removeIf(dependency -> dependency.getName().equals(name));
newProjectDescriptor.setDependencies(!resultDependencies.isEmpty() ? resultDependencies : null);
save(newProjectDescriptor);
}
public void editDependencies() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
clean(newProjectDescriptor);
List resultDependencies = new ArrayList<>();
for (ListItem dependency : dependencies) {
if (dependency.isSelected()) {
resultDependencies.add(dependency.getItem());
}
}
newProjectDescriptor.setDependencies(!resultDependencies.isEmpty() ? resultDependencies : null);
save(newProjectDescriptor);
}
public void editSources() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
List sourceList = new ArrayList<>();
String[] sourceArray = StringUtils.toLines(sources);
if (CollectionUtils.isNotEmpty(sourceArray)) {
for (String source : sourceArray) {
PathEntry sourcePath = new PathEntry(source);
sourceList.add(sourcePath);
}
}
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
clean(newProjectDescriptor);
newProjectDescriptor.setClasspath(!sourceList.isEmpty() ? sourceList : null);
save(newProjectDescriptor);
}
public void reconcileOpenAPI() {
tryLockProject();
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(projectDescriptor);
clean(newProjectDescriptor);
String openAPIPathParam = FileNameFormatter
.normalizePath(WebStudioUtils.getRequestParameter("importOpenAPIForm:openAPIPath"));
OpenAPI openAPI = projectDescriptor.getOpenapi();
if (openAPI != null) {
openAPI.setPath(openAPIPathParam);
openAPI.setMode(OpenAPI.Mode.RECONCILIATION);
} else {
openAPI = new OpenAPI(openAPIPathParam, OpenAPI.Mode.RECONCILIATION, null, null);
}
newProjectDescriptor.setOpenapi(openAPI);
save(newProjectDescriptor);
}
public void getModulesInfo() {
ProjectDescriptor currentProjectDescriptor = studio.getCurrentProjectDescriptor();
String algorithmModuleNameParam = WebStudioUtils.getRequestParameter("importOpenAPIForm:algorithmModuleName");
String modelsModuleNameParam = WebStudioUtils.getRequestParameter("importOpenAPIForm:modelModuleName");
Module algoModule = studio.getModule(currentProjectDescriptor, algorithmModuleNameParam);
Module modelsModule = studio.getModule(currentProjectDescriptor, modelsModuleNameParam);
ModuleInfoDTO rulesDTO = getModuleInfoDTO(algoModule, "Algorithms");
ModuleInfoDTO modelsDTO = getModuleInfoDTO(modelsModule, "Models");
modulesInfoList = Arrays.asList(rulesDTO, modelsDTO);
}
private ModuleInfoDTO getModuleInfoDTO(Module module, String type) {
ModuleInfoDTO result = null;
if (module != null) {
PathEntry rulesRootPath = module.getRulesRootPath();
result = new ModuleInfoDTO(module.getName(),
rulesRootPath != null ? getArtefactPath(rulesRootPath.getPath(),
studio.getCurrentProject().getFolderPath()) : null,
type);
}
return result;
}
public void createOrUpdateOpenAPISchema() {
ProjectDescriptor currentDescriptor = studio.getCurrentProjectDescriptor();
List modules = currentDescriptor.getModules();
if (modules.isEmpty()) {
throw new Message("Project has no modules.");
}
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
studio.init(currentProject.getDesignRepository().getId(),
currentProject.getBranch(),
currentProject.getName(),
modules.iterator().next().getName());
org.openl.rules.ui.ProjectModel projectModel = studio.getModel();
while (!isCompilationCompleted(projectModel)) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new Message("Project compilation has been interrupted.", e);
}
}
final String existedOpenAPIFilePath = getExistedOpenAPIFilePath();
final boolean update = existedOpenAPIFilePath != null;
CompiledOpenClass compiledOpenClass = projectModel.getCompiledOpenClass();
final boolean hasCompilationErrors;
if (compiledOpenClass instanceof ValidatedCompiledOpenClass) {
ValidatedCompiledOpenClass validated = (ValidatedCompiledOpenClass) compiledOpenClass;
hasCompilationErrors = validated.hasErrors() && !validated.hasOnlyValidationErrors();
} else {
hasCompilationErrors = compiledOpenClass.hasErrors();
}
if (hasCompilationErrors) {
throw new Message(
String.format("Cannot %s OpenAPI file. Project has compilation error.", update ? "update" : "create"));
}
tryLockProject();
try {
OpenApiGenerator generator = OpenApiGenerator
.builder(projectModel.getModuleInfo().getProject(), projectModel.getRulesInstantiationStrategy(projectModel.getModuleInfo().getProject()))
.generator();
final OpenAPI.Type openAPIType = Optional.of(OpenAPI.Type.JSON)
.map(t -> update ? OpenAPI.Type.chooseType(FileUtils.getExtension(existedOpenAPIFilePath)) : t)
.orElse(OpenAPI.Type.JSON);
try (InputStream in = serializeOpenApi(generator, openAPIType)) {
if (update) {
AProjectResource resource = ((AProjectResource) currentProject.getProject()
.getArtefact(existedOpenAPIFilePath));
validatePermissionForEditing(resource);
resource.setContent(in);
} else {
validatePermissionForCreating(currentProject, openAPIType.getDefaultFileName());
currentProject.addResource(openAPIType.getDefaultFileName(), in);
AProjectArtefact projectArtefact = currentProject.getArtefact(openAPIType.getDefaultFileName());
if (!designRepositoryAclService.hasAcl(projectArtefact) && !designRepositoryAclService
.createAcl(projectArtefact, AclPermissionsSets.NEW_FILE_PERMISSIONS, true)) {
String message = String.format("Granting permissions to a new file '%s' is failed.",
ProjectArtifactUtils.extractResourceName(projectArtefact));
WebStudioUtils.addErrorMessage(message);
}
}
}
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(currentDescriptor);
clean(newProjectDescriptor);
if (update && newProjectDescriptor.getOpenapi() != null) {
OpenAPI openAPI = newProjectDescriptor.getOpenapi();
openAPI.setPath(existedOpenAPIFilePath);
openAPI.setMode(OpenAPI.Mode.RECONCILIATION);
} else {
OpenAPI openAPI = new OpenAPI();
openAPI.setPath(openAPIType.getDefaultFileName());
openAPI.setMode(OpenAPI.Mode.RECONCILIATION);
newProjectDescriptor.setOpenapi(openAPI);
}
save(newProjectDescriptor);
} catch (OpenApiGenerationException e) {
throw new Message(e.getMessage(), e);
} catch (Message e) {
throw e;
} catch (Exception e) {
throw new Message(
String.format("Failed to %s OpenAPI file. Check compilation.", update ? "update" : "create"),
e);
} finally {
if (!currentProject.isModified()) {
currentProject.unlock();
}
}
}
private static boolean isCompilationCompleted(org.openl.rules.ui.ProjectModel projectModel) {
return projectModel.isProjectCompilationCompleted() || Optional.ofNullable(projectModel.getModuleInfo())
.map(Module::getWebstudioConfiguration)
.map(WebstudioConfiguration::isCompileThisModuleOnly)
.orElse(Boolean.FALSE);
}
private static InputStream serializeOpenApi(OpenApiGenerator generator,
OpenAPI.Type openAPIType) throws JsonProcessingException, RulesInstantiationException, OpenApiGenerationException {
String generatedOpenAPISchema;
switch (openAPIType) {
case JSON:
generatedOpenAPISchema = Json.pretty().writeValueAsString(generator.generate());
break;
case YAML:
case YML:
generatedOpenAPISchema = Yaml.pretty().writeValueAsString(generator.generate());
break;
default:
throw new IllegalStateException(); // Must newer happened.
}
return IOUtils.toInputStream(generatedOpenAPISchema);
}
public String getExistedOpenAPIFilePath() {
ProjectDescriptor currentDescriptor = studio.getCurrentProjectDescriptor();
RulesProject currentProject = studio.getCurrentProject();
Optional openApiPath = Optional.ofNullable(currentDescriptor.getOpenapi())
.map(OpenAPI::getPath)
.filter(StringUtils::isNotBlank);
if (openApiPath.isPresent() && currentProject.hasArtefact(openApiPath.get())) {
return openApiPath.get();
}
return Stream.of(OpenAPI.Type.values())
.map(OpenAPI.Type::getDefaultFileName)
.filter(currentProject::hasArtefact)
.findFirst()
.orElse(null);
}
public void regenerateOpenAPI() {
studio.initProjectHistory();
tryLockProject();
ProjectDescriptor currentProjectDescriptor = studio.getCurrentProjectDescriptor();
List modules = currentProjectDescriptor.getModules();
String openAPIPathParam = FileNameFormatter
.normalizePath(WebStudioUtils.getRequestParameter("generateOpenAPIForm:openAPIPath"));
String algorithmModuleNameParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:algorithmModuleName");
String modelModuleNameParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:modelModuleName");
String algorithmModulePathParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:algorithmModulePath");
String modelModulePathParam = WebStudioUtils.getRequestParameter("generateOpenAPIForm:modelModulePath");
if (!NameChecker.checkName(algorithmModuleNameParam) || !NameChecker.checkName(modelModuleNameParam)) {
throw new Message("Module names are not correct.");
}
if (modelModulePathParam.equalsIgnoreCase(algorithmModulePathParam)) {
throw new Message("Module paths cannot be the same.");
}
try {
studio.freezeProject(currentProjectDescriptor.getName());
Module existingAlgorithmModule = studio.getModule(currentProjectDescriptor, algorithmModuleNameParam);
boolean isNewAlgorithmModule = existingAlgorithmModule == null;
Module existingModelModule = studio.getModule(currentProjectDescriptor, modelModuleNameParam);
boolean isNewDataModule = existingModelModule == null;
validatePaths(algorithmModulePathParam, modelModulePathParam, isNewAlgorithmModule, isNewDataModule);
boolean openAPIInfoChanged;
boolean classPathChanged = false;
final OpenAPI existingOpenAPI = currentProjectDescriptor.getOpenapi();
OpenAPI openAPI = new OpenAPI();
openAPI.setPath(openAPIPathParam);
openAPI.setMode(OpenAPI.Mode.GENERATION);
List currentClassPath = currentProjectDescriptor.getClasspath();
boolean openAPIClassesInClassPath = CollectionUtils.isNotEmpty(currentClassPath) && currentClassPath
.stream()
.anyMatch(pathEntry -> pathEntry.getPath().equals(OpenAPIHelper.DEF_JAVA_CLASS_PATH));
if (existingOpenAPI == null || existingOpenAPI.getPath() == null || existingOpenAPI.getMode() == null) {
openAPIInfoChanged = true;
} else {
boolean pathWasChanged = !existingOpenAPI.getPath().equals(openAPIPathParam);
boolean modeWasChanged = !existingOpenAPI.getMode().equals(OpenAPI.Mode.GENERATION);
openAPIInfoChanged = pathWasChanged || modeWasChanged;
}
RulesProject currentProject = studio.getCurrentProject();
AProjectArtefact openAPIFile = getOpenAPIFile(openAPIPathParam, currentProject);
if (!isNewAlgorithmModule) {
deleteExistingExcelFile(existingAlgorithmModule,
currentProject,
"It's impossible to delete existing generated Rules file.");
openAPI.setAlgorithmModuleName(algorithmModuleNameParam);
} else {
Module rulesModule = new Module();
rulesModule.setRulesRootPath(new PathEntry(algorithmModulePathParam));
rulesModule.setName(algorithmModuleNameParam);
modules.add(rulesModule);
openAPI.setAlgorithmModuleName(algorithmModuleNameParam);
openAPIInfoChanged = true;
}
if (!isNewDataModule) {
deleteExistingExcelFile(existingModelModule,
currentProject,
"It's impossible to delete existing generated Data Types file.");
openAPI.setModelModuleName(modelModuleNameParam);
} else {
Module modelsModule = new Module();
modelsModule.setRulesRootPath(new PathEntry(modelModulePathParam));
modelsModule.setName(modelModuleNameParam);
modules.add(modelsModule);
openAPI.setModelModuleName(modelModuleNameParam);
openAPIInfoChanged = true;
}
String workspacePath = studio.getWorkspacePath();
String internalOpenAPIPath = openAPIFile.getArtefactPath().getStringValue();
OpenAPIModelConverter converter = new OpenAPIScaffoldingConverter();
ProjectModel projectModel = getProjectModel(FileNameFormatter.normalizePath(workspacePath),
internalOpenAPIPath,
converter);
modules.stream().filter(m -> m.getName().equals(algorithmModuleNameParam)).findFirst().ifPresent(m -> {
MethodFilter filter = new MethodFilter();
filter.setIncludes(projectModel.getIncludeMethodFilter());
m.setMethodFilter(filter);
});
addDataTypesFile(modelModulePathParam, currentProject, projectModel);
addAlgorithmsFile(modelModuleNameParam, algorithmModulePathParam, currentProject, projectModel);
OpenAPIGeneratedClasses generated = new OpenAPIJavaClassGenerator(projectModel).generate();
boolean annotationTemplateClassesAreGenerated = generated.hasAnnotationTemplateClass();
deletePreviouslyGeneratedOpenAPIClasses(currentProject);
addGeneratedGroovyScripts(currentProject, generated, annotationTemplateClassesAreGenerated);
if (annotationTemplateClassesAreGenerated) {
if (!openAPIClassesInClassPath) {
classPathChanged = true;
}
} else {
if (openAPIClassesInClassPath) {
classPathChanged = true;
}
}
editOrCreateRulesDeploy(currentProject,
projectModel,
generated,
currentProject.hasArtefact(RULES_DEPLOY_XML));
studio.storeProjectHistory();
refreshProject(currentProject.getRepository().getId(), currentProject.getName());
if (openAPIInfoChanged || classPathChanged) {
editDescriptorIfNeeded(currentProjectDescriptor,
openAPIInfoChanged,
classPathChanged,
openAPI,
annotationTemplateClassesAreGenerated);
}
} finally {
studio.releaseProject(currentProjectDescriptor.getName());
}
}
private void validatePermissionForEditing(AProjectArtefact artefact) {
if (!designRepositoryAclService.isGranted(artefact, List.of(AclPermission.EDIT))) {
throw new Message(String.format("There is no permission for modifying '%s' file.",
ProjectArtifactUtils.extractResourceName(artefact)));
}
}
private void validatePermissionForCreating(RulesProject currentProject, String path) {
String p = designRepositoryAclService.getPath(currentProject);
if (!designRepositoryAclService
.isGranted(currentProject.getRepository().getId(), p + "/" + path, List.of(AclPermission.ADD))) {
throw new Message(String.format("There is no permission for creating '%s/%s' file.",
ProjectArtifactUtils.extractResourceName(currentProject),
path));
}
}
private void addGeneratedGroovyScripts(RulesProject currentProject,
OpenAPIGeneratedClasses generated,
boolean annotationTemplateClassesAreGenerated) {
if (annotationTemplateClassesAreGenerated) {
try {
GroovyScriptFile groovyFile = generated.getAnnotationTemplateGroovyFile();
String groovyPath = openAPIHelper.makePathToTheGeneratedFile(groovyFile.getPath());
validatePermissionForCreating(currentProject, groovyPath);
currentProject.addResource(groovyPath, IOUtils.toInputStream(groovyFile.getScriptText()));
} catch (ProjectException e) {
throw new Message("Failed to add generated annotation template class.");
}
}
try {
for (GroovyScriptFile groovyCommonFile : generated.getGroovyCommonClasses()) {
String javaInterfacePath = openAPIHelper.makePathToTheGeneratedFile(groovyCommonFile.getPath());
validatePermissionForCreating(currentProject, javaInterfacePath);
currentProject.addResource(javaInterfacePath, IOUtils.toInputStream(groovyCommonFile.getScriptText()));
}
} catch (ProjectException e) {
throw new Message("Failed to add generated common classes.");
}
}
private void deletePreviouslyGeneratedOpenAPIClasses(RulesProject currentProject) {
try {
currentProject.deleteArtefactsInFolder(
OpenAPIHelper.DEF_JAVA_CLASS_PATH + "/" + OpenAPIJavaClassGenerator.DEFAULT_OPEN_API_PATH.replace(".",
"/"));
} catch (ProjectException e) {
throw new Message(
String.format("Failed to remove previously generated file for project %s.", currentProject.getName()));
}
}
private void editDescriptorIfNeeded(ProjectDescriptor currentProjectDescriptor,
boolean openAPIInfoChanged,
boolean classPathChanged,
OpenAPI openAPI,
boolean annotationTemplateClassesAreGenerated) {
RulesProject currentProject = studio.getCurrentProject();
validatePermissionsForDescriptorFile(currentProject, true);
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(currentProjectDescriptor);
clean(newProjectDescriptor);
if (openAPIInfoChanged) {
newProjectDescriptor.setOpenapi(openAPI);
}
if (classPathChanged) {
List classpath = newProjectDescriptor.getClasspath();
if (annotationTemplateClassesAreGenerated) {
PathEntry openAPIClasses = new PathEntry(OpenAPIHelper.DEF_JAVA_CLASS_PATH);
if (classpath == null) {
List generatedClassPath = new ArrayList<>();
generatedClassPath.add(openAPIClasses);
newProjectDescriptor.setClasspath(generatedClassPath);
} else {
classpath.add(openAPIClasses);
}
} else {
if (classpath != null) {
classpath.removeIf(pathEntry -> pathEntry.getPath().equals(OpenAPIHelper.DEF_JAVA_CLASS_PATH));
}
}
}
save(newProjectDescriptor);
}
private void addAlgorithmsFile(String modelModuleNameParam,
String algorithmModulePathParam,
RulesProject currentProject,
ProjectModel projectModel) {
try (InputStream spreadsheets = openAPIHelper.generateAlgorithmsModule(projectModel
.getSpreadsheetResultModels(), projectModel.getDataModels(), getEnvironmentModel(modelModuleNameParam))) {
validatePermissionForCreating(currentProject, algorithmModulePathParam);
currentProject.addResource(algorithmModulePathParam, spreadsheets);
} catch (IOException | ProjectException e) {
log.error(e.getMessage(), e);
throw new Message("Failed to add rules file.");
}
}
private void addDataTypesFile(String modelModulePathParam, RulesProject currentProject, ProjectModel projectModel) {
try (InputStream dataTypes = openAPIHelper.generateDataTypesFile(projectModel.getDatatypeModels())) {
validatePermissionForCreating(currentProject, modelModulePathParam);
currentProject.addResource(modelModulePathParam, dataTypes);
} catch (IOException | ProjectException e) {
log.error(e.getMessage(), e);
throw new Message("Failed to add data types file.");
}
}
private void validatePaths(String algorithmModulePathParam,
String modelModulePathParam,
boolean isNewAlgorithmModule,
boolean isNewDataModule) {
if (isNewAlgorithmModule) {
checkPath(algorithmModulePathParam);
}
if (isNewDataModule) {
checkPath(modelModulePathParam);
}
}
private AProjectArtefact getOpenAPIFile(String openAPIPath, RulesProject currentProject) {
AProjectArtefact openAPIFile;
try {
openAPIFile = currentProject.getArtefactByPath(new ArtefactPathImpl(openAPIPath));
} catch (ProjectException e) {
throw new Message("There is no openAPI file wasn't found with path " + openAPIPath + ".");
}
return openAPIFile;
}
private void deleteExistingExcelFile(Module existingModule, RulesProject currentProject, String errorMessage) {
AProjectArtefact artefact = null;
try {
if (existingModule.getRulesRootPath() != null) {
artefact = currentProject
.getArtefactByPath(new ArtefactPathImpl(getArtefactPath(existingModule.getRulesRootPath().getPath(),
studio.getCurrentProject().getFolderPath())));
}
} catch (ProjectException e) {
log.warn("Existing file wasn't found in module {}", existingModule.getName(), e);
}
if (artefact != null) {
if (!designRepositoryAclService.isGranted(artefact, List.of(AclPermission.DELETE))) {
throw new Message(String.format("There is no permission for deleting '%s' file.",
ProjectArtifactUtils.extractResourceName(artefact)));
}
try {
currentProject.deleteArtefact(artefact.getInternalPath());
} catch (ProjectException e) {
throw new Message(errorMessage);
}
}
}
private void checkPath(String path) {
Path existingArtefact = studio.getCurrentProjectDescriptor().getProjectFolder().resolve(path);
if (Files.exists(existingArtefact)) {
throw new Message("Artefact with the path " + path + " already exists.");
}
}
private void editOrCreateRulesDeploy(RulesProject currentProject,
ProjectModel projectModel,
OpenAPIGeneratedClasses generatedClasses,
boolean rulesDeployExists) {
try {
configureSerializer();
} catch (IOException | JAXBException e) {
log.error("Error was occurred during serializer configuration.");
}
try {
if (rulesDeployExists) {
AProjectResource artifact = (AProjectResource) currentProject.getArtefact(RULES_DEPLOY_XML);
validatePermissionForEditing(artifact);
try (InputStream rulesDeployContent = artifact.getContent()) {
RulesDeploy rulesDeploy = rulesDeploySerializerFactory
.getSerializer(SupportedVersion.getLastVersion())
.deserialize(rulesDeployContent);
artifact.setContent(openAPIHelper
.editOrCreateRulesDeploy(rulesDeploySerializer, projectModel, generatedClasses, rulesDeploy));
}
} else {
try (ByteArrayInputStream rulesDeployInputStream = openAPIHelper
.editOrCreateRulesDeploy(rulesDeploySerializer, projectModel, generatedClasses, null)) {
validatePermissionForCreating(currentProject, RULES_DEPLOY_XML);
currentProject.addResource(RULES_DEPLOY_XML, rulesDeployInputStream);
}
}
} catch (ProjectException | IOException | JAXBException e) {
throw new Message("Failed to add 'rules-deploy.xml' file to the project.");
}
}
private ProjectModel getProjectModel(String workspacePath,
String internalOpenAPIPath,
OpenAPIModelConverter converter) {
ProjectModel projectModel;
try {
projectModel = converter.extractProjectModel(workspacePath + "/" + internalOpenAPIPath);
} catch (Exception e) {
throw new Message("OpenAPI file is corrupted.");
}
return projectModel;
}
private String getArtefactPath(String filePath, String basePath) {
if (filePath.startsWith(basePath)) {
filePath = filePath.substring(filePath.lastIndexOf(basePath) + basePath.length() + 1);
}
return FileNameFormatter.normalizePath(filePath);
}
private EnvironmentModel getEnvironmentModel(String moduleName) {
EnvironmentModel environmentModel = new EnvironmentModel();
environmentModel.setDependencies(Collections.singletonList(moduleName));
return environmentModel;
}
private void tryLockProject() {
RulesProject currentProject = studio.getCurrentProject();
if (!currentProject.tryLock()) {
throw new Message("Project is locked by the other user.");
}
}
private void save(ProjectDescriptor projectDescriptor) {
RulesProject project = studio.getCurrentProject();
InputStream rulesDeployContent = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
configureSerializer();
projectDescriptorManager.writeDescriptor(projectDescriptor, byteArrayOutputStream);
ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
if (project.hasArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME)) {
AProjectResource artifact = (AProjectResource) project
.getArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
validatePermissionForEditing(artifact);
artifact.setContent(inputStream);
} else {
validatePermissionForCreating(project,
ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
project.addResource(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME, inputStream);
AProjectArtefact projectArtefact = project
.getArtefact(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME);
if (!designRepositoryAclService.hasAcl(projectArtefact) && !designRepositoryAclService
.createAcl(projectArtefact, AclPermissionsSets.NEW_FILE_PERMISSIONS, true)) {
String message = String.format("Granting permissions to a new file '%s' is failed.",
ProjectArtifactUtils.extractResourceName(projectArtefact));
WebStudioUtils.addErrorMessage(message);
}
}
if (project.hasArtefact(RULES_DEPLOY_XML)) {
AProjectResource artifact = (AProjectResource) project.getArtefact(RULES_DEPLOY_XML);
validatePermissionForEditing(artifact);
rulesDeployContent = artifact.getContent();
RulesDeploy rulesDeploy = rulesDeploySerializerFactory.getSerializer(SupportedVersion.getLastVersion())
.deserialize(rulesDeployContent);
artifact.setContent(new ByteArrayInputStream(
rulesDeploySerializer.serialize(rulesDeploy).getBytes(StandardCharsets.UTF_8)));
}
refreshProject(project.getRepository().getId(), project.getName());
} catch (ValidationException e) {
throw new Message(e.getMessage());
} catch (Message e) {
throw e;
} catch (Exception e) {
throw new Message("Error while saving the project.");
} finally {
IOUtils.closeQuietly(rulesDeployContent);
}
WebStudioUtils.getWebStudio().resetProjects();
}
private void configureSerializer() throws IOException, JAXBException {
IProjectDescriptorSerializer serializer;
SupportedVersion version = supportedVersion;
if (version == null) {
version = getSupportedVersion();
}
File projectFolder = studio.getCurrentProjectDescriptor().getProjectFolder().toFile();
projectDescriptorSerializerFactory.setSupportedVersion(projectFolder, version);
serializer = projectDescriptorSerializerFactory.getSerializer(version);
projectDescriptorManager.setSerializer(serializer);
rulesDeploySerializer = rulesDeploySerializerFactory.getSerializer(version);
}
private void clean(ProjectDescriptor descriptor) {
if (CollectionUtils.isEmpty(descriptor.getClasspath())) {
descriptor.setClasspath(null);
}
if (CollectionUtils.isEmpty(descriptor.getPropertiesFileNamePatterns())) {
descriptor.setPropertiesFileNamePatterns(null);
}
if (StringUtils.isBlank(descriptor.getPropertiesFileNameProcessor())) {
descriptor.setPropertiesFileNameProcessor(null);
}
if (CollectionUtils.isEmpty(descriptor.getDependencies())) {
descriptor.setDependencies(null);
}
OpenAPI openapi = descriptor.getOpenapi();
if (openapi != null) {
if (StringUtils.isBlank(openapi.getPath())) {
openapi.setPath(null);
}
if (StringUtils.isBlank(openapi.getAlgorithmModuleName())) {
openapi.setAlgorithmModuleName(null);
}
if (StringUtils.isBlank(openapi.getModelModuleName())) {
openapi.setModelModuleName(null);
}
}
List modules = descriptor.getModules();
if (CollectionUtils.isEmpty(modules)) {
descriptor.setModules(null);
return;
}
for (Module module : modules) {
PathEntry rulesRootPath = module.getRulesRootPath();
if (rulesRootPath != null) {
if (StringUtils.isNotBlank(rulesRootPath.getPath())) {
rulesRootPath.setPath(getModulePath(module));
} else {
module.setRulesRootPath(null);
}
}
MethodFilter methodFilter = module.getMethodFilter();
if (methodFilter != null) {
if (CollectionUtils.isEmpty(methodFilter.getIncludes()) && CollectionUtils
.isEmpty(methodFilter.getExcludes())) {
module.setMethodFilter(null);
} else if (CollectionUtils.isEmpty(methodFilter.getIncludes())) {
methodFilter.setIncludes(null);
} else if (CollectionUtils.isEmpty(methodFilter.getExcludes())) {
methodFilter.setExcludes(null);
}
}
}
descriptor.setProjectFolder(null);
}
private ProjectDescriptor cloneProjectDescriptor(ProjectDescriptor projectDescriptor) {
return Cloner.clone(projectDescriptor);
}
public UIInput getPropertiesFileNameProcessorInput() {
return propertiesFileNameProcessorInput;
}
public void setPropertiesFileNameProcessorInput(UIInput propertiesFileNameProcessorInput) {
this.propertiesFileNameProcessorInput = propertiesFileNameProcessorInput;
}
public String getCurrentModuleName() {
return currentModuleName;
}
public void setCurrentModuleName(String currentModuleName) {
this.currentModuleName = currentModuleName;
}
public List getModulesWithWildcard() {
return getOriginalProjectDescriptor().getModules();
}
public boolean isModuleWithWildcard(Module module) {
return projectDescriptorManager.isModuleWithWildcard(module);
}
public boolean isModuleMatchesSomePathPattern(Module module) {
return projectDescriptorManager.isCoveredByWildcardModule(getOriginalProjectDescriptor(), module);
}
private Module getModuleWithWildcard(Module module) {
List modules = getOriginalProjectDescriptor().getModules();
for (Module originalModule : modules) {
if (isModuleWithWildcard(originalModule)) {
List modulesMatchingPathPattern = getModulesMatchingPathPattern(originalModule);
for (Module m : modulesMatchingPathPattern) {
if (module.getName().equals(m.getName())) {
return originalModule;
}
}
}
}
return null;
}
public String getModulePathPattern() {
if (currentModuleName == null) {
return null;
}
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(getOriginalProjectDescriptor());
Module module;
if (currentModuleIndex != null) {
module = newProjectDescriptor.getModules().get(currentModuleIndex);
} else {
module = studio.getModule(newProjectDescriptor, currentModuleName);
}
if (module == null) {
module = getModuleWithWildcard(studio.getModule(studio.getCurrentProjectDescriptor(), currentModuleName));
}
return getModulePath(module);
}
public boolean isCurrentModuleMatchesSomePathPattern() {
if (currentModuleName == null) {
return false;
}
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
Module module = studio.getModule(projectDescriptor, currentModuleName);
return module != null && isModuleMatchesSomePathPattern(module);
}
public boolean isCurrentModuleHasPath(String path) {
if (currentModuleName == null || path == null) {
return false;
}
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
Module module = studio.getModule(projectDescriptor, currentModuleName);
return module != null && path.equals(getModulePath(module));
}
public List getModulePathsForPathPattern() {
if (currentModuleName == null) {
return Collections.emptyList();
}
ProjectDescriptor projectDescriptor = studio.getCurrentProjectDescriptor();
ProjectDescriptor newProjectDescriptor = cloneProjectDescriptor(getOriginalProjectDescriptor());
Module module = studio.getModule(projectDescriptor, currentModuleName);
Module otherModule = null;
if (module != null) {
otherModule = getModuleWithWildcard(module);
}
if (otherModule != null) {
module = otherModule;
} else {
if (currentModuleIndex != null) {
module = newProjectDescriptor.getModules().get(currentModuleIndex);
} else {
module = studio.getModule(newProjectDescriptor, currentModuleName);
}
if (!projectDescriptorManager.isModuleWithWildcard(module)) {
// Single module
return Collections.singletonList(getModulePath(module));
}
}
// Multiple modules
List modules = getModulesMatchingPathPattern(module);
return CollectionUtils.map(modules, this::getModulePath);
}
public void setNewFileName(String newFileName) {
this.newFileName = newFileName;
}
public void setCurrentPathPattern(String currentPathPattern) {
this.currentPathPattern = currentPathPattern;
}
public Boolean getFileNameMatched() {
if (newFileName == null) {
return null;
}
ProjectDescriptor projectDescriptor = getOriginalProjectDescriptor();
PropertiesFileNameProcessorBuilder builder = new PropertiesFileNameProcessorBuilder();
Boolean fileNameMatched = null;
try {
String[] patterns = projectDescriptor.getPropertiesFileNamePatterns();
if (patterns != null) {
builder.build(projectDescriptor).process(newFileName);
fileNameMatched = true;
}
} catch (InvalidFileNameProcessorException | InvalidFileNamePatternException ignored) {
// Cannot check for name correctness
} catch (NoMatchFileNameException e) {
fileNameMatched = false;
}
return fileNameMatched;
}
public String getChangedWildcardMatch() {
if (currentPathPattern == null) {
return null;
}
ProjectDescriptor projectDescriptor = getOriginalProjectDescriptor();
PathMatcher pathMatcher = projectDescriptorManager.getPathMatcher();
for (Module m : projectDescriptor.getModules()) {
if (projectDescriptorManager.isModuleWithWildcard(m)) {
String path = m.getRulesRootPath().getPath();
if (pathMatcher.match(path, newFileName)) {
if (!currentPathPattern.equals(path)) {
// Module file name captured by another path pattern (not current one).
// User should ensure that he didn't do that unintentionally.
return path;
}
break;
}
}
}
return null;
}
public List getModulesMatchingPathPattern(Module module) {
if (module == null || !projectDescriptorManager.isModuleWithWildcard(module)) {
return Collections.emptyList();
}
try {
return projectDescriptorManager.getAllModulesMatchingPathPattern(studio.getCurrentProjectDescriptor(),
module,
module.getRulesRootPath().getPath());
} catch (IOException e) {
if (log.isErrorEnabled()) {
log.error(e.getMessage(), e);
}
return Collections.emptyList();
}
}
public boolean isEmptyMethodFilter(Module module) {
MethodFilter methodFilter = module.getMethodFilter();
if (methodFilter == null) {
return true;
}
if (methodFilter.getIncludes() != null) {
ArrayList includes = new ArrayList<>(methodFilter.getIncludes());
includes.removeAll(Arrays.asList("", null));
if (!includes.isEmpty()) {
return false;
}
}
if (methodFilter.getExcludes() != null) {
ArrayList excludes = new ArrayList<>(methodFilter.getExcludes());
excludes.removeAll(Arrays.asList("", null));
return excludes.isEmpty();
}
return true;
}
public String getCurrentPropertiesFileNameProcessor() {
return studio.getCurrentProjectDescriptor().getPropertiesFileNameProcessor();
}
public SupportedVersion getSupportedVersion() {
if (supportedVersion != null) {
return supportedVersion;
}
ProjectDescriptor descriptor = studio.getCurrentProjectDescriptor();
return projectDescriptorSerializerFactory.getSupportedVersion(descriptor.getProjectFolder().toFile());
}
public void setSupportedVersion(SupportedVersion supportedVersion) {
this.supportedVersion = supportedVersion;
}
public boolean isPropertiesFileNamePatternSupported() {
return getSupportedVersion().compareTo(SupportedVersion.V5_12) >= 0;
}
public boolean isProjectDependenciesSupported() {
return getSupportedVersion().compareTo(SupportedVersion.V5_12) >= 0;
}
public SupportedVersion[] getPossibleVersions() {
return SupportedVersion.values();
}
private ProjectDescriptor getOriginalProjectDescriptor() {
ProjectDescriptor descriptor = studio.getCurrentProjectDescriptor();
try {
File file = descriptor.getProjectFolder()
.resolve(ProjectDescriptorBasedResolvingStrategy.PROJECT_DESCRIPTOR_FILE_NAME)
.toFile();
return projectDescriptorManager.readOriginalDescriptor(file);
} catch (FileNotFoundException ignored) {
return descriptor;
} catch (IOException | ValidationException | JAXBException e) {
log.error(e.getMessage(), e);
return descriptor;
}
}
public void setCurrentModuleIndex(Integer currentModuleIndex) {
this.currentModuleIndex = currentModuleIndex;
}
public Integer getCurrentModuleIndex() {
return currentModuleIndex;
}
public List getModulesInfoList() {
return modulesInfoList;
}
public void setModulesInfoList(List modulesInfoList) {
this.modulesInfoList = modulesInfoList;
}
}