Revert "Devfile validation via message entity provider" (#14812)
This reverts commit fc531ea015.
7.20.x
parent
70d0933cd9
commit
720aab0051
|
|
@ -42,7 +42,6 @@ import org.eclipse.che.api.user.server.jpa.JpaPreferenceDao;
|
|||
import org.eclipse.che.api.user.server.jpa.JpaUserDao;
|
||||
import org.eclipse.che.api.user.server.spi.PreferenceDao;
|
||||
import org.eclipse.che.api.user.server.spi.UserDao;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceEntityProvider;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceLockService;
|
||||
import org.eclipse.che.api.workspace.server.WorkspaceStatusCache;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileModule;
|
||||
|
|
@ -149,7 +148,6 @@ public class WsMasterModule extends AbstractModule {
|
|||
|
||||
install(new DevfileModule());
|
||||
|
||||
bind(WorkspaceEntityProvider.class);
|
||||
bind(org.eclipse.che.api.workspace.server.TemporaryWorkspaceRemover.class);
|
||||
bind(org.eclipse.che.api.workspace.server.WorkspaceService.class);
|
||||
install(new FactoryModuleBuilder().build(ServersCheckerFactory.class));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,5 @@ public class CoreRestModule extends AbstractModule {
|
|||
bind(RuntimeExceptionMapper.class);
|
||||
bind(ApiInfo.class).toProvider(ApiInfoProvider.class);
|
||||
Multibinder.newSetBinder(binder(), Class.class, Names.named("che.json.ignored_classes"));
|
||||
bind(WebApplicationExceptionMapper.class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,89 +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.api.core.rest;
|
||||
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.ForbiddenException;
|
||||
import javax.ws.rs.NotAcceptableException;
|
||||
import javax.ws.rs.NotAllowedException;
|
||||
import javax.ws.rs.NotAuthorizedException;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.NotSupportedException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
|
||||
/**
|
||||
* Mapper for the {@link WebApplicationException} exceptions.
|
||||
*
|
||||
* @author Max Shaposhnyk
|
||||
*/
|
||||
@Provider
|
||||
@Singleton
|
||||
public class WebApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(WebApplicationException exception) {
|
||||
|
||||
ServiceError error = newDto(ServiceError.class).withMessage(exception.getMessage());
|
||||
|
||||
if (exception instanceof BadRequestException) {
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof ForbiddenException) {
|
||||
return Response.status(Response.Status.FORBIDDEN)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof NotFoundException) {
|
||||
return Response.status(Response.Status.NOT_FOUND)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof NotAuthorizedException) {
|
||||
return Response.status(Response.Status.UNAUTHORIZED)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof NotAcceptableException) {
|
||||
return Response.status(Status.NOT_ACCEPTABLE)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof NotAllowedException) {
|
||||
return Response.status(Status.METHOD_NOT_ALLOWED)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else if (exception instanceof NotSupportedException) {
|
||||
return Response.status(Status.UNSUPPORTED_MEDIA_TYPE)
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
} else {
|
||||
return Response.serverError()
|
||||
.entity(DtoFactory.getInstance().toJson(error))
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,7 +158,7 @@ public class WorkspacePermissionsFilterTest {
|
|||
.post(SECURE_PATH + "/workspace/devfile?namespace=userok");
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(workspaceService).create(any(DevfileDto.class), any(), any(), eq("userok"), any());
|
||||
verify(workspaceService).create(anyString(), any(), any(), eq("userok"), any());
|
||||
verify(permissionsFilter).checkAccountPermissions("userok", AccountOperation.CREATE_WORKSPACE);
|
||||
verifyZeroInteractions(subject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,138 +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.api.workspace.server;
|
||||
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static org.eclipse.che.api.workspace.server.DtoConverter.asDto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.ext.MessageBodyReader;
|
||||
import javax.ws.rs.ext.MessageBodyWriter;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileManager;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||
import org.eclipse.che.api.workspace.server.dto.DtoServerImpls.WorkspaceDtoImpl;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
|
||||
/**
|
||||
* Entity provider for {@link WorkspaceDto}. Performs schema validation of devfile part of the
|
||||
* workspace before actual {@link DevfileDto} creation.
|
||||
*
|
||||
* @author Max Shaposhnyk
|
||||
*/
|
||||
@Singleton
|
||||
@Provider
|
||||
@Produces({APPLICATION_JSON})
|
||||
@Consumes({APPLICATION_JSON})
|
||||
public class WorkspaceEntityProvider
|
||||
implements MessageBodyReader<WorkspaceDto>, MessageBodyWriter<WorkspaceDto> {
|
||||
|
||||
private DevfileManager devfileManager;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Inject
|
||||
public WorkspaceEntityProvider(DevfileManager devfileManager) {
|
||||
this.devfileManager = devfileManager;
|
||||
SimpleModule module = new SimpleModule();
|
||||
module.addDeserializer(DevfileDto.class, new DevfileDtoDeserializer());
|
||||
mapper.registerModule(module);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(
|
||||
Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
|
||||
return type == WorkspaceDto.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkspaceDto readFrom(
|
||||
Class<WorkspaceDto> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType,
|
||||
MultivaluedMap<String, String> httpHeaders,
|
||||
InputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
return mapper
|
||||
.readerFor(WorkspaceDtoImpl.class)
|
||||
.without(DeserializationFeature.WRAP_EXCEPTIONS)
|
||||
.readValue(entityStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(
|
||||
Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
|
||||
return WorkspaceDto.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize(
|
||||
WorkspaceDto workspaceDto,
|
||||
Class<?> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(
|
||||
WorkspaceDto workspaceDto,
|
||||
Class<?> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType,
|
||||
MultivaluedMap<String, Object> httpHeaders,
|
||||
OutputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
httpHeaders.putSingle(HttpHeaders.CACHE_CONTROL, "public, no-cache, no-store, no-transform");
|
||||
try (Writer w = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) {
|
||||
w.write(DtoFactory.getInstance().toJson(workspaceDto));
|
||||
w.flush();
|
||||
}
|
||||
}
|
||||
|
||||
class DevfileDtoDeserializer extends JsonDeserializer<DevfileDto> {
|
||||
@Override
|
||||
public DevfileDto deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
try {
|
||||
return asDto(devfileManager.parseJson(p.readValueAsTree().toString()));
|
||||
} catch (DevfileFormatException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,12 +17,14 @@ import static java.util.Collections.emptyMap;
|
|||
import static java.util.stream.Collectors.toList;
|
||||
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
|
||||
import static org.eclipse.che.api.workspace.server.DtoConverter.asDto;
|
||||
import static org.eclipse.che.api.workspace.server.WorkspaceKeyValidator.validateKey;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_AUTO_START;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_DEVFILE_REGISTRY_URL_PROPERTY;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
|
|
@ -64,13 +66,16 @@ import org.eclipse.che.api.core.ValidationException;
|
|||
import org.eclipse.che.api.core.model.workspace.Workspace;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
|
||||
import org.eclipse.che.api.core.rest.Service;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileManager;
|
||||
import org.eclipse.che.api.workspace.server.devfile.FileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineAccessForbidden;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenException;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenProvider;
|
||||
|
|
@ -84,7 +89,6 @@ import org.eclipse.che.api.workspace.shared.dto.RuntimeDto;
|
|||
import org.eclipse.che.api.workspace.shared.dto.ServerDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
|
||||
|
|
@ -106,6 +110,7 @@ public class WorkspaceService extends Service {
|
|||
private final String apiEndpoint;
|
||||
private final boolean cheWorkspaceAutoStart;
|
||||
private final FileContentProvider devfileContentProvider;
|
||||
private final DevfileManager devfileManager;
|
||||
|
||||
@Inject
|
||||
public WorkspaceService(
|
||||
|
|
@ -116,7 +121,8 @@ public class WorkspaceService extends Service {
|
|||
WorkspaceLinksGenerator linksGenerator,
|
||||
@Named(CHE_WORKSPACE_PLUGIN_REGISTRY_URL_PROPERTY) @Nullable String pluginRegistryUrl,
|
||||
@Named(CHE_WORKSPACE_DEVFILE_REGISTRY_URL_PROPERTY) @Nullable String devfileRegistryUrl,
|
||||
URLFetcher urlFetcher) {
|
||||
URLFetcher urlFetcher,
|
||||
DevfileManager devfileManager) {
|
||||
this.apiEndpoint = apiEndpoint;
|
||||
this.cheWorkspaceAutoStart = cheWorkspaceAutoStart;
|
||||
this.workspaceManager = workspaceManager;
|
||||
|
|
@ -125,6 +131,7 @@ public class WorkspaceService extends Service {
|
|||
this.pluginRegistryUrl = pluginRegistryUrl;
|
||||
this.devfileRegistryUrl = devfileRegistryUrl;
|
||||
this.devfileContentProvider = new URLFileContentProvider(null, urlFetcher);
|
||||
this.devfileManager = devfileManager;
|
||||
}
|
||||
|
||||
@POST
|
||||
|
|
@ -189,12 +196,16 @@ public class WorkspaceService extends Service {
|
|||
return Response.status(201).entity(asDtoWithLinksAndToken(workspace)).build();
|
||||
}
|
||||
|
||||
@Beta
|
||||
@Path("/devfile")
|
||||
@POST
|
||||
@Consumes({APPLICATION_JSON, "text/yaml", "text/x-yaml"})
|
||||
@Produces(APPLICATION_JSON)
|
||||
@ApiOperation(
|
||||
value = "Creates a new workspace based on the Devfile.",
|
||||
notes =
|
||||
"This method is in beta phase. It's strongly recommended to use `POST /devfile` instead"
|
||||
+ " to get a workspace from Devfile. Workspaces created with this method are not stable yet.",
|
||||
consumes = "application/json, text/yaml, text/x-yaml",
|
||||
produces = APPLICATION_JSON,
|
||||
nickname = "createFromDevfile",
|
||||
|
|
@ -211,8 +222,7 @@ public class WorkspaceService extends Service {
|
|||
@ApiResponse(code = 500, message = "Internal server error occurred")
|
||||
})
|
||||
public Response create(
|
||||
@ApiParam(value = "The devfile of the workspace to create", required = true)
|
||||
DevfileDto devfile,
|
||||
@ApiParam(value = "The devfile of the workspace to create", required = true) String devfile,
|
||||
@ApiParam(
|
||||
value =
|
||||
"Workspace attribute defined in 'attrName:attrValue' format. "
|
||||
|
|
@ -232,15 +242,29 @@ public class WorkspaceService extends Service {
|
|||
throws ConflictException, BadRequestException, ForbiddenException, NotFoundException,
|
||||
ServerException {
|
||||
requiredNotNull(devfile, "Devfile");
|
||||
|
||||
DevfileImpl devfileModel;
|
||||
try {
|
||||
if (APPLICATION_JSON_TYPE.isCompatible(contentType)) {
|
||||
devfileModel = devfileManager.parseJson(devfile);
|
||||
} else {
|
||||
devfileModel = devfileManager.parseYaml(devfile);
|
||||
}
|
||||
} catch (DevfileException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
|
||||
final Map<String, String> attributes = parseAttrs(attrsList);
|
||||
|
||||
if (namespace == null) {
|
||||
namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
|
||||
}
|
||||
|
||||
WorkspaceImpl workspace;
|
||||
try {
|
||||
workspace =
|
||||
workspaceManager.createWorkspace(
|
||||
devfile,
|
||||
devfileModel,
|
||||
namespace,
|
||||
attributes,
|
||||
// create a new cache for each request so that we don't have to care about lifetime
|
||||
|
|
|
|||
|
|
@ -1,140 +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.api.workspace.server.devfile;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static org.eclipse.che.api.workspace.server.DtoConverter.asDto;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.NotSupportedException;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.ext.MessageBodyReader;
|
||||
import javax.ws.rs.ext.MessageBodyWriter;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
import org.eclipse.che.dto.server.DtoFactory;
|
||||
|
||||
/**
|
||||
* Parses {@link DevfileDto} either from Json or yaml content, and performs schema validation before
|
||||
* the actual DTO created.
|
||||
*
|
||||
* @author Max Shaposhnyk
|
||||
*/
|
||||
@Singleton
|
||||
@Provider
|
||||
@Produces({APPLICATION_JSON})
|
||||
@Consumes({APPLICATION_JSON, "text/yaml", "text/x-yaml"})
|
||||
public class DevfileEntityProvider
|
||||
implements MessageBodyReader<DevfileDto>, MessageBodyWriter<DevfileDto> {
|
||||
|
||||
private DevfileManager devfileManager;
|
||||
|
||||
@Inject
|
||||
public DevfileEntityProvider(DevfileManager devfileManager) {
|
||||
this.devfileManager = devfileManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable(
|
||||
Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
|
||||
return type == DevfileDto.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevfileDto readFrom(
|
||||
Class<DevfileDto> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType,
|
||||
MultivaluedMap<String, String> httpHeaders,
|
||||
InputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
|
||||
try {
|
||||
if (mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
|
||||
return asDto(
|
||||
devfileManager.parseJson(
|
||||
CharStreams.toString(
|
||||
new InputStreamReader(entityStream, getCharsetOrUtf8(mediaType)))));
|
||||
} else if (mediaType.isCompatible(MediaType.valueOf("text/yaml"))
|
||||
|| mediaType.isCompatible(MediaType.valueOf("text/x-yaml"))) {
|
||||
return asDto(
|
||||
devfileManager.parseYaml(
|
||||
CharStreams.toString(
|
||||
new InputStreamReader(entityStream, getCharsetOrUtf8(mediaType)))));
|
||||
}
|
||||
} catch (DevfileFormatException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
throw new NotSupportedException("Unknown media type " + mediaType.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWriteable(
|
||||
Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
|
||||
return DevfileDto.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize(
|
||||
DevfileDto devfileDto,
|
||||
Class<?> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(
|
||||
DevfileDto devfileDto,
|
||||
Class<?> type,
|
||||
Type genericType,
|
||||
Annotation[] annotations,
|
||||
MediaType mediaType,
|
||||
MultivaluedMap<String, Object> httpHeaders,
|
||||
OutputStream entityStream)
|
||||
throws IOException, WebApplicationException {
|
||||
httpHeaders.putSingle(HttpHeaders.CACHE_CONTROL, "public, no-cache, no-store, no-transform");
|
||||
try (Writer w = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) {
|
||||
w.write(DtoFactory.getInstance().toJson(devfileDto));
|
||||
w.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private String getCharsetOrUtf8(MediaType mediaType) {
|
||||
String charset = mediaType == null ? null : mediaType.getParameters().get("charset");
|
||||
if (isNullOrEmpty(charset)) {
|
||||
charset = "UTF-8";
|
||||
}
|
||||
return charset;
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,6 @@ public class DevfileModule extends AbstractModule {
|
|||
@Override
|
||||
protected void configure() {
|
||||
bind(DevfileService.class);
|
||||
bind(DevfileEntityProvider.class);
|
||||
|
||||
DevfileBindings.onWorkspaceApplierBinder(
|
||||
binder(),
|
||||
|
|
|
|||
|
|
@ -1,59 +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.api.workspace.server;
|
||||
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileManager;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
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;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class WorkspaceEntityProviderTest {
|
||||
|
||||
@Mock private DevfileManager devfileManager;
|
||||
|
||||
@InjectMocks private WorkspaceEntityProvider workspaceEntityProvider;
|
||||
|
||||
@Test
|
||||
public void shouldBuildDtoFromValidJson() throws Exception {
|
||||
|
||||
when(devfileManager.parseJson(anyString())).thenReturn(new DevfileImpl());
|
||||
|
||||
WorkspaceDto actual = newDto(WorkspaceDto.class).withDevfile(newDto(DevfileDto.class));
|
||||
|
||||
workspaceEntityProvider.readFrom(
|
||||
WorkspaceDto.class,
|
||||
WorkspaceDto.class,
|
||||
null,
|
||||
MediaType.APPLICATION_JSON_TYPE,
|
||||
new MultivaluedHashMap<>(),
|
||||
new ByteArrayInputStream(
|
||||
DtoFactory.getInstance().toJson(actual).getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
verify(devfileManager).parseJson(anyString());
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,6 @@ import java.util.Map;
|
|||
import org.eclipse.che.account.shared.model.Account;
|
||||
import org.eclipse.che.account.spi.AccountImpl;
|
||||
import org.eclipse.che.api.core.Page;
|
||||
import org.eclipse.che.api.core.ValidationException;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
import org.eclipse.che.api.core.model.workspace.config.ProjectConfig;
|
||||
|
|
@ -63,7 +62,9 @@ import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus;
|
|||
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
|
||||
import org.eclipse.che.api.core.rest.CheJsonProvider;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileManager;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.MachineConfigImpl;
|
||||
|
|
@ -73,6 +74,7 @@ import org.eclipse.che.api.workspace.server.model.impl.RuntimeImpl;
|
|||
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
|
||||
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.server.model.impl.devfile.DevfileImpl;
|
||||
import org.eclipse.che.api.workspace.server.token.MachineTokenProvider;
|
||||
import org.eclipse.che.api.workspace.shared.Constants;
|
||||
import org.eclipse.che.api.workspace.shared.dto.CommandDto;
|
||||
|
|
@ -132,6 +134,7 @@ public class WorkspaceServiceTest {
|
|||
@Mock private WorkspaceManager wsManager;
|
||||
@Mock private MachineTokenProvider machineTokenProvider;
|
||||
@Mock private WorkspaceLinksGenerator linksGenerator;
|
||||
@Mock private DevfileManager devfileManager;
|
||||
@Mock private URLFetcher urlFetcher;
|
||||
|
||||
private WorkspaceService service;
|
||||
|
|
@ -147,7 +150,8 @@ public class WorkspaceServiceTest {
|
|||
linksGenerator,
|
||||
CHE_WORKSPACE_PLUGIN_REGISTRY_ULR,
|
||||
CHE_WORKSPACE_DEVFILE_REGISTRY_ULR,
|
||||
urlFetcher);
|
||||
urlFetcher,
|
||||
devfileManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -189,6 +193,8 @@ public class WorkspaceServiceTest {
|
|||
final DevfileDto devfileDto = createDevfileDto();
|
||||
final WorkspaceImpl workspace = createWorkspace(devfileDto);
|
||||
|
||||
when(devfileManager.parseJson(any())).thenReturn(new DevfileImpl());
|
||||
|
||||
when(wsManager.createWorkspace(any(Devfile.class), anyString(), any(), any()))
|
||||
.thenReturn(workspace);
|
||||
|
||||
|
|
@ -220,13 +226,52 @@ public class WorkspaceServiceTest {
|
|||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAcceptYamlDevfileWhenCreatingWorkspace() throws Exception {
|
||||
final DevfileDto devfileDto = createDevfileDto();
|
||||
final WorkspaceImpl workspace = createWorkspace(devfileDto);
|
||||
|
||||
when(devfileManager.parseYaml(any())).thenReturn(new DevfileImpl());
|
||||
|
||||
when(wsManager.createWorkspace(any(Devfile.class), anyString(), any(), any()))
|
||||
.thenReturn(workspace);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
.auth()
|
||||
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
|
||||
.contentType("text/yaml")
|
||||
.when()
|
||||
.post(
|
||||
SECURE_PATH
|
||||
+ "/workspace/devfile"
|
||||
+ "?namespace=test"
|
||||
+ "&attribute=factoryId:factory123"
|
||||
+ "&attribute=custom:custom:value");
|
||||
|
||||
assertEquals(response.getStatusCode(), 201);
|
||||
assertEquals(
|
||||
new WorkspaceImpl(unwrapDto(response, WorkspaceDto.class), TEST_ACCOUNT), workspace);
|
||||
verify(wsManager)
|
||||
.createWorkspace(
|
||||
any(Devfile.class),
|
||||
eq("test"),
|
||||
eq(
|
||||
ImmutableMap.of(
|
||||
"factoryId", "factory123",
|
||||
"custom", "custom:value")),
|
||||
any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnBadRequestOnInvalidDevfile() throws Exception {
|
||||
final DevfileDto devfileDto = createDevfileDto();
|
||||
final WorkspaceImpl workspace = createWorkspace(devfileDto);
|
||||
|
||||
when(devfileManager.parseJson(any())).thenThrow(new DevfileFormatException("boom"));
|
||||
|
||||
when(wsManager.createWorkspace(any(Devfile.class), anyString(), any(), any()))
|
||||
.thenThrow(new ValidationException("boom"));
|
||||
.thenReturn(workspace);
|
||||
|
||||
final Response response =
|
||||
given()
|
||||
|
|
@ -245,6 +290,8 @@ public class WorkspaceServiceTest {
|
|||
assertEquals(response.getStatusCode(), 400);
|
||||
String error = unwrapError(response);
|
||||
assertEquals(error, "boom");
|
||||
|
||||
verify(wsManager, never()).createWorkspace(any(Devfile.class), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -1,81 +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.api.workspace.server.devfile;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import javax.ws.rs.NotSupportedException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedHashMap;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class DevfileEntityProviderTest {
|
||||
|
||||
@Mock private DevfileManager devfileManager;
|
||||
|
||||
@InjectMocks private DevfileEntityProvider devfileEntityProvider;
|
||||
|
||||
@Test
|
||||
public void shouldBuildDtoFromValidYaml() throws Exception {
|
||||
|
||||
when(devfileManager.parseYaml(anyString())).thenReturn(new DevfileImpl());
|
||||
|
||||
devfileEntityProvider.readFrom(
|
||||
DevfileDto.class,
|
||||
DevfileDto.class,
|
||||
null,
|
||||
MediaType.valueOf("text/x-yaml"),
|
||||
new MultivaluedHashMap<>(),
|
||||
getClass().getClassLoader().getResourceAsStream("devfile/devfile.yaml"));
|
||||
|
||||
verify(devfileManager).parseYaml(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBuildDtoFromValidJson() throws Exception {
|
||||
|
||||
when(devfileManager.parseJson(anyString())).thenReturn(new DevfileImpl());
|
||||
|
||||
devfileEntityProvider.readFrom(
|
||||
DevfileDto.class,
|
||||
DevfileDto.class,
|
||||
null,
|
||||
MediaType.APPLICATION_JSON_TYPE,
|
||||
new MultivaluedHashMap<>(),
|
||||
getClass().getClassLoader().getResourceAsStream("devfile/devfile.json"));
|
||||
|
||||
verify(devfileManager).parseJson(anyString());
|
||||
}
|
||||
|
||||
@Test(
|
||||
expectedExceptions = NotSupportedException.class,
|
||||
expectedExceptionsMessageRegExp = "Unknown media type text/plain")
|
||||
public void shouldThrowErrorOnInvalidMediaType() throws Exception {
|
||||
|
||||
devfileEntityProvider.readFrom(
|
||||
DevfileDto.class,
|
||||
DevfileDto.class,
|
||||
null,
|
||||
MediaType.TEXT_PLAIN_TYPE,
|
||||
new MultivaluedHashMap<>(),
|
||||
getClass().getClassLoader().getResourceAsStream("devfile/devfile.json"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
{
|
||||
"apiVersion": "1.0.0",
|
||||
"metadata": {
|
||||
"name": "petclinic-dev-environment",
|
||||
"generateName": "petclinic-"
|
||||
},
|
||||
"projects": [
|
||||
{
|
||||
"name": "petclinic",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"location": "git@github.com:spring-projects/spring-petclinic.git"
|
||||
}
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"alias": "mvn-stack",
|
||||
"type": "chePlugin",
|
||||
"id": "eclipse/chemaven-jdk8/1.0.0"
|
||||
},
|
||||
{
|
||||
"type": "cheEditor",
|
||||
"id": "eclipse/che-theia/0.0.3"
|
||||
},
|
||||
{
|
||||
"alias": "jdt.ls",
|
||||
"type": "chePlugin",
|
||||
"id": "org.eclipse.chetheia-jdtls:0.0.3",
|
||||
"preferences": {
|
||||
"java.home": "/home/user/jdk11",
|
||||
"java.jdt.ls.vmargs": "-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication",
|
||||
"java.jtg.memory": 12345,
|
||||
"java.boolean": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "openshift",
|
||||
"reference": "petclinic.yaml",
|
||||
"selector": {
|
||||
"app.kubernetes.io/name": "mysql",
|
||||
"app.kubernetes.io/component": "database",
|
||||
"app.kubernetes.io/part-of": "petclinic"
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"name": "build",
|
||||
"actions": [
|
||||
{
|
||||
"type": "exec",
|
||||
"component": "mvn-stack",
|
||||
"command": "mvn package",
|
||||
"workdir": "/projects/spring-petclinic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "run",
|
||||
"attributes": {
|
||||
"runType": "sequential"
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"type": "exec",
|
||||
"component": "mvn-stack",
|
||||
"command": "mvn spring-boot:run",
|
||||
"workdir": "/projects/spring-petclinic"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "other",
|
||||
"actions": [
|
||||
{
|
||||
"type": "exec",
|
||||
"component": "jdt.ls",
|
||||
"command": "run.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue