\n"
- + "
benoitf\n"
- + " merged 1 commit into\n"
+ + "
mshaposhnik\n"
+ + " wants to merge 1 commit into\n"
+ "\n"
+ "\n"
+ "\n"
- + "
master\n"
+ + "
master\n"
+ "\n"
+ "from\n"
+ "\n"
diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrlTest.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrlTest.java
index b6e0f11635..bc0189583c 100644
--- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrlTest.java
+++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrlTest.java
@@ -29,7 +29,7 @@ import org.testng.annotations.Test;
public class GithubUrlTest {
/** Parser used to create the url. */
- @InjectMocks private GithubURLParserImpl githubUrlParser;
+ @InjectMocks private GithubURLParser githubUrlParser;
/** Instance of the url created */
private GithubUrl githubUrl;
@@ -41,19 +41,19 @@ public class GithubUrlTest {
assertNotNull(this.githubUrl);
}
- /** Check when there is .codenvy.dockerfile in the repository */
+ /** Check when there is .devfile in the repository */
@Test
- public void checkDockerfileLocation() {
+ public void checkDevfileLocation() {
assertEquals(
- githubUrl.dockerFileLocation(),
- "https://raw.githubusercontent.com/eclipse/che/master/.factory.dockerfile");
+ githubUrl.devfileFileLocation(),
+ "https://raw.githubusercontent.com/eclipse/che/master/.devfile");
}
- /** Check when there is .codenvy.json file in the repository */
+ /** Check when there is .factory.json file in the repository */
@Test
- public void checkCodenvyFactoryJsonFileLocation() {
+ public void checkFactoryJsonFileLocation() {
assertEquals(
- githubUrl.factoryJsonFileLocation(),
+ githubUrl.factoryFileLocation(),
"https://raw.githubusercontent.com/eclipse/che/master/.factory.json");
}
diff --git a/plugins/plugin-urlfactory/pom.xml b/plugins/plugin-urlfactory/pom.xml
deleted file mode 100644
index a3eb3240df..0000000000
--- a/plugins/plugin-urlfactory/pom.xml
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
-
- 4.0.0
-
- che-plugin-parent
- org.eclipse.che.plugin
- 6.17.0-SNAPSHOT
- ../pom.xml
-
- che-plugin-url-factory
- jar
- Che Plugin :: URL Factory
-
- true
-
-
-
- com.google.guava
- guava
-
-
- javax.inject
- javax.inject
-
-
- javax.validation
- validation-api
-
-
- org.apache.commons
- commons-compress
-
-
- org.eclipse.che.core
- che-core-api-dto
-
-
- org.eclipse.che.core
- che-core-api-factory-shared
-
-
- org.eclipse.che.core
- che-core-api-model
-
-
- org.eclipse.che.core
- che-core-api-workspace-shared
-
-
- org.slf4j
- slf4j-api
-
-
- javax.servlet
- javax.servlet-api
- provided
-
-
- javax.ws.rs
- javax.ws.rs-api
- provided
-
-
- ch.qos.logback
- logback-classic
- test
-
-
- com.jayway.restassured
- rest-assured
- test
-
-
- org.eclipse.che.core
- che-core-commons-json
- test
-
-
- org.eclipse.jetty
- jetty-http
- test
-
-
- org.eclipse.jetty
- jetty-server
- test
-
-
- org.eclipse.jetty
- jetty-servlet
- test
-
-
- org.everrest
- everrest-assured
- test
-
-
- org.everrest
- everrest-core
- test
-
-
- org.hamcrest
- hamcrest-core
- test
-
-
- org.hamcrest
- hamcrest-library
- test
-
-
- org.mockito
- mockito-core
- test
-
-
- org.mockito
- mockito-testng
- test
-
-
- org.slf4j
- jcl-over-slf4j
- test
-
-
- org.testng
- testng
- test
-
-
-
diff --git a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilder.java b/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilder.java
deleted file mode 100644
index 652995cf74..0000000000
--- a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilder.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2012-2018 Red Hat, Inc.
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * Red Hat, Inc. - initial API and implementation
- */
-package org.eclipse.che.plugin.urlfactory;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Collections.singletonMap;
-import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE;
-import static org.eclipse.che.dto.server.DtoFactory.newDto;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.CharStreams;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import org.eclipse.che.api.factory.shared.dto.FactoryDto;
-import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
-import org.eclipse.che.api.workspace.shared.dto.MachineConfigDto;
-import org.eclipse.che.api.workspace.shared.dto.RecipeDto;
-import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
-import org.eclipse.che.dto.server.DtoFactory;
-
-/**
- * Handle the creation of some elements used inside a {@link FactoryDto}.
- *
- * @author Florent Benoit
- */
-@Singleton
-public class URLFactoryBuilder {
-
- /** Default docker image (if repository has no dockerfile) */
- protected static final String DEFAULT_DOCKER_IMAGE = "eclipse/ubuntu_jdk8";
-
- /** Default docker type (if repository has no dockerfile) */
- protected static final String DEFAULT_MEMORY_LIMIT_BYTES = Long.toString(2000L * 1024L * 1024L);
-
- protected static final String MACHINE_NAME = "ws-machine";
-
- private final URLChecker urlChecker;
- private final URLFetcher urlFetcher;
-
- @Inject
- public URLFactoryBuilder(URLChecker urlChecker, URLFetcher urlFetcher) {
- this.urlChecker = urlChecker;
- this.urlFetcher = urlFetcher;
- }
-
- /**
- * Build a default factory using the provided json file or create default one
- *
- * @param jsonFileLocation location of factory json file
- * @return a factory
- */
- public FactoryDto createFactory(String jsonFileLocation) {
-
- // Check if there is factory json file inside the repository
- if (jsonFileLocation != null) {
- String factoryJsonContent = urlFetcher.fetch(jsonFileLocation);
- if (!Strings.isNullOrEmpty(factoryJsonContent)) {
- // Adapt an old factory format to a new one if necessary
- try {
- final ByteArrayInputStream contentStream =
- new ByteArrayInputStream(factoryJsonContent.getBytes(UTF_8));
- factoryJsonContent = CharStreams.toString(new InputStreamReader(contentStream, UTF_8));
- } catch (IOException x) {
- throw new IllegalStateException(x.getLocalizedMessage(), x);
- }
- return DtoFactory.getInstance().createDtoFromJson(factoryJsonContent, FactoryDto.class);
- }
- }
-
- // else return a default factory
- return newDto(FactoryDto.class).withV("4.0");
- }
-
- /**
- * Help to generate default workspace configuration
- *
- * @param environmentName the name of the environment to create
- * @param name the name of the workspace
- * @param dockerFileLocation the optional location for codenvy dockerfile to use
- * @return a workspace configuration
- */
- public WorkspaceConfigDto buildWorkspaceConfig(
- String environmentName, String name, String dockerFileLocation) {
-
- // if remote repository contains a codenvy docker file, use it
- // else use the default image.
- RecipeDto recipeDto;
- if (dockerFileLocation != null && urlChecker.exists(dockerFileLocation)) {
- recipeDto =
- newDto(RecipeDto.class)
- .withLocation(dockerFileLocation)
- .withType("dockerfile")
- .withContentType("text/x-dockerfile");
- } else {
- recipeDto = newDto(RecipeDto.class).withContent(DEFAULT_DOCKER_IMAGE).withType("dockerimage");
- }
- MachineConfigDto machine =
- newDto(MachineConfigDto.class)
- .withInstallers(
- ImmutableList.of(
- "org.eclipse.che.ws-agent", "org.eclipse.che.exec", "org.eclipse.che.terminal"))
- .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, DEFAULT_MEMORY_LIMIT_BYTES));
-
- // setup environment
- EnvironmentDto environmentDto =
- newDto(EnvironmentDto.class)
- .withRecipe(recipeDto)
- .withMachines(singletonMap(MACHINE_NAME, machine));
-
- // workspace configuration using the environment
- return newDto(WorkspaceConfigDto.class)
- .withDefaultEnv(environmentName)
- .withEnvironments(singletonMap(environmentName, environmentDto))
- .withName(name);
- }
-}
diff --git a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java b/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java
deleted file mode 100644
index c5f8454b1f..0000000000
--- a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFactoryBuilderTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (c) 2012-2018 Red Hat, Inc.
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- * Red Hat, Inc. - initial API and implementation
- */
-package org.eclipse.che.plugin.urlfactory;
-
-import static java.lang.Boolean.FALSE;
-import static java.util.Collections.singletonMap;
-import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE;
-import static org.eclipse.che.dto.server.DtoFactory.newDto;
-import static org.eclipse.che.plugin.urlfactory.URLFactoryBuilder.DEFAULT_DOCKER_IMAGE;
-import static org.eclipse.che.plugin.urlfactory.URLFactoryBuilder.DEFAULT_MEMORY_LIMIT_BYTES;
-import static org.eclipse.che.plugin.urlfactory.URLFactoryBuilder.MACHINE_NAME;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-
-import com.google.common.collect.ImmutableList;
-import org.eclipse.che.api.factory.shared.dto.FactoryDto;
-import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
-import org.eclipse.che.api.workspace.shared.dto.MachineConfigDto;
-import org.eclipse.che.api.workspace.shared.dto.RecipeDto;
-import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
-import org.eclipse.che.dto.server.DtoFactory;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.testng.MockitoTestNGListener;
-import org.testng.annotations.Listeners;
-import org.testng.annotations.Test;
-
-/**
- * Testing {@link URLFactoryBuilder}
- *
- * @author Florent Benoit
- */
-@Listeners(MockitoTestNGListener.class)
-public class URLFactoryBuilderTest {
-
- /** Check if URL is existing or not */
- @Mock private URLChecker urlChecker;
-
- /** Grab content of URLs */
- @Mock private URLFetcher urlFetcher;
-
- /** Tested instance. */
- @InjectMocks private URLFactoryBuilder urlFactoryBuilder;
-
- /** Check if not specifying a custom docker file we have the default value */
- @Test
- public void checkDefaultImage() throws Exception {
-
- RecipeDto recipeDto =
- newDto(RecipeDto.class).withContent(DEFAULT_DOCKER_IMAGE).withType("dockerimage");
- MachineConfigDto machine =
- newDto(MachineConfigDto.class)
- .withInstallers(
- ImmutableList.of(
- "org.eclipse.che.ws-agent", "org.eclipse.che.exec", "org.eclipse.che.terminal"))
- .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, DEFAULT_MEMORY_LIMIT_BYTES));
-
- // setup environment
- EnvironmentDto environmentDto =
- newDto(EnvironmentDto.class)
- .withRecipe(recipeDto)
- .withMachines(singletonMap(MACHINE_NAME, machine));
- // setup environment
- WorkspaceConfigDto expectedWsConfig =
- newDto(WorkspaceConfigDto.class)
- .withDefaultEnv("foo")
- .withEnvironments(singletonMap("foo", environmentDto))
- .withName("dumm");
-
- WorkspaceConfigDto actualWsConfigDto =
- urlFactoryBuilder.buildWorkspaceConfig("foo", "dumm", null);
-
- assertEquals(actualWsConfigDto, expectedWsConfig);
- }
-
- /**
- * Check that by specifying a location of custom dockerfile it's stored in the machine source if
- * URL is accessible
- */
- @Test
- public void checkWithCustomDockerfile() throws Exception {
-
- String myLocation = "http://foo-location";
- RecipeDto recipeDto =
- newDto(RecipeDto.class)
- .withLocation(myLocation)
- .withType("dockerfile")
- .withContentType("text/x-dockerfile");
- MachineConfigDto machine =
- newDto(MachineConfigDto.class)
- .withInstallers(
- ImmutableList.of(
- "org.eclipse.che.ws-agent", "org.eclipse.che.exec", "org.eclipse.che.terminal"))
- .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, DEFAULT_MEMORY_LIMIT_BYTES));
-
- // setup environment
- EnvironmentDto environmentDto =
- newDto(EnvironmentDto.class)
- .withRecipe(recipeDto)
- .withMachines(singletonMap(MACHINE_NAME, machine));
-
- WorkspaceConfigDto expectedWsConfig =
- newDto(WorkspaceConfigDto.class)
- .withDefaultEnv("foo")
- .withEnvironments(singletonMap("foo", environmentDto))
- .withName("dumm");
-
- when(urlChecker.exists(myLocation)).thenReturn(true);
-
- WorkspaceConfigDto actualWsConfigDto =
- urlFactoryBuilder.buildWorkspaceConfig("foo", "dumm", myLocation);
-
- assertEquals(actualWsConfigDto, expectedWsConfig);
- }
-
- /**
- * Check that by specifying a location of custom dockerfile it's stored in the machine source if
- * URL is accessible
- */
- @Test
- public void checkWithNonAccessibleCustomDockerfile() throws Exception {
- String myLocation = "http://foo-location";
- RecipeDto recipeDto =
- newDto(RecipeDto.class).withContent(DEFAULT_DOCKER_IMAGE).withType("dockerimage");
- MachineConfigDto machine =
- newDto(MachineConfigDto.class)
- .withInstallers(
- ImmutableList.of(
- "org.eclipse.che.ws-agent", "org.eclipse.che.exec", "org.eclipse.che.terminal"))
- .withAttributes(singletonMap(MEMORY_LIMIT_ATTRIBUTE, DEFAULT_MEMORY_LIMIT_BYTES));
-
- // setup environment
- EnvironmentDto environmentDto =
- newDto(EnvironmentDto.class)
- .withRecipe(recipeDto)
- .withMachines(singletonMap(MACHINE_NAME, machine));
-
- WorkspaceConfigDto expectedWsConfig =
- newDto(WorkspaceConfigDto.class)
- .withDefaultEnv("foo")
- .withEnvironments(singletonMap("foo", environmentDto))
- .withName("dumm");
-
- when(urlChecker.exists(myLocation)).thenReturn(false);
-
- WorkspaceConfigDto actualWsConfigDto =
- urlFactoryBuilder.buildWorkspaceConfig("foo", "dumm", myLocation);
-
- assertEquals(actualWsConfigDto, expectedWsConfig);
- }
-
- /** Check that with a custom factory.json we've this factory being built */
- @Test
- public void checkWithCustomFactoryJsonFile() throws Exception {
-
- WorkspaceConfigDto workspaceConfigDto = newDto(WorkspaceConfigDto.class);
- FactoryDto templateFactory =
- newDto(FactoryDto.class).withV("4.0").withName("florent").withWorkspace(workspaceConfigDto);
- String jsonFactory = DtoFactory.getInstance().toJson(templateFactory);
-
- String myLocation = "http://foo-location";
- when(urlChecker.exists(myLocation)).thenReturn(FALSE);
- when(urlFetcher.fetch(myLocation)).thenReturn(jsonFactory);
-
- FactoryDto factory = urlFactoryBuilder.createFactory(myLocation);
-
- assertEquals(templateFactory, factory);
- }
-
- /** Check that without specifying a custom factory.json we've default factory */
- @Test
- public void checkWithDefaultFactoryJsonFile() throws Exception {
-
- FactoryDto factory = urlFactoryBuilder.createFactory(null);
-
- assertNull(factory.getWorkspace());
- assertEquals(factory.getV(), "4.0");
- }
-}
diff --git a/plugins/plugin-urlfactory/src/test/resources/logback-test.xml b/plugins/plugin-urlfactory/src/test/resources/logback-test.xml
deleted file mode 100644
index 57dbb8b531..0000000000
--- a/plugins/plugin-urlfactory/src/test/resources/logback-test.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
- %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n
-
-
-
-
-
-
-
-
-
diff --git a/plugins/pom.xml b/plugins/pom.xml
index d6ffef9a0d..18824abcf0 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -48,7 +48,6 @@
plugin-nodejs-debugger
plugin-php
plugin-languageserver
-
plugin-urlfactory
plugin-json
plugin-composer
plugin-zend-debugger
diff --git a/pom.xml b/pom.xml
index ed83edfa8d..32d9db1ed1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1836,11 +1836,6 @@
che-plugin-testing-testng-server
${che.version}
-
- org.eclipse.che.plugin
- che-plugin-url-factory
- ${che.version}
-
org.eclipse.che.plugin
che-plugin-web-ext-server
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileManager.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileManager.java
new file mode 100644
index 0000000000..3e31cefd2e
--- /dev/null
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileManager.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.devfile.server;
+
+import static java.util.Collections.emptyMap;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.google.common.annotations.Beta;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.eclipse.che.api.core.ConflictException;
+import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.ServerException;
+import org.eclipse.che.api.core.ValidationException;
+import org.eclipse.che.api.devfile.model.Devfile;
+import org.eclipse.che.api.devfile.server.validator.DevfileIntegrityValidator;
+import org.eclipse.che.api.devfile.server.validator.DevfileSchemaValidator;
+import org.eclipse.che.api.workspace.server.WorkspaceManager;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
+import org.eclipse.che.commons.env.EnvironmentContext;
+
+/**
+ * Facade for devfile related operations.
+ *
+ * @author Max Shaposhnyk
+ */
+@Beta
+@Singleton
+public class DevfileManager {
+
+ private final ObjectMapper objectMapper;
+ private DevfileSchemaValidator schemaValidator;
+ private DevfileIntegrityValidator integrityValidator;
+ private DevfileConverter devfileConverter;
+ private WorkspaceManager workspaceManager;
+
+ @Inject
+ public DevfileManager(
+ DevfileSchemaValidator schemaValidator,
+ DevfileIntegrityValidator integrityValidator,
+ DevfileConverter devfileConverter,
+ WorkspaceManager workspaceManager) {
+ this.schemaValidator = schemaValidator;
+ this.integrityValidator = integrityValidator;
+ this.devfileConverter = devfileConverter;
+ this.workspaceManager = workspaceManager;
+ this.objectMapper = new ObjectMapper(new YAMLFactory());
+ }
+
+ /**
+ * Creates {@link Devfile} from given devfile content. Performs schema and integrity validation of
+ * input data.
+ *
+ * @param devfileContent raw content of devfile
+ * @param verbose when true, method returns more explained validation error messages if any
+ * @return Devfile object created from the source content
+ * @throws DevfileFormatException when any of schema or integrity validations fail
+ * @throws JsonProcessingException when parsing error occurs
+ */
+ public Devfile parse(String devfileContent, boolean verbose)
+ throws DevfileFormatException, JsonProcessingException {
+ JsonNode parsed = schemaValidator.validateBySchema(devfileContent, verbose);
+ Devfile devfile = objectMapper.treeToValue(parsed, Devfile.class);
+ integrityValidator.validateDevfile(devfile);
+ return devfile;
+ }
+
+ /**
+ * Creates {@link WorkspaceImpl} from given devfile with available name search
+ *
+ * @param devfile source devfile
+ * @return created {@link WorkspaceImpl} instance
+ * @throws DevfileFormatException when devfile integrity validation fail
+ * @throws ValidationException when incoming configuration or attributes are not valid
+ * @throws ConflictException when any conflict occurs
+ * @throws NotFoundException when user account is not found
+ * @throws ServerException when other error occurs
+ */
+ public WorkspaceImpl createWorkspace(Devfile devfile)
+ throws ServerException, DevfileFormatException, ConflictException, NotFoundException,
+ ValidationException {
+ WorkspaceConfigImpl workspaceConfig = createWorkspaceConfig(devfile);
+ final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
+ return workspaceManager.createWorkspace(
+ findAvailableName(workspaceConfig), namespace, emptyMap());
+ }
+
+ /**
+ * Creates {@link WorkspaceConfigImpl} from given devfile with integrity validation
+ *
+ * @param devfile source devfile
+ * @return created {@link WorkspaceConfigImpl} instance
+ * @throws DevfileFormatException when devfile integrity validation fail
+ */
+ public WorkspaceConfigImpl createWorkspaceConfig(Devfile devfile) throws DevfileFormatException {
+ integrityValidator.validateDevfile(devfile);
+ return devfileConverter.devFileToWorkspaceConfig(devfile);
+ }
+
+ /**
+ * Exports provided workspace into devfile
+ *
+ * @param key string composite workspace key
+ * @see WorkspaceManager#getByKey(String)
+ * @return devfile representation of given workspace
+ * @throws NotFoundException when no workspace can be found by given key
+ * @throws ConflictException when workspace cannot be exported into devfile
+ * @throws ServerException when other error occurs
+ */
+ public Devfile exportWorkspace(String key)
+ throws NotFoundException, ServerException, ConflictException {
+ WorkspaceImpl workspace = workspaceManager.getWorkspace(key);
+ try {
+ return devfileConverter.workspaceToDevFile(workspace.getConfig());
+ } catch (WorkspaceExportException e) {
+ throw new ConflictException(e.getMessage());
+ }
+ }
+
+ private WorkspaceConfigImpl findAvailableName(WorkspaceConfigImpl config) throws ServerException {
+ String nameCandidate = config.getName();
+ String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
+ int counter = 0;
+ while (true) {
+ try {
+ workspaceManager.getWorkspace(nameCandidate, namespace);
+ nameCandidate = config.getName() + "_" + ++counter;
+ } catch (NotFoundException nf) {
+ config.setName(nameCandidate);
+ break;
+ }
+ }
+ return config;
+ }
+}
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
index 17a5068881..b365d80da3 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileService.java
@@ -11,13 +11,11 @@
*/
package org.eclipse.che.api.devfile.server;
-import static java.util.Collections.emptyMap;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.workspace.server.DtoConverter.asDto;
import static org.eclipse.che.api.workspace.server.WorkspaceKeyValidator.validateKey;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.swagger.annotations.Api;
@@ -45,39 +43,29 @@ import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.ValidationException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.devfile.model.Devfile;
+import org.eclipse.che.api.devfile.server.schema.DevfileSchemaProvider;
import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator;
-import org.eclipse.che.api.workspace.server.WorkspaceManager;
-import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
-import org.eclipse.che.commons.env.EnvironmentContext;
@Api(value = "/devfile", description = "Devfile REST API")
@Path("/devfile")
public class DevfileService extends Service {
private WorkspaceLinksGenerator linksGenerator;
- private DevfileSchemaValidator schemaValidator;
- private DevfileIntegrityValidator integrityValidator;
private DevfileSchemaProvider schemaCachedProvider;
- private WorkspaceManager workspaceManager;
private ObjectMapper objectMapper;
- private DevfileConverter devfileConverter;
+ private DevfileManager devfileManager;
@Inject
public DevfileService(
WorkspaceLinksGenerator linksGenerator,
- DevfileSchemaValidator schemaValidator,
- DevfileIntegrityValidator integrityValidator,
DevfileSchemaProvider schemaCachedProvider,
- WorkspaceManager workspaceManager) {
+ DevfileManager devfileManager) {
this.linksGenerator = linksGenerator;
- this.schemaValidator = schemaValidator;
- this.integrityValidator = integrityValidator;
this.schemaCachedProvider = schemaCachedProvider;
- this.workspaceManager = workspaceManager;
+ this.devfileManager = devfileManager;
this.objectMapper = new ObjectMapper(new YAMLFactory());
- this.devfileConverter = new DevfileConverter();
}
/**
@@ -134,22 +122,15 @@ public class DevfileService extends Service {
throws ServerException, ConflictException, NotFoundException, ValidationException,
BadRequestException {
- Devfile devFile;
- WorkspaceConfigImpl workspaceConfig;
+ WorkspaceImpl workspace;
try {
- JsonNode parsed = schemaValidator.validateBySchema(data, verbose);
- devFile = objectMapper.treeToValue(parsed, Devfile.class);
- integrityValidator.validateDevfile(devFile);
- workspaceConfig = devfileConverter.devFileToWorkspaceConfig(devFile);
- } catch (IOException e) {
- throw new ServerException(e.getMessage());
+ Devfile devfile = devfileManager.parse(data, verbose);
+ workspace = devfileManager.createWorkspace(devfile);
} catch (DevfileFormatException e) {
throw new BadRequestException(e.getMessage());
+ } catch (JsonProcessingException e) {
+ throw new ServerException(e.getMessage());
}
-
- final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
- WorkspaceImpl workspace =
- workspaceManager.createWorkspace(findAvailableName(workspaceConfig), namespace, emptyMap());
return Response.status(201)
.entity(asDto(workspace).withLinks(linksGenerator.genLinks(workspace, getServiceContext())))
.build();
@@ -158,8 +139,6 @@ public class DevfileService extends Service {
/**
* Generates the devfile based on an existing workspace. Key is workspace id or
* namespace/workspace_name
- *
- * @see WorkspaceManager#getByKey(String)
*/
@GET
@Path("/{key:.*}")
@@ -185,33 +164,11 @@ public class DevfileService extends Service {
}))
@PathParam("key")
String key)
- throws NotFoundException, ServerException, BadRequestException, ConflictException {
+ throws NotFoundException, ServerException, BadRequestException, ConflictException,
+ JsonProcessingException {
validateKey(key);
- WorkspaceImpl workspace = workspaceManager.getWorkspace(key);
- try {
- Devfile workspaceDevFile = devfileConverter.workspaceToDevFile(workspace.getConfig());
- // Write object as YAML
- return Response.ok().entity(objectMapper.writeValueAsString(workspaceDevFile)).build();
- } catch (JsonProcessingException e) {
- throw new ServerException(e.getMessage(), e);
- } catch (WorkspaceExportException e) {
- throw new ConflictException(e.getMessage());
- }
- }
-
- private WorkspaceConfigImpl findAvailableName(WorkspaceConfigImpl config) throws ServerException {
- String nameCandidate = config.getName();
- String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
- int counter = 0;
- while (true) {
- try {
- workspaceManager.getWorkspace(nameCandidate, namespace);
- nameCandidate = config.getName() + "_" + ++counter;
- } catch (NotFoundException nf) {
- config.setName(nameCandidate);
- break;
- }
- }
- return config;
+ return Response.ok()
+ .entity(objectMapper.writeValueAsString(devfileManager.exportWorkspace(key)))
+ .build();
}
}
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/schema/DevfileSchemaProvider.java
similarity index 96%
rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/schema/DevfileSchemaProvider.java
index 22e29114e0..69d8e0fa22 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaProvider.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/schema/DevfileSchemaProvider.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.api.devfile.server;
+package org.eclipse.che.api.devfile.server.schema;
import static org.eclipse.che.api.devfile.server.Constants.SCHEMA_LOCATION;
import static org.eclipse.che.commons.lang.IoUtil.getResource;
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidator.java
similarity index 97%
rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidator.java
rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidator.java
index c7dae824b1..d4666b5368 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidator.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidator.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.api.devfile.server;
+package org.eclipse.che.api.devfile.server.validator;
import static java.lang.String.format;
import static java.util.stream.Collectors.toSet;
@@ -25,6 +25,7 @@ import org.eclipse.che.api.devfile.model.Command;
import org.eclipse.che.api.devfile.model.Devfile;
import org.eclipse.che.api.devfile.model.Project;
import org.eclipse.che.api.devfile.model.Tool;
+import org.eclipse.che.api.devfile.server.DevfileFormatException;
/** Validates devfile logical integrity. */
@Singleton
diff --git a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidator.java
similarity index 85%
rename from wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
rename to wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidator.java
index 00b827c3e4..24fb53a4a9 100644
--- a/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidator.java
+++ b/wsmaster/che-core-api-devfile/src/main/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidator.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.api.devfile.server;
+package org.eclipse.che.api.devfile.server.validator;
import static java.lang.String.format;
@@ -26,6 +26,8 @@ import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.inject.Inject;
import javax.inject.Singleton;
+import org.eclipse.che.api.devfile.server.DevfileFormatException;
+import org.eclipse.che.api.devfile.server.schema.DevfileSchemaProvider;
/** Validates YAML devfile content against given JSON schema. */
@Singleton
@@ -36,13 +38,14 @@ public class DevfileSchemaValidator {
private DevfileSchemaProvider schemaProvider;
@Inject
- DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) {
+ public DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) {
this.schemaProvider = schemaProvider;
this.validator = JsonSchemaFactory.byDefault().getValidator();
this.yamlReader = new ObjectMapper(new YAMLFactory());
}
- JsonNode validateBySchema(String yamlContent, boolean verbose) throws DevfileFormatException {
+ public JsonNode validateBySchema(String yamlContent, boolean verbose)
+ throws DevfileFormatException {
ProcessingReport report;
JsonNode data;
try {
diff --git a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json
index 9a3aeaf77c..bee438ba97 100644
--- a/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json
+++ b/wsmaster/che-core-api-devfile/src/main/resources/schema/devfile.json
@@ -12,7 +12,6 @@
"required": [
"specVersion",
"name",
- "projects",
"tools",
"commands"
],
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileManagerTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileManagerTest.java
new file mode 100644
index 0000000000..f2dfbf308c
--- /dev/null
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileManagerTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.devfile.server;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.testng.AssertJUnit.assertEquals;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import java.io.IOException;
+import org.eclipse.che.account.spi.AccountImpl;
+import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.devfile.model.Devfile;
+import org.eclipse.che.api.devfile.server.schema.DevfileSchemaProvider;
+import org.eclipse.che.api.devfile.server.validator.DevfileIntegrityValidator;
+import org.eclipse.che.api.devfile.server.validator.DevfileSchemaValidator;
+import org.eclipse.che.api.workspace.server.WorkspaceManager;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
+import org.eclipse.che.commons.env.EnvironmentContext;
+import org.eclipse.che.commons.json.JsonHelper;
+import org.eclipse.che.commons.json.JsonParseException;
+import org.eclipse.che.commons.subject.Subject;
+import org.eclipse.che.commons.subject.SubjectImpl;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+import org.testng.reporters.Files;
+
+@Listeners(MockitoTestNGListener.class)
+public class DevfileManagerTest {
+
+ private DevfileSchemaValidator schemaValidator;
+ private DevfileIntegrityValidator integrityValidator;
+ private DevfileConverter devfileConverter;
+ @Mock private WorkspaceManager workspaceManager;
+
+ private static final Subject TEST_SUBJECT = new SubjectImpl("name", "id", "token", false);
+
+ private DevfileManager devfileManager;
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+ schemaValidator = spy(new DevfileSchemaValidator(new DevfileSchemaProvider()));
+ integrityValidator = spy(new DevfileIntegrityValidator());
+ devfileConverter = spy(new DevfileConverter());
+ devfileManager =
+ new DevfileManager(schemaValidator, integrityValidator, devfileConverter, workspaceManager);
+ }
+
+ @Test
+ public void testValidateAndConvert() throws Exception {
+ String yamlContent =
+ Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml"));
+ devfileManager.parse(yamlContent, true);
+ verify(schemaValidator).validateBySchema(eq(yamlContent), eq(true));
+ verify(integrityValidator).validateDevfile(any(Devfile.class));
+ }
+
+ @Test(
+ expectedExceptions = JsonProcessingException.class,
+ expectedExceptionsMessageRegExp = "Unrecognized field \"foos\" [\\w\\W]+")
+ public void shouldThrowExceptionWhenUnconvertableContentProvided() throws Exception {
+ String yamlContent =
+ Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml"))
+ .concat("foos:");
+ devfileManager.parse(yamlContent, true);
+ verify(schemaValidator).validateBySchema(eq(yamlContent), eq(true));
+ verifyNoMoreInteractions(integrityValidator);
+ }
+
+ @Test
+ public void shouldFindAvailableNameAndCreateWorkspace() throws Exception {
+ ArgumentCaptor captor = ArgumentCaptor.forClass(WorkspaceConfigImpl.class);
+ EnvironmentContext current = new EnvironmentContext();
+ current.setSubject(TEST_SUBJECT);
+ EnvironmentContext.setCurrent(current);
+ WorkspaceImpl ws = mock(WorkspaceImpl.class);
+ when(workspaceManager.createWorkspace(any(), anyString(), anyMap()))
+ .thenReturn(createWorkspace(WorkspaceStatus.STOPPED));
+ when(workspaceManager.getWorkspace(anyString(), anyString()))
+ .thenAnswer(
+ invocation -> {
+ String wsname = invocation.getArgument(0);
+ if ("petclinic-dev-environment".equals(wsname)
+ || "petclinic-dev-environment_1".equals(wsname)) {
+ return ws;
+ }
+ throw new NotFoundException("ws not found");
+ });
+ String yamlContent =
+ Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml"));
+ Devfile devfile = devfileManager.parse(yamlContent, true);
+ // when
+ devfileManager.createWorkspace(devfile);
+ // then
+ verify(workspaceManager).createWorkspace(captor.capture(), anyString(), anyMap());
+ assertEquals("petclinic-dev-environment_2", captor.getValue().getName());
+ }
+
+ private WorkspaceImpl createWorkspace(WorkspaceStatus status)
+ throws IOException, JsonParseException {
+ return WorkspaceImpl.builder()
+ .setConfig(createConfig())
+ .generateId()
+ .setAccount(new AccountImpl("anyId", TEST_SUBJECT.getUserName(), "test"))
+ .setStatus(status)
+ .build();
+ }
+
+ private WorkspaceConfigImpl createConfig() throws IOException, JsonParseException {
+ String jsonContent =
+ Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json"));
+ return JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null);
+ }
+}
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java
index b025b1590c..01d54f1c75 100644
--- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileServiceTest.java
@@ -16,39 +16,31 @@ import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
import java.io.IOException;
import org.eclipse.che.account.spi.AccountImpl;
-import org.eclipse.che.api.core.NotFoundException;
-import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.devfile.model.Devfile;
+import org.eclipse.che.api.devfile.server.schema.DevfileSchemaProvider;
import org.eclipse.che.api.workspace.server.WorkspaceLinksGenerator;
-import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
-import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.json.JsonHelper;
import org.eclipse.che.commons.json.JsonParseException;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.everrest.assured.EverrestJetty;
-import org.everrest.core.Filter;
-import org.everrest.core.GenericContainerRequest;
-import org.everrest.core.RequestFilter;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
@@ -62,14 +54,9 @@ public class DevfileServiceTest {
@Mock private WorkspaceLinksGenerator linksGenerator;
- @Mock private WorkspaceManager workspaceManager;
- @Mock private EnvironmentContext environmentContext;
- @Mock private DevfileIntegrityValidator integrityValidator;
+ @Mock private DevfileManager devfileManager;
private DevfileSchemaProvider schemaProvider = new DevfileSchemaProvider();
- private DevfileSchemaValidator validator;
-
- @SuppressWarnings("unused")
- private static final EnvironmentFilter FILTER = new EnvironmentFilter();
+ private ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false);
@@ -78,10 +65,7 @@ public class DevfileServiceTest {
@BeforeMethod
public void initService() {
- this.validator = spy(new DevfileSchemaValidator(schemaProvider));
- this.devFileService =
- new DevfileService(
- linksGenerator, validator, integrityValidator, schemaProvider, workspaceManager);
+ this.devFileService = new DevfileService(linksGenerator, schemaProvider, devfileManager);
}
@Test
@@ -98,25 +82,14 @@ public class DevfileServiceTest {
}
@Test
- public void shouldAcceptDevFileAndFindAvailableName() throws Exception {
- ArgumentCaptor captor = ArgumentCaptor.forClass(WorkspaceConfigImpl.class);
- EnvironmentContext.setCurrent(environmentContext);
- WorkspaceImpl ws = mock(WorkspaceImpl.class);
- when(workspaceManager.createWorkspace(any(), eq(SUBJECT.getUserName()), anyMap()))
- .thenReturn(createWorkspace(WorkspaceStatus.STOPPED));
+ public void shouldAcceptDevFileContentAndCreateWorkspace() throws Exception {
+ ArgumentCaptor captor = ArgumentCaptor.forClass(Devfile.class);
String yamlContent =
Files.readFile(getClass().getClassLoader().getResourceAsStream("devfile.yaml"));
- when(workspaceManager.getWorkspace(anyString(), anyString()))
- .thenAnswer(
- invocation -> {
- String wsname = invocation.getArgument(0);
- if (wsname.equals("petclinic-dev-environment")
- || wsname.equals("petclinic-dev-environment_1")) {
- return ws;
- }
- throw new NotFoundException("ws not found");
- });
-
+ Devfile devfile = createDevfile(yamlContent);
+ WorkspaceImpl ws = createWorkspace(WorkspaceStatus.STOPPED);
+ when(devfileManager.parse(anyString(), anyBoolean())).thenReturn(devfile);
+ when(devfileManager.createWorkspace(any(Devfile.class))).thenReturn(ws);
final Response response =
given()
.auth()
@@ -127,16 +100,19 @@ public class DevfileServiceTest {
.post(SECURE_PATH + "/devfile");
assertEquals(response.getStatusCode(), 201);
- verify(validator).validateBySchema(eq(yamlContent), eq(false));
- verify(workspaceManager).createWorkspace(captor.capture(), eq(SUBJECT.getUserName()), anyMap());
- assertEquals("petclinic-dev-environment_2", captor.getValue().getName());
+ verify(devfileManager).createWorkspace(captor.capture());
+ assertEquals(devfile, captor.getValue());
+ }
+
+ private Devfile createDevfile(String yamlContent) throws IOException {
+ JsonNode node = mapper.readTree(yamlContent);
+ return mapper.treeToValue(node, Devfile.class);
}
@Test
public void shouldCreateDevFileFromWorkspace() throws Exception {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
- when(workspaceManager.getWorkspace(anyString()))
- .thenReturn(createWorkspace(WorkspaceStatus.STOPPED));
+ when(devfileManager.exportWorkspace(anyString())).thenReturn(new Devfile());
final Response response =
given()
@@ -160,17 +136,9 @@ public class DevfileServiceTest {
.build();
}
- private WorkspaceConfig createConfig() throws IOException, JsonParseException {
+ private WorkspaceConfigImpl createConfig() throws IOException, JsonParseException {
String jsonContent =
Files.readFile(getClass().getClassLoader().getResourceAsStream("workspace_config.json"));
return JsonHelper.fromJson(jsonContent, WorkspaceConfigImpl.class, null);
}
-
- @Filter
- public static class EnvironmentFilter implements RequestFilter {
- @Override
- public void doFilter(GenericContainerRequest request) {
- EnvironmentContext.getCurrent().setSubject(SUBJECT);
- }
- }
}
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidatorTest.java
similarity index 97%
rename from wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidatorTest.java
rename to wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidatorTest.java
index 5879babe2e..a33993a167 100644
--- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileIntegrityValidatorTest.java
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileIntegrityValidatorTest.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.api.devfile.server;
+package org.eclipse.che.api.devfile.server.validator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
@@ -21,6 +21,7 @@ import org.eclipse.che.api.devfile.model.Devfile;
import org.eclipse.che.api.devfile.model.Project;
import org.eclipse.che.api.devfile.model.Source;
import org.eclipse.che.api.devfile.model.Tool;
+import org.eclipse.che.api.devfile.server.DevfileFormatException;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.reporters.Files;
diff --git a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java
similarity index 88%
rename from wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java
rename to wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java
index b5088af537..2f0b306a73 100644
--- a/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/DevfileSchemaValidatorTest.java
+++ b/wsmaster/che-core-api-devfile/src/test/java/org/eclipse/che/api/devfile/server/validator/DevfileSchemaValidatorTest.java
@@ -9,8 +9,10 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.api.devfile.server;
+package org.eclipse.che.api.devfile.server.validator;
+import org.eclipse.che.api.devfile.server.DevfileFormatException;
+import org.eclipse.che.api.devfile.server.schema.DevfileSchemaProvider;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.reporters.Files;
diff --git a/wsmaster/che-core-api-factory-shared/src/main/java/org/eclipse/che/api/factory/shared/Constants.java b/wsmaster/che-core-api-factory-shared/src/main/java/org/eclipse/che/api/factory/shared/Constants.java
index 38a6743b22..db11191187 100644
--- a/wsmaster/che-core-api-factory-shared/src/main/java/org/eclipse/che/api/factory/shared/Constants.java
+++ b/wsmaster/che-core-api-factory-shared/src/main/java/org/eclipse/che/api/factory/shared/Constants.java
@@ -18,18 +18,16 @@ package org.eclipse.che.api.factory.shared;
*/
public final class Constants {
+ public static final String CURRENT_VERSION = "4.0";
+
// factory links rel attributes
public static final String IMAGE_REL_ATT = "image";
public static final String RETRIEVE_FACTORY_REL_ATT = "self";
- public static final String SNIPPET_REL_ATT = "snippet";
public static final String FACTORY_ACCEPTANCE_REL_ATT = "accept";
public static final String NAMED_FACTORY_ACCEPTANCE_REL_ATT = "accept-named";
- // factory snippet types
- public static final String MARKDOWN_SNIPPET_TYPE = "markdown";
- public static final String IFRAME_SNIPPET_TYPE = "iframe";
- public static final String HTML_SNIPPET_TYPE = "html";
- public static final String URL_SNIPPET_TYPE = "url";
+ // url factory parameter names
+ public static final String URL_PARAMETER_NAME = "url";
private Constants() {}
}
diff --git a/wsmaster/che-core-api-factory/pom.xml b/wsmaster/che-core-api-factory/pom.xml
index 73d9417105..35bd95b6b0 100644
--- a/wsmaster/che-core-api-factory/pom.xml
+++ b/wsmaster/che-core-api-factory/pom.xml
@@ -54,6 +54,10 @@
org.eclipse.che.core
che-core-api-core
+
+ org.eclipse.che.core
+ che-core-api-devfile
+
org.eclipse.che.core
che-core-api-dto
@@ -150,6 +154,21 @@
che-core-sql-schema
test
+
+ org.eclipse.jetty
+ jetty-http
+ test
+
+
+ org.eclipse.jetty
+ jetty-server
+ test
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ test
+
org.eclipse.persistence
org.eclipse.persistence.core
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolver.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolver.java
new file mode 100644
index 0000000000..d38940381a
--- /dev/null
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DefaultFactoryParameterResolver.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.factory.server;
+
+import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;
+
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.validation.constraints.NotNull;
+import org.eclipse.che.api.core.BadRequestException;
+import org.eclipse.che.api.core.ServerException;
+import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
+import org.eclipse.che.api.factory.shared.dto.FactoryDto;
+
+/**
+ * Default {@link FactoryParametersResolver} implementation. Tries to resolve factory based on
+ * provided parameters. Presumes url parameters as direct URL to a devfile content.
+ */
+@Singleton
+public class DefaultFactoryParameterResolver implements FactoryParametersResolver {
+
+ private URLFactoryBuilder urlFactoryBuilder;
+
+ @Inject
+ public DefaultFactoryParameterResolver(URLFactoryBuilder urlFactoryBuilder) {
+ this.urlFactoryBuilder = urlFactoryBuilder;
+ }
+
+ @Override
+ public boolean accept(Map factoryParameters) {
+ return !factoryParameters.get(URL_PARAMETER_NAME).isEmpty();
+ }
+
+ /**
+ * Creates factory based on provided parameters. Presumes url parameter as direct URL to a devfile
+ * content.
+ *
+ * @param factoryParameters map containing factory data parameters provided through URL
+ */
+ @Override
+ public FactoryDto createFactory(@NotNull final Map factoryParameters)
+ throws BadRequestException, ServerException {
+ // create factory from the following devfile location
+ return urlFactoryBuilder
+ .createFactoryFromDevfile(factoryParameters.get(URL_PARAMETER_NAME))
+ .orElse(null);
+ }
+}
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryManager.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryManager.java
index a3aa78c238..dbafac1672 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryManager.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryManager.java
@@ -19,6 +19,7 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.factory.server.model.impl.AuthorImpl;
@@ -118,9 +119,8 @@ public class FactoryManager {
* @return stored data, if specified attributes is correct
* @throws ServerException when any server errors occurs
*/
- @SuppressWarnings("unchecked")
- public > T getByAttribute(
+ public Page extends Factory> getByAttribute(
int maxItems, int skipCount, List> attributes) throws ServerException {
- return (T) factoryDao.getByAttribute(maxItems, skipCount, attributes);
+ return factoryDao.getByAttributes(maxItems, skipCount, attributes);
}
}
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryParametersResolver.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryParametersResolver.java
index 5f5353309c..191b97df03 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryParametersResolver.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryParametersResolver.java
@@ -14,6 +14,7 @@ package org.eclipse.che.api.factory.server;
import java.util.Map;
import javax.validation.constraints.NotNull;
import org.eclipse.che.api.core.BadRequestException;
+import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
/**
@@ -39,5 +40,5 @@ public interface FactoryParametersResolver {
* @throws BadRequestException when data are invalid
*/
FactoryDto createFactory(@NotNull Map factoryParameters)
- throws BadRequestException;
+ throws BadRequestException, ServerException;
}
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryService.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryService.java
index f6f6d7555e..02a0962b73 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryService.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/FactoryService.java
@@ -27,7 +27,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -51,6 +50,7 @@ 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.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.core.model.user.User;
@@ -80,15 +80,12 @@ import org.eclipse.che.dto.server.DtoFactory;
public class FactoryService extends Service {
/** Error message if there is no plugged resolver. */
- public static final String ERROR_NO_RESOLVER_AVAILABLE =
- "Cannot build factory with any of the provided parameters.";
+ public static final String FACTORY_NOT_RESOLVABLE =
+ "Cannot build factory with any of the provided parameters. Please check parameters correctness, and resend query.";
/** Validate query parameter. If true, factory will be validated */
public static final String VALIDATE_QUERY_PARAMETER = "validate";
- /** Set of resolvers for factories. Injected through an holder. */
- private final Set factoryParametersResolvers;
-
private final FactoryManager factoryManager;
private final UserManager userManager;
private final PreferenceManager preferenceManager;
@@ -97,6 +94,7 @@ public class FactoryService extends Service {
private final FactoryAcceptValidator acceptValidator;
private final FactoryBuilder factoryBuilder;
private final WorkspaceManager workspaceManager;
+ private final FactoryParametersResolverHolder factoryParametersResolverHolder;
@Inject
public FactoryService(
@@ -117,8 +115,7 @@ public class FactoryService extends Service {
this.editValidator = editValidator;
this.factoryBuilder = factoryBuilder;
this.workspaceManager = workspaceManager;
- this.factoryParametersResolvers =
- factoryParametersResolverHolder.getFactoryParametersResolvers();
+ this.factoryParametersResolverHolder = factoryParametersResolverHolder;
}
@POST
@@ -193,7 +190,7 @@ public class FactoryService extends Service {
@ApiResponse(code = 500, message = "Internal server error")
})
@Deprecated
- public List getFactoryByAttribute(
+ public Response getFactoryByAttribute(
@DefaultValue("0") @QueryParam("skipCount") Integer skipCount,
@DefaultValue("30") @QueryParam("maxItems") Integer maxItems,
@Context UriInfo uriInfo)
@@ -219,11 +216,13 @@ public class FactoryService extends Service {
}
}
- final List factories = new ArrayList<>();
- for (Factory factory : factoryManager.getByAttribute(maxItems, skipCount, query)) {
- factories.add(injectLinks(asDto(factory)));
+ Page extends Factory> factoriesPage =
+ factoryManager.getByAttribute(maxItems, skipCount, query);
+ List list = new ArrayList<>();
+ for (Factory factory : factoriesPage.getItems()) {
+ list.add(injectLinks(asDto(factory)));
}
- return factories;
+ return Response.ok().entity(list).header("Link", createLinkHeader(factoriesPage)).build();
}
@PUT
@@ -276,7 +275,7 @@ public class FactoryService extends Service {
@ApiResponse(code = 500, message = "Internal server error")
})
public void removeFactory(@ApiParam(value = "Factory identifier") @PathParam("id") String id)
- throws ForbiddenException, ServerException {
+ throws ServerException {
factoryManager.removeFactory(id);
}
@@ -329,23 +328,23 @@ public class FactoryService extends Service {
@DefaultValue("false")
@QueryParam(VALIDATE_QUERY_PARAMETER)
Boolean validate)
- throws ServerException, BadRequestException {
+ throws BadRequestException, ServerException {
// check parameter
requiredNotNull(parameters, "Factory build parameters");
// search matching resolver and create factory from matching resolver
- for (FactoryParametersResolver resolver : factoryParametersResolvers) {
- if (resolver.accept(parameters)) {
- final FactoryDto factory = resolver.createFactory(parameters);
- if (validate) {
- acceptValidator.validateOnAccept(factory);
- }
- return injectLinks(factory);
- }
+ FactoryDto resolvedFactory =
+ factoryParametersResolverHolder
+ .getFactoryParametersResolver(parameters)
+ .createFactory(parameters);
+ if (resolvedFactory == null) {
+ throw new BadRequestException(FACTORY_NOT_RESOLVABLE);
}
- // no match
- throw new BadRequestException(ERROR_NO_RESOLVER_AVAILABLE);
+ if (validate) {
+ acceptValidator.validateOnAccept(resolvedFactory);
+ }
+ return injectLinks(resolvedFactory);
}
/** Injects factory links. If factory is named then accept named link will be injected. */
@@ -424,24 +423,32 @@ public class FactoryService extends Service {
}
}
- /** Usage of a dedicated class to manage the optional resolvers */
+ /** Usage of a dedicated class to manage the optional service-specific resolvers */
protected static class FactoryParametersResolverHolder {
/** Optional inject for the resolvers. */
@com.google.inject.Inject(optional = true)
- private Set factoryParametersResolvers;
+ @SuppressWarnings("unused")
+ private Set specificFactoryParametersResolvers;
+
+ @Inject private DefaultFactoryParameterResolver defaultFactoryResolver;
/**
- * Provides the set of resolvers if there are some else return an empty set.
+ * Provides a suitable resolver for the given parameters
*
- * @return a non null set
+ * @return suitable service-specific resolver or default one
*/
- public Set getFactoryParametersResolvers() {
- if (factoryParametersResolvers != null) {
- return factoryParametersResolvers;
- } else {
- return Collections.emptySet();
+ public FactoryParametersResolver getFactoryParametersResolver(Map parameters) {
+ if (specificFactoryParametersResolvers == null) {
+ return defaultFactoryResolver;
}
+ for (FactoryParametersResolver factoryParametersResolver :
+ specificFactoryParametersResolvers) {
+ if (factoryParametersResolver.accept(parameters)) {
+ return factoryParametersResolver;
+ }
+ }
+ return defaultFactoryResolver;
}
}
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ValueHelper.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ValueHelper.java
index 2186d70e79..b3f748f82f 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ValueHelper.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ValueHelper.java
@@ -27,7 +27,7 @@ public class ValueHelper {
*/
public static boolean isEmpty(Object value) {
return (null == value)
- || (value.getClass().equals(String.class) && isNullOrEmpty((String) value)
+ || ((value.getClass().equals(String.class) && isNullOrEmpty((String) value))
|| (Collection.class.isAssignableFrom(value.getClass())
&& ((Collection) value).isEmpty())
|| (Map.class.isAssignableFrom(value.getClass()) && ((Map) value).isEmpty()));
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java
index bd90c6d585..b5ee0d066b 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/jpa/JpaFactoryDao.java
@@ -11,16 +11,19 @@
*/
package org.eclipse.che.api.factory.server.jpa;
+import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
+import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
+import static org.eclipse.che.api.core.Pages.iterate;
import com.google.inject.persist.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
-import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
@@ -30,6 +33,7 @@ import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
@@ -92,7 +96,7 @@ public class JpaFactoryDao implements FactoryDao {
}
@Override
- @Transactional
+ @Transactional(rollbackOn = {ServerException.class})
public FactoryImpl getById(String id) throws NotFoundException, ServerException {
requireNonNull(id);
try {
@@ -107,42 +111,94 @@ public class JpaFactoryDao implements FactoryDao {
}
@Override
- @Transactional
- public List getByAttribute(
+ @Transactional(rollbackOn = {ServerException.class})
+ public Page getByAttributes(
int maxItems, int skipCount, List> attributes) throws ServerException {
+ checkArgument(maxItems >= 0, "The number of items to return can't be negative.");
+ checkArgument(
+ skipCount >= 0 && skipCount <= Integer.MAX_VALUE,
+ "The number of items to skip can't be negative or greater than " + Integer.MAX_VALUE);
try {
LOG.debug(
"FactoryDao#getByAttributes #maxItems: {} #skipCount: {}, #attributes: {}",
maxItems,
skipCount,
attributes);
- final Map params = new HashMap<>();
- String query = "SELECT factory FROM Factory factory";
- if (!attributes.isEmpty()) {
- final StringJoiner matcher = new StringJoiner(" AND ", " WHERE ", " ");
- int i = 0;
- for (Pair attribute : attributes) {
- final String parameterName = "parameterName" + i++;
- params.put(parameterName, attribute.second);
- matcher.add("factory." + attribute.first + " = :" + parameterName);
- }
- query = query + matcher;
+ final long count = countFactoriesByAttributes(attributes);
+ if (count == 0) {
+ return new Page<>(emptyList(), skipCount, maxItems, count);
}
- final TypedQuery typedQuery =
- managerProvider
- .get()
- .createQuery(query, FactoryImpl.class)
- .setFirstResult(skipCount)
- .setMaxResults(maxItems);
- for (Map.Entry entry : params.entrySet()) {
- typedQuery.setParameter(entry.getKey(), entry.getValue());
- }
- return typedQuery.getResultList().stream().map(FactoryImpl::new).collect(Collectors.toList());
+ List result = getFactoriesByAttributes(maxItems, skipCount, attributes);
+ return new Page<>(result, skipCount, maxItems, count);
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
}
+ @Override
+ @Transactional(rollbackOn = {ServerException.class})
+ public Page getByUser(String userId, int maxItems, long skipCount)
+ throws ServerException {
+ requireNonNull(userId);
+ final Pair factoryCreator = Pair.of("creator.userId", userId);
+ try {
+ long totalCount = countFactoriesByAttributes(singletonList(factoryCreator));
+ return new Page<>(
+ getFactoriesByAttributes(maxItems, skipCount, singletonList(factoryCreator)),
+ skipCount,
+ maxItems,
+ totalCount);
+ } catch (RuntimeException ex) {
+ throw new ServerException(ex.getMessage(), ex);
+ }
+ }
+
+ private List getFactoriesByAttributes(
+ int maxItems, long skipCount, List> attributes) {
+ final Map params = new HashMap<>();
+ StringBuilder query = new StringBuilder("SELECT factory FROM Factory factory");
+ if (!attributes.isEmpty()) {
+ final StringJoiner matcher = new StringJoiner(" AND ", " WHERE ", " ");
+ int i = 0;
+ for (Pair attribute : attributes) {
+ final String parameterName = "parameterName" + i++;
+ params.put(parameterName, attribute.second);
+ matcher.add("factory." + attribute.first + " = :" + parameterName);
+ }
+ query.append(matcher);
+ }
+ TypedQuery typedQuery =
+ managerProvider
+ .get()
+ .createQuery(query.toString(), FactoryImpl.class)
+ .setFirstResult((int) skipCount)
+ .setMaxResults(maxItems);
+ for (Map.Entry entry : params.entrySet()) {
+ typedQuery.setParameter(entry.getKey(), entry.getValue());
+ }
+ return typedQuery.getResultList().stream().map(FactoryImpl::new).collect(toList());
+ }
+
+ private Long countFactoriesByAttributes(List> attributes) {
+ final Map params = new HashMap<>();
+ StringBuilder query = new StringBuilder("SELECT COUNT(factory) FROM Factory factory");
+ if (!attributes.isEmpty()) {
+ final StringJoiner matcher = new StringJoiner(" AND ", " WHERE ", " ");
+ int i = 0;
+ for (Pair attribute : attributes) {
+ final String parameterName = "parameterName" + i++;
+ params.put(parameterName, attribute.second);
+ matcher.add("factory." + attribute.first + " = :" + parameterName);
+ }
+ query.append(matcher);
+ }
+ TypedQuery typedQuery = managerProvider.get().createQuery(query.toString(), Long.class);
+ for (Map.Entry entry : params.entrySet()) {
+ typedQuery.setParameter(entry.getKey(), entry.getValue());
+ }
+ return typedQuery.getSingleResult();
+ }
+
@Transactional
protected void doCreate(FactoryImpl factory) {
final EntityManager manager = managerProvider.get();
@@ -196,9 +252,10 @@ public class JpaFactoryDao implements FactoryDao {
@Override
public void onCascadeEvent(BeforeUserRemovedEvent event) throws ServerException {
- final Pair factoryCreator =
- Pair.of("creator.userId", event.getUser().getId());
- for (FactoryImpl factory : factoryDao.getByAttribute(0, 0, singletonList(factoryCreator))) {
+ for (FactoryImpl factory :
+ iterate(
+ (maxItems, skipCount) ->
+ factoryDao.getByUser(event.getUser().getId(), maxItems, skipCount))) {
factoryDao.remove(factory.getId());
}
}
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/spi/FactoryDao.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/spi/FactoryDao.java
index 886aa61a72..867f82f140 100644
--- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/spi/FactoryDao.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/spi/FactoryDao.java
@@ -14,6 +14,7 @@ package org.eclipse.che.api.factory.server.spi;
import java.util.List;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.commons.lang.Pair;
@@ -70,6 +71,16 @@ public interface FactoryDao {
*/
FactoryImpl getById(String id) throws NotFoundException, ServerException;
+ /**
+ * Gets all factories of specified user.
+ *
+ * @param userId user identifier
+ * @return list factory instances, never null
+ * @throws NullPointerException when {@code userId} is null
+ * @throws ServerException when any other error occurs
+ */
+ Page getByUser(String userId, int maxItems, long skipCount) throws ServerException;
+
/**
* Gets the factories for the list of attributes.
*
@@ -80,6 +91,6 @@ public interface FactoryDao {
* @throws IllegalArgumentException when {@code skipCount} or {@code maxItems} is negative
* @throws ServerException when any other error occurs
*/
- List getByAttribute(
+ Page getByAttributes(
int maxItems, int skipCount, List> attributes) throws ServerException;
}
diff --git a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMerger.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMerger.java
similarity index 70%
rename from plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMerger.java
rename to wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMerger.java
index 26b3813b83..15d1580dec 100644
--- a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMerger.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMerger.java
@@ -9,11 +9,12 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static java.util.Collections.singletonList;
import java.util.List;
+import java.util.function.Supplier;
import javax.inject.Singleton;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
@@ -33,22 +34,22 @@ public class ProjectConfigDtoMerger {
*
*
* - no projects --> add whole project
- *
- if projects
+ *
- if projects:
*
- * - : if there is only one project: add source if missing
+ *
- if there is only one project: add source if missing
*
- if many projects: do nothing
*
*
*
- * @param factory
- * @param computedProjectConfig
- * @return
+ * @param factory source factory
+ * @param configSupplier supplier which can compute project config on demand
+ * @return factory with merged project sources
*/
- public FactoryDto merge(FactoryDto factory, ProjectConfigDto computedProjectConfig) {
+ public FactoryDto merge(FactoryDto factory, Supplier configSupplier) {
final List projects = factory.getWorkspace().getProjects();
if (projects == null || projects.isEmpty()) {
- factory.getWorkspace().setProjects(singletonList(computedProjectConfig));
+ factory.getWorkspace().setProjects(singletonList(configSupplier.get()));
return factory;
}
@@ -56,7 +57,7 @@ public class ProjectConfigDtoMerger {
if (projects.size() == 1) {
ProjectConfigDto projectConfig = projects.get(0);
if (projectConfig.getSource() == null)
- projectConfig.setSource(computedProjectConfig.getSource());
+ projectConfig.setSource(configSupplier.get().getSource());
}
return factory;
diff --git a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLChecker.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLChecker.java
similarity index 98%
rename from plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLChecker.java
rename to wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLChecker.java
index a25c0226b6..f7136e9ae9 100644
--- a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLChecker.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLChecker.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static java.util.Objects.requireNonNull;
diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java
new file mode 100644
index 0000000000..78fcda811d
--- /dev/null
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.factory.server.urlfactory;
+
+import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE;
+import static org.eclipse.che.dto.server.DtoFactory.newDto;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import org.eclipse.che.api.core.BadRequestException;
+import org.eclipse.che.api.core.ServerException;
+import org.eclipse.che.api.devfile.model.Devfile;
+import org.eclipse.che.api.devfile.server.DevfileFormatException;
+import org.eclipse.che.api.devfile.server.DevfileManager;
+import org.eclipse.che.api.factory.shared.dto.FactoryDto;
+import org.eclipse.che.api.workspace.server.DtoConverter;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
+import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
+import org.eclipse.che.dto.server.DtoFactory;
+
+/**
+ * Handle the creation of some elements used inside a {@link FactoryDto}.
+ *
+ * @author Florent Benoit
+ * @author Max Shaposhnyk
+ */
+@Singleton
+public class URLFactoryBuilder {
+
+ private final String defaultCheEditor;
+ private final String defaultChePlugins;
+
+ private final URLFetcher urlFetcher;
+ private final DevfileManager devfileManager;
+
+ @Inject
+ public URLFactoryBuilder(
+ @Named("che.factory.default_editor") String defaultCheEditor,
+ @Named("che.factory.default_plugins") String defaultChePlugins,
+ URLFetcher urlFetcher,
+ DevfileManager devfileManager) {
+ this.defaultCheEditor = defaultCheEditor;
+ this.defaultChePlugins = defaultChePlugins;
+ this.urlFetcher = urlFetcher;
+ this.devfileManager = devfileManager;
+ }
+
+ /**
+ * Build a factory using the provided json file or create default one
+ *
+ * @param jsonFileLocation location of factory json file
+ * @return a factory or null if factory json in not found
+ */
+ public Optional createFactoryFromJson(String jsonFileLocation) {
+ // Check if there is factory json file inside the repository
+ if (jsonFileLocation != null) {
+ final String factoryJsonContent = urlFetcher.fetch(jsonFileLocation);
+ if (!Strings.isNullOrEmpty(factoryJsonContent)) {
+ return Optional.of(
+ DtoFactory.getInstance().createDtoFromJson(factoryJsonContent, FactoryDto.class));
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Build a factory using the provided devfile
+ *
+ * @param devfileLocation location of devfile
+ * @return a factory or null if devfile is not found
+ */
+ public Optional createFactoryFromDevfile(String devfileLocation)
+ throws BadRequestException, ServerException {
+ if (devfileLocation == null) {
+ return Optional.empty();
+ }
+ final String devfileYamlContent = urlFetcher.fetch(devfileLocation);
+ if (Strings.isNullOrEmpty(devfileYamlContent)) {
+ return Optional.empty();
+ }
+ try {
+ Devfile devfile = devfileManager.parse(devfileYamlContent, false);
+ WorkspaceConfigImpl wsConfig = devfileManager.createWorkspaceConfig(devfile);
+ return Optional.of(
+ newDto(FactoryDto.class)
+ .withV(CURRENT_VERSION)
+ .withWorkspace(DtoConverter.asDto(wsConfig)));
+ } catch (DevfileFormatException e) {
+ throw new BadRequestException(e.getMessage());
+ } catch (IOException x) {
+ throw new ServerException(x.getLocalizedMessage(), x);
+ }
+ }
+
+ /**
+ * Help to generate default workspace configuration
+ *
+ * @param name the name of the workspace
+ * @return a workspace configuration
+ */
+ public WorkspaceConfigDto buildDefaultWorkspaceConfig(String name) {
+
+ Map attributes = new HashMap<>();
+ attributes.put(WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, defaultCheEditor);
+ attributes.put(WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, defaultChePlugins);
+
+ // workspace configuration using the environment
+ return newDto(WorkspaceConfigDto.class).withName(name).withAttributes(attributes);
+ }
+}
diff --git a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFetcher.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcher.java
similarity index 89%
rename from plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFetcher.java
rename to wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcher.java
index f6969edf2e..458d7df915 100644
--- a/plugins/plugin-urlfactory/src/main/java/org/eclipse/che/plugin/urlfactory/URLFetcher.java
+++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcher.java
@@ -9,11 +9,13 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.io.ByteStreams;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -25,7 +27,6 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
-import org.apache.commons.compress.utils.BoundedInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,8 +41,8 @@ public class URLFetcher {
/** Logger. */
private static final Logger LOG = LoggerFactory.getLogger(URLFetcher.class);
- /** Maximum size of allowed data. (40KB) */
- protected static final long MAXIMUM_READ_BYTES = 40 * 1000;
+ /** Maximum size of allowed data. (80KB) */
+ protected static final long MAXIMUM_READ_BYTES = 80 * 1024;
/** The Compiled REGEX PATTERN that can be used for http|https git urls */
final Pattern GIT_HTTP_URL_PATTERN = Pattern.compile("(?^http[s]?://.*)\\.git$");
@@ -77,7 +78,7 @@ public class URLFetcher {
try (InputStream inputStream = urlConnection.getInputStream();
BufferedReader reader =
new BufferedReader(
- new InputStreamReader(new BoundedInputStream(inputStream, getLimit()), UTF_8))) {
+ new InputStreamReader(ByteStreams.limit(inputStream, getLimit()), UTF_8))) {
value = reader.lines().collect(Collectors.joining("\n"));
} catch (IOException e) {
// we shouldn't fetch if check is done before
@@ -104,6 +105,7 @@ public class URLFetcher {
* @return if the url ends with .git will return the url without .git otherwise return the url as
* it is
*/
+ @VisibleForTesting
String sanitized(String url) {
if (url != null) {
final Matcher matcher = GIT_HTTP_URL_PATTERN.matcher(url);
diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/FactoryServiceTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/FactoryServiceTest.java
index 759dfe5408..15e1869898 100644
--- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/FactoryServiceTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/FactoryServiceTest.java
@@ -22,14 +22,17 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static org.eclipse.che.api.factory.server.DtoConverter.asDto;
import static org.eclipse.che.api.factory.server.FactoryService.VALIDATE_QUERY_PARAMETER;
+import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION;
+import static org.eclipse.che.dto.server.DtoFactory.newDto;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyMapOf;
+import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.spy;
@@ -38,21 +41,20 @@ import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import javax.ws.rs.core.UriInfo;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
@@ -77,7 +79,9 @@ import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl.WorkspaceConfigImplBuilder;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
+import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl.WorkspaceImplBuilder;
import org.eclipse.che.api.workspace.shared.dto.CommandDto;
import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
@@ -126,12 +130,10 @@ public class FactoryServiceTest {
@Mock private FactoryEditValidator editValidator;
@Mock private WorkspaceManager workspaceManager;
@Mock private FactoryParametersResolverHolder factoryParametersResolverHolder;
- @Mock private UriInfo uriInfo;
private FactoryBuilder factoryBuilderSpy;
private User user;
- private Set factoryParametersResolvers;
private FactoryService service;
@@ -144,11 +146,8 @@ public class FactoryServiceTest {
@BeforeMethod
public void setUp() throws Exception {
factoryBuilderSpy = spy(new FactoryBuilder(new SourceStorageParametersValidator()));
- factoryParametersResolvers = new HashSet<>();
lenient().doNothing().when(factoryBuilderSpy).checkValid(any(FactoryDto.class));
lenient().doNothing().when(factoryBuilderSpy).checkValid(any(FactoryDto.class), anyBoolean());
- when(factoryParametersResolverHolder.getFactoryParametersResolvers())
- .thenReturn(factoryParametersResolvers);
user = new UserImpl(USER_ID, USER_EMAIL, ADMIN_USER_NAME);
lenient().when(userManager.getById(anyString())).thenReturn(user);
lenient()
@@ -169,6 +168,7 @@ public class FactoryServiceTest {
@Filter
public static class EnvironmentFilter implements RequestFilter {
+ @Override
public void doFilter(GenericContainerRequest request) {
EnvironmentContext context = EnvironmentContext.getCurrent();
context.setSubject(new SubjectImpl(ADMIN_USER_NAME, USER_ID, ADMIN_USER_PASSWORD, false));
@@ -253,10 +253,10 @@ public class FactoryServiceTest {
@Test
public void shouldReturnFactoryListByNameAttribute() throws Exception {
- final Factory factory = createFactory();
- when(factoryManager.getByAttribute(1, 0, ImmutableList.of(Pair.of("name", factory.getName()))))
- .thenReturn(ImmutableList.of(factory));
-
+ final FactoryImpl factory = createFactory();
+ doReturn(new Page<>(ImmutableList.of(factory), 0, 1, 1))
+ .when(factoryManager)
+ .getByAttribute(1, 0, ImmutableList.of(Pair.of("name", factory.getName())));
final Response response =
given()
.auth()
@@ -288,11 +288,11 @@ public class FactoryServiceTest {
@Test
public void shouldReturnFactoryListByCreatorAttribute() throws Exception {
- final Factory factory1 = createNamedFactory("factory1");
- final Factory factory2 = createNamedFactory("factory2");
- when(factoryManager.getByAttribute(
- 2, 0, ImmutableList.of(Pair.of("creator.userId", user.getName()))))
- .thenReturn(ImmutableList.of(factory1, factory2));
+ final FactoryImpl factory1 = createNamedFactory("factory1");
+ final FactoryImpl factory2 = createNamedFactory("factory2");
+ doReturn(new Page<>(ImmutableList.of(factory1, factory2), 0, 2, 2))
+ .when(factoryManager)
+ .getByAttribute(2, 0, ImmutableList.of(Pair.of("creator.userId", user.getName())));
final Response response =
given()
@@ -406,28 +406,26 @@ public class FactoryServiceTest {
public void shouldGenerateFactoryJsonIncludeGivenProjects() throws Exception {
// given
final String wsId = "workspace123234";
- WorkspaceImpl.WorkspaceImplBuilder ws = WorkspaceImpl.builder();
- WorkspaceConfigImpl.WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
+ WorkspaceImplBuilder ws = WorkspaceImpl.builder();
+ WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
ws.setId(wsId);
wsConfig.setProjects(
Arrays.asList(
- DTO.createDto(ProjectConfigDto.class)
+ newDto(ProjectConfigDto.class)
.withPath("/proj1")
.withSource(
- DTO.createDto(SourceStorageDto.class).withType("git").withLocation("location")),
- DTO.createDto(ProjectConfigDto.class)
+ newDto(SourceStorageDto.class).withType("git").withLocation("location")),
+ newDto(ProjectConfigDto.class)
.withPath("/proj2")
.withSource(
- DTO.createDto(SourceStorageDto.class)
- .withType("git")
- .withLocation("location"))));
+ newDto(SourceStorageDto.class).withType("git").withLocation("location"))));
wsConfig.setName("wsname");
- wsConfig.setEnvironments(singletonMap("env1", DTO.createDto(EnvironmentDto.class)));
+ wsConfig.setEnvironments(singletonMap("env1", newDto(EnvironmentDto.class)));
wsConfig.setDefaultEnv("env1");
ws.setStatus(WorkspaceStatus.RUNNING);
wsConfig.setCommands(
singletonList(
- DTO.createDto(CommandDto.class)
+ newDto(CommandDto.class)
.withName("MCI")
.withType("mvn")
.withCommandLine("clean install")));
@@ -453,20 +451,20 @@ public class FactoryServiceTest {
public void shouldNotGenerateFactoryIfNoProjectsWithSourceStorage() throws Exception {
// given
final String wsId = "workspace123234";
- WorkspaceImpl.WorkspaceImplBuilder ws = WorkspaceImpl.builder();
- WorkspaceConfigImpl.WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
+ WorkspaceImplBuilder ws = WorkspaceImpl.builder();
+ WorkspaceConfigImplBuilder wsConfig = WorkspaceConfigImpl.builder();
ws.setId(wsId);
wsConfig.setProjects(
Arrays.asList(
- DTO.createDto(ProjectConfigDto.class).withPath("/proj1"),
- DTO.createDto(ProjectConfigDto.class).withPath("/proj2")));
+ newDto(ProjectConfigDto.class).withPath("/proj1"),
+ newDto(ProjectConfigDto.class).withPath("/proj2")));
wsConfig.setName("wsname");
- wsConfig.setEnvironments(singletonMap("env1", DTO.createDto(EnvironmentDto.class)));
+ wsConfig.setEnvironments(singletonMap("env1", newDto(EnvironmentDto.class)));
wsConfig.setDefaultEnv("env1");
ws.setStatus(WorkspaceStatus.RUNNING);
wsConfig.setCommands(
singletonList(
- DTO.createDto(CommandDto.class)
+ newDto(CommandDto.class)
.withName("MCI")
.withType("mvn")
.withCommandLine("clean install")));
@@ -525,7 +523,8 @@ public class FactoryServiceTest {
@Test
public void checkValidateResolver() throws Exception {
final FactoryParametersResolver dummyResolver = Mockito.mock(FactoryParametersResolver.class);
- factoryParametersResolvers.add(dummyResolver);
+ when(factoryParametersResolverHolder.getFactoryParametersResolver(anyMap()))
+ .thenReturn(dummyResolver);
// invalid factory
final String invalidFactoryMessage = "invalid factory";
@@ -535,12 +534,10 @@ public class FactoryServiceTest {
// create factory
final FactoryDto expectFactory =
- DTO.createDto(FactoryDto.class).withV("4.0").withName("matchingResolverFactory");
+ newDto(FactoryDto.class).withV(CURRENT_VERSION).withName("matchingResolverFactory");
// accept resolver
- when(dummyResolver.accept(anyMapOf(String.class, String.class))).thenReturn(true);
- when(dummyResolver.createFactory(anyMapOf(String.class, String.class)))
- .thenReturn(expectFactory);
+ when(dummyResolver.createFactory(anyMap())).thenReturn(expectFactory);
// when
final Map map = new HashMap<>();
@@ -557,22 +554,22 @@ public class FactoryServiceTest {
assertTrue(response.getBody().asString().contains(invalidFactoryMessage));
// check we call resolvers
- verify(dummyResolver).accept(anyMapOf(String.class, String.class));
- verify(dummyResolver).createFactory(anyMapOf(String.class, String.class));
+ factoryParametersResolverHolder.getFactoryParametersResolver(anyMap());
+ verify(dummyResolver).createFactory(anyMap());
// check we call validator
verify(acceptValidator).validateOnAccept(any());
}
- private Factory createFactory() {
+ private FactoryImpl createFactory() {
return createNamedFactory(FACTORY_NAME);
}
- private Factory createNamedFactory(String name) {
+ private FactoryImpl createNamedFactory(String name) {
return createFactoryWithStorage(name, PROJECT_SOURCE_TYPE, PROJECT_SOURCE_LOCATION);
}
- private Factory createFactoryWithStorage(String name, String type, String location) {
+ private FactoryImpl createFactoryWithStorage(String name, String type, String location) {
return FactoryImpl.builder()
.setId(FACTORY_ID)
.setVersion("4.0")
@@ -620,9 +617,7 @@ public class FactoryServiceTest {
private static List unwrapDtoList(Response response, Class dtoClass)
throws IOException {
- return FluentIterable.from(
- DtoFactory.getInstance()
- .createListDtoFromJson(response.body().asInputStream(), dtoClass))
- .toList();
+ return new ArrayList<>(
+ DtoFactory.getInstance().createListDtoFromJson(response.body().asInputStream(), dtoClass));
}
}
diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java
index 1f0bb09412..e5517b8047 100644
--- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/builder/FactoryBuilderTest.java
@@ -173,7 +173,7 @@ public class FactoryBuilderTest {
@Test(
expectedExceptions = ConflictException.class,
expectedExceptionsMessageRegExp =
- "You are missing a mandatory parameter \"workspace.projects\\[1\\].type\". .*")
+ "You are missing a mandatory parameter \"workspace.projects\\[1\\].path\". .*")
public void shouldThrowExceptionWithMessagePointingToMissingMandatoryParameter()
throws Exception {
factoryBuilder = new FactoryBuilder(sourceProjectParametersValidator);
@@ -196,7 +196,7 @@ public class FactoryBuilderTest {
.withAttributes(singletonMap("key", singletonList("value")))
.withDescription("description")
.withName("test")
- .withPath("/test");
+ .withPath("");
FactoryDto factory = prepareFactory();
factory.getWorkspace().setProjects(asList(project, project2));
diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java
index cf65c0f7a5..49d14321e8 100644
--- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/spi/tck/FactoryDaoTest.java
@@ -31,6 +31,7 @@ import java.util.stream.Stream;
import javax.inject.Inject;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
+import org.eclipse.che.api.core.Page;
import org.eclipse.che.api.core.model.factory.Button;
import org.eclipse.che.api.factory.server.model.impl.ActionImpl;
import org.eclipse.che.api.factory.server.model.impl.AuthorImpl;
@@ -213,9 +214,9 @@ public class FactoryDaoTest {
public void shouldGetFactoryByIdAttribute() throws Exception {
final FactoryImpl factory = factories[0];
final List> attributes = ImmutableList.of(Pair.of("id", factory.getId()));
- final List result = factoryDao.getByAttribute(1, 0, attributes);
+ final Page result = factoryDao.getByAttributes(1, 0, attributes);
- assertEquals(new HashSet<>(result), ImmutableSet.of(factory));
+ assertEquals(new HashSet<>(result.getItems()), ImmutableSet.of(factory));
}
@Test(dependsOnMethods = "shouldUpdateFactory")
@@ -231,17 +232,25 @@ public class FactoryDaoTest {
factory3.getPolicies().setReferer("ref2");
factoryDao.update(factory1);
factoryDao.update(factory3);
- final List result = factoryDao.getByAttribute(factories.length, 0, attributes);
+ final Page result = factoryDao.getByAttributes(factories.length, 0, attributes);
- assertEquals(new HashSet<>(result), ImmutableSet.of(factories[0], factories[2], factories[4]));
+ assertEquals(
+ new HashSet<>(result.getItems()),
+ ImmutableSet.of(factories[0], factories[2], factories[4]));
}
@Test
public void shouldFindAllFactoriesWhenAttributesNotSpecified() throws Exception {
final List> attributes = emptyList();
- final List result = factoryDao.getByAttribute(factories.length, 0, attributes);
+ final Page result = factoryDao.getByAttributes(factories.length, 0, attributes);
- assertEquals(new HashSet<>(result), new HashSet<>(asList(factories)));
+ assertEquals(new HashSet<>(result.getItems()), new HashSet<>(asList(factories)));
+ }
+
+ @Test
+ public void shouldFindAllFactoriesOfSpecifiedUser() throws Exception {
+ final Page result = factoryDao.getByUser(users[1].getId(), 30, 0);
+ assertEquals(new HashSet<>(result.getItems()), new HashSet<>(asList(factories[1])));
}
@Test(expectedExceptions = NotFoundException.class, dependsOnMethods = "shouldGetFactoryById")
diff --git a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMergerTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMergerTest.java
similarity index 93%
rename from plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMergerTest.java
rename to wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMergerTest.java
index 1357b60cf1..61619615f8 100644
--- a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/ProjectConfigDtoMergerTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/ProjectConfigDtoMergerTest.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static org.eclipse.che.dto.server.DtoFactory.newDto;
import static org.testng.Assert.assertEquals;
@@ -60,7 +60,7 @@ public class ProjectConfigDtoMergerTest {
Assert.assertTrue(factory.getWorkspace().getProjects().isEmpty());
// merge
- projectConfigDtoMerger.merge(factory, computedProjectConfig);
+ projectConfigDtoMerger.merge(factory, () -> computedProjectConfig);
// project
assertEquals(factory.getWorkspace().getProjects().size(), 1);
@@ -79,7 +79,7 @@ public class ProjectConfigDtoMergerTest {
Assert.assertNull(projectConfigDto.getSource());
// merge
- projectConfigDtoMerger.merge(factory, computedProjectConfig);
+ projectConfigDtoMerger.merge(factory, () -> computedProjectConfig);
// project still 1
assertEquals(factory.getWorkspace().getProjects().size(), 1);
diff --git a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLCheckerTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLCheckerTest.java
similarity index 91%
rename from plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLCheckerTest.java
rename to wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLCheckerTest.java
index 109ece57c3..72ed59eba8 100644
--- a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLCheckerTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLCheckerTest.java
@@ -9,7 +9,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static org.eclipse.jetty.http.HttpStatus.NOT_FOUND_404;
import static org.eclipse.jetty.http.HttpStatus.OK_200;
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -81,9 +80,7 @@ public class URLCheckerTest {
public void checkUrlFileNotExists() {
// test to check if this url exist
- URL urlJson =
- URLCheckerTest.class.getResource(
- "/" + URLCheckerTest.class.getPackage().getName().replace('.', '/') + "/.che.json");
+ URL urlJson = getClass().getClassLoader().getResource(".che.json");
Assert.assertNotNull(urlJson);
boolean exists = URLChecker.exists(urlJson.toString() + "-notfound");
@@ -101,9 +98,7 @@ public class URLCheckerTest {
@Test
public void checkUrlIsInvalid() throws MalformedURLException {
// test to check if this url exist
- URL urlJson =
- URLCheckerTest.class.getResource(
- "/" + URLCheckerTest.class.getPackage().getName().replace('.', '/') + "/.che.json");
+ URL urlJson = getClass().getClassLoader().getResource(".che.json");
Assert.assertNotNull(urlJson);
boolean exists = URLChecker.exists(new URL(urlJson.toString() + "-notfound"));
@@ -166,8 +161,8 @@ public class URLCheckerTest {
/** Dummy servlet class. */
static class MyServlet extends HttpServlet {
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getOutputStream().print("hello");
}
}
diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java
new file mode 100644
index 0000000000..dcce2c5e53
--- /dev/null
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilderTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.factory.server.urlfactory;
+
+import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE;
+import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE;
+import static org.eclipse.che.dto.server.DtoFactory.newDto;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.che.api.devfile.server.DevfileManager;
+import org.eclipse.che.api.factory.shared.dto.FactoryDto;
+import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
+import org.eclipse.che.dto.server.DtoFactory;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+/**
+ * Testing {@link URLFactoryBuilder}
+ *
+ * @author Florent Benoit
+ * @author Max Shaposhnyk
+ */
+@Listeners(MockitoTestNGListener.class)
+public class URLFactoryBuilderTest {
+
+ private final String defaultEditor = "org.eclipse.che.editor.theia:1.0.0";
+ private final String defaultPlugin = "che-machine-exec-plugin:0.0.1";
+ /** Grab content of URLs */
+ @Mock private URLFetcher urlFetcher;
+
+ @Mock private DevfileManager devfileManager;
+
+ /** Tested instance. */
+ private URLFactoryBuilder urlFactoryBuilder;
+
+ @BeforeClass
+ public void setUp() {
+ this.urlFactoryBuilder =
+ new URLFactoryBuilder(defaultEditor, defaultPlugin, urlFetcher, devfileManager);
+ }
+
+ @Test
+ public void checkDefaultConfiguration() throws Exception {
+ Map attributes = new HashMap<>();
+ attributes.put(WORKSPACE_TOOLING_EDITOR_ATTRIBUTE, defaultEditor);
+ attributes.put(WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE, defaultPlugin);
+ // setup environment
+ WorkspaceConfigDto expectedWsConfig =
+ newDto(WorkspaceConfigDto.class).withAttributes(attributes).withName("foo");
+
+ WorkspaceConfigDto actualWsConfigDto = urlFactoryBuilder.buildDefaultWorkspaceConfig("foo");
+
+ assertEquals(actualWsConfigDto, expectedWsConfig);
+ }
+
+ /** Check that with a custom factory.json we've this factory being built */
+ @Test
+ public void checkWithCustomFactoryJsonFile() throws Exception {
+
+ WorkspaceConfigDto workspaceConfigDto = newDto(WorkspaceConfigDto.class);
+ FactoryDto templateFactory =
+ newDto(FactoryDto.class)
+ .withV(CURRENT_VERSION)
+ .withName("florent")
+ .withWorkspace(workspaceConfigDto);
+ String jsonFactory = DtoFactory.getInstance().toJson(templateFactory);
+
+ String myLocation = "http://foo-location";
+ when(urlFetcher.fetch(myLocation)).thenReturn(jsonFactory);
+
+ FactoryDto factory = urlFactoryBuilder.createFactoryFromJson(myLocation).get();
+
+ assertEquals(templateFactory, factory);
+ }
+}
diff --git a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFetcherTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcherTest.java
similarity index 84%
rename from plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFetcherTest.java
rename to wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcherTest.java
index 0626208dcf..5c72eccf3a 100644
--- a/plugins/plugin-urlfactory/src/test/java/org/eclipse/che/plugin/urlfactory/URLFetcherTest.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/urlfactory/URLFetcherTest.java
@@ -9,10 +9,10 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
-package org.eclipse.che.plugin.urlfactory;
+package org.eclipse.che.api.factory.server.urlfactory;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.eclipse.che.plugin.urlfactory.URLFetcher.MAXIMUM_READ_BYTES;
+import static org.eclipse.che.api.factory.server.urlfactory.URLFetcher.MAXIMUM_READ_BYTES;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
@@ -51,9 +51,7 @@ public class URLFetcherTest {
public void checkGetContent() {
// test to download this class object
- URL urlJson =
- URLFetcherTest.class.getResource(
- "/" + URLFetcherTest.class.getPackage().getName().replace('.', '/') + "/.che.json");
+ URL urlJson = getClass().getClassLoader().getResource(".che.json");
Assert.assertNotNull(urlJson);
String content = URLFetcher.fetch(urlJson.toString());
@@ -82,9 +80,7 @@ public class URLFetcherTest {
public void checkMissingContent() {
// test to download this class object
- URL urlJson =
- URLFetcherTest.class.getResource(
- "/" + URLFetcherTest.class.getPackage().getName().replace('.', '/') + "/.che.json");
+ URL urlJson = getClass().getClassLoader().getResource(".che.json");
Assert.assertNotNull(urlJson);
// add extra path to make url not found
@@ -95,9 +91,7 @@ public class URLFetcherTest {
/** Check when we reach custom limit */
@Test
public void checkPartialContent() {
- URL urlJson =
- URLFetcherTest.class.getResource(
- "/" + URLFetcherTest.class.getPackage().getName().replace('.', '/') + "/.che.json");
+ URL urlJson = getClass().getClassLoader().getResource(".che.json");
Assert.assertNotNull(urlJson);
String content = new OneByteURLFetcher().fetch(urlJson.toString());
@@ -118,9 +112,9 @@ public class URLFetcherTest {
}
/** Limit to only one Byte. */
- class OneByteURLFetcher extends URLFetcher {
-
+ static class OneByteURLFetcher extends URLFetcher {
/** Override the limit */
+ @Override
protected long getLimit() {
return 1;
}
diff --git a/plugins/plugin-urlfactory/src/test/resources/org/eclipse/che/plugin/urlfactory/.che.json b/wsmaster/che-core-api-factory/src/test/resources/.che.json
similarity index 100%
rename from plugins/plugin-urlfactory/src/test/resources/org/eclipse/che/plugin/urlfactory/.che.json
rename to wsmaster/che-core-api-factory/src/test/resources/.che.json
diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java
index abfb35b5d1..cb45371c20 100644
--- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java
+++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/ProjectConfigDto.java
@@ -50,7 +50,7 @@ public interface ProjectConfigDto extends ProjectConfig {
ProjectConfigDto withDescription(String description);
@Override
- @FactoryParameter(obligation = MANDATORY)
+ @FactoryParameter(obligation = OPTIONAL)
String getType();
void setType(String type);