diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index 51d111fcdb..560dae9501 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -369,10 +369,6 @@ org.eclipse.che.plugin che-plugin-machine-ext-server - - org.eclipse.che.plugin - che-plugin-url-factory - org.eclipse.persistence org.eclipse.persistence.core diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index 56ed55831c..903331e54b 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -30,8 +30,8 @@ import org.eclipse.che.api.core.notification.RemoteSubscriptionStorage; import org.eclipse.che.api.core.rest.CheJsonProvider; import org.eclipse.che.api.core.rest.MessageBodyAdapter; import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor; -import org.eclipse.che.api.devfile.server.DevfileSchemaValidator; import org.eclipse.che.api.devfile.server.DevfileService; +import org.eclipse.che.api.devfile.server.validator.DevfileSchemaValidator; import org.eclipse.che.api.factory.server.FactoryAcceptValidator; import org.eclipse.che.api.factory.server.FactoryCreateValidator; import org.eclipse.che.api.factory.server.FactoryEditValidator; @@ -141,6 +141,7 @@ public class WsMasterModule extends AbstractModule { bind(org.eclipse.che.api.factory.server.FactoryService.class); install(new org.eclipse.che.api.factory.server.jpa.FactoryJpaModule()); + // Service-specific factory resolvers. Multibinder factoryParametersResolverMultibinder = Multibinder.newSetBinder(binder(), FactoryParametersResolver.class); factoryParametersResolverMultibinder.addBinding().to(GithubFactoryParametersResolver.class); diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 0a1d34d9ad..61a5541c8e 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -574,3 +574,11 @@ che.wsagent.cors.allowed_origins=NULL che.wsagent.cors.allow_credentials=true # This property is used to provide value for WS Agent CORS enabling. che.wsagent.cors.enabled=true + +## Factory defaults. +# Editor and plugin which will be used for factories which are created from remote git repository +# which doesn't contain any Che-specific workspace descriptors (like .devfile of .factory.json) +che.factory.default_editor=org.eclipse.che.editor.theia:1.0.0 +# multiple plugins must be comma-separated, for example: +# pluginFooName:pluginFooVersion,pluginBarName:pluginBarVersion +che.factory.default_plugins=che-machine-exec-plugin:0.0.1 diff --git a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java index 64797d5a2e..51ac493b73 100644 --- a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java +++ b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/java/org/eclipse/che/multiuser/integration/jpa/cascaderemoval/JpaEntitiesCascadeRemovalTest.java @@ -87,7 +87,6 @@ import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.api.workspace.server.spi.environment.InternalEnvironmentFactory; import org.eclipse.che.api.workspace.server.wsplugins.ChePluginsApplier; import org.eclipse.che.commons.env.EnvironmentContext; -import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.commons.subject.SubjectImpl; import org.eclipse.che.commons.test.db.H2DBTestServer; import org.eclipse.che.commons.test.db.H2JpaCleaner; @@ -342,10 +341,7 @@ public class JpaEntitiesCascadeRemovalTest { assertTrue(preferenceDao.getPreferences(user.getId()).isEmpty()); assertTrue(sshDao.get(user.getId()).isEmpty()); assertTrue(workspaceDao.getByNamespace(account.getName(), 30, 0).isEmpty()); - assertTrue( - factoryDao - .getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))) - .isEmpty()); + assertTrue(factoryDao.getByUser(user.getId(), 30, 0).isEmpty()); // Check workers and parent entity is removed assertTrue(workspaceDao.getByNamespace(user2.getId(), 30, 0).isEmpty()); assertEquals(workerDao.getWorkers(workspace3.getId(), 1, 0).getTotalItemsCount(), 0); diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/pom.xml b/plugins/plugin-github/che-plugin-github-factory-resolver/pom.xml index c063792320..3c1112174d 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/pom.xml +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/pom.xml @@ -30,10 +30,6 @@ com.google.guava guava - - com.google.inject - guice - javax.inject javax.inject @@ -62,14 +58,6 @@ org.eclipse.che.core che-core-api-workspace-shared - - org.eclipse.che.core - che-core-commons-inject - - - org.eclipse.che.plugin - che-plugin-url-factory - ch.qos.logback logback-classic diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GitHubFactoryModule.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GitHubFactoryModule.java deleted file mode 100644 index 62e7218456..0000000000 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GitHubFactoryModule.java +++ /dev/null @@ -1,24 +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.github.factory.resolver; - -import com.google.inject.AbstractModule; -import org.eclipse.che.inject.DynaModule; - -/** @author Max Shaposhnik (mshaposhnik@codenvy.com) */ -@DynaModule -public class GitHubFactoryModule extends AbstractModule { - @Override - protected void configure() { - bind(GithubURLParser.class).to(LegacyGithubURLParser.class); - } -} diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolver.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolver.java index d24ce772c2..09461f7135 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolver.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolver.java @@ -11,39 +11,54 @@ */ package org.eclipse.che.plugin.github.factory.resolver; +import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; +import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; import static org.eclipse.che.dto.server.DtoFactory.newDto; 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.FactoryParametersResolver; +import org.eclipse.che.api.factory.server.urlfactory.ProjectConfigDtoMerger; +import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder; import org.eclipse.che.api.factory.shared.dto.FactoryDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; -import org.eclipse.che.plugin.urlfactory.ProjectConfigDtoMerger; -import org.eclipse.che.plugin.urlfactory.URLFactoryBuilder; /** * Provides Factory Parameters resolver for github repositories. * * @author Florent Benoit */ +@Singleton public class GithubFactoryParametersResolver implements FactoryParametersResolver { - /** Parameter name. */ - protected static final String URL_PARAMETER_NAME = "url"; - /** Parser which will allow to check validity of URLs and create objects. */ - @Inject private GithubURLParser githubUrlParser; + private GithubURLParser githubUrlParser; /** Builder allowing to build objects from github URL. */ - @Inject private GithubSourceStorageBuilder githubSourceStorageBuilder; + private GithubSourceStorageBuilder githubSourceStorageBuilder; - @Inject private URLFactoryBuilder urlFactoryBuilder; + /** Builds factory by fetching json/devfile content from given URL */ + private URLFactoryBuilder urlFactoryBuilder; /** ProjectDtoMerger */ @Inject private ProjectConfigDtoMerger projectConfigDtoMerger; + @Inject + public GithubFactoryParametersResolver( + GithubURLParser githubUrlParser, + GithubSourceStorageBuilder githubSourceStorageBuilder, + URLFactoryBuilder urlFactoryBuilder, + ProjectConfigDtoMerger projectConfigDtoMerger) { + this.githubUrlParser = githubUrlParser; + this.githubSourceStorageBuilder = githubSourceStorageBuilder; + this.urlFactoryBuilder = urlFactoryBuilder; + this.projectConfigDtoMerger = projectConfigDtoMerger; + } + /** * Check if this resolver can be used with the given parameters. * @@ -66,30 +81,35 @@ public class GithubFactoryParametersResolver implements FactoryParametersResolve */ @Override public FactoryDto createFactory(@NotNull final Map factoryParameters) - throws BadRequestException { + throws BadRequestException, ServerException { // no need to check null value of url parameter as accept() method has performed the check - final GithubUrl githubUrl = githubUrlParser.parse(factoryParameters.get("url")); + final GithubUrl githubUrl = githubUrlParser.parse(factoryParameters.get(URL_PARAMETER_NAME)); // create factory from the following location if location exists, else create default factory - FactoryDto factory = urlFactoryBuilder.createFactory(githubUrl.factoryJsonFileLocation()); - + FactoryDto factory = + urlFactoryBuilder + .createFactoryFromDevfile(githubUrl.devfileFileLocation()) + .orElseGet( + () -> + urlFactoryBuilder + .createFactoryFromJson(githubUrl.factoryFileLocation()) + .orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION))); // add workspace configuration if not defined if (factory.getWorkspace() == null) { factory.setWorkspace( - urlFactoryBuilder.buildWorkspaceConfig( - githubUrl.getRepository(), githubUrl.getUsername(), githubUrl.dockerFileLocation())); + urlFactoryBuilder.buildDefaultWorkspaceConfig(githubUrl.getRepository())); } - // Compute project configuration - ProjectConfigDto projectConfigDto = - newDto(ProjectConfigDto.class) - .withSource(githubSourceStorageBuilder.build(githubUrl)) - .withName(githubUrl.getRepository()) - .withType("blank") - .withPath("/".concat(githubUrl.getRepository())); - - // apply merging operation from existing and computed settings - return projectConfigDtoMerger.merge(factory, projectConfigDto); + // apply merging operation from existing and computed settings if needed + return projectConfigDtoMerger.merge( + factory, + () -> { + // Compute project configuration + return newDto(ProjectConfigDto.class) + .withSource(githubSourceStorageBuilder.build(githubUrl)) + .withName(githubUrl.getRepository()) + .withPath("/".concat(githubUrl.getRepository())); + }); } } diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubSourceStorageBuilder.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubSourceStorageBuilder.java index c24ca6863f..3ea64bc98b 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubSourceStorageBuilder.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubSourceStorageBuilder.java @@ -16,6 +16,7 @@ import static org.eclipse.che.dto.server.DtoFactory.newDto; import com.google.common.base.Strings; import java.util.HashMap; import java.util.Map; +import javax.inject.Singleton; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; @@ -24,6 +25,7 @@ import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; * * @author Florent Benoit */ +@Singleton public class GithubSourceStorageBuilder { /** @@ -42,7 +44,7 @@ public class GithubSourceStorageBuilder { } return newDto(SourceStorageDto.class) .withLocation(githubUrl.repositoryLocation()) - .withType("git") + .withType("github") .withParameters(parameters); } } diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParser.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParser.java index 348bb1ee86..21a38a39db 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParser.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParser.java @@ -11,26 +11,86 @@ */ package org.eclipse.che.plugin.github.factory.resolver; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import org.eclipse.che.api.factory.server.urlfactory.URLFetcher; + /** - * Interface for Gitlab repository URL parsers. + * Parser of String Github URLs and provide {@link GithubUrl} objects. * - * @author Max Shaposhnik + * @author Florent Benoit */ -public interface GithubURLParser { +@Singleton +public class GithubURLParser { + + /** Fetcher to grab PR data */ + @Inject private URLFetcher urlFetcher; /** - * Check if the URL is a valid Github url for the given provider. - * - * @param url a not null string representation of URL - * @return {@code true} if the URL is a valid url for the given provider. + * Regexp to find repository details (repository name, project name and branch and subfolder) + * Examples of valid URLs are in the test class. */ - boolean isValid(String url); + protected static final Pattern GITHUB_PATTERN = + Pattern.compile( + "^(?:http)(?:s)?(?:\\:\\/\\/)github.com/(?[^/]++)/(?[^/]++)((?:/tree/(?[^/]++)(?:/(?.*))?)|(/pull/(?[^/]++)))?$"); - /** - * Provides a parsed URL object of the given provider type. - * - * @param url URL to transform into a managed object - * @return managed url object - */ - GithubUrl parse(String url); + /** Regexp to find repository and branch name from PR link */ + protected static final Pattern PR_DATA_PATTERN = + Pattern.compile( + ".*
Closed|Open|Merged)[\\s|\\S]+<\\/div>[\\s|\\S]+into[\\s]+(from[\\s]*)*[^\\\\/]+)\\/(?[^\\:]+):(?[^\\\"]+).*", + Pattern.DOTALL); + + public boolean isValid(@NotNull String url) { + return GITHUB_PATTERN.matcher(url).matches(); + } + + public GithubUrl parse(String url) { + // Apply github url to the regexp + Matcher matcher = GITHUB_PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException( + String.format( + "The given github url %s is not a valid URL github url. It should start with https://github.com//", + url)); + } + + String repoUser = matcher.group("repoUser"); + String repoName = matcher.group("repoName"); + String branchName = matcher.group("branchName"); + + String pullRequestId = matcher.group("pullRequestId"); + if (pullRequestId != null) { + // there is a Pull Request ID, analyze content to extract repository and branch to use + String prData = this.urlFetcher.fetch(url); + Matcher prMatcher = PR_DATA_PATTERN.matcher(prData); + if (prMatcher.matches()) { + String prState = prMatcher.group("prState"); + if (!"open".equalsIgnoreCase(prState)) { + throw new IllegalArgumentException( + String.format( + "The given Pull Request url %s is not Opened, (found %s), thus it can't be opened as branch may have been removed.", + url, prState)); + } + repoUser = prMatcher.group("prRepoUser"); + repoName = prMatcher.group("prRepoName"); + branchName = prMatcher.group("prBranch"); + } else { + throw new IllegalArgumentException( + String.format( + "The given Pull Request github url %s is not a valid Pull Request URL github url. Unable to extract the data", + url)); + } + } + + return new GithubUrl() + .withUsername(repoUser) + .withRepository(repoName) + .withBranch(branchName) + .withSubfolder(matcher.group("subFolder")) + .withDevfileFilename(".devfile") + .withFactoryFilename(".factory.json"); + } } diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserImpl.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserImpl.java deleted file mode 100644 index 3fbc97a501..0000000000 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserImpl.java +++ /dev/null @@ -1,96 +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.github.factory.resolver; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.inject.Inject; -import javax.validation.constraints.NotNull; -import org.eclipse.che.plugin.urlfactory.URLFetcher; - -/** - * Parser of String Github URLs and provide {@link GithubUrl} objects. - * - * @author Florent Benoit - */ -public class GithubURLParserImpl implements GithubURLParser { - - /** Fetcher to grab PR data */ - @Inject private URLFetcher urlFetcher; - - /** - * Regexp to find repository details (repository name, project name and branch and subfolder) - * Examples of valid URLs are in the test class. - */ - protected static final Pattern GITHUB_PATTERN = - Pattern.compile( - "^(?:http)(?:s)?(?:\\:\\/\\/)github.com/(?[^/]++)/(?[^/]++)((?:/tree/(?[^/]++)(?:/(?.*))?)|(/pull/(?[^/]++)))?$"); - - /** Regexp to find repository and branch name from PR link */ - protected static final Pattern PR_DATA_PATTERN = - Pattern.compile( - ".*
Closed|Open|Merged)[\\s|\\S]+<\\/div>[\\s|\\S]+from[\\s|\\S]+[^\\\\/]+)\\/(?[^\\:]+):(?[^\\\"]+).*", - Pattern.DOTALL); - - @Override - public boolean isValid(@NotNull String url) { - return GITHUB_PATTERN.matcher(url).matches(); - } - - @Override - public GithubUrl parse(String url) { - // Apply github url to the regexp - Matcher matcher = GITHUB_PATTERN.matcher(url); - if (!matcher.matches()) { - throw new IllegalArgumentException( - String.format( - "The given github url %s is not a valid URL github url. It should start with https://github.com//", - url)); - } - - String repoUser = matcher.group("repoUser"); - String repoName = matcher.group("repoName"); - String branchName = matcher.group("branchName"); - - String pullRequestId = matcher.group("pullRequestId"); - if (pullRequestId != null) { - // there is a Pull Request ID, analyze content to extract repository and branch to use - String prData = this.urlFetcher.fetch(url); - Matcher prMatcher = PR_DATA_PATTERN.matcher(prData); - if (prMatcher.matches()) { - String prState = prMatcher.group("prState"); - if (!"open".equalsIgnoreCase(prState)) { - throw new IllegalArgumentException( - String.format( - "The given Pull Request url %s is not Opened, (found %s), thus it can't be opened as branch may have been removed.", - url, prState)); - } - repoUser = prMatcher.group("prRepoUser"); - repoName = prMatcher.group("prRepoName"); - branchName = prMatcher.group("prBranch"); - } else { - throw new IllegalArgumentException( - String.format( - "The given Pull Request github url %s is not a valid Pull Request URL github url. Unable to extract the data", - url)); - } - } - - return new GithubUrl() - .withUsername(repoUser) - .withRepository(repoName) - .withBranch(branchName) - .withSubfolder(matcher.group("subFolder")) - .withDockerfileFilename(".factory.dockerfile") - .withFactoryFilename(".factory.json"); - } -} diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrl.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrl.java index d19c3679a3..73682690d4 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrl.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/GithubUrl.java @@ -39,12 +39,12 @@ public class GithubUrl { /** Subfolder if any */ private String subfolder; - /** Dockerfile filename */ - private String dockerfileFilename; - /** Factory json filename */ private String factoryFilename; + /** Devfile filename */ + private String devfileFilename; + /** * Creation of this instance is made by the parser so user may not need to create a new instance * directly @@ -80,16 +80,16 @@ public class GithubUrl { } /** - * Gets dockerfile file name of this github url + * Gets devfile file name of this github url * - * @return the dockerfile file name + * @return the devfile file name */ - public String getDockerfileFilename() { - return this.dockerfileFilename; + public String getDevfileFilename() { + return this.devfileFilename; } - protected GithubUrl withDockerfileFilename(String dockerfileFilename) { - this.dockerfileFilename = dockerfileFilename; + protected GithubUrl withDevfileFilename(String devfileFilename) { + this.devfileFilename = devfileFilename; return this; } @@ -143,27 +143,12 @@ public class GithubUrl { return this; } - /** - * Provides the location to dockerfile - * - * @return location of dockerfile in a repository - */ - protected String dockerFileLocation() { - return new StringJoiner("/") - .add("https://raw.githubusercontent.com") - .add(username) - .add(repository) - .add(branch) - .add(dockerfileFilename) - .toString(); - } - /** * Provides the location to factory json file * * @return location of factory json file in a repository */ - protected String factoryJsonFileLocation() { + protected String factoryFileLocation() { return new StringJoiner("/") .add("https://raw.githubusercontent.com") .add(username) @@ -173,6 +158,21 @@ public class GithubUrl { .toString(); } + /** + * Provides the location to devfile yaml file + * + * @return location of devfile yaml file in a repository + */ + protected String devfileFileLocation() { + return new StringJoiner("/") + .add("https://raw.githubusercontent.com") + .add(username) + .add(repository) + .add(branch) + .add(devfileFilename) + .toString(); + } + /** * Provides location to the repository part of the full github URL. * diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/LegacyGithubURLParser.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/LegacyGithubURLParser.java deleted file mode 100644 index ee157f88ec..0000000000 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/main/java/org/eclipse/che/plugin/github/factory/resolver/LegacyGithubURLParser.java +++ /dev/null @@ -1,43 +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.github.factory.resolver; - -import javax.inject.Inject; -import org.eclipse.che.plugin.urlfactory.URLChecker; - -/** - * Support old dockerfila and factory filenames; - * - * @author Max Shaposhnik - */ -public class LegacyGithubURLParser extends GithubURLParserImpl { - - private URLChecker urlChecker; - - @Inject - public LegacyGithubURLParser(URLChecker urlChecker) { - this.urlChecker = urlChecker; - } - - @Override - public GithubUrl parse(String url) { - GithubUrl githubUrl = super.parse(url); - if (!urlChecker.exists(githubUrl.dockerFileLocation())) { - githubUrl.withDockerfileFilename(".codenvy.dockerfile"); - } - - if (!urlChecker.exists(githubUrl.factoryJsonFileLocation())) { - githubUrl.withFactoryFilename(".codenvy.json"); - } - return githubUrl; - } -} diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolverTest.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolverTest.java index 9c556e0aa1..27863a40a1 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolverTest.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubFactoryParametersResolverTest.java @@ -12,8 +12,9 @@ package org.eclipse.che.plugin.github.factory.resolver; import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; +import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; import static org.eclipse.che.dto.server.DtoFactory.newDto; -import static org.eclipse.che.plugin.github.factory.resolver.GithubFactoryParametersResolver.URL_PARAMETER_NAME; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -25,12 +26,13 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.util.Map; -import org.eclipse.che.api.core.BadRequestException; +import java.util.Optional; +import java.util.function.Supplier; +import org.eclipse.che.api.factory.server.urlfactory.ProjectConfigDtoMerger; +import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder; import org.eclipse.che.api.factory.shared.dto.FactoryDto; import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto; import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto; -import org.eclipse.che.plugin.urlfactory.ProjectConfigDtoMerger; -import org.eclipse.che.plugin.urlfactory.URLFactoryBuilder; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; @@ -49,7 +51,7 @@ import org.testng.annotations.Test; public class GithubFactoryParametersResolverTest { /** Parser which will allow to check validity of URLs and create objects. */ - @Spy private GithubURLParserImpl githubUrlParser = new GithubURLParserImpl(); + @Spy private GithubURLParser githubUrlParser = new GithubURLParser(); /** Converter allowing to convert github URL to other objects. */ @Spy @@ -61,18 +63,21 @@ public class GithubFactoryParametersResolverTest { /** Parser which will allow to check validity of URLs and create objects. */ @Mock private URLFactoryBuilder urlFactoryBuilder; - /** Capturing the project config DTO parameter. */ - @Captor private ArgumentCaptor projectConfigDtoArgumentCaptor; + /** Capturing the project config DTO supplier parameter. */ + @Captor private ArgumentCaptor> projectConfigDtoArgumentCaptor; - /** Capturing the parameter when calling {@link URLFactoryBuilder#createFactory(String)} */ - @Captor private ArgumentCaptor jsonFileLocationArgumentCaptor; + /** + * Capturing the parameter when calling {@link URLFactoryBuilder#createFactoryFromJson(String)} or + * {@link URLFactoryBuilder#createFactoryFromDevfile(String)} + */ + @Captor private ArgumentCaptor fileLocationArgumentCaptor; /** Instance of resolver that will be tested. */ @InjectMocks private GithubFactoryParametersResolver githubFactoryParametersResolver; /** Check missing parameter name can't be accepted by this resolver */ @Test - public void checkMissingParameter() throws BadRequestException { + public void checkMissingParameter() { Map parameters = singletonMap("foo", "this is a foo bar"); boolean accept = githubFactoryParametersResolver.accept(parameters); // shouldn't be accepted @@ -81,7 +86,7 @@ public class GithubFactoryParametersResolverTest { /** Check url which is not a github url can't be accepted by this resolver */ @Test - public void checkInvalidAcceptUrl() throws BadRequestException { + public void checkInvalidAcceptUrl() { Map parameters = singletonMap(URL_PARAMETER_NAME, "http://www.eclipse.org/che"); boolean accept = githubFactoryParametersResolver.accept(parameters); // shouldn't be accepted @@ -90,7 +95,7 @@ public class GithubFactoryParametersResolverTest { /** Check github url will be be accepted by this resolver */ @Test - public void checkValidAcceptUrl() throws BadRequestException { + public void checkValidAcceptUrl() { Map parameters = singletonMap(URL_PARAMETER_NAME, "https://github.com/codenvy/codenvy.git"); boolean accept = githubFactoryParametersResolver.accept(parameters); @@ -100,37 +105,66 @@ public class GithubFactoryParametersResolverTest { /** Check that with a simple valid URL github url it works */ @Test - public void shouldReturnGitHubSimpleFactory() throws Exception { + public void shouldReturnGitHubSimpleJsonFactory() throws Exception { String githubUrl = "https://github.com/eclipse/che"; - FactoryDto computedFactory = newDto(FactoryDto.class).withV("4.0"); - when(urlFactoryBuilder.createFactory(anyString())).thenReturn(computedFactory); + FactoryDto computedFactory = newDto(FactoryDto.class).withV(CURRENT_VERSION); + when(urlFactoryBuilder.createFactoryFromJson(anyString())) + .thenReturn(Optional.of(computedFactory)); githubFactoryParametersResolver.createFactory(singletonMap(URL_PARAMETER_NAME, githubUrl)); - // check we called the builder with the following codenvy json file - verify(urlFactoryBuilder).createFactory(jsonFileLocationArgumentCaptor.capture()); + // check we called the builder with the following factory json file + verify(urlFactoryBuilder).createFactoryFromJson(fileLocationArgumentCaptor.capture()); assertEquals( - jsonFileLocationArgumentCaptor.getValue(), + fileLocationArgumentCaptor.getValue(), "https://raw.githubusercontent.com/eclipse/che/master/.factory.json"); // check we provide dockerfile and correct env - verify(urlFactoryBuilder) - .buildWorkspaceConfig( - eq("che"), - eq("eclipse"), - eq("https://raw.githubusercontent.com/eclipse/che/master/.factory.dockerfile")); + verify(urlFactoryBuilder).buildDefaultWorkspaceConfig(eq("che")); // check project config built verify(projectConfigDtoMerger) .merge(any(FactoryDto.class), projectConfigDtoArgumentCaptor.capture()); - ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue(); + ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue().get(); SourceStorageDto sourceStorageDto = projectConfigDto.getSource(); assertNotNull(sourceStorageDto); - assertEquals(sourceStorageDto.getType(), "git"); + assertEquals(sourceStorageDto.getType(), "github"); + assertEquals(sourceStorageDto.getLocation(), githubUrl); + Map sourceParameters = sourceStorageDto.getParameters(); + assertEquals(sourceParameters.size(), 1); + assertEquals(sourceParameters.get("branch"), "master"); + } + + /** Check that with a simple valid URL github url it works */ + @Test + public void shouldReturnGitHubDevfileFactory() throws Exception { + + String githubUrl = "https://github.com/eclipse/che"; + + FactoryDto computedFactory = newDto(FactoryDto.class).withV(CURRENT_VERSION); + when(urlFactoryBuilder.createFactoryFromDevfile(anyString())) + .thenReturn(Optional.of(computedFactory)); + + githubFactoryParametersResolver.createFactory(singletonMap(URL_PARAMETER_NAME, githubUrl)); + + // check we called the builder with the following devfile + verify(urlFactoryBuilder).createFactoryFromDevfile(fileLocationArgumentCaptor.capture()); + assertEquals( + fileLocationArgumentCaptor.getValue(), + "https://raw.githubusercontent.com/eclipse/che/master/.devfile"); + // check project config built + verify(projectConfigDtoMerger) + .merge(any(FactoryDto.class), projectConfigDtoArgumentCaptor.capture()); + + ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue().get(); + + SourceStorageDto sourceStorageDto = projectConfigDto.getSource(); + assertNotNull(sourceStorageDto); + assertEquals(sourceStorageDto.getType(), "github"); assertEquals(sourceStorageDto.getLocation(), githubUrl); Map sourceParameters = sourceStorageDto.getParameters(); assertEquals(sourceParameters.size(), 1); @@ -145,32 +179,29 @@ public class GithubFactoryParametersResolverTest { String githubCloneUrl = "https://github.com/eclipse/che"; String githubBranch = "4.2.x"; - FactoryDto computedFactory = newDto(FactoryDto.class).withV("4.0"); - when(urlFactoryBuilder.createFactory(anyString())).thenReturn(computedFactory); + FactoryDto computedFactory = newDto(FactoryDto.class).withV(CURRENT_VERSION); + when(urlFactoryBuilder.createFactoryFromJson(anyString())) + .thenReturn(Optional.of(computedFactory)); githubFactoryParametersResolver.createFactory(singletonMap(URL_PARAMETER_NAME, githubUrl)); - // check we called the builder with the following codenvy json file - verify(urlFactoryBuilder).createFactory(jsonFileLocationArgumentCaptor.capture()); + // check we called the builder with the following factory json file + verify(urlFactoryBuilder).createFactoryFromJson(fileLocationArgumentCaptor.capture()); assertEquals( - jsonFileLocationArgumentCaptor.getValue(), + fileLocationArgumentCaptor.getValue(), "https://raw.githubusercontent.com/eclipse/che/4.2.x/.factory.json"); // check we provide dockerfile and correct env - verify(urlFactoryBuilder) - .buildWorkspaceConfig( - eq("che"), - eq("eclipse"), - eq("https://raw.githubusercontent.com/eclipse/che/4.2.x/.factory.dockerfile")); + verify(urlFactoryBuilder).buildDefaultWorkspaceConfig(eq("che")); // check project config built verify(projectConfigDtoMerger) .merge(any(FactoryDto.class), projectConfigDtoArgumentCaptor.capture()); - ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue(); + ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue().get(); SourceStorageDto sourceStorageDto = projectConfigDto.getSource(); assertNotNull(sourceStorageDto); - assertEquals(sourceStorageDto.getType(), "git"); + assertEquals(sourceStorageDto.getType(), "github"); assertEquals(sourceStorageDto.getLocation(), githubCloneUrl); Map sourceParameters = sourceStorageDto.getParameters(); assertEquals(sourceParameters.size(), 1); @@ -186,32 +217,29 @@ public class GithubFactoryParametersResolverTest { String githubBranch = "4.2.x"; String githubKeepdir = "dashboard"; - FactoryDto computedFactory = newDto(FactoryDto.class).withV("4.0"); - when(urlFactoryBuilder.createFactory(anyString())).thenReturn(computedFactory); + FactoryDto computedFactory = newDto(FactoryDto.class).withV(CURRENT_VERSION); + when(urlFactoryBuilder.createFactoryFromJson(anyString())) + .thenReturn(Optional.of(computedFactory)); githubFactoryParametersResolver.createFactory(singletonMap(URL_PARAMETER_NAME, githubUrl)); - // check we called the builder with the following codenvy json file - verify(urlFactoryBuilder).createFactory(jsonFileLocationArgumentCaptor.capture()); + // check we called the builder with the following factory json file + verify(urlFactoryBuilder).createFactoryFromJson(fileLocationArgumentCaptor.capture()); assertEquals( - jsonFileLocationArgumentCaptor.getValue(), + fileLocationArgumentCaptor.getValue(), "https://raw.githubusercontent.com/eclipse/che/4.2.x/.factory.json"); // check we provide dockerfile and correct env - verify(urlFactoryBuilder) - .buildWorkspaceConfig( - eq("che"), - eq("eclipse"), - eq("https://raw.githubusercontent.com/eclipse/che/4.2.x/.factory.dockerfile")); + verify(urlFactoryBuilder).buildDefaultWorkspaceConfig(eq("che")); // check project config built verify(projectConfigDtoMerger) .merge(any(FactoryDto.class), projectConfigDtoArgumentCaptor.capture()); - ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue(); + ProjectConfigDto projectConfigDto = projectConfigDtoArgumentCaptor.getValue().get(); SourceStorageDto sourceStorageDto = projectConfigDto.getSource(); assertNotNull(sourceStorageDto); - assertEquals(sourceStorageDto.getType(), "git"); + assertEquals(sourceStorageDto.getType(), "github"); assertEquals(sourceStorageDto.getLocation(), githubCloneUrl); Map sourceParameters = sourceStorageDto.getParameters(); assertEquals(sourceParameters.size(), 2); diff --git a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserTest.java b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserTest.java index 422a292dd1..0d9ba94ee8 100644 --- a/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserTest.java +++ b/plugins/plugin-github/che-plugin-github-factory-resolver/src/test/java/org/eclipse/che/plugin/github/factory/resolver/GithubURLParserTest.java @@ -17,7 +17,7 @@ import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import org.eclipse.che.plugin.urlfactory.URLFetcher; +import org.eclipse.che.api.factory.server.urlfactory.URLFetcher; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -37,7 +37,7 @@ public class GithubURLParserTest { @Mock private URLFetcher urlFetcher; /** Instance of component that will be tested. */ - @InjectMocks private GithubURLParserImpl githubUrlParser; + @InjectMocks private GithubURLParser githubUrlParser; /** Check invalid url (not a github one) */ @Test(expectedExceptions = IllegalArgumentException.class) @@ -113,17 +113,18 @@ public class GithubURLParserTest { "
\n" + "
\n" + "
\n" - + " \n" - + " Open\n" - + "
\n" - + "
" + + " \n" + + " Open\n" + + "
\n" + + "\n" + + "
\n" + "
\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 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 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);