CHE-2937. Add ability to create batch of projects

6.19.x
Roman Nikitenko 2016-11-08 10:27:35 +02:00 committed by RomanNikitenko
parent f1710e6a9b
commit 2339b0dd6e
35 changed files with 1962 additions and 621 deletions

View File

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.project;
import java.util.List;
import java.util.Map;
/**
* Defines configuration for creating new project
*
* @author Roman Nikitenko
*/
public interface NewProjectConfig extends ProjectConfig {
/** Sets project name */
void setName(String name);
/** Sets project path */
void setPath(String path);
/** Sets project description */
void setDescription(String description);
/** Sets primary project type */
void setType(String type);
/** Sets mixin project types */
void setMixins(List<String> mixins);
/** Sets project attributes */
void setAttributes(Map<String, List<String>> attributes);
/** Sets options for generator to create project */
void setOptions(Map<String, String> options);
/** Returns options for generator to create project */
Map<String, String> getOptions();
}

View File

@ -33,4 +33,4 @@ public interface ProjectConfig {
SourceStorage getSource();
}
}

View File

@ -12,11 +12,10 @@ package org.eclipse.che.ide.api.project;
import com.google.common.annotations.Beta;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -37,6 +36,7 @@ public class MutableProjectConfig implements ProjectConfig {
private Map<String, List<String>> attributes;
private MutableSourceStorage sourceStorage;
private Map<String, String> options;
private List<NewProjectConfig> projects;
public MutableProjectConfig(ProjectConfig source) {
name = source.getName();
@ -90,7 +90,7 @@ public class MutableProjectConfig implements ProjectConfig {
@Override
public List<String> getMixins() {
if (mixins == null) {
mixins = new ArrayList<>();
mixins = newArrayList();
}
return mixins;
@ -128,7 +128,7 @@ public class MutableProjectConfig implements ProjectConfig {
public Map<String, String> getOptions() {
if (options == null) {
options = new HashMap<>();
options = newHashMap();
}
return options;
}
@ -137,6 +137,28 @@ public class MutableProjectConfig implements ProjectConfig {
this.options = options;
}
/**
* Returns the list of configurations to creating projects
*
* @return the list of {@link NewProjectConfig} to creating projects
*/
public List<NewProjectConfig> getProjects() {
if (projects == null) {
return newArrayList();
}
return projects;
}
/**
* Sets the list of configurations to creating projects
*
* @param projects
* the list of {@link NewProjectConfig} to creating projects
*/
public void setProjects(List<NewProjectConfig> projects) {
this.projects = projects;
}
public class MutableSourceStorage implements SourceStorage {
private String type;
private String location;

View File

@ -0,0 +1,173 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.project;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of {@link NewProjectConfig} for creating project
*
* @author Roman Nikitenko
*/
public class NewProjectConfigImpl implements NewProjectConfig {
private String name;
private String path;
private String description;
private String type;
private SourceStorage sourceStorage;
private List<String> mixins;
private Map<String, List<String>> attributes;
private Map<String, String> options;
/** Constructor for creating project import configuration */
public NewProjectConfigImpl(String name,
String path,
String description,
String type,
SourceStorage sourceStorage) {
this(name, path, description, type, sourceStorage, null, null, null);
}
/** Constructor for creating project generator configuration */
public NewProjectConfigImpl(String name,
String path,
String description,
String type,
Map<String, List<String>> attributes,
Map<String, String> options) {
this(name, path, description, type, null, null, attributes, options);
}
/** Constructor for creating configuration from project template descriptor */
public NewProjectConfigImpl(ProjectTemplateDescriptor descriptor) {
this(descriptor.getName(),
descriptor.getPath(),
descriptor.getDescription(),
descriptor.getProjectType(),
descriptor.getSource(),
descriptor.getMixins(),
descriptor.getAttributes(),
descriptor.getOptions());
}
/** Constructor for creating configuration from DTO object */
public NewProjectConfigImpl(NewProjectConfigDto dto) {
this(dto.getName(),
dto.getPath(),
dto.getDescription(),
dto.getType(),
dto.getSource(),
dto.getMixins(),
dto.getAttributes(),
dto.getOptions());
}
public NewProjectConfigImpl(String name,
String path,
String description,
String type,
SourceStorage sourceStorage,
List<String> mixins,
Map<String, List<String>> attributes,
Map<String, String> options) {
this.name = name;
this.path = path;
this.description = description;
this.type = type;
this.sourceStorage = sourceStorage;
this.mixins = mixins;
this.attributes = attributes != null ? attributes : new HashMap<String, List<String>>();
this.options = options != null ? options : new HashMap<String, String>();
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getPath() {
return path;
}
@Override
public void setPath(String path) {
this.path = path;
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public String getType() {
return type;
}
@Override
public void setType(String type) {
this.type = type;
}
@Override
public List<String> getMixins() {
return mixins != null ? mixins : new ArrayList<String>();
}
@Override
public void setMixins(List<String> mixins) {
this.mixins = mixins;
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes != null ? attributes : new HashMap<String, List<String>>();
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.attributes = attributes;
}
@Override
public Map<String, String> getOptions() {
return options != null ? options : new HashMap<String, String>();
}
@Override
public void setOptions(Map<String, String> options) {
this.options = options;
}
@Override
public SourceStorage getSource() {
return sourceStorage;
}
}

View File

@ -14,6 +14,7 @@ import org.eclipse.che.api.project.shared.dto.ItemReference;
import org.eclipse.che.api.project.shared.dto.SourceEstimation;
import org.eclipse.che.api.project.shared.dto.TreeElement;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.ide.resource.Path;
@ -92,6 +93,24 @@ public interface ProjectServiceClient {
*/
Promise<ProjectConfigDto> createProject(ProjectConfigDto configuration, Map<String, String> options);
/**
* Create batch of projects according to their configurations.
* <p/>
* Notes: a project will be created by importing when project configuration contains {@link SourceStorageDto}
* object, otherwise this one will be created corresponding its {@link NewProjectConfigDto}:
* <li> - {@link NewProjectConfigDto} object contains only one mandatory {@link NewProjectConfigDto#setPath(String)} field.
* In this case Project will be created as project of "blank" type </li>
* <li> - a project will be created as project of "blank" type when declared primary project type is not registered, </li>
* <li> - a project will be created without mixin project type when declared mixin project type is not registered</li>
* <li> - for creating a project by generator {@link NewProjectConfigDto#getOptions()} should be specified.</li>
*
* @param configurations
* the list of configurations to creating projects
* @return {@link Promise} with the list of {@link ProjectConfigDto}
* @see ProjectConfigDto
*/
Promise<List<ProjectConfigDto>> createBatchProjects(List<NewProjectConfigDto> configurations);
/**
* Returns the item description by given {@code path}.
*

View File

@ -26,6 +26,7 @@ import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.promises.client.callback.AsyncPromiseHelper;
import org.eclipse.che.api.promises.client.callback.PromiseHelper;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.ide.MimeType;
@ -65,7 +66,8 @@ import static org.eclipse.che.ide.rest.HTTPHeader.CONTENT_TYPE;
*/
public class ProjectServiceClientImpl implements ProjectServiceClient {
private static final String PROJECT = "/project";
private static final String PROJECT = "/project";
private static final String BATCH_PROJECTS = "/batch";
private static final String ITEM = "/item";
private static final String TREE = "/tree";
@ -213,6 +215,16 @@ public class ProjectServiceClientImpl implements ProjectServiceClient {
.send(unmarshaller.newUnmarshaller(ProjectConfigDto.class));
}
@Override
public Promise<List<ProjectConfigDto>> createBatchProjects(List<NewProjectConfigDto> configurations) {
final String url = getBaseUrl() + BATCH_PROJECTS;
final String loaderMessage = configurations.size() > 1 ? "Creating the batch of projects..." : "Creating project...";
return reqFactory.createPostRequest(url, configurations)
.header(ACCEPT, MimeType.APPLICATION_JSON)
.loader(loaderFactory.newLoader(loaderMessage))
.send(unmarshaller.newListUnmarshaller(ProjectConfigDto.class));
}
/** {@inheritDoc} */
@Override
public Promise<ItemReference> createFile(Path path, String content) {

View File

@ -16,7 +16,7 @@ import javax.validation.constraints.NotNull;
import java.util.List;
/**
* Registry for {@link org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor}s.
* Registry for {@link ProjectTemplateDescriptor}s.
*
* @author Artem Zatsarynnyi
*/

View File

@ -99,7 +99,7 @@ public class ProjectWizard extends AbstractWizard<MutableProjectConfig> {
});
} else if (mode == IMPORT) {
appContext.getWorkspaceRoot()
.importProject()
.newProject()
.withBody(dataObject)
.send()
.thenPromise(new Function<Project, Promise<Project>>() {

View File

@ -13,9 +13,13 @@ package org.eclipse.che.ide.projecttype.wizard.categoriespage;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.inject.Inject;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.project.shared.dto.ProjectTypeDto;
import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.project.MutableProjectConfig;
import org.eclipse.che.ide.api.project.NewProjectConfigImpl;
import org.eclipse.che.ide.api.project.type.ProjectTemplateRegistry;
import org.eclipse.che.ide.api.project.type.ProjectTypeRegistry;
import org.eclipse.che.ide.api.project.type.wizard.PreSelectedProjectTypeManager;
@ -23,12 +27,12 @@ import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode;
import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistry;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.api.wizard.AbstractWizardPage;
import org.eclipse.che.ide.api.project.MutableProjectConfig;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.resources.selector.SelectPathPresenter;
import org.eclipse.che.ide.resources.selector.SelectionPathHandler;
import org.eclipse.che.ide.util.NameUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -162,13 +166,20 @@ public class CategoriesPagePresenter extends AbstractWizardPage<MutableProjectCo
if (projectTemplateSelectionListener != null) {
projectTemplateSelectionListener.onProjectTemplateSelected(templateDescriptor);
}
updateProjectConfigs(dataObject.getPath(), selectedProjectTemplate);
updateDelegate.updateControls();
}
@Override
public void projectNameChanged(String name) {
final String newProjectPath = originParent.append(name).toString();
if (selectedProjectTemplate != null) {
updateProjectConfigs(newProjectPath, selectedProjectTemplate);
}
dataObject.setName(name);
dataObject.setPath(originParent.append(name).toString());
dataObject.setPath(newProjectPath);
updateDelegate.updateControls();
if (NameUtils.checkProjectName(name)) {
@ -211,6 +222,26 @@ public class CategoriesPagePresenter extends AbstractWizardPage<MutableProjectCo
projectTemplateSelectionListener = listener;
}
private void updateProjectConfigs(String newProjectPath, ProjectTemplateDescriptor projectTemplate) {
final List<NewProjectConfigDto> configDtoList = projectTemplate.getProjects();
if (newProjectPath.equals("/")) {
return;
}
final String templatePath = projectTemplate.getPath();
final List<NewProjectConfig> updatedConfigs = new ArrayList<>(configDtoList.size());
for (NewProjectConfigDto configDto : configDtoList) {
final NewProjectConfig newConfig = new NewProjectConfigImpl(configDto);
final String projectPath = configDto.getPath();
if (projectPath.startsWith(templatePath)) {
final String path = projectPath.replaceFirst(templatePath, newProjectPath);
newConfig.setPath(path);
}
updatedConfigs.add(newConfig);
}
dataObject.setProjects(updatedConfigs);
}
private void loadProjectTypesAndTemplates() {
List<ProjectTypeDto> projectTypes = projectTypeRegistry.getProjectTypes();
Map<String, Set<ProjectTypeDto>> typesByCategory = new HashMap<>();

View File

@ -14,12 +14,14 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.project.shared.dto.AttributeDto;
import org.eclipse.che.api.project.shared.dto.ProjectTypeDto;
import org.eclipse.che.api.project.templates.shared.dto.ProjectTemplateDescriptor;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.api.project.MutableProjectConfig;
import org.eclipse.che.ide.api.project.NewProjectConfigImpl;
import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode;
import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistrar;
import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistry;
@ -181,7 +183,15 @@ public class ProjectWizardPresenter implements Wizard.UpdateDelegate,
if (wizardMode == UPDATE) {
newProject.setAttributes(prevData.getAttributes());
} else {
List<AttributeDto> attributes = projectType.getAttributes();
final MutableProjectConfig.MutableSourceStorage sourceStorage = prevData.getSource();
if (sourceStorage != null) { // some values should be cleared when user switch between categories
sourceStorage.setLocation("");
sourceStorage.setType("");
sourceStorage.getParameters().clear();
}
prevData.getProjects().clear();
final List<AttributeDto> attributes = projectType.getAttributes();
Map<String, List<String>> prevDataAttributes = prevData.getAttributes();
Map<String, List<String>> newAttributes = new HashMap<>();
for (AttributeDto attribute : attributes) {
@ -203,8 +213,9 @@ public class ProjectWizardPresenter implements Wizard.UpdateDelegate,
wizard.navigateToFirst();
// set dataObject's values from projectTemplate
dataObject.setType(projectTemplate.getProjectType());
dataObject.setSource(projectTemplate.getSource());
final NewProjectConfig newProjectConfig = new NewProjectConfigImpl(projectTemplate);
dataObject.setType(newProjectConfig.getType());
dataObject.setSource(newProjectConfig.getSource());
}
/** Creates or returns project wizard for the specified projectType with the given dataObject. */

View File

@ -16,6 +16,7 @@ import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.core.rest.shared.dto.Link;
@ -27,6 +28,7 @@ import org.eclipse.che.api.promises.client.FunctionException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseProvider;
import org.eclipse.che.api.promises.client.js.Promises;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
@ -56,6 +58,7 @@ import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.ide.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -263,22 +266,22 @@ public final class ResourceManager {
* @since 4.4.0
*/
protected Promise<Project> update(final Path path, final ProjectRequest request) {
final ProjectConfig projectConfig = request.getBody();
final SourceStorage source = projectConfig.getSource();
final SourceStorageDto sourceDto = dtoFactory.createDto(SourceStorageDto.class);
if (request.getBody().getSource() != null) {
sourceDto.setLocation(request.getBody().getSource().getLocation());
sourceDto.setType(request.getBody().getSource().getType());
sourceDto.setParameters(request.getBody().getSource().getParameters());
if (source != null) {
sourceDto.setLocation(source.getLocation());
sourceDto.setType(source.getType());
sourceDto.setParameters(source.getParameters());
}
final ProjectConfigDto dto = dtoFactory.createDto(ProjectConfigDto.class)
.withName(request.getBody().getName())
.withName(projectConfig.getName())
.withPath(path.toString())
.withDescription(request.getBody().getDescription())
.withType(request.getBody().getType())
.withMixins(request.getBody().getMixins())
.withAttributes(request.getBody().getAttributes())
.withDescription(projectConfig.getDescription())
.withType(projectConfig.getType())
.withMixins(projectConfig.getMixins())
.withAttributes(projectConfig.getAttributes())
.withSource(sourceDto);
return ps.updateProject(dto).thenPromise(new Function<ProjectConfigDto, Promise<Project>>() {
@ -410,21 +413,9 @@ public final class ResourceManager {
checkArgument(typeRegistry.getProjectType(createRequest.getBody().getType()) != null, "Invalid project type");
final Path path = Path.valueOf(createRequest.getBody().getPath());
return findResource(path, true).thenPromise(new Function<Optional<Resource>, Promise<Project>>() {
@Override
public Promise<Project> apply(Optional<Resource> resource) throws FunctionException {
final MutableProjectConfig projectConfig = (MutableProjectConfig)createRequest.getBody();
final ProjectConfigDto dto = dtoFactory.createDto(ProjectConfigDto.class)
.withName(projectConfig.getName())
.withPath(path.toString())
.withDescription(projectConfig.getDescription())
.withType(projectConfig.getType())
.withMixins(projectConfig.getMixins())
.withAttributes(projectConfig.getAttributes());
if (resource.isPresent()) {
if (resource.get().isProject()) {
throw new IllegalStateException("Project already exists");
@ -435,22 +426,32 @@ public final class ResourceManager {
return update(path, createRequest);
}
return ps.createProject(dto, projectConfig.getOptions()).thenPromise(new Function<ProjectConfigDto, Promise<Project>>() {
final MutableProjectConfig projectConfig = (MutableProjectConfig)createRequest.getBody();
final List<NewProjectConfig> projectConfigList = projectConfig.getProjects();
projectConfigList.add(asDto(projectConfig));
final List<NewProjectConfigDto> configDtoList = asDto(projectConfigList);
return ps.createBatchProjects(configDtoList).thenPromise(new Function<List<ProjectConfigDto>, Promise<Project>>() {
@Override
public Promise<Project> apply(ProjectConfigDto config) throws FunctionException {
final Project newResource = resourceFactory.newProjectImpl(config, ResourceManager.this);
store.register(newResource);
public Promise<Project> apply(final List<ProjectConfigDto> configList) throws FunctionException {
return ps.getProjects().then(new Function<List<ProjectConfigDto>, Project>() {
@Override
public Project apply(List<ProjectConfigDto> updatedConfiguration) throws FunctionException {
//cache new configs
cachedConfigs = updatedConfiguration.toArray(new ProjectConfigDto[updatedConfiguration.size()]);
eventBus.fireEvent(new ResourceChangedEvent(new ResourceDeltaImpl(newResource, ADDED | DERIVED)));
for (ProjectConfigDto projectConfigDto : configList) {
if (projectConfigDto.getPath().equals(path.toString())) {
final Project newResource = resourceFactory.newProjectImpl(projectConfigDto, ResourceManager.this);
store.register(newResource);
eventBus.fireEvent(new ResourceChangedEvent(new ResourceDeltaImpl(newResource, ADDED | DERIVED)));
return newResource;
return newResource;
}
}
throw new IllegalStateException("Created project is not found");
}
});
}
@ -459,6 +460,46 @@ public final class ResourceManager {
});
}
private NewProjectConfigDto asDto(MutableProjectConfig config) {
final SourceStorage source = config.getSource();
final SourceStorageDto sourceStorageDto = dtoFactory.createDto(SourceStorageDto.class)
.withType(source.getType())
.withLocation(source.getLocation())
.withParameters(source.getParameters());
return dtoFactory.createDto(NewProjectConfigDto.class)
.withName(config.getName())
.withPath(config.getPath())
.withDescription(config.getDescription())
.withSource(sourceStorageDto)
.withType(config.getType())
.withMixins(config.getMixins())
.withAttributes(config.getAttributes())
.withOptions(config.getOptions());
}
private List<NewProjectConfigDto> asDto(List<NewProjectConfig> configList) {
List<NewProjectConfigDto> result = new ArrayList<>(configList.size());
for (NewProjectConfig config : configList) {
final SourceStorage source = config.getSource();
final SourceStorageDto sourceStorageDto = dtoFactory.createDto(SourceStorageDto.class)
.withType(source.getType())
.withLocation(source.getLocation())
.withParameters(source.getParameters());
result.add(dtoFactory.createDto(NewProjectConfigDto.class)
.withName(config.getName())
.withPath(config.getPath())
.withDescription(config.getDescription())
.withSource(sourceStorageDto)
.withType(config.getType())
.withMixins(config.getMixins())
.withAttributes(config.getAttributes())
.withOptions(config.getOptions()));
}
return result;
}
protected Promise<Project> importProject(final Project.ProjectRequest importRequest) {
checkArgument(checkProjectName(importRequest.getBody().getName()), "Invalid project name");
checkNotNull(importRequest.getBody().getSource(), "Null source configuration occurred");

View File

@ -139,7 +139,7 @@ public class ProjectWizardTest {
public void shouldImportProjectSuccessfully() throws Exception {
prepareWizard(IMPORT);
when(workspaceRoot.importProject()).thenReturn(createProjectRequest);
when(workspaceRoot.newProject()).thenReturn(createProjectRequest);
when(createProjectRequest.withBody(any(ProjectConfig.class))).thenReturn(createProjectRequest);
when(createProjectRequest.send()).thenReturn(createProjectPromise);
when(createProjectPromise.then(any(Operation.class))).thenReturn(createProjectPromise);
@ -159,7 +159,7 @@ public class ProjectWizardTest {
public void shouldFailOnImportProject() throws Exception {
prepareWizard(IMPORT);
when(workspaceRoot.importProject()).thenReturn(createProjectRequest);
when(workspaceRoot.newProject()).thenReturn(createProjectRequest);
when(createProjectRequest.withBody(any(ProjectConfig.class))).thenReturn(createProjectRequest);
when(createProjectRequest.send()).thenReturn(createProjectPromise);
when(createProjectPromise.then(any(Operation.class))).thenReturn(createProjectPromise);

View File

@ -16,7 +16,8 @@ import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.project.server.NewProjectConfig;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.project.server.NewProjectConfigImpl;
import org.eclipse.che.api.project.server.ProjectManager;
import org.eclipse.che.api.project.server.ProjectRegistry;
import org.eclipse.che.api.project.server.RegisteredProject;
@ -104,7 +105,7 @@ public class ClasspathUpdaterService {
ServerException {
RegisteredProject project = projectRegistry.getProject(projectPath);
NewProjectConfig projectConfig = new NewProjectConfig(projectPath,
NewProjectConfig projectConfig = new NewProjectConfigImpl(projectPath,
project.getName(),
project.getType(),
project.getSource());

View File

@ -61,4 +61,10 @@ public interface MavenLocalizationConstant extends Messages {
@Key("window.loader.title")
String windowLoaderTitle();
@Key("maven.page.estimate.errorMessage")
String mavenPageEstimateErrorMessage();
@Key("maven.page.errorDialog.title")
String mavenPageErrorDialogTitle();
}

View File

@ -27,6 +27,7 @@ import org.eclipse.che.ide.api.wizard.AbstractWizardPage;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.plugin.maven.client.MavenArchetype;
import org.eclipse.che.plugin.maven.client.MavenExtension;
import org.eclipse.che.plugin.maven.client.MavenLocalizationConstant;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@ -62,18 +63,21 @@ import static org.eclipse.che.plugin.maven.shared.MavenAttributes.VERSION;
*/
public class MavenPagePresenter extends AbstractWizardPage<MutableProjectConfig> implements MavenPageView.ActionDelegate {
private final MavenPageView view;
private final DialogFactory dialogFactory;
private final AppContext appContext;
private final MavenPageView view;
private final DialogFactory dialogFactory;
private final AppContext appContext;
private final MavenLocalizationConstant localization;
@Inject
public MavenPagePresenter(MavenPageView view,
DialogFactory dialogFactory,
AppContext appContext) {
AppContext appContext,
MavenLocalizationConstant localization) {
super();
this.view = view;
this.dialogFactory = dialogFactory;
this.appContext = appContext;
this.localization = localization;
view.setDelegate(this);
}
@ -104,6 +108,13 @@ public class MavenPagePresenter extends AbstractWizardPage<MutableProjectConfig>
container.get().estimate(MAVEN_ID).then(new Operation<SourceEstimation>() {
@Override
public void apply(SourceEstimation estimation) throws OperationException {
if (!estimation.isMatched()) {
final String resolution = estimation.getResolution();
final String errorMessage = resolution.isEmpty() ? localization.mavenPageEstimateErrorMessage() : resolution;
dialogFactory.createMessageDialog(localization.mavenPageErrorDialogTitle(), errorMessage, null).show();
return;
}
Map<String, List<String>> estimatedAttributes = estimation.getAttributes();
List<String> artifactIdValues = estimatedAttributes.get(ARTIFACT_ID);
if (artifactIdValues != null && !artifactIdValues.isEmpty()) {
@ -136,7 +147,7 @@ public class MavenPagePresenter extends AbstractWizardPage<MutableProjectConfig>
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
dialogFactory.createMessageDialog("Not valid Maven project", arg.getMessage(), null).show();
dialogFactory.createMessageDialog(localization.mavenPageErrorDialogTitle(), arg.getMessage(), null).show();
Log.error(MavenPagePresenter.class, arg);
}
});

View File

@ -36,3 +36,6 @@ loader.action.name=Dependencies resolver
loader.action.description=Maven Dependencies Resolver
window.loader.title=Resolving dependencies
##### Wizard Maven Page #####
maven.page.errorDialog.title=Not valid Maven project
maven.page.estimate.errorMessage=Source code not matches Maven project type requirements

View File

@ -22,6 +22,7 @@ import org.eclipse.che.ide.api.dialogs.DialogFactory;
import org.eclipse.che.ide.api.dialogs.MessageDialog;
import org.eclipse.che.ide.api.project.MutableProjectConfig;
import org.eclipse.che.ide.api.resources.Container;
import org.eclipse.che.plugin.maven.client.MavenLocalizationConstant;
import org.eclipse.che.plugin.maven.shared.MavenAttributes;
import org.junit.Before;
import org.junit.Test;
@ -52,13 +53,15 @@ public class MavenPagePresenterTest {
private final static String TEXT = "to be or not to be";
@Mock
private MavenPageView view;
private MavenPageView view;
@Mock
private EventBus eventBus;
private EventBus eventBus;
@Mock
private DialogFactory dialogFactory;
private DialogFactory dialogFactory;
@Mock
private AppContext appContext;
private AppContext appContext;
@Mock
private MavenLocalizationConstant localization;
@InjectMocks
private MavenPagePresenter mavenPagePresenter;
@ -106,11 +109,13 @@ public class MavenPagePresenterTest {
@Test
public void warningWindowShouldBeShowedIfProjectEstimationHasSomeError() throws Exception {
final String dialogTitle = "Not valid Maven project";
PromiseError promiseError = mock(PromiseError.class);
MessageDialog messageDialog = mock(MessageDialog.class);
context.put(WIZARD_MODE_KEY, UPDATE.toString());
when(promiseError.getMessage()).thenReturn(TEXT);
when(localization.mavenPageErrorDialogTitle()).thenReturn(dialogTitle);
when(dialogFactory.createMessageDialog(anyString(), anyString(), anyObject())).thenReturn(messageDialog);
when(sourceEstimationPromise.then(Matchers.<Operation<SourceEstimation>>anyObject())).thenReturn(sourceEstimationPromise);
when(sourceEstimationPromise.catchError(Matchers.<Operation<PromiseError>>anyObject())).thenReturn(sourceEstimationPromise);
@ -124,7 +129,7 @@ public class MavenPagePresenterTest {
containerArgumentErrorCapture.getValue().apply(promiseError);
verify(promiseError).getMessage();
verify(dialogFactory).createMessageDialog("Not valid Maven project", TEXT, null);
verify(dialogFactory).createMessageDialog(dialogTitle, TEXT, null);
verify(messageDialog).show();
}

View File

@ -15,19 +15,20 @@ package org.eclipse.che.api.project.shared;
*/
public class Constants {
public static final String BLANK_ID = "blank";
public static final String ZIP_IMPORTER_ID = "zip";
public static final String VCS_PROVIDER_NAME = "vcs.provider.name";
public static final String BLANK_ID = "blank";
public static final String ZIP_IMPORTER_ID = "zip";
public static final String VCS_PROVIDER_NAME = "vcs.provider.name";
// rels for known project links
public static final String LINK_REL_GET_PROJECTS = "get projects";
public static final String LINK_REL_CREATE_PROJECT = "create project";
public static final String LINK_REL_UPDATE_PROJECT = "update project";
public static final String LINK_REL_EXPORT_ZIP = "zipball sources";
public static final String LINK_REL_CHILDREN = "children";
public static final String LINK_REL_TREE = "tree";
public static final String LINK_REL_DELETE = "delete";
public static final String LINK_REL_GET_CONTENT = "get content";
public static final String LINK_REL_UPDATE_CONTENT = "update content";
public static final String LINK_REL_GET_PROJECTS = "get projects";
public static final String LINK_REL_CREATE_PROJECT = "create project";
public static final String LINK_REL_CREATE_BATCH_PROJECTS = "create batch of projects";
public static final String LINK_REL_UPDATE_PROJECT = "update project";
public static final String LINK_REL_EXPORT_ZIP = "zipball sources";
public static final String LINK_REL_CHILDREN = "children";
public static final String LINK_REL_TREE = "tree";
public static final String LINK_REL_DELETE = "delete";
public static final String LINK_REL_GET_CONTENT = "get content";
public static final String LINK_REL_UPDATE_CONTENT = "update content";
public static final String LINK_REL_PROJECT_TYPES = "project types";

View File

@ -24,7 +24,6 @@ import java.util.Map;
@DTO
public interface SourceEstimation {
/** Gets unique id of type of project. */
@ApiModelProperty(value = "type ID", position = 1)
String getType();
@ -44,4 +43,10 @@ public interface SourceEstimation {
SourceEstimation withMatched(boolean matched);
/** Gets resolution - the reason that source code not matches project type requirements. */
@ApiModelProperty(value = "Resolution", position = 4)
String getResolution();
SourceEstimation withResolution(String resolution);
}

View File

@ -1,118 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.project.server.type.BaseProjectType;
import org.eclipse.che.api.vfs.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author gazarenkov
*/
public class NewProjectConfig implements ProjectConfig {
private final String path;
private final String type;
private final List<String> mixins;
private final String name;
private final String description;
private final Map<String, List<String>> attributes;
private final SourceStorage origin;
/**
* Full qualified constructor
*
* @param path
* @param type
* @param mixins
* @param name
* @param description
* @param attributes
* @param origin
*/
public NewProjectConfig(String path,
String type,
List<String> mixins,
String name,
String description,
Map<String, List<String>> attributes,
SourceStorage origin) {
this.path = path;
this.type = (type == null) ? BaseProjectType.ID : type;
this.mixins = (mixins == null) ? new ArrayList<>() : mixins;
this.name = name;
this.description = description;
this.attributes = (attributes == null) ? new HashMap<>() : attributes;
this.origin = origin;
}
/**
* Constructor for project import
*
* @param path
* @param name
* @param type
* @param origin
*/
public NewProjectConfig(String path, String name, String type, SourceStorage origin) {
this(path, type, null, name, null, null, origin);
}
/**
* Constructor for reinit
*
* @param path
*/
public NewProjectConfig(Path path) {
this(path.toString(), null, null, path.getName(), null, null, null);
}
@Override
public String getName() {
return name;
}
@Override
public String getPath() {
return path;
}
@Override
public String getDescription() {
return description;
}
@Override
public String getType() {
return type;
}
@Override
public List<String> getMixins() {
return mixins;
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes;
}
@Override
public SourceStorage getSource() {
return origin;
}
}

View File

@ -0,0 +1,178 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.project.server.type.BaseProjectType;
import org.eclipse.che.api.vfs.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
/**
* Implementation of {@link NewProjectConfig} for creating project
*
* @author gazarenkov
*/
public class NewProjectConfigImpl implements NewProjectConfig {
private String path;
private String type;
private List<String> mixins;
private String name;
private String description;
private Map<String, List<String>> attributes;
private Map<String, String> options;
private SourceStorage origin;
/**
* Full qualified constructor
*
* @param path
* project path
* @param type
* project type
* @param mixins
* mixin project types
* @param name
* project name
* @param description
* project description
* @param attributes
* project attributes
* @param options
* options for generator for creating project
* @param origin
* source configuration
*/
public NewProjectConfigImpl(String path,
String type,
List<String> mixins,
String name,
String description,
Map<String, List<String>> attributes,
Map<String, String> options,
SourceStorage origin) {
this.path = path;
this.type = (type == null) ? BaseProjectType.ID : type;
this.mixins = (mixins == null) ? new ArrayList<>() : mixins;
this.name = name;
this.description = description;
this.attributes = (attributes == null) ? newHashMap() : attributes;
this.options = (options == null) ? newHashMap() : options;
this.origin = origin;
}
/**
* Constructor for project import
*
* @param path
* project path
* @param name
* project name
* @param type
* project type
* @param origin
* source configuration
*/
public NewProjectConfigImpl(String path, String name, String type, SourceStorage origin) {
this(path, type, null, name, null, null, null, origin);
}
/**
* Constructor for reinit
*
* @param path
*/
public NewProjectConfigImpl(Path path) {
this(path.toString(), null, null, path.getName(), null, null, null, null);
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getPath() {
return path;
}
@Override
public void setPath(String path) {
this.path = path;
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public String getType() {
return type;
}
@Override
public void setType(String type) {
this.type = type;
}
@Override
public List<String> getMixins() {
return mixins != null ? mixins : newArrayList();
}
@Override
public void setMixins(List<String> mixins) {
this.mixins = mixins;
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes != null ? attributes : newHashMap();
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.attributes = attributes;
}
@Override
public SourceStorage getSource() {
return origin;
}
@Override
public void setOptions(Map<String, String> options) {
this.options = options;
}
@Override
public Map<String, String> getOptions() {
return options != null ? options : newHashMap();
}
}

View File

@ -12,16 +12,19 @@ package org.eclipse.che.api.project.server;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.core.model.project.type.ProjectType;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.util.LineConsumerFactory;
import org.eclipse.che.api.project.server.RegisteredProject.Problem;
import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler;
import org.eclipse.che.api.project.server.handlers.CreateProjectHandler;
import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry;
@ -33,7 +36,6 @@ import org.eclipse.che.api.project.server.type.BaseProjectType;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.project.server.type.ProjectTypeResolution;
import org.eclipse.che.api.project.server.type.ValueStorageException;
import org.eclipse.che.api.project.shared.dto.event.FileWatcherEventType;
import org.eclipse.che.api.vfs.Path;
import org.eclipse.che.api.vfs.VirtualFile;
@ -61,6 +63,10 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
/**
* Facade for all project related operations.
@ -196,7 +202,7 @@ public final class ProjectManager {
public RegisteredProject getProject(String projectPath) throws ServerException, NotFoundException {
final RegisteredProject project = projectRegistry.getProject(projectPath);
if (project == null) {
throw new NotFoundException(String.format("Project '%s' doesn't exist.", projectPath));
throw new NotFoundException(format("Project '%s' doesn't exist.", projectPath));
}
return project;
@ -229,67 +235,179 @@ public final class ProjectManager {
throw new ConflictException("Path for new project should be defined ");
}
final String path = ProjectRegistry.absolutizePath(projectConfig.getPath());
if (projectConfig.getType() == null) {
throw new ConflictException("Project Type is not defined " + path);
throw new ConflictException("Project Type is not defined " + projectConfig.getPath());
}
final String path = ProjectRegistry.absolutizePath(projectConfig.getPath());
if (projectRegistry.getProject(path) != null) {
throw new ConflictException("Project config already exists " + path);
throw new ConflictException("Project config already exists for " + path);
}
final CreateProjectHandler generator = handlers.getCreateProjectHandler(projectConfig.getType());
FolderEntry projectFolder;
if (generator != null) {
Map<String, AttributeValue> valueMap = new HashMap<>();
Map<String, List<String>> attributes = projectConfig.getAttributes();
if (attributes != null) {
for (Map.Entry<String, List<String>> entry : attributes.entrySet()) {
valueMap.put(entry.getKey(), new AttributeValue(entry.getValue()));
}
}
if (options == null) {
options = new HashMap<>();
}
Path projectPath = Path.of(path);
generator.onCreateProject(projectPath, valueMap, options);
projectFolder = new FolderEntry(vfs.getRoot().getChild(projectPath), projectRegistry);
} else {
projectFolder = new FolderEntry(vfs.getRoot().createFolder(path), projectRegistry);
}
final RegisteredProject project;
try {
project = projectRegistry.putProject(projectConfig, projectFolder, true, false);
} catch (Exception e) {
// rollback project folder
projectFolder.getVirtualFile().delete();
throw e;
}
// unlike imported it is not appropriate for newly created project to have problems
if(!project.getProblems().isEmpty()) {
// rollback project folder
projectFolder.getVirtualFile().delete();
// remove project entry
projectRegistry.removeProjects(projectConfig.getPath());
throw new ServerException("Problems occured: " + project.getProblemsStr());
}
workspaceProjectsHolder.sync(projectRegistry);
projectRegistry.fireInitHandlers(project);
return project;
return doCreateProject(projectConfig, options);
} finally {
projectTreeChangesDetector.resume();
}
}
/** Note: Use {@link ProjectTreeChangesDetector#suspend()} and {@link ProjectTreeChangesDetector#resume()} while creating a project */
private RegisteredProject doCreateProject(ProjectConfig projectConfig, Map<String, String> options) throws ConflictException,
ForbiddenException,
ServerException,
NotFoundException {
final String path = ProjectRegistry.absolutizePath(projectConfig.getPath());
final CreateProjectHandler generator = handlers.getCreateProjectHandler(projectConfig.getType());
FolderEntry projectFolder;
if (generator != null) {
Map<String, AttributeValue> valueMap = new HashMap<>();
Map<String, List<String>> attributes = projectConfig.getAttributes();
if (attributes != null) {
for (Map.Entry<String, List<String>> entry : attributes.entrySet()) {
valueMap.put(entry.getKey(), new AttributeValue(entry.getValue()));
}
}
if (options == null) {
options = new HashMap<>();
}
Path projectPath = Path.of(path);
generator.onCreateProject(projectPath, valueMap, options);
projectFolder = new FolderEntry(vfs.getRoot().getChild(projectPath), projectRegistry);
} else {
projectFolder = new FolderEntry(vfs.getRoot().createFolder(path), projectRegistry);
}
final RegisteredProject project = projectRegistry.putProject(projectConfig, projectFolder, true, false);
workspaceProjectsHolder.sync(projectRegistry);
projectRegistry.fireInitHandlers(project);
return project;
}
/**
* Create batch of projects according to their configurations.
* <p/>
* Notes: - a project will be created by importing when project configuration contains {@link SourceStorage} object,
* otherwise this one will be created corresponding its {@link NewProjectConfig}:
* <li> - {@link NewProjectConfig} object contains only one mandatory {@link NewProjectConfig#setPath(String)} field.
* In this case Project will be created as project of {@link BaseProjectType} type </li>
* <li> - a project will be created as project of {@link BaseProjectType} type with {@link Problem#code} = 12
* when declared primary project type is not registered, </li>
* <li> - a project will be created with {@link Problem#code} = 12 and without mixin project type
* when declared mixin project type is not registered</li>
* <li> - for creating a project by generator {@link NewProjectConfig#getOptions()} should be specified.</li>
*
* @param projectConfigList
* the list of configurations to create projects
* @param rewrite
* whether rewrite or not (throw exception otherwise) if such a project exists
* @return the list of new projects
* @throws BadRequestException
* when {@link NewProjectConfig} object not contains mandatory {@link NewProjectConfig#setPath(String)} field.
* @throws ConflictException
* when the same path project exists and {@code rewrite} is {@code false}
* @throws ForbiddenException
* when trying to overwrite the project and this one contains at least one locked file
* @throws NotFoundException
* when parent folder does not exist
* @throws UnauthorizedException
* if user isn't authorized to access to location at importing source code
* @throws ServerException
* if other error occurs
*/
public List<RegisteredProject> createBatchProjects(List<? extends NewProjectConfig> projectConfigList, boolean rewrite)
throws BadRequestException, ConflictException, ForbiddenException, NotFoundException, ServerException, UnauthorizedException,
IOException {
projectTreeChangesDetector.suspend();
try {
final List<RegisteredProject> projects = new ArrayList<>(projectConfigList.size());
validateProjectConfigurations(projectConfigList, rewrite);
final List<NewProjectConfig> sortedConfigList = projectConfigList
.stream()
.sorted((config1, config2) -> config1.getPath().compareTo(config2.getPath()))
.collect(Collectors.toList());
for (NewProjectConfig projectConfig : sortedConfigList) {
RegisteredProject registeredProject;
final String pathToProject = projectConfig.getPath();
//creating project(by config or by importing source code)
try {
final SourceStorage sourceStorage = projectConfig.getSource();
if (sourceStorage != null && !isNullOrEmpty(sourceStorage.getLocation())) {
doImportProject(pathToProject, sourceStorage, rewrite);
} else if (!isVirtualFileExist(pathToProject)) {
registeredProject = doCreateProject(projectConfig, projectConfig.getOptions());
projects.add(registeredProject);
continue;
}
} catch (Exception e) {
if (!isVirtualFileExist(pathToProject)) {//project folder is absent
rollbackCreatingBatchProjects(projects);
throw e;
}
}
//update project
if (isVirtualFileExist(pathToProject)) {
try {
registeredProject = updateProject(projectConfig);
} catch (Exception e) {
registeredProject = projectRegistry.putProject(projectConfig, asFolder(pathToProject), true, false);
registeredProject.getProblems().add(new Problem(14, "The project is not updated, caused by " + e.getLocalizedMessage()));
}
} else {
registeredProject = projectRegistry.putProject(projectConfig, null, true, false);
}
projects.add(registeredProject);
}
return projects;
} finally {
projectTreeChangesDetector.resume();
}
}
private void rollbackCreatingBatchProjects(List<RegisteredProject> projects) {
for (RegisteredProject project : projects) {
try {
final FolderEntry projectFolder = project.getBaseFolder();
if (projectFolder != null) {
projectFolder.getVirtualFile().delete();
}
projectRegistry.removeProjects(project.getPath());
} catch (Exception e) {
LOG.warn(e.getLocalizedMessage());
}
}
}
private void validateProjectConfigurations(List<? extends NewProjectConfig> projectConfigList, boolean rewrite)
throws NotFoundException, ServerException, ConflictException, ForbiddenException, BadRequestException {
for (NewProjectConfig projectConfig : projectConfigList) {
final String pathToProject = projectConfig.getPath();
if (isNullOrEmpty(pathToProject)) {
throw new BadRequestException("Path for new project should be defined");
}
final String path = ProjectRegistry.absolutizePath(pathToProject);
final RegisteredProject registeredProject = projectRegistry.getProject(path);
if (registeredProject != null && rewrite) {
delete(path);
} else if (registeredProject != null) {
throw new ConflictException(format("Project config already exists for %s", path));
}
final String projectTypeId = projectConfig.getType();
if (isNullOrEmpty(projectTypeId)) {
projectConfig.setType(BaseProjectType.ID);
}
}
}
/**
* Updating project means:
* - getting the project (should exist)
@ -311,31 +429,17 @@ public final class ProjectManager {
ServerException,
NotFoundException,
ConflictException {
String path = newConfig.getPath();
final String path = newConfig.getPath();
if (path == null) {
throw new ConflictException("Project path is not defined");
}
final FolderEntry baseFolder = asFolder(path);
// If a project does not exist in the target path, create a new one
if (baseFolder == null) {
throw new NotFoundException(String.format("Folder '%s' doesn't exist.", path));
throw new NotFoundException(format("Folder '%s' doesn't exist.", path));
}
ProjectConfig oldConfig = projectRegistry.getProject(path);
final RegisteredProject project = projectRegistry.putProject(newConfig, baseFolder, true, false);
// unlike imported it is not appropriate for updated project to have problems
if(!project.getProblems().isEmpty()) {
// rollback project folder
projectRegistry.putProject(oldConfig, baseFolder, false, false);
throw new ServerException("Problems occured: " + project.getProblemsStr());
}
workspaceProjectsHolder.sync(projectRegistry);
projectRegistry.fireInitHandlers(project);
@ -371,57 +475,67 @@ public final class ProjectManager {
NotFoundException {
projectTreeChangesDetector.suspend();
try {
final ProjectImporter importer = importers.getImporter(sourceStorage.getType());
if (importer == null) {
throw new NotFoundException(String.format("Unable import sources project from '%s'. Sources type '%s' is not supported.",
sourceStorage.getLocation(), sourceStorage.getType()));
}
// Preparing websocket output publisher to broadcast output of import process to the ide clients while importing
final LineConsumerFactory outputOutputConsumerFactory =
() -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300);
String normalizePath = (path.startsWith("/")) ? path : "/".concat(path);
FolderEntry folder = asFolder(normalizePath);
if (folder != null && !rewrite) {
throw new ConflictException(String.format("Project %s already exists ", path));
}
if (folder == null) {
folder = getProjectsRoot().createFolder(normalizePath);
}
try {
importer.importSources(folder, sourceStorage, outputOutputConsumerFactory);
} catch (final Exception e) {
folder.remove();
throw e;
}
final String name = folder.getPath().getName();
for (ProjectConfig project : workspaceProjectsHolder.getProjects()) {
if (normalizePath.equals(project.getPath())) {
// TODO Needed for factory project importing with keepDir. It needs to find more appropriate solution
List<String> innerProjects = projectRegistry.getProjects(normalizePath);
for (String innerProject : innerProjects) {
RegisteredProject registeredProject = projectRegistry.getProject(innerProject);
projectRegistry.putProject(registeredProject, asFolder(registeredProject.getPath()), true, false);
}
RegisteredProject rp = projectRegistry.putProject(project, folder, true, false);
workspaceProjectsHolder.sync(projectRegistry);
return rp;
}
}
RegisteredProject rp = projectRegistry
.putProject(new NewProjectConfig(normalizePath, name, BaseProjectType.ID, sourceStorage), folder, true, false);
workspaceProjectsHolder.sync(projectRegistry);
return rp;
return doImportProject(path, sourceStorage, rewrite);
} finally {
projectTreeChangesDetector.resume();
}
}
/** Note: Use {@link ProjectTreeChangesDetector#suspend()} and {@link ProjectTreeChangesDetector#resume()} while importing source code */
private RegisteredProject doImportProject(String path, SourceStorage sourceStorage, boolean rewrite) throws ServerException,
IOException,
ForbiddenException,
UnauthorizedException,
ConflictException,
NotFoundException {
final ProjectImporter importer = importers.getImporter(sourceStorage.getType());
if (importer == null) {
throw new NotFoundException(format("Unable import sources project from '%s'. Sources type '%s' is not supported.",
sourceStorage.getLocation(), sourceStorage.getType()));
}
// Preparing websocket output publisher to broadcast output of import process to the ide clients while importing
final LineConsumerFactory outputOutputConsumerFactory =
() -> new ProjectImportOutputWSLineConsumer(path, workspaceProjectsHolder.getWorkspaceId(), 300);
String normalizePath = (path.startsWith("/")) ? path : "/".concat(path);
FolderEntry folder = asFolder(normalizePath);
if (folder != null && !rewrite) {
throw new ConflictException(format("Project %s already exists ", path));
}
if (folder == null) {
folder = getProjectsRoot().createFolder(normalizePath);
}
try {
importer.importSources(folder, sourceStorage, outputOutputConsumerFactory);
} catch (final Exception e) {
folder.remove();
throw e;
}
final String name = folder.getPath().getName();
for (ProjectConfig project : workspaceProjectsHolder.getProjects()) {
if (normalizePath.equals(project.getPath())) {
// TODO Needed for factory project importing with keepDir. It needs to find more appropriate solution
List<String> innerProjects = projectRegistry.getProjects(normalizePath);
for (String innerProject : innerProjects) {
RegisteredProject registeredProject = projectRegistry.getProject(innerProject);
projectRegistry.putProject(registeredProject, asFolder(registeredProject.getPath()), true, false);
}
RegisteredProject rp = projectRegistry.putProject(project, folder, true, false);
workspaceProjectsHolder.sync(projectRegistry);
return rp;
}
}
RegisteredProject rp = projectRegistry
.putProject(new NewProjectConfigImpl(normalizePath, name, BaseProjectType.ID, sourceStorage), folder, true, false);
workspaceProjectsHolder.sync(projectRegistry);
return rp;
}
/**
* Estimates if the folder can be treated as a project of particular type
*
@ -431,11 +545,9 @@ public final class ProjectManager {
* @return resolution object
* @throws ServerException
* @throws NotFoundException
* @throws ValueStorageException
*/
public ProjectTypeResolution estimateProject(String path, String projectTypeId) throws ServerException,
NotFoundException,
ValueStorageException {
NotFoundException {
final ProjectTypeDef projectType = projectTypeRegistry.getProjectType(projectTypeId);
if (projectType == null) {
throw new NotFoundException("Project Type to estimate needed.");
@ -468,13 +580,9 @@ public final class ProjectManager {
continue;
}
try {
final ProjectTypeResolution resolution = estimateProject(path, type.getId());
if (resolution.matched()) {
resolutions.add(resolution);
}
} catch (ValueStorageException e) {
LOG.warn(e.getLocalizedMessage(), e);
final ProjectTypeResolution resolution = estimateProject(path, type.getId());
if (resolution.matched()) {
resolutions.add(resolution);
}
}
@ -606,13 +714,14 @@ public final class ProjectManager {
if (move.isProject()) {
final RegisteredProject project = projectRegistry.getProject(itemPath);
NewProjectConfig projectConfig = new NewProjectConfig(newItem.getPath().toString(),
project.getType(),
project.getMixins(),
newName,
project.getDescription(),
project.getAttributes(),
project.getSource());
NewProjectConfig projectConfig = new NewProjectConfigImpl(newItem.getPath().toString(),
project.getType(),
project.getMixins(),
newName,
project.getDescription(),
project.getAttributes(),
null,
project.getSource());
if (move instanceof FolderEntry) {
projectRegistry.removeProjects(project.getPath());
@ -623,6 +732,10 @@ public final class ProjectManager {
return move;
}
boolean isVirtualFileExist(String path) throws ServerException {
return asVirtualFileEntry(path) != null;
}
FolderEntry asFolder(String path) throws NotFoundException, ServerException {
final VirtualFileEntry entry = asVirtualFileEntry(path);
if (entry == null) {
@ -630,13 +743,13 @@ public final class ProjectManager {
}
if (!entry.isFolder()) {
throw new NotFoundException(String.format("Item '%s' isn't a folder. ", path));
throw new NotFoundException(format("Item '%s' isn't a folder. ", path));
}
return (FolderEntry)entry;
}
VirtualFileEntry asVirtualFileEntry(String path) throws NotFoundException, ServerException {
VirtualFileEntry asVirtualFileEntry(String path) throws ServerException {
final String apath = ProjectRegistry.absolutizePath(path);
final FolderEntry root = getProjectsRoot();
return root.getChild(apath);
@ -649,7 +762,7 @@ public final class ProjectManager {
}
if (!entry.isFile()) {
throw new NotFoundException(String.format("Item '%s' isn't a file. ", path));
throw new NotFoundException(format("Item '%s' isn't a file. ", path));
}
return (FileEntry)entry;
@ -676,7 +789,7 @@ public final class ProjectManager {
}
searcher.add(file);
} catch (Exception e) {
LOG.warn(String.format("Project: %s", project.getPath()), e.getMessage());
LOG.warn(format("Project: %s", project.getPath()), e.getMessage());
}
});
}

View File

@ -14,6 +14,7 @@ import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry;
@ -181,15 +182,12 @@ public class ProjectRegistry {
* whether this is automatically detected or explicitly defined project
* @return project
* @throws ServerException
* @throws ConflictException
* @throws NotFoundException
* when path for project is undefined
*/
RegisteredProject putProject(ProjectConfig config,
FolderEntry folder,
boolean updated,
boolean detected) throws ServerException,
ConflictException,
NotFoundException {
boolean detected) throws ServerException {
final RegisteredProject project = new RegisteredProject(folder, config, updated, detected, this.projectTypeRegistry);
projects.put(project.getPath(), project);
@ -223,8 +221,7 @@ public class ProjectRegistry {
* Attributes defined with particular Project Type
* If incoming Project Type is primary and:
* - If the folder located on projectPath is a Project, its Primary PT will be converted to incoming PT
* - If the folder located on projectPath is NOT a Project the folder will be converted to "detected" Project
* with incoming Primary PT
* - If the folder located on projectPath is NOT a Project the folder will be converted to "detected" Project with incoming Primary PT
* If incoming Project Type is mixin and:
* - If the folder located on projectPath is a Project, this PT will be added (if not already there) to its Mixin PTs
* - If the folder located on projectPath is NOT a Project - ConflictException will be thrown
@ -268,7 +265,7 @@ public class ProjectRegistry {
final String path = absolutizePath(projectPath);
final String name = Path.of(projectPath).getName();
conf = new NewProjectConfig(path, type, newMixins, name, name, null, null);
conf = new NewProjectConfigImpl(path, type, newMixins, name, name, null, null, null);
return putProject(conf, root.getChildFolder(path), true, true);
}
@ -283,12 +280,13 @@ public class ProjectRegistry {
newType = type;
}
conf = new NewProjectConfig(project.getPath(),
conf = new NewProjectConfigImpl(project.getPath(),
newType,
newMixins,
project.getName(),
project.getDescription(),
project.getAttributes(),
null,
project.getSource());
return putProject(conf, project.getBaseFolder(), true, project.isDetected());
@ -339,12 +337,13 @@ public class ProjectRegistry {
newType = BaseProjectType.ID;
}
final NewProjectConfig conf = new NewProjectConfig(project.getPath(),
final NewProjectConfig conf = new NewProjectConfigImpl(project.getPath(),
newType,
newMixins,
project.getName(),
project.getDescription(),
project.getAttributes(),
null,
project.getSource());
return putProject(conf, project.getBaseFolder(), true, project.isDetected());
@ -367,7 +366,7 @@ public class ProjectRegistry {
putProject(null, folder, true, false);
}
}
} catch (ServerException | ConflictException | NotFoundException e) {
} catch (ServerException e) {
LOG.warn(e.getLocalizedMessage());
}
}

View File

@ -43,6 +43,7 @@ import org.eclipse.che.api.vfs.search.QueryExpression;
import org.eclipse.che.api.vfs.search.SearchResult;
import org.eclipse.che.api.vfs.search.SearchResultEntry;
import org.eclipse.che.api.vfs.search.Searcher;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.commons.env.EnvironmentContext;
@ -90,6 +91,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.core.util.LinksHelper.createLink;
import static org.eclipse.che.api.project.server.DtoConverter.asDto;
import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CHILDREN;
import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CREATE_BATCH_PROJECTS;
import static org.eclipse.che.api.project.shared.Constants.LINK_REL_CREATE_PROJECT;
import static org.eclipse.che.api.project.shared.Constants.LINK_REL_DELETE;
import static org.eclipse.che.api.project.shared.Constants.LINK_REL_GET_CONTENT;
@ -206,6 +208,37 @@ public class ProjectService extends Service {
return injectProjectLinks(configDto);
}
@POST
@Path("/batch")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Creates batch of projects according to their configurations",
notes = "A project will be created by importing when project configuration contains source object. " +
"For creating a project by generator options should be specified.",
response = ProjectConfigDto.class)
@ApiResponses({@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 400, message = "Path for new project should be defined"),
@ApiResponse(code = 403, message = "Operation is forbidden"),
@ApiResponse(code = 409, message = "Project with specified name already exist in workspace"),
@ApiResponse(code = 500, message = "Server error")})
@GenerateLink(rel = LINK_REL_CREATE_BATCH_PROJECTS)
public List<ProjectConfigDto> createBatchProjects(
@Description("list of descriptors for projects") List<NewProjectConfigDto> projectConfigList,
@ApiParam(value = "Force rewrite existing project", allowableValues = "true,false")
@QueryParam("force") boolean rewrite)
throws ConflictException, ForbiddenException, ServerException, NotFoundException, IOException, UnauthorizedException,
BadRequestException {
List<ProjectConfigDto> result = new ArrayList<>(projectConfigList.size());
for (RegisteredProject registeredProject : projectManager.createBatchProjects(projectConfigList, rewrite)) {
ProjectConfigDto projectConfig = injectProjectLinks(asDto(registeredProject));
result.add(projectConfig);
eventService.publish(new ProjectCreatedEvent(workspace, registeredProject.getPath()));
}
return result;
}
@PUT
@Path("/{path:.*}")
@Consumes(MediaType.APPLICATION_JSON)
@ -271,6 +304,7 @@ public class ProjectService extends Service {
return DtoFactory.newDto(SourceEstimation.class)
.withType(projectType)
.withMatched(resolution.matched())
.withResolution(resolution.getResolution())
.withAttributes(attributes);
}

View File

@ -11,13 +11,10 @@
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.type.Attribute;
import org.eclipse.che.api.project.server.RegisteredProject.Problem;
import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.project.server.type.ValueStorageException;
import java.util.ArrayList;
import java.util.HashMap;
@ -26,6 +23,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
/**
* @author gazarenkov
*/
@ -33,37 +33,40 @@ public class ProjectTypes {
private final String projectPath;
private final ProjectTypeRegistry projectTypeRegistry;
private ProjectTypeDef primary;
private ProjectTypeDef primary;
private final Map<String, ProjectTypeDef> mixins;
private final Map<String, ProjectTypeDef> all;
private final Map<String, Attribute> attributeDefs;
private final List<Problem> problems;
ProjectTypes(String projectPath,
String type,
List<String> mixinTypes,
ProjectTypeRegistry projectTypeRegistry,
List<Problem> problems) throws ProjectTypeConstraintException, NotFoundException {
String type,
List<String> mixinTypes,
ProjectTypeRegistry projectTypeRegistry,
List<Problem> problems) {
mixins = new HashMap<>();
all = new HashMap<>();
attributeDefs = new HashMap<>();
this.problems = problems != null ? problems : newArrayList();
this.projectTypeRegistry = projectTypeRegistry;
this.projectPath = projectPath;
ProjectTypeDef tmpPrimary;
if (type == null) {
problems.add(new Problem(12, "No primary type defined for " + projectPath + " Base Project Type assigned."));
this.problems.add(new Problem(12, "No primary type defined for " + projectPath + " Base Project Type assigned."));
tmpPrimary = ProjectTypeRegistry.BASE_TYPE;
} else {
try {
tmpPrimary = projectTypeRegistry.getProjectType(type);
} catch (NotFoundException e) {
problems.add(new Problem(12, "Primary type " + type + " defined for " + projectPath + " is not registered. Base Project Type assigned."));
this.problems.add(new Problem(12, "Primary type " + type + " defined for " + projectPath +
" is not registered. Base Project Type assigned."));
tmpPrimary = ProjectTypeRegistry.BASE_TYPE;
}
if (!tmpPrimary.isPrimaryable()) {
problems.add(new Problem(12, "Project type " + tmpPrimary.getId() + " is not allowable to be primary type. Base Project Type assigned."));
this.problems.add(new Problem(12, "Project type " + tmpPrimary.getId() + " is not allowable to be primary type. Base Project Type assigned."));
tmpPrimary = ProjectTypeRegistry.BASE_TYPE;
}
}
@ -90,12 +93,12 @@ public class ProjectTypes {
try {
mixin = projectTypeRegistry.getProjectType(mixinFromConfig);
} catch (NotFoundException e) {
problems.add(new Problem(12, "Project type " + mixinFromConfig + " is not registered. Skipped."));
this.problems.add(new Problem(12, "Project type " + mixinFromConfig + " is not registered. Skipped."));
continue;
}
if (!mixin.isMixable()) {
problems.add(new Problem(12, "Project type " + mixin + " is not allowable to be mixin. It not mixable. Skipped."));
this.problems.add(new Problem(12, "Project type " + mixin + " is not allowable to be mixin. It not mixable. Skipped."));
continue;
}
@ -105,14 +108,15 @@ public class ProjectTypes {
// detect duplicated attributes
for (Attribute attr : mixin.getAttributes()) {
if (attributeDefs.containsKey(attr.getName())) {
problems.add(new Problem(13, "Attribute name conflict. Duplicated attributes detected " + projectPath +
" Attribute " + attr.getName() + " declared in " + mixin.getId() + " already declared in " +
attributeDefs.get(attr.getName()).getProjectType()+" Skipped."));
final String attrName = attr.getName();
if (attributeDefs.containsKey(attrName)) {
this.problems.add(new Problem(13,
format("Attribute name conflict. Duplicated attributes detected for %s. " +
"Attribute %s declared in %s already declared in %s. Skipped.",
projectPath, attrName, mixin.getId(), attributeDefs.get(attrName).getProjectType())));
continue;
}
attributeDefs.put(attr.getName(), attr);
attributeDefs.put(attrName, attr);
}
// Silently remove repeated items from mixins if any
@ -147,22 +151,22 @@ public class ProjectTypes {
void reset(Set<Attribute> attributesToDel) {
Set<String> ptsToDel = new HashSet<>();
for(Attribute attr : attributesToDel) {
for (Attribute attr : attributesToDel) {
ptsToDel.add(attr.getProjectType());
}
Set <String>attrNamesToDel = new HashSet<>();
for(String pt : ptsToDel) {
Set<String> attrNamesToDel = new HashSet<>();
for (String pt : ptsToDel) {
ProjectTypeDef typeDef = all.get(pt);
for(Attribute attrDef: typeDef.getAttributes()) {
for (Attribute attrDef : typeDef.getAttributes()) {
attrNamesToDel.add(attrDef.getName());
}
}
// remove project types
for(String typeId : ptsToDel) {
for (String typeId : ptsToDel) {
this.all.remove(typeId);
if(this.primary.getId().equals(typeId)) {
if (this.primary.getId().equals(typeId)) {
this.primary = ProjectTypeRegistry.BASE_TYPE;
this.all.put(ProjectTypeRegistry.BASE_TYPE.getId(), ProjectTypeRegistry.BASE_TYPE);
} else {
@ -171,30 +175,27 @@ public class ProjectTypes {
}
// remove attributes
for(String attr : attrNamesToDel) {
for (String attr : attrNamesToDel) {
this.attributeDefs.remove(attr);
}
}
void addTransient(FolderEntry projectFolder) throws ServerException,
NotFoundException,
ProjectTypeConstraintException,
ValueStorageException {
void addTransient(FolderEntry projectFolder) {
for (ProjectTypeDef pt : projectTypeRegistry.getProjectTypes()) {
// NOTE: Only mixable types allowed
if (pt.isMixable() && !pt.isPersisted() && pt.resolveSources(projectFolder).matched()) {
all.put(pt.getId(), pt);
mixins.put(pt.getId(), pt);
for (Attribute attr : pt.getAttributes()) {
if (attributeDefs.containsKey(attr.getName())) {
throw new ProjectTypeConstraintException(
"Attribute name conflict. Duplicated attributes detected " + projectPath +
" Attribute " + attr.getName() + " declared in " + pt.getId() + " already declared in " +
attributeDefs.get(attr.getName()).getProjectType()
);
final String attrName = attr.getName();
if (attributeDefs.containsKey(attrName)) {
problems.add(new Problem(13,
format("Attribute name conflict. Duplicated attributes detected for %s. " +
"Attribute %s declared in %s already declared in %s. Skipped.",
projectPath, attrName, pt.getId(), attributeDefs.get(attrName).getProjectType())));
}
attributeDefs.put(attr.getName(), attr);
attributeDefs.put(attrName, attr);
}
}
}

View File

@ -10,14 +10,12 @@
*******************************************************************************/
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.core.model.project.type.Attribute;
import org.eclipse.che.api.core.model.project.type.Value;
import org.eclipse.che.api.project.server.type.AttributeValue;
import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.project.server.type.ValueProvider;
@ -27,12 +25,12 @@ import org.eclipse.che.api.vfs.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static java.lang.String.format;
/**
* Internal Project implementation.
* It is supposed that it is object always consistent.
@ -63,15 +61,14 @@ public class RegisteredProject implements ProjectConfig {
* if this project was detected, initialized when "parent" project initialized
* @param projectTypeRegistry
* project type registry
* @throws ServerException
* when path for project is undefined
*/
RegisteredProject(FolderEntry folder,
ProjectConfig config,
boolean updated,
boolean detected,
ProjectTypeRegistry projectTypeRegistry) throws NotFoundException,
ProjectTypeConstraintException,
ServerException,
ValueStorageException {
ProjectTypeRegistry projectTypeRegistry) throws ServerException {
problems = new ArrayList<>();
attributes = new HashMap<>();
@ -85,7 +82,7 @@ public class RegisteredProject implements ProjectConfig {
}
this.folder = folder;
this.config = (config == null) ? new NewProjectConfig(path) : config;
this.config = config == null ? new NewProjectConfigImpl(path) : config;
this.updated = updated;
this.detected = detected;
@ -97,6 +94,7 @@ public class RegisteredProject implements ProjectConfig {
problems.add(new Problem(11, "No project configured in workspace " + this.config.getPath()));
}
// 1. init project types
this.types = new ProjectTypes(this.config.getPath(), this.config.getType(), this.config.getMixins(), projectTypeRegistry, problems);
@ -110,15 +108,9 @@ public class RegisteredProject implements ProjectConfig {
/**
* Initialize project attributes.
*
* @throws ValueStorageException
* @throws ProjectTypeConstraintException
* @throws ServerException
* @throws NotFoundException
* Note: the problem with {@link Problem#code} = 13 will be added when a value for some attribute is not initialized
*/
private void initAttributes() throws ValueStorageException, ProjectTypeConstraintException, ServerException, NotFoundException {
Set<Attribute> invalidAttributes = new HashSet<>();
private void initAttributes() {
// we take only defined attributes, others ignored
for (Map.Entry<String, Attribute> entry : types.getAttributeDefs().entrySet()) {
@ -140,12 +132,17 @@ public class RegisteredProject implements ProjectConfig {
if (folder != null) {
if (!valueProvider.isSettable() || value.isEmpty()) {
// get provided value
value = new AttributeValue(valueProvider.getValues(name));
} else {
// set provided (not empty) value
valueProvider.setValues(name, value.getList());
try {
if (!valueProvider.isSettable() || value.isEmpty()) {
// get provided value
value = new AttributeValue(valueProvider.getValues(name));
} else {
// set provided (not empty) value
valueProvider.setValues(name, value.getList());
}
} catch (ValueStorageException e) {
this.problems.add(new Problem(13, format("Value for attribute %s is not initialized, caused by: %s",
variable.getId(), e.getLocalizedMessage())));
}
} else {
@ -155,7 +152,6 @@ public class RegisteredProject implements ProjectConfig {
if (value.isEmpty() && variable.isRequired()) {
this.problems.add(new Problem(13, "Value for required attribute is not initialized " + variable.getId()));
invalidAttributes.add(variable);
//throw new ProjectTypeConstraintException("Value for required attribute is not initialized " + variable.getId());
}
@ -164,9 +160,6 @@ public class RegisteredProject implements ProjectConfig {
}
}
}
types.reset(invalidAttributes);
}
/**

View File

@ -48,13 +48,14 @@ public abstract class WorkspaceProjectsSyncer {
if(!project.isSynced() && !project.isDetected()) {
final ProjectConfig config = new NewProjectConfig(project.getPath(),
project.getType(),
project.getMixins(),
project.getName(),
project.getDescription(),
project.getPersistableAttributes(),
project.getSource());
final ProjectConfig config = new NewProjectConfigImpl(project.getPath(),
project.getType(),
project.getMixins(),
project.getName(),
project.getDescription(),
project.getPersistableAttributes(),
null,
project.getSource());
boolean found = false;
for(ProjectConfig r : remote) {

View File

@ -20,6 +20,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
import static java.lang.String.format;
/**
* @author gazarenkov
*/
@ -169,7 +172,7 @@ public abstract class ProjectTypeDef implements ProjectType {
this.ancestors.add(ancestor);
}
public ProjectTypeResolution resolveSources(FolderEntry projectFolder) throws ValueStorageException {
public ProjectTypeResolution resolveSources(FolderEntry projectFolder) {
Map<String, Value> matchAttrs = new HashMap<>();
for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
Attribute attr = entry.getValue();
@ -178,11 +181,22 @@ public abstract class ProjectTypeDef implements ProjectType {
Variable var = (Variable)attr;
ValueProviderFactory factory = var.getValueProviderFactory();
if (factory != null) {
Value value = new AttributeValue(factory.newInstance(projectFolder).getValues(name));
if (value.isEmpty()) {
Value value;
String errorMessage = "";
try {
value = new AttributeValue(factory.newInstance(projectFolder).getValues(name));
} catch (ValueStorageException e) {
value = null;
errorMessage = e.getLocalizedMessage();
}
if (value == null || value.isEmpty()) {
if (var.isRequired()) {
// this PT is not match
return new DefaultResolution(id, new HashMap<>(), false);
errorMessage = errorMessage.isEmpty() ? format("Value for required attribute %s is not initialized", name)
: errorMessage;
return new DefaultResolution(id, errorMessage);
}
} else {
// add one more matched attribute
@ -204,6 +218,12 @@ public abstract class ProjectTypeDef implements ProjectType {
this.match = match;
}
/** Use this one when source code not matches project type requirements */
public DefaultResolution(String type, String resolution) {
super(type, newHashMap(), resolution);
this.match = false;
}
@Override
public boolean matched() {
return match;

View File

@ -21,10 +21,16 @@ public abstract class ProjectTypeResolution {
private String type;
private Map<String, Value> attributes;
private String resolution;
public ProjectTypeResolution(String type, Map<String, Value> attributes) {
this(type, attributes, "");
}
public ProjectTypeResolution(String type, Map<String, Value> attributes, String resolution) {
this.type = type;
this.attributes = attributes;
this.resolution = resolution;
}
/**
@ -34,6 +40,13 @@ public abstract class ProjectTypeResolution {
return type;
}
/**
* @return the reason that current source code NOT matches project type requirements
*/
public String getResolution() {
return resolution;
}
/**
* @return true if current source code in generally matches project type requirements
* by default (but not necessarily) it may check if there are all required provided attributes

View File

@ -10,21 +10,25 @@
*******************************************************************************/
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.core.util.LineConsumerFactory;
import org.eclipse.che.api.core.util.ValueHolder;
import org.eclipse.che.api.project.server.RegisteredProject.Problem;
import org.eclipse.che.api.project.server.handlers.CreateProjectHandler;
import org.eclipse.che.api.project.server.importer.ProjectImporter;
import org.eclipse.che.api.project.server.type.AttributeValue;
import org.eclipse.che.api.project.server.type.BaseProjectType;
import org.eclipse.che.api.project.server.type.Variable;
import org.eclipse.che.api.vfs.Path;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.dto.server.DtoFactory;
@ -33,8 +37,10 @@ import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -43,6 +49,7 @@ import java.util.zip.ZipOutputStream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@ -52,7 +59,7 @@ import static org.junit.Assert.fail;
* @author gazarenkov
*/
public class ProjectManagerWriteTest extends WsAgentTestBase {
private static final String FILE_CONTENT = "to be or not to be";
@Before
public void setUp() throws Exception {
@ -66,14 +73,412 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
projectTypeRegistry.registerProjectType(new PTsettableVP());
projectHandlerRegistry.register(new SrcGenerator());
}
@Test
public void testCreateBatchProjectsByConfigs() throws Exception {
final String projectPath1 = "/testProject1";
final String projectPath2 = "/testProject2";
final NewProjectConfig config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, null);
final NewProjectConfig config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, null);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config1);
configs.add(config2);
pm.createBatchProjects(configs, false);
checkProjectExist(projectPath1);
checkProjectExist(projectPath2);
assertEquals(2, projectRegistry.getProjects().size());
}
@Test
public void testCreateBatchProjectsByImportingSourceCode() throws Exception {
final String projectPath1 = "/testProject1";
final String projectPath2 = "/testProject2";
final String importType1 = "importType1";
final String importType2 = "importType2";
final String [] paths1 = {"folder1/", "folder1/file1.txt"};
final List<String> children1 = new ArrayList<>(Arrays.asList(paths1));
registerImporter(importType1, prepareZipArchiveBasedOn(children1));
final String [] paths2 = {"folder2/", "folder2/file2.txt"};
final List<String> children2 = new ArrayList<>(Arrays.asList(paths2));
registerImporter(importType2, prepareZipArchiveBasedOn(children2));
final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1);
final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1);
final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2);
final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config1);
configs.add(config2);
pm.createBatchProjects(configs, false);
final RegisteredProject project1 = projectRegistry.getProject(projectPath1);
final FolderEntry projectFolder1 = project1.getBaseFolder();
checkProjectExist(projectPath1);
checkChildrenFor(projectFolder1, children1);
final RegisteredProject project2 = projectRegistry.getProject(projectPath2);
final FolderEntry projectFolder2 = project2.getBaseFolder();
checkProjectExist(projectPath2);
checkChildrenFor(projectFolder2, children2);
}
@Test
public void testCreateProjectWhenSourceCodeIsNotReachable() throws Exception {
final String projectPath = "/testProject";
final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType");
final NewProjectConfigDto config = createProjectConfigObject("testProject1", projectPath, BaseProjectType.ID, source);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config);
try {
pm.createBatchProjects(configs, false);
fail("Exception should be thrown when source code is not reachable");
} catch (Exception e) {
assertEquals(0, projectRegistry.getProjects().size());
assertNull(projectRegistry.getProject(projectPath));
assertNull(pm.getProjectsRoot().getChild(projectPath));
}
}
@Test
public void shouldRollbackCreatingBatchProjects() throws Exception {
// we should rollback operation of creating batch projects when we have not source code for at least one project
// For example: two projects were success created, but we could not get source code for third configuration
// At this use case we should rollback the operation and clean up all created projects
final String projectPath1 = "/testProject1";
final String projectPath2 = "/testProject2";
final String projectPath3 = "/testProject3";
final String importType1 = "importType1";
final String importType2 = "importType2";
final String [] paths1 = {"folder1/", "folder1/file1.txt"};
final List<String> children1 = new ArrayList<>(Arrays.asList(paths1));
registerImporter(importType1, prepareZipArchiveBasedOn(children1));
final String [] paths2 = {"folder2/", "folder2/file2.txt"};
final List<String> children2 = new ArrayList<>(Arrays.asList(paths2));
registerImporter(importType2, prepareZipArchiveBasedOn(children2));
final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1);
final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath1, BaseProjectType.ID, source1);
final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2);
final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath2, BaseProjectType.ID, source2);
final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType");
final NewProjectConfigDto config3 = createProjectConfigObject("testProject3", projectPath3, BaseProjectType.ID, source);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config1); //will be success created
configs.add(config2); //will be success created
configs.add(config3); //we be failed - we have not registered importer - source code will not be imported
try {
pm.createBatchProjects(configs, false);
fail("We should rollback operation of creating batch projects when we could not get source code for at least one project");
} catch (Exception e) {
assertEquals(0, projectRegistry.getProjects().size());
assertNull(projectRegistry.getProject(projectPath1));
assertNull(pm.getProjectsRoot().getChild(projectPath1));
assertNull(projectRegistry.getProject(projectPath2));
assertNull(pm.getProjectsRoot().getChild(projectPath2));
assertNull(projectRegistry.getProject(projectPath3));
assertNull(pm.getProjectsRoot().getChild(projectPath3));
}
}
@Test
public void testCreateBatchProjectsWithInnerProject() throws Exception {
final String rootProjectPath = "/testProject1";
final String innerProjectPath = "/testProject1/innerProject";
final String importType = "importType1";
final String innerProjectType = "pt2";
Map<String, List<String>> attributes = new HashMap<>();
attributes.put("pt2-var2", new AttributeValue("test").getList());
final String [] paths1 = {"folder1/", "folder1/file1.txt"};
final String [] paths2 = {"innerProject/", "innerProject/folder2/", "innerProject/folder2/file2.txt"};
final List<String> children1 = Arrays.asList(paths1);
final List<String> children2 = Arrays.asList(paths2);
final List<String> children = new ArrayList<>(children1);
children.addAll(children2);
registerImporter(importType, prepareZipArchiveBasedOn(children));
SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType);
NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source);
NewProjectConfigDto config2 = createProjectConfigObject("innerProject", innerProjectPath, innerProjectType, null);
config2.setAttributes(attributes);
List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config1);
configs.add(config2);
pm.createBatchProjects(configs, false);
RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath);
FolderEntry rootProjectFolder = rootProject.getBaseFolder();
RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath);
FolderEntry innerProjectFolder = innerProject.getBaseFolder();
assertNotNull(rootProject);
assertTrue(rootProjectFolder.getVirtualFile().exists());
assertEquals(rootProjectPath, rootProject.getPath());
checkChildrenFor(rootProjectFolder, children1);
assertNotNull(innerProject);
assertTrue(innerProjectFolder.getVirtualFile().exists());
assertEquals(innerProjectPath, innerProject.getPath());
assertEquals(innerProjectType, innerProject.getType());
checkChildrenFor(rootProjectFolder, children2);
}
@Test
public void testCreateBatchProjectsWithInnerProjectWhenInnerProjectContainsSource() throws Exception {
final String rootProjectPath = "/rootProject";
final String innerProjectPath = "/rootProject/innerProject";
final String rootImportType = "rootImportType";
final String innerImportType = "innerImportType";
final String innerProjectType = "pt2";
Map<String, List<String>> attributes = new HashMap<>();
attributes.put("pt2-var2", new AttributeValue("test").getList());
final String [] paths1 = {"folder1/", "folder1/file1.txt"};
final List<String> children1 = new ArrayList<>(Arrays.asList(paths1));
registerImporter(rootImportType, prepareZipArchiveBasedOn(children1));
final String [] paths2 = {"folder2/", "folder2/file2.txt"};
final List<String> children2 = new ArrayList<>(Arrays.asList(paths2));
registerImporter(innerImportType, prepareZipArchiveBasedOn(children2));
final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(rootImportType);
final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", rootProjectPath, BaseProjectType.ID, source1);
final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(innerImportType);
final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", innerProjectPath, innerProjectType, source2);
config2.setAttributes(attributes);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config2);
configs.add(config1);
pm.createBatchProjects(configs, false);
RegisteredProject rootProject = projectRegistry.getProject(rootProjectPath);
FolderEntry rootProjectFolder = rootProject.getBaseFolder();
checkProjectExist(rootProjectPath);
checkChildrenFor(rootProjectFolder, children1);
RegisteredProject innerProject = projectRegistry.getProject(innerProjectPath);
FolderEntry innerProjectFolder = innerProject.getBaseFolder();
assertNotNull(innerProject);
assertTrue(innerProjectFolder.getVirtualFile().exists());
assertEquals(innerProjectPath, innerProject.getPath());
assertEquals(innerProjectType, innerProject.getType());
checkChildrenFor(innerProjectFolder, children2);
}
@Test
public void testCreateBatchProjectsWithMixInnerProjects() throws Exception { // Projects should be sorted by path before creating
final String [] paths = {"/1/z", "/2/z", "/1/d", "/2", "/1", "/1/a"};
final List<String> projectsPaths = new ArrayList<>(Arrays.asList(paths));
final List<NewProjectConfig> configs = new ArrayList<>(projectsPaths.size());
for (String path : projectsPaths) {
configs.add(createProjectConfigObject(path.substring(path.length() - 1, path.length()), path, BaseProjectType.ID, null));
}
pm.createBatchProjects(configs, false);
for (String path : projectsPaths) {
checkProjectExist(path);
}
}
@Test
public void testCreateBatchProjectsWhenConfigContainsOnlyPath()
throws Exception { // NewProjectConfig object contains only one mandatory Project Path field
final String projectPath1 = "/testProject1";
final String projectPath2 = "/testProject2";
final NewProjectConfig config1 = createProjectConfigObject(null, projectPath1, null, null);
final NewProjectConfig config2 = createProjectConfigObject(null, projectPath2, null, null);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config1);
configs.add(config2);
pm.createBatchProjects(configs, false);
checkProjectExist(projectPath1);
checkProjectExist(projectPath2);
assertEquals(2, projectRegistry.getProjects().size());
}
@Test
public void shouldThrowBadRequestExceptionAtCreatingBatchProjectsWhenConfigNotContainsPath()
throws Exception { //Path is mandatory field for NewProjectConfig
final SourceStorageDto source = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType("importType");
final NewProjectConfig config = createProjectConfigObject("project", null, BaseProjectType.ID, source);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config);
try {
pm.createBatchProjects(configs, false);
fail("BadRequestException should be thrown : path field is mandatory");
} catch (BadRequestException e) {
assertEquals(0, projectRegistry.getProjects().size());
}
}
@Test
public void shouldThrowConflictExceptionAtCreatingBatchProjectsWhenProjectWithPathAlreadyExist() throws Exception {
final String path = "/somePath";
final NewProjectConfig config = createProjectConfigObject("project", path, BaseProjectType.ID, null);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config);
pm.createBatchProjects(configs, false);
checkProjectExist(path);
assertEquals(1, projectRegistry.getProjects().size());
try {
pm.createBatchProjects(configs, false);
fail("ConflictException should be thrown : Project config with the same path is already exists");
} catch (ConflictException e) {
assertEquals(1, projectRegistry.getProjects().size());
}
}
@Test
public void shouldCreateParentFolderAtCreatingProjectWhenParentDoesNotExist() throws Exception {
final String nonExistentParentPath = "/rootProject";
final String innerProjectPath = "/rootProject/innerProject";
final NewProjectConfig config = createProjectConfigObject(null, innerProjectPath, null, null);
final List<NewProjectConfig> configs = new ArrayList<>(2);
configs.add(config);
pm.createBatchProjects(configs, false);
checkProjectExist(nonExistentParentPath);
checkProjectExist(innerProjectPath);
assertEquals(2, projectRegistry.getProjects().size());
}
@Test
public void shouldRewriteProjectAtCreatingBatchProjectsWhenProjectAlreadyExist() throws Exception {
final String projectPath = "/testProject";
final String importType1 = "importType1";
final String importType2 = "importType2";
final String [] paths1 = {"folder1/", "folder1/file1.txt"};
final List<String> children1 = new ArrayList<>(Arrays.asList(paths1));
registerImporter(importType1, prepareZipArchiveBasedOn(children1));
final String [] paths2 = {"folder2/", "folder2/file2.txt"};
final List<String> children2 = new ArrayList<>(Arrays.asList(paths2));
registerImporter(importType2, prepareZipArchiveBasedOn(children2));
final SourceStorageDto source1 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType1);
final NewProjectConfigDto config1 = createProjectConfigObject("testProject1", projectPath, "blank", source1);
final SourceStorageDto source2 = DtoFactory.newDto(SourceStorageDto.class).withLocation("someLocation").withType(importType2);
final NewProjectConfigDto config2 = createProjectConfigObject("testProject2", projectPath, "blank", source2);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config1);
pm.createBatchProjects(configs, false);
final FolderEntry projectFolder1 = projectRegistry.getProject(projectPath).getBaseFolder();
checkProjectExist(projectPath);
checkChildrenFor(projectFolder1, children1);
assertEquals(1, projectRegistry.getProjects().size());
configs.clear();
configs.add(config2);
pm.createBatchProjects(configs, true);
final FolderEntry projectFolder2 = projectRegistry.getProject(projectPath).getBaseFolder();
checkProjectExist(projectPath);
checkChildrenFor(projectFolder2, children2);
assertEquals(1, projectRegistry.getProjects().size());
assertNull(projectFolder2.getChild("folder1/"));
assertNull(projectFolder2.getChild("folder1/file1.txt"));
}
@Test
public void shouldSetBlankTypeAtCreatingBatchProjectsWhenConfigContainsUnregisteredProjectType()
throws Exception {// If declared primary PT is not registered, project is created as Blank, with Problem 12
final String projectPath = "/testProject";
final String projectType = "unregisteredProjectType";
final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, projectType, null);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config);
pm.createBatchProjects(configs, false);
final RegisteredProject project = projectRegistry.getProject(projectPath);
final List<Problem> problems = project.getProblems();
checkProjectExist(projectPath);
assertNotEquals(projectType, project.getType());
assertEquals(1, problems.size());
assertEquals(12, problems.get(0).code);
assertEquals(1, projectRegistry.getProjects().size());
}
@Test
public void shouldCreateBatchProjectsWithoutMixinPTWhenThisOneIsUnregistered()
throws Exception {// If declared mixin PT is not registered, project is created w/o it, with Problem 12
final String projectPath = "/testProject";
final String mixinPType = "unregistered";
final NewProjectConfig config = createProjectConfigObject("projectName", projectPath, BaseProjectType.ID, null);
config.getMixins().add(mixinPType);
final List<NewProjectConfig> configs = new ArrayList<>(1);
configs.add(config);
pm.createBatchProjects(configs, false);
final RegisteredProject project = projectRegistry.getProject(projectPath);
final List<Problem> problems = project.getProblems();
checkProjectExist(projectPath);
assertEquals(1, problems.size());
assertEquals(12, problems.get(0).code);
assertTrue(project.getMixins().isEmpty());
assertEquals(1, projectRegistry.getProjects().size());
}
@Test
public void testCreateProject() throws Exception {
Map<String, List<String>> attrs = new HashMap<>();
List<String> v = new ArrayList<>();
v.add("meV");
@ -95,74 +500,85 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
assertEquals("/createProject", project.getPath());
assertEquals(2, project.getAttributeEntries().size());
assertEquals("meV", project.getAttributeEntries().get("var1").getString());
}
@Test
public void testCreateProjectInvalidAttribute() throws Exception {
ProjectConfig pc = new NewProjectConfig("/testCreateProjectInvalidAttributes", "pt2", null, "name", "descr", null, null);
try {
pm.createProject(pc, null);
fail("ProjectTypeConstraintException should be thrown : pt-var2 attribute is mandatory");
} catch (ServerException e) {
//
}
}
@Test
public void testCreateProjectWithRequiredProvidedAttribute() throws Exception {
public void testCreateProjectWithInvalidAttribute() throws Exception {
// SPECS:
// If project type has provided required attributes,
// respective CreateProjectHandler MUST be provided
// Project will be created with problem code = 13(Value for required attribute is not initialized)
// when required attribute is not initialized
final String path = "/testCreateProjectInvalidAttributes";
final String projectType = "pt2";
final NewProjectConfig config = new NewProjectConfigImpl(path, projectType, null, "name", "descr", null, null, null);
Map<String, List<String>> attributes = new HashMap<>();
pm.createProject(config, null);
RegisteredProject project = projectRegistry.getProject(path);
assertNotNull(project);
assertNotNull(pm.getProjectsRoot().getChild(path));
assertEquals(projectType, project.getType());
List<Problem> problems = project.getProblems();
assertNotNull(problems);
assertFalse(problems.isEmpty());
assertEquals(1, problems.size());
assertEquals(13, problems.get(0).code);
}
@Test
public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasGenerator() throws Exception {
final String path = "/testCreateProjectWithRequiredProvidedAttribute";
final String projectTypeId = "pt3";
final Map<String, List<String>> attributes = new HashMap<>();
attributes.put("pt2-var2", new AttributeValue("test").getList());
ProjectConfig pc =
new NewProjectConfig("/testCreateProjectWithRequiredProvidedAttribute", "pt3", null, "name", "descr", attributes, null);
final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", attributes, null, null);
pm.createProject(pc, null);
RegisteredProject project = projectRegistry.getProject("testCreateProjectWithRequiredProvidedAttribute");
assertEquals("pt3", project.getType());
final RegisteredProject project = projectRegistry.getProject(path);
assertEquals(projectTypeId, project.getType());
assertNotNull(project.getBaseFolder().getChild("file1"));
assertEquals("pt2-provided1", project.getAttributes().get("pt2-provided1").get(0));
}
@Test
public void testFailCreateProjectWithNoRequiredGenerator() throws Exception {
public void testCreateProjectWithRequiredProvidedAttributeWhenGivenProjectTypeHasNotGenerator() throws Exception {
// SPECS:
// If there are no respective CreateProjectHandler ServerException will be thrown
// Project will be created with problem code = 13 (Value for required attribute is not initialized)
// when project type has provided required attributes
// but have not respective generator(CreateProjectHandler)
ProjectConfig pc = new NewProjectConfig("/testFailCreateProjectWithNoRequiredGenerator", "pt4", null, "name", "descr", null, null);
try {
pm.createProject(pc, null);
fail("ProjectTypeConstraintException: Value for required attribute is not initialized pt4:pt4-provided1");
} catch (ServerException e) {
}
final String path = "/testCreateProjectWithRequiredProvidedAttribute";
final String projectTypeId = "pt4";
final ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
final RegisteredProject project = projectRegistry.getProject(path);
final List<VirtualFileEntry> children = project.getBaseFolder().getChildren();
final List<Problem> problems = project.getProblems();
assertNotNull(project);
assertNotNull(pm.getProjectsRoot().getChild(path));
assertEquals(projectTypeId, project.getType());
assertTrue(children.isEmpty());
assertTrue(project.getAttributes().isEmpty());
assertFalse(problems.isEmpty());
assertEquals(1, problems.size());
assertEquals(13, problems.get(0).code);
}
@Test
public void testSamePathProjectCreateFailed() throws Exception {
// SPECS:
// If there is a project with the same path ConflictException will be thrown on create project
ProjectConfig pc = new NewProjectConfig("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null);
pm.createProject(pc, null);
pc = new NewProjectConfig("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null);
pc = new NewProjectConfigImpl("/testSamePathProjectCreateFailed", "blank", null, "name", "descr", null, null, null);
try {
pm.createProject(pc, null);
@ -171,94 +587,109 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
}
assertNotNull(projectRegistry.getProject("/testSamePathProjectCreateFailed"));
}
@Test
public void testInvalidPTProjectCreateFailed() throws Exception {
// SPECS:
// project will be created as project of "blank" type
// with problem code 12(Primary type "someType" is not registered. Base Project Type assigned.)
// when primary project type is not registered in PT registry
final String path = "/testInvalidPTProjectCreateFailed";
ProjectConfig pc = new NewProjectConfigImpl(path, "invalid", null, "name", "descr", null, null, null);
pm.createProject(pc, null);
RegisteredProject project = projectRegistry.getProject(path);
assertNotNull(project);
assertNotNull(pm.getProjectsRoot().getChild(path));
assertEquals(BaseProjectType.ID, project.getType());
List<Problem> problems = project.getProblems();
assertNotNull(problems);
assertFalse(problems.isEmpty());
assertEquals(1, problems.size());
assertEquals(12, problems.get(0).code);
//clean up
project.getBaseFolder().getVirtualFile().delete();
projectRegistry.removeProjects(path);
assertNull(projectRegistry.getProject(path));
// SPECS:
// If either primary or some mixin project type is not registered in PT registry
// project creation failed with NotFoundException
ProjectConfig pc = new NewProjectConfig("/testInvalidPTProjectCreateFailed", "invalid", null, "name", "descr", null, null);
try {
pm.createProject(pc, null);
fail("NotFoundException: Project Type not found: invalid");
} catch (ServerException e) {
}
assertNull(projectRegistry.getProject("/testInvalidPTProjectCreateFailed"));
assertNull(pm.getProjectsRoot().getChild("/testInvalidPTProjectCreateFailed"));
//assertNull(projectRegistry.folder("/testInvalidPTProjectCreateFailed"));
// check mixin as well
// project will be created without mixin project type and
// with problem code 12(Project type "someType" is not registered. Skipped.)
// when mixin project type is not registered in PT registry
List<String> ms = new ArrayList<>();
ms.add("invalid");
pc = new NewProjectConfig("/testInvalidPTProjectCreateFailed", "blank", ms, "name", "descr", null, null);
try {
pm.createProject(pc, null);
fail("NotFoundException: Project Type not found: invalid");
} catch (ServerException e) {
}
pc = new NewProjectConfigImpl(path, "blank", ms, "name", "descr", null, null, null);
pm.createProject(pc, null);
project = projectRegistry.getProject(path);
assertNotNull(project);
assertNotNull(pm.getProjectsRoot().getChild(path));
assertTrue(project.getMixins().isEmpty());
problems = project.getProblems();
assertNotNull(problems);
assertFalse(problems.isEmpty());
assertEquals(1, problems.size());
assertEquals(12, problems.get(0).code);
}
@Test
public void testConflictAttributesProjectCreateFailed() throws Exception {
// SPECS:
// If there are attributes with the same name in primary and mixin PT or between mixins
// Project creation failed with ProjectTypeConstraintException
// project will be created with problem code 13(Attribute name conflict)
// when there are attributes with the same name in primary and mixin PT or between mixins
final String path = "/testConflictAttributesProjectCreateFailed";
final String projectTypeId = "pt2";
final String mixin = "m2";
final List<String> ms = new ArrayList<>(1);
ms.add(mixin);
List<String> ms = new ArrayList<>();
ms.add("m2");
ProjectConfig pc = new NewProjectConfigImpl(path, projectTypeId, ms, "name", "descr", null, null, null);
pm.createProject(pc, null);
ProjectConfig pc = new NewProjectConfig("/testConflictAttributesProjectCreateFailed", "pt2", ms, "name", "descr", null, null);
try {
pm.createProject(pc, null);
fail("ProjectTypeConstraintException: Attribute name conflict. Duplicated attributes detected /testConflictAttributesProjectCreateFailed Attribute pt2-const1 declared in m2 already declared in pt2");
} catch (ServerException e) {
}
final RegisteredProject project = projectRegistry.getProject(path);
assertNotNull(project);
assertNotNull(pm.getProjectsRoot().getChild(path));
//assertNull(projectRegistry.folder("/testConflictAttributesProjectCreateFailed"));
assertNull(pm.getProjectsRoot().getChild("/testConflictAttributesProjectCreateFailed"));
final List<String> mixins = project.getMixins();
assertFalse(mixins.isEmpty());
assertEquals(mixin, mixins.get(0));
final List<Problem> problems = project.getProblems();
assertNotNull(problems);
assertFalse(problems.isEmpty());
assertEquals(13, problems.get(0).code);
}
@Test
public void testInvalidConfigProjectCreateFailed() throws Exception {
// SPECS:
// If project path is not defined
// Project creation failed with ConflictException
ProjectConfig pc = new NewProjectConfig(null, "pt2", null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl(null, "pt2", null, "name", "descr", null, null, null);
try {
pm.createProject(pc, null);
fail("ConflictException: Path for new project should be defined ");
} catch (ConflictException e) {
}
}
@Test
public void testCreateInnerProject() throws Exception {
ProjectConfig pc = new NewProjectConfig("/testCreateInnerProject", BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testCreateInnerProject", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
pc = new NewProjectConfig("/testCreateInnerProject/inner", BaseProjectType.ID, null, "name", "descr", null, null);
pc = new NewProjectConfigImpl("/testCreateInnerProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
assertNotNull(projectRegistry.getProject("/testCreateInnerProject/inner"));
@ -267,13 +698,12 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
// If there are no parent folder it will be created
pc = new NewProjectConfig("/nothing/inner", BaseProjectType.ID, null, "name", "descr", null, null);
pc = new NewProjectConfigImpl("/nothing/inner", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
assertNotNull(projectRegistry.getProject("/nothing/inner"));
assertNotNull(projectRegistry.getProject("/nothing"));
assertNotNull(pm.getProjectsRoot().getChildFolder("/nothing"));
}
@ -281,14 +711,14 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
public void testUpdateProjectWithPersistedAttributes() throws Exception {
Map<String, List<String>> attributes = new HashMap<>();
ProjectConfig pc = new NewProjectConfig("/testUpdateProject", BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", BaseProjectType.ID, null, "name", "descr", null, null, null);
RegisteredProject p = pm.createProject(pc, null);
assertEquals(BaseProjectType.ID, p.getType());
assertEquals("name", p.getName());
attributes.put("pt2-var2", new AttributeValue("updated").getList());
ProjectConfig pc1 = new NewProjectConfig("/testUpdateProject", "pt2", null, "updatedName", "descr", attributes, null);
ProjectConfig pc1 = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "updatedName", "descr", attributes, null, null);
p = pm.updateProject(pc1);
@ -301,38 +731,30 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
@Test
public void testUpdateProjectWithProvidedAttributes() throws Exception {
// SPECS: Project should be updated with problem code = 13 when value for required attribute is not initialized
Map<String, List<String>> attributes = new HashMap<>();
attributes.put("pt2-var2", new AttributeValue("test").getList());
ProjectConfig pc = new NewProjectConfig("/testUpdateProject", "pt2", null, "name", "descr", attributes, null);
RegisteredProject p = pm.createProject(pc, null);
ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProject", "pt2", null, "name", "descr", attributes, null, null);
pm.createProject(pc, null);
// SPECS:
// If project type is updated with one required provided attributes
// those attributes should be provided before update
pc = new NewProjectConfig("/testUpdateProject", "pt3", null, "updatedName", "descr", attributes, null);
try {
pm.updateProject(pc);
fail("ProjectTypeConstraintException: Value for required attribute is not initialized pt3:pt2-provided1 ");
} catch (ServerException e) {
}
pc = new NewProjectConfigImpl("/testUpdateProject", "pt3", null, "updatedName", "descr", attributes, null, null);
p.getBaseFolder().createFolder("file1");
p = pm.updateProject(pc);
assertEquals(new AttributeValue("pt2-provided1"), p.getAttributeEntries().get("pt2-provided1"));
RegisteredProject project = pm.updateProject(pc);
final List<Problem> problems = project.getProblems();
assertNotNull(problems);
assertFalse(problems.isEmpty());
assertEquals(1, problems.size());
assertEquals(13, problems.get(0).code);
}
@Test
public void testUpdateProjectOnRawFolder() throws Exception {
ProjectConfig pc = new NewProjectConfig("/testUpdateProjectOnRawFolder", BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testUpdateProjectOnRawFolder", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
String folderPath = "/testUpdateProjectOnRawFolder/folder";
pm.getProjectsRoot().createFolder(folderPath);
@ -340,18 +762,15 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
// SPECS:
// If update is called on raw folder new project should be created
pc = new NewProjectConfig(folderPath, BaseProjectType.ID, null, "raw", "descr", null, null);
pc = new NewProjectConfigImpl(folderPath, BaseProjectType.ID, null, "raw", "descr", null, null, null);
pm.updateProject(pc);
assertEquals(BaseProjectType.ID, pm.getProject(folderPath).getType());
}
@Test
public void testInvalidUpdateConfig() throws Exception {
ProjectConfig pc = new NewProjectConfig(null, BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl(null, BaseProjectType.ID, null, "name", "descr", null, null, null);
try {
pm.updateProject(pc);
@ -359,7 +778,7 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
} catch (ConflictException e) {
}
pc = new NewProjectConfig("/nothing", BaseProjectType.ID, null, "name", "descr", null, null);
pc = new NewProjectConfigImpl("/nothing", BaseProjectType.ID, null, "name", "descr", null, null, null);
try {
pm.updateProject(pc);
fail("NotFoundException: Project '/nothing' doesn't exist.");
@ -371,9 +790,9 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
@Test
public void testDeleteProject() throws Exception {
ProjectConfig pc = new NewProjectConfig("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
pc = new NewProjectConfig("/testDeleteProject/inner", BaseProjectType.ID, null, "name", "descr", null, null);
pc = new NewProjectConfigImpl("/testDeleteProject/inner", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
assertNotNull(projectRegistry.getProject("/testDeleteProject/inner"));
@ -384,13 +803,11 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
assertNull(projectRegistry.getProject("/testDeleteProject"));
assertNull(pm.getProjectsRoot().getChild("/testDeleteProject/inner"));
//assertNull(projectRegistry.folder("/testDeleteProject/inner"));
}
@Test
public void testDeleteProjectEvent() throws Exception {
ProjectConfig pc = new NewProjectConfig("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null);
ProjectConfig pc = new NewProjectConfigImpl("/testDeleteProject", BaseProjectType.ID, null, "name", "descr", null, null, null);
pm.createProject(pc, null);
String[] deletedPath = new String[1];
@ -401,13 +818,11 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
pm.delete("/testDeleteProject");
assertEquals("/testDeleteProject", deletedPath[0]);
}
@Test
public void testImportProject() throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
String fileContent = "to be or not to be";
ZipOutputStream zipOut = new ZipOutputStream(bout);
@ -433,7 +848,6 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
assertNotNull(project.getBaseFolder().getChild("file1"));
assertEquals(fileContent, project.getBaseFolder().getChild("file1").getVirtualFile().getContentAsString());
}
@Test
@ -467,11 +881,11 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
@Test
public void testProvidedAttributesNotSerialized() throws Exception {
Map<String, List<String>> attributes = new HashMap<>();
attributes.put("pt2-var2", new AttributeValue("test2").getList());
attributes.put("pt2-var1", new AttributeValue("test1").getList());
ProjectConfig pc = new NewProjectConfig("/testProvidedAttributesNotSerialized", "pt3", null, "name", "descr", attributes, null);
ProjectConfig pc =
new NewProjectConfigImpl("/testProvidedAttributesNotSerialized", "pt3", null, "name", "descr", attributes, null, null);
pm.createProject(pc, null);
@ -493,10 +907,9 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
@Test
public void testSettableValueProvider() throws Exception {
assertTrue(((Variable)projectTypeRegistry.getProjectType("settableVPPT").getAttribute("my")).isValueProvided());
ProjectConfig pc = new NewProjectConfig("/testSettableValueProvider", "settableVPPT", null, "", "", new HashMap<>(), null);
ProjectConfig pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", new HashMap<>(), null, null);
pm.createProject(pc, null);
@ -507,18 +920,64 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
Map<String, List<String>> attributes = new HashMap<>();
attributes.put("my", new AttributeValue("set").getList());
pc = new NewProjectConfig("/testSettableValueProvider", "settableVPPT", null, "", "", attributes, null);
pc = new NewProjectConfigImpl("/testSettableValueProvider", "settableVPPT", null, "", "", attributes, null, null);
pm.updateProject(pc);
project = pm.getProject("/testSettableValueProvider");
assertEquals("set", project.getAttributes().get("my").get(0));
}
/* ---------------------------------- */
/* private */
/* ---------------------------------- */
private void checkProjectExist(String projectPath) {
RegisteredProject project = projectRegistry.getProject(projectPath);
FolderEntry projectFolder = project.getBaseFolder();
assertNotNull(project);
assertTrue(projectFolder.getVirtualFile().exists());
assertEquals(projectPath, project.getPath());
assertEquals(BaseProjectType.ID, project.getType());
}
private void checkChildrenFor(FolderEntry projectFolder, List<String> children) throws ServerException, ForbiddenException {
for (String path : children) {
assertNotNull(projectFolder.getChild(path));
if (path.contains("file")) {
String fileContent = projectFolder.getChild(path).getVirtualFile().getContentAsString();
assertEquals(FILE_CONTENT, fileContent);
}
}
}
private InputStream prepareZipArchiveBasedOn(List<String> paths) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(bout);
for (String path : paths) {
zipOut.putNextEntry(new ZipEntry(path));
if (path.contains("file")) {
zipOut.write(FILE_CONTENT.getBytes());
}
}
zipOut.close();
return new ByteArrayInputStream(bout.toByteArray());
}
private NewProjectConfigDto createProjectConfigObject(String projectName,
String projectPath,
String projectType,
SourceStorageDto sourceStorage) {
return DtoFactory.newDto(NewProjectConfigDto.class)
.withPath(projectPath)
.withName(projectName)
.withType(projectType)
.withDescription("description")
.withSource(sourceStorage)
.withAttributes(new HashMap<>());
}
private void registerImporter(String importType, InputStream zip) throws Exception {
final ValueHolder<FolderEntry> folderHolder = new ValueHolder<>();
importerRegistry.register(new ProjectImporter() {
@ -570,7 +1029,6 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
throws ForbiddenException, ConflictException, ServerException {
FolderEntry baseFolder = new FolderEntry(vfsProvider.getVirtualFileSystem().getRoot().createFolder(projectPath.toString()));
baseFolder.createFolder("file1");
}
@Override
@ -578,5 +1036,4 @@ public class ProjectManagerWriteTest extends WsAgentTestBase {
return "pt3";
}
}
}

View File

@ -10,6 +10,8 @@
*******************************************************************************/
package org.eclipse.che.api.project.server;
import com.google.common.io.ByteStreams;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
@ -29,6 +31,7 @@ import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry;
import org.eclipse.che.api.project.server.importer.ProjectImporter;
import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry;
import org.eclipse.che.api.project.server.type.AttributeValue;
import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.project.server.type.ReadonlyValueProvider;
@ -52,7 +55,6 @@ import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
import org.eclipse.che.commons.json.JsonHelper;
import org.eclipse.che.commons.lang.IoUtil;
import org.eclipse.che.commons.lang.ws.rs.ExtMediaType;
import org.eclipse.che.commons.subject.SubjectImpl;
@ -81,6 +83,7 @@ import javax.ws.rs.core.Application;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.Charset;
@ -106,6 +109,7 @@ import java.util.stream.IntStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static javax.ws.rs.HttpMethod.DELETE;
import static javax.ws.rs.HttpMethod.GET;
@ -115,6 +119,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static org.eclipse.che.commons.lang.ws.rs.ExtMediaType.APPLICATION_ZIP;
import static org.everrest.core.ApplicationContext.anApplicationContext;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
@ -414,24 +419,9 @@ public class ProjectServiceTest {
@Test
public void testCreateProject() throws Exception {
phRegistry.register(new CreateProjectHandler() {
@Override
public void onCreateProject(Path projectPath, Map<String, AttributeValue> attributes, Map<String, String> options)
throws ForbiddenException, ConflictException, ServerException {
FolderEntry projectFolder = new FolderEntry(vfsProvider.getVirtualFileSystem().getRoot().createFolder("new_project"));
projectFolder.createFolder("a");
projectFolder.createFolder("b");
projectFolder.createFile("test.txt", "test".getBytes(Charset.defaultCharset()));
}
@Override
public String getProjectType() {
return "testCreateProject";
}
});
final String projectName = "new_project";
final String projectType = "testCreateProject";
phRegistry.register(createProjectHandlerFor(projectName, projectType));
Map<String, List<String>> headers = new HashMap<>();
headers.put("Content-Type", singletonList(APPLICATION_JSON));
@ -450,9 +440,9 @@ public class ProjectServiceTest {
final ProjectConfigDto newProjectConfig = DtoFactory.getInstance().createDto(ProjectConfigDto.class)
.withPath("/new_project")
.withName("new_project")
.withName(projectName)
.withDescription("new project")
.withType("testCreateProject")
.withType(projectType)
.withAttributes(attributeValues)
.withSource(DtoFactory.getInstance().createDto(SourceStorageDto.class));
projects.add(newProjectConfig);
@ -467,11 +457,11 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
ProjectConfigDto result = (ProjectConfigDto)response.getEntity();
assertNotNull(result);
assertEquals(result.getName(), "new_project");
assertEquals(result.getName(), projectName);
assertEquals(result.getPath(), "/new_project");
assertEquals(result.getDescription(), newProjectConfig.getDescription());
assertEquals(result.getType(), newProjectConfig.getType());
assertEquals(result.getType(), "testCreateProject");
assertEquals(result.getType(), projectType);
Map<String, List<String>> attributes = result.getAttributes();
assertNotNull(attributes);
assertEquals(attributes.size(), 1);
@ -492,11 +482,63 @@ public class ProjectServiceTest {
assertNotNull(project.getBaseFolder().getChild("a"));
assertNotNull(project.getBaseFolder().getChild("b"));
assertNotNull(project.getBaseFolder().getChild("test.txt"));
}
@Test
public void testCreateBatchProjects() throws Exception {
//prepare first project
final String projectName1 = "testProject1";
final String projectTypeId1 = "testProjectType1";
final String projectPath1 = "/testProject1";
createTestProjectType(projectTypeId1);
phRegistry.register(createProjectHandlerFor(projectName1, projectTypeId1));
//prepare inner project
final String innerProjectName = "innerProject";
final String innerProjectTypeId = "testProjectType2";
final String innerProjectPath = "/testProject1/innerProject";
createTestProjectType(innerProjectTypeId);
phRegistry.register(createProjectHandlerFor(innerProjectName, innerProjectTypeId));
//prepare project to import
final String importProjectName = "testImportProject";
final String importProjectTypeId = "testImportProjectType";
final String importProjectPath = "/testImportProject";
final String importType = "importType";
final String [] paths = {"a", "b", "test.txt"};
final List<String> children = new ArrayList<>(Arrays.asList(paths));
registerImporter(importType, prepareZipArchiveBasedOn(children));
createTestProjectType(importProjectTypeId);
Map<String, List<String>> headers = new HashMap<>();
headers.put("Content-Type", singletonList(APPLICATION_JSON));
try (InputStream content = getClass().getResourceAsStream("batchNewProjectConfigs.json")) {
ContainerResponse response = launcher.service(POST,
"http://localhost:8080/api/project/batch",
"http://localhost:8080/api",
headers,
ByteStreams.toByteArray(content), null);
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
final List<ProjectConfigDto> result = (List<ProjectConfigDto>)response.getEntity();
assertNotNull(result);
assertEquals(result.size(), 3);
final ProjectConfigDto importProjectConfig = result.get(0);
checkProjectIsCreated(importProjectName, importProjectPath, importProjectTypeId, importProjectConfig);
final ProjectConfigDto config1 = result.get(1);
checkProjectIsCreated(projectName1, projectPath1, projectTypeId1, config1);
final ProjectConfigDto innerProjectConfig = result.get(2);
checkProjectIsCreated(innerProjectName, innerProjectPath, innerProjectTypeId, innerProjectConfig);
}
}
@Test
public void testUpdateProject() throws Exception {
@ -636,10 +678,9 @@ public class ProjectServiceTest {
ptRegistry.registerProjectType(pt);
ContainerResponse response =
launcher.service(GET, String.format("http://localhost:8080/api/project/estimate/%s?type=%s",
"testEstimateProjectGood", "testEstimateProjectPT"),
"http://localhost:8080/api", null, null, null);
ContainerResponse response = launcher.service(GET, format("http://localhost:8080/api/project/estimate/%s?type=%s",
"testEstimateProjectGood", "testEstimateProjectPT"),
"http://localhost:8080/api", null, null, null);
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
//noinspection unchecked
SourceEstimation result = (SourceEstimation)response.getEntity();
@ -648,14 +689,15 @@ public class ProjectServiceTest {
assertEquals(result.getAttributes().get("calculated_attribute").get(0), "checked");
// if project not matched
response = launcher.service(GET, String.format("http://localhost:8080/api/project/estimate/%s?type=%s",
"testEstimateProjectBad", "testEstimateProjectPT"),
response = launcher.service(GET, format("http://localhost:8080/api/project/estimate/%s?type=%s",
"testEstimateProjectBad", "testEstimateProjectPT"),
"http://localhost:8080/api", null, null, null);
assertEquals(response.getStatus(), 409, "Error: " + response.getEntity());
String msg = JsonHelper.parseJson(response.getEntity().toString()).getElement("message").getStringValue();
assertEquals(errMessage, msg);
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
//noinspection unchecked
result = (SourceEstimation)response.getEntity();
assertFalse(result.isMatched());
assertEquals(result.getAttributes().size(), 0);
}
@ -697,8 +739,8 @@ public class ProjectServiceTest {
ptRegistry.registerProjectType(pt);
ContainerResponse response =
launcher.service(GET, String.format("http://localhost:8080/api/project/resolve/%s",
"testEstimateProjectGood"),
launcher.service(GET, format("http://localhost:8080/api/project/resolve/%s",
"testEstimateProjectGood"),
"http://localhost:8080/api", null, null, null);
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
List<SourceEstimation> result = (List<SourceEstimation>) response.getEntity();
@ -746,7 +788,7 @@ public class ProjectServiceTest {
" \"type\": \"%s\"\n" +
"}";
byte[] b = String.format(json, importType).getBytes(Charset.defaultCharset());
byte[] b = format(json, importType).getBytes(Charset.defaultCharset());
ContainerResponse response = launcher.service(POST,
"http://localhost:8080/api/project/import/new_project",
"http://localhost:8080/api", headers, b, null);
@ -878,7 +920,7 @@ public class ProjectServiceTest {
public void testCreateFolderInRoot() throws Exception {
String folder = "my_folder";
ContainerResponse response = launcher.service(POST,
String.format("http://localhost:8080/api/project/folder/%s", folder),
format("http://localhost:8080/api/project/folder/%s", folder),
"http://localhost:8080/api", null, null, null);
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
ItemReference fileItem = (ItemReference)response.getEntity();
@ -887,7 +929,7 @@ public class ProjectServiceTest {
assertEquals(fileItem.getPath(), "/" + folder);
validateFolderLinks(fileItem);
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(String.format("http://localhost:8080/api/project/children/%s", folder)));
URI.create(format("http://localhost:8080/api/project/children/%s", folder)));
}
@Test
@ -1052,7 +1094,8 @@ public class ProjectServiceTest {
String overwrittenContent = "that is the question";
((FolderEntry)myProject.getBaseFolder().getChild("a/b")).createFile(originFileName, originContent.getBytes(Charset.defaultCharset()));
((FolderEntry)myProject.getBaseFolder().getChild("a/b/c")).createFile(destinationFileName, overwrittenContent.getBytes(Charset.defaultCharset()));
((FolderEntry)myProject.getBaseFolder().getChild("a/b/c")).createFile(destinationFileName,
overwrittenContent.getBytes(Charset.defaultCharset()));
Map<String, List<String>> headers = new HashMap<>();
headers.put(CONTENT_TYPE, singletonList(APPLICATION_JSON));
@ -1127,9 +1170,9 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild("a/b/test.txt"));
assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder)));
}
@Test
@ -1165,11 +1208,11 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild("a/b/test.txt"));
assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder)));
assertEquals(myProject.getBaseFolder().getChild("a/b/test.txt").getName(),
myProject.getBaseFolder().getChild(String.format("a/b/c/%s/%s", renamedFolder, originFileName)).getName());
myProject.getBaseFolder().getChild(format("a/b/c/%s/%s", renamedFolder, originFileName)).getName());
}
@Test
@ -1210,8 +1253,8 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/file/my_project/a/b/c/%s", destinationName)));
VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(String.format("a/b/c/%s", destinationName));
format("http://localhost:8080/api/project/file/my_project/a/b/c/%s", destinationName)));
VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(format("a/b/c/%s", destinationName));
assertNotNull(theTargetFile); // new
}
@ -1238,8 +1281,8 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/file/my_project/a/b/%s", destinationName)));
VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(String.format("a/b/%s", destinationName));
format("http://localhost:8080/api/project/file/my_project/a/b/%s", destinationName)));
VirtualFileEntry theTargetFile = myProject.getBaseFolder().getChild(format("a/b/%s", destinationName));
assertNotNull(theTargetFile); // new
}
@ -1333,8 +1376,8 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder)));
format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder)));
}
@Test
@ -1360,8 +1403,8 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/children/my_project/a/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(String.format("a/%s/test.txt", renamedFolder)));
format("http://localhost:8080/api/project/children/my_project/a/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(format("a/%s/test.txt", renamedFolder)));
}
@Test
@ -1397,8 +1440,8 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
URI.create(
String.format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(String.format("a/b/c/%s/test.txt", renamedFolder)));
format("http://localhost:8080/api/project/children/my_project/a/b/c/%s", renamedFolder)));
assertNotNull(myProject.getBaseFolder().getChild(format("a/b/c/%s/test.txt", renamedFolder)));
}
@Test
@ -1416,7 +1459,7 @@ public class ProjectServiceTest {
Map<String, List<String>> headers = new HashMap<>();
headers.put(CONTENT_TYPE, singletonList(ExtMediaType.APPLICATION_ZIP));
ContainerResponse response = launcher.service(POST,
String.format("http://localhost:8080/api/project/import/my_project/a/b"),
format("http://localhost:8080/api/project/import/my_project/a/b"),
"http://localhost:8080/api", headers, zip, null);
assertEquals(response.getStatus(), 201, "Error: " + response.getEntity());
assertEquals(response.getHttpHeaders().getFirst("Location"),
@ -1520,8 +1563,8 @@ public class ProjectServiceTest {
@Test
public void testGetMissingItem() throws Exception {
ContainerResponse response = launcher.service(GET,
"http://localhost:8080/api/project/item/some_missing_project/a/b",
"http://localhost:8080/api", null, null, null);
"http://localhost:8080/api/project/item/some_missing_project/a/b",
"http://localhost:8080/api", null, null, null);
assertEquals(response.getStatus(), 404, "Error: " + response.getEntity());
}
@ -1731,8 +1774,10 @@ public class ProjectServiceTest {
"to" + URL_ENCODED_SPACE +
"be" + URL_ENCODED_QUOTES;
RegisteredProject myProject = pm.getProject("my_project");
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("a/b").createFile("test.txt", "Pay attention! To be or to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(
Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("a/b").createFile("test.txt", "Pay attention! To be or to be that is the question".getBytes(
Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("c").createFile("_test", "Pay attention! To be or to not be that is the question".getBytes(Charset.defaultCharset()));
ContainerResponse response =
@ -1755,11 +1800,14 @@ public class ProjectServiceTest {
"the" + URL_ENCODED_QUOTES + URL_ENCODED_SPACE + AND_OPERATOR + URL_ENCODED_SPACE +
"question" + URL_ENCODED_ASTERISK;
RegisteredProject myProject = pm.getProject("my_project");
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(
Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("a/b")
.createFile("containsSearchTextAlso.txt", "Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset()));
.createFile("containsSearchTextAlso.txt",
"Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("c")
.createFile("notContainsSearchText", "Pay attention! To be or to not be that is the questEon".getBytes(Charset.defaultCharset()));
.createFile("notContainsSearchText",
"Pay attention! To be or to not be that is the questEon".getBytes(Charset.defaultCharset()));
ContainerResponse response =
launcher.service(GET,"http://localhost:8080/api/project/search/my_project" + queryToSearch,
@ -1780,7 +1828,8 @@ public class ProjectServiceTest {
String queryToSearch = "?text=" +
"question" + URL_ENCODED_ASTERISK;
RegisteredProject myProject = pm.getProject("my_project");
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(
Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("a/b")
.createFile("containsSearchTextAlso.txt", "Pay attention! To be or not to be that is the questionS".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("c")
@ -1806,10 +1855,12 @@ public class ProjectServiceTest {
"question" + URL_ENCODED_SPACE + NOT_OPERATOR + URL_ENCODED_SPACE + URL_ENCODED_QUOTES +
"attention!" + URL_ENCODED_QUOTES;
RegisteredProject myProject = pm.getProject("my_project");
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("x/y").createFile("containsSearchText.txt", "To be or not to be that is the question".getBytes(
Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("b")
.createFile("notContainsSearchText", "Pay attention! To be or not to be that is the question".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("c").createFile("alsoNotContainsSearchText", "To be or to not be that is the ...".getBytes(Charset.defaultCharset()));
myProject.getBaseFolder().createFolder("c").createFile("alsoNotContainsSearchText",
"To be or to not be that is the ...".getBytes(Charset.defaultCharset()));
ContainerResponse response =
launcher.service(GET, "http://localhost:8080/api/project/search/my_project" + queryToSearch,
@ -1838,7 +1889,8 @@ public class ProjectServiceTest {
URL_ENCODED_BACKSLASH + ':' + "projectName=test";
RegisteredProject myProject = pm.getProject("my_project");
myProject.getBaseFolder().createFolder("x/y")
.createFile("test.txt", "http://localhost:8080/ide/dev6?action=createProject:projectName=test".getBytes(Charset.defaultCharset()));
.createFile("test.txt",
"http://localhost:8080/ide/dev6?action=createProject:projectName=test".getBytes(Charset.defaultCharset()));
ContainerResponse response = launcher.service(GET, "http://localhost:8080/api/project/search/my_project" + queryToSearch,
"http://localhost:8080/api", null, null, null);
@ -1864,11 +1916,11 @@ public class ProjectServiceTest {
assertEquals(response.getStatus(), 200, "Error: " + response.getEntity());
List<ItemReference> result = (List<ItemReference>)response.getEntity();
assertEquals(result.size(), 2);
assertEqualsNoOrder(new Object[] {
assertEqualsNoOrder(new Object[]{
result.get(0).getPath(),
result.get(1).getPath()
},
new Object[] {
new Object[]{
"/my_project/a/b/test.txt",
"/my_project/x/y/test.txt"
});
@ -1895,12 +1947,12 @@ public class ProjectServiceTest {
Link link = item.getLink("delete");
assertNotNull(link);
assertEquals(link.getMethod(), DELETE);
assertEquals(link.getHref(), "http://localhost:8080/api/project" + item.getPath());
assertEquals(link.getHref(), "http://localhost:8080/api/project" + item.getPath());
link = item.getLink("update content");
assertNotNull(link);
assertEquals(link.getMethod(), PUT);
assertEquals(link.getConsumes(), "*/*");
assertEquals(link.getHref(), "http://localhost:8080/api/project" + "/file" + item.getPath());
assertEquals(link.getHref(), "http://localhost:8080/api/project" + "/file" + item.getPath());
}
private void validateFolderLinks(ItemReference item) {
@ -1974,6 +2026,77 @@ public class ProjectServiceTest {
}
}
private InputStream prepareZipArchiveBasedOn(List<String> paths) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(bout);
for (String path : paths) {
zipOut.putNextEntry(new ZipEntry(path));
}
zipOut.close();
return new ByteArrayInputStream(bout.toByteArray());
}
private void checkProjectIsCreated(String expectedName, String expectedPath, String expectedType, ProjectConfigDto actualConfig)
throws ServerException, NotFoundException {
final String projectDescription = "someDescription";
assertEquals(actualConfig.getName(), expectedName);
assertEquals(actualConfig.getPath(), expectedPath);
assertEquals(actualConfig.getDescription(), projectDescription);
assertEquals(actualConfig.getType(), expectedType);
final String expectedAttribute = "new_test_attribute";
final String expectedAttributeValue = "some_attribute_value";
final Map<String, List<String>> attributes = actualConfig.getAttributes();
assertNotNull(attributes);
assertEquals(attributes.size(), 1);
assertEquals(attributes.get(expectedAttribute), singletonList(expectedAttributeValue));
validateProjectLinks(actualConfig);
RegisteredProject project = pm.getProject(expectedPath);
assertNotNull(project);
assertEquals(project.getDescription(), projectDescription);
assertEquals(project.getProjectType().getId(), expectedType);
String attributeVal = project.getAttributeEntries().get(expectedAttribute).getString();
assertNotNull(attributeVal);
assertEquals(attributeVal, expectedAttributeValue);
assertNotNull(project.getBaseFolder().getChild("a"));
assertNotNull(project.getBaseFolder().getChild("b"));
assertNotNull(project.getBaseFolder().getChild("test.txt"));
}
private void createTestProjectType(final String projectTypeId) throws ProjectTypeConstraintException {
final ProjectTypeDef pt = new ProjectTypeDef(projectTypeId, "my project type", true, false) {
{
addConstantDefinition("new_test_attribute", "attr description", "some_attribute_value");
}
};
ptRegistry.registerProjectType(pt);
}
private CreateProjectHandler createProjectHandlerFor(final String projectName, final String projectTypeId) {
return new CreateProjectHandler() {
@Override
public void onCreateProject(Path projectPath, Map<String, AttributeValue> attributes, Map<String, String> options)
throws ForbiddenException, ConflictException, ServerException {
final String pathToProject = projectPath.toString();
final String pathToParent = pathToProject.substring(0, pathToProject.lastIndexOf("/"));
final FolderEntry projectFolder = new FolderEntry(
vfsProvider.getVirtualFileSystem().getRoot().getChild(Path.of(pathToParent)).createFolder(projectName));
projectFolder.createFolder("a");
projectFolder.createFolder("b");
projectFolder.createFile("test.txt", "test".getBytes(Charset.defaultCharset()));
}
@Override
public String getProjectType() {
return projectTypeId;
}
};
}
private class LocalProjectType extends ProjectTypeDef {
private LocalProjectType(String typeId, String typeName) {
super(typeId, typeName, true, false);

View File

@ -10,15 +10,11 @@
*******************************************************************************/
package org.eclipse.che.api.project.server;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.project.server.handlers.CreateProjectHandler;
import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry;
import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry;
import org.eclipse.che.api.project.server.type.AttributeValue;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ProjectTypeRegistry;
import org.eclipse.che.api.project.server.type.ReadonlyValueProvider;
@ -26,7 +22,6 @@ import org.eclipse.che.api.project.server.type.SettableValueProvider;
import org.eclipse.che.api.project.server.type.ValueProvider;
import org.eclipse.che.api.project.server.type.ValueProviderFactory;
import org.eclipse.che.api.project.server.type.ValueStorageException;
import org.eclipse.che.api.vfs.Path;
import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler;
import org.eclipse.che.api.vfs.impl.file.FileTreeWatcher;
import org.eclipse.che.api.vfs.impl.file.FileWatcherNotificationHandler;

View File

@ -0,0 +1,68 @@
[
{
"name": "innerProject",
"displayName": "innerProject",
"path": "/testProject1/innerProject",
"description": "someDescription",
"type": "testProjectType2",
"mixins": [],
"attributes": {
"new_test_attribute": [
"some_attribute_value"
]
},
"modules": [],
"problems": [],
"source": {
"type": "",
"location": "",
"parameters": {}
},
"commands": [],
"links": []
},
{
"name": "testProject1",
"displayName": "testProject1",
"path": "/testProject1",
"description": "someDescription",
"type": "testProjectType1",
"mixins": [],
"attributes": {
"new_test_attribute": [
"some_attribute_value"
]
},
"modules": [],
"problems": [],
"source": {
"type": "",
"location": "",
"parameters": {}
},
"commands": [],
"links": []
},
{
"name": "testImportProject",
"displayName": "testImportProject",
"path": "/testImportProject",
"description": "someDescription",
"type": "testImportProjectType",
"mixins": [],
"attributes": {
"new_test_attribute": [
"some_attribute_value"
]
},
"modules": [],
"problems": [],
"source": {
"type": "importType",
"location": "someLocation",
"parameters": {}
},
"commands": [],
"links": []
}
]

View File

@ -12,7 +12,7 @@ package org.eclipse.che.api.project.templates.shared.dto;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.NewProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectProblemDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.dto.shared.DTO;
@ -110,4 +110,16 @@ public interface ProjectTemplateDescriptor {
void setTags(List<String> tags);
ProjectTemplateDescriptor withTags(List<String> tags);
List<NewProjectConfigDto> getProjects();
void setProjects(List<NewProjectConfigDto> projects);
ProjectTemplateDescriptor withProjects(List<NewProjectConfigDto> projects);
Map<String, String> getOptions();
void setOptions(Map<String, String> options);
ProjectTemplateDescriptor withOptions(Map<String, String> options);
}

View File

@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.workspace.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.project.NewProjectConfig;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
import java.util.Map;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
/**
* Data transfer object (DTO) for creating of project.
*
* @author Roman Nikitenko
*/
@DTO
public interface NewProjectConfigDto extends ProjectConfigDto, NewProjectConfig {
@Override
@FactoryParameter(obligation = OPTIONAL)
String getName();
@Override
@FactoryParameter(obligation = OPTIONAL)
String getType();
@Override
@FactoryParameter(obligation = OPTIONAL)
SourceStorageDto getSource();
@Override
@FactoryParameter(obligation = OPTIONAL)
Map<String, String> getOptions();
NewProjectConfigDto withName(String name);
NewProjectConfigDto withPath(String path);
NewProjectConfigDto withDescription(String description);
NewProjectConfigDto withType(String type);
NewProjectConfigDto withMixins(List<String> mixins);
NewProjectConfigDto withAttributes(Map<String, List<String>> attributes);
NewProjectConfigDto withSource(SourceStorageDto source);
NewProjectConfigDto withLinks(List<Link> links);
NewProjectConfigDto withProblems(List<ProjectProblemDto> problems);
NewProjectConfigDto withOptions(Map<String, String> options);
}