workspaces incremental progress

This commit is contained in:
Jonathan Shook 2020-08-11 10:26:31 -05:00
parent 4e8370a6a3
commit 1b96f8876d
10 changed files with 274 additions and 57 deletions

View File

@ -4,11 +4,18 @@ package io.nosqlbench.docsys.api;
* Any class which is annotated with <pre>{@code @Service(WebServiceObject.class)}</pre> * Any class which is annotated with <pre>{@code @Service(WebServiceObject.class)}</pre>
* will be found and loaded as a service. * will be found and loaded as a service.
* *
* For the methods used to configure these objects, consult * For the methods used to configure these objects, consult the
* <A href="https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/jaxrs-resources.html#d0e2040">jax-rs resources documentation</A> * references below:
* *
* and * @see <A href="https://eclipse-ee4j.github.io/jersey.github
* <A href="https://jax-rs.github.io/apidocs/2.1/">Jax-RS API Docs</A> * .io/documentation/latest/jaxrs-resources.html#d0e2040">Jersey jax-rs
* resources documentation</A>
*
* @see <A href="https://github.com/jax-rs/spec/blob/master/spec
* .pdf">JAX-RS: Java™ API for RESTful Web Services Version 2.1
* Proposed Final Draft June 9, 2017</A>
**
* @see <A href="https://jax-rs.github.io/apidocs/2.1/">Jax-RS API Docs</A>
*/ */
public interface WebServiceObject { public interface WebServiceObject {
} }

View File

@ -17,6 +17,7 @@ import javax.ws.rs.core.MediaType;
@Singleton @Singleton
@Path("_") @Path("_")
public class DocServerStatusEndpoint implements WebServiceObject { public class DocServerStatusEndpoint implements WebServiceObject {
private final static Logger logger = private final static Logger logger =
LogManager.getLogger(DocServerStatusEndpoint.class); LogManager.getLogger(DocServerStatusEndpoint.class);

View File

@ -0,0 +1,32 @@
<template>
<v-app>
<v-app-bar app dark color="secondary">
<v-toolbar-title>NoSQLBench - Workspaces</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn text href="https://github.com/nosqlbench/nosqlbench/wiki/Submitting-Feedback">SUBMIT FEEDBACK</v-btn>
</v-toolbar-items>
</v-app-bar>
<v-layout justify-center align-center>
<v-content>
<v-card max-width="344">
<v-card-title>workspace-name</v-card-title>
<v-card-text>workspace details go here</v-card-text>
</v-card>
</v-content>
</v-layout>
</v-app>
</template>
<script>
export default {
name: "workspaces.vue"
}
</script>
<style scoped>
</style>

View File

@ -1,93 +1,103 @@
package io.nosqlbench.engine.rest.resources; package io.nosqlbench.engine.rest.resources;
import io.nosqlbench.docsys.api.WebServiceObject; import io.nosqlbench.docsys.api.WebServiceObject;
import io.nosqlbench.engine.rest.domain.WorkSpace; import io.nosqlbench.engine.rest.services.WorkspaceService;
import io.nosqlbench.engine.rest.transfertypes.WorkspaceView; import io.nosqlbench.engine.rest.transfertypes.WorkspaceView;
import io.nosqlbench.engine.rest.transfertypes.WorkspacesInfo;
import io.nosqlbench.nb.annotations.Service; import io.nosqlbench.nb.annotations.Service;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.*; import javax.ws.rs.*;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException; import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Optional; import java.util.List;
@Path("/services/workspaces") @Path("/services/workspaces/")
@Singleton @Singleton
@Service(WebServiceObject.class) @Service(WebServiceObject.class)
public class WorkspacesEndpoint implements WebServiceObject { public class WorkspacesEndpoint implements WebServiceObject {
private final static java.nio.file.Path workspacesRoot = Paths.get("workspaces"); private final static Logger logger =
LogManager.getLogger(WorkspacesEndpoint.class);
public static final String WORKSPACE_ROOT = "workspace_root";
@Context
private Configuration config;
private final static java.nio.file.Path workspacesRoot = Paths.get("workspaces");
private WorkspaceService svc;
/**
* @return A list of workspaces as a
* {@link List} of {@link WorkspaceView}
*/
@GET @GET
@Path("")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response listWorkspaces() { public Response getWorkspacesInfo() {
WorkspacesInfo info = new WorkspacesInfo(workspacesRoot); List<WorkspaceView> wsviews = getSvc().getWorkspaceViews();
return Response.ok(info).build(); return Response.ok(wsviews).build();
} }
@GET @GET
@Path("{workspace}") @Path("{workspace}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response listWorkspace(@PathParam("workspace") String workspace) { public Response getWorkspaceInfo(@PathParam("workspace") String workspace) {
WorkspaceView view = new WorkspaceView(workspace); WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
return Response.ok(view).build(); return Response.ok(workpaceView).build();
}
@POST
@Path("{workspaceName}/upload/{filepath}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileIntoWorkspace(
) {
return Response.ok().build();
} }
@POST @POST
@Path("{workspaceName}/{filepath}") @Path("{workspaceName}/{filepath}")
@Consumes(MediaType.APPLICATION_OCTET_STREAM) public Response putFileInWorkspace(
public Response putFile( @PathParam("workspaceName") String workspaceName,
@PathParam("workspaceName") String workspaceName, @PathParam("filepath") String filename,
@PathParam("filepath") String filename ByteBuffer content
) { ) {
WorkSpace workspace = getWorkspace(workspaceName); try {
Optional<Path> puttedFile = workspace.put(workspace); getSvc().putFile(workspaceName, filename, content);
if (puttedFile.isPresent()) {
return Response.ok().build(); return Response.ok().build();
} else { } catch (Exception e) {
return Response.status(Response.Status.BAD_REQUEST).build(); return Response.status(Response.Status.BAD_REQUEST).build();
} }
} }
@GET @GET
@Path("{workspaceName}/{filename}") @Path("{workspaceName}/{filename}")
public Response getFile( public Response getFileInWorkspace(
@PathParam("workspaceName") String workspaceName, @PathParam("workspaceName") String workspaceName,
@PathParam("filename") String filename) { @PathParam("filename") String filename) {
WorkSpace workSpace = new WorkSpace(workspacesRoot, workspaceName); try {
Optional<java.nio.file.Path> optFile = workSpace.get(filename); WorkspaceService.FileInfo fileinfo = getSvc().readFile(workspaceName, filename);
if (fileinfo != null) {
if (optFile.isPresent()) { return Response.ok(fileinfo.getContent(), fileinfo.getMediaType()).build();
try { } else {
java.nio.file.Path filepath = optFile.get(); return Response.noContent().status(Response.Status.NOT_FOUND).build();
String contentType = Files.probeContentType(filepath);
MediaType mediaType = MediaType.valueOf(contentType);
byte[] bytes = Files.readAllBytes(filepath);
return Response.ok(bytes, mediaType).build();
} catch (IOException e) {
throw new RuntimeException(e);
} }
} else { } catch (Exception e) {
return Response.noContent().status(Response.Status.NOT_FOUND).build(); return Response.serverError().entity(e.getMessage()).build();
} }
} }
private WorkspaceService getSvc() {
private WorkSpace getWorkspace(String workspace) { if (svc == null) {
if (!workspace.matches("[a-zA-Z][a-zA-Z0-9]+")) { svc = new WorkspaceService(config.getProperties().get(WORKSPACE_ROOT));
throw new RuntimeException("Workspaces must start with an alphabetic" +
" character, and contain only letters and numbers.");
} }
WorkSpace workSpace = new WorkSpace(workspacesRoot, workspace); return svc;
return workSpace;
} }
} }

View File

@ -0,0 +1,134 @@
package io.nosqlbench.engine.rest.services;
import io.nosqlbench.engine.rest.transfertypes.WorkspaceView;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
public class WorkspaceService {
private final Path root;
public static String DEFAULT = "default";
public WorkspaceService(Object root) {
if (root instanceof Path) {
this.root = (Path) root;
} else if (root instanceof CharSequence) {
this.root = Paths.get(((CharSequence) root).toString());
} else if (root == null) {
this.root = Paths.get(System.getProperty("user.dir"),
"workspaces");
try {
Files.createDirectories(this.root);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException("Unable to use workspaces root " +
"path of type " + root.getClass().getCanonicalName());
}
createDefaultIfNotExist();
}
private void createDefaultIfNotExist() {
getWorkspaceView(DEFAULT);
}
public List<WorkspaceView> getWorkspaceViews() {
List<WorkspaceView> views = new ArrayList<>();
DirectoryStream<Path> wsrEntries = null;
try {
wsrEntries = Files.newDirectoryStream(root);
} catch (IOException e) {
throw new RuntimeException(e);
}
for (Path entry : wsrEntries) {
views.add(new WorkspaceView(entry));
}
return views;
}
public WorkspaceView getWorkspaceView(String workspace) {
if (!workspace.matches("[a-zA-Z][a-zA-Z0-9]+")) {
throw new RuntimeException("Workspaces must start with an alphabetic" +
" character, and contain only letters and numbers.");
}
Path wspath = root.resolve(Paths.get(workspace));
if (!Files.exists(wspath)) {
try {
Files.createDirectories(wspath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return new WorkspaceView(wspath);
}
public void putFile(String workspaceName, String filename, ByteBuffer content) {
Path toWrite = root.resolve(workspaceName).resolve(filename);
try {
Files.write(toWrite, content.array(),
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Read the bytes of the named file in the named workspace.
*
* @param workspaceName The workspace name to look in for the file
* @param filename The filename within the workspace to read
* @return null if the file is not found
* @throws RuntimeException if the file was found but could not be
* read.
*/
public FileInfo readFile(String workspaceName, String filename) {
Path filePath = workspacePath(workspaceName).resolve(filename);
if (Files.exists(filePath)) {
return new FileInfo(filePath);
} else {
return null;
}
}
private Path workspacePath(String workspaceName) {
return root.resolve(workspaceName);
}
public final static class FileInfo {
private final Path path;
public FileInfo(Path path) {
this.path = path;
}
public MediaType getMediaType() {
try {
String contentType = Files.probeContentType(path);
MediaType mediaType = MediaType.valueOf(contentType);
return mediaType;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public ByteBuffer getContent() {
byte[] bytes = new byte[0];
try {
bytes = Files.readAllBytes(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
return ByteBuffer.wrap(bytes);
}
}
}

View File

@ -0,0 +1,11 @@
/**
* Classes in this package are meant to provide a basic
* internal service facade to be used by endpoints.
* This simplifies endpoint implementations and facilitates DRY
* implementations.
*
* These implementations should only expose primitive types,
* collections of primitive types, or views of transfer types
* as implemented in that package.
*/
package io.nosqlbench.engine.rest.services;

View File

@ -1,10 +1,16 @@
package io.nosqlbench.engine.rest.transfertypes; package io.nosqlbench.engine.rest.transfertypes;
import java.nio.file.Path;
public class WorkspaceView { public class WorkspaceView {
private final String workspace; private final Path workspaceRoot;
public WorkspaceView(String workspace) { public WorkspaceView(Path workspaceRoot) {
this.workspace = workspace; this.workspaceRoot = workspaceRoot;
}
public String getName() {
return workspaceRoot.getFileName().toString();
} }
} }

View File

@ -7,10 +7,10 @@ import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class WorkspacesInfo { public class WorkspacesView {
private Path workspacesRoot; private Path workspacesRoot;
public WorkspacesInfo(Path workspacesRoot) { public WorkspacesView(Path workspacesRoot) {
this.workspacesRoot = workspacesRoot; this.workspacesRoot = workspacesRoot;
} }

View File

@ -0,0 +1,13 @@
/**
* Types in this package are meant to provide a mapping
* between internal state and external views. Specifically,
* these types should only include details which are meant to
* be shared by endpoints. This can be achieved by wrapping
* internal state and exposing only the visible properties, or
* it can be done by implementing types which are built from
* common internal types.
*
* Service objects in the services package should only provide
* primitive values or the view types from this package.
*/
package io.nosqlbench.engine.rest.transfertypes;

View File

@ -27,3 +27,6 @@ echo "Do mvn release:prepare..."
#mvn $MAVEN_REPO_LOCAL --batch-mode --global-settings release.xml -Dusername=$GITHUB_ACCESS_TOKEN release:prepare #mvn $MAVEN_REPO_LOCAL --batch-mode --global-settings release.xml -Dusername=$GITHUB_ACCESS_TOKEN release:prepare
mvn --batch-mode --global-settings release.xml -Dusername=$GITHUB_ACCESS_TOKEN clean release:prepare -DdevelopmentVersion=${NEXT_SNAPSHOT} -DreleaseVersion=${RELEASE_VERSION} mvn --batch-mode --global-settings release.xml -Dusername=$GITHUB_ACCESS_TOKEN clean release:prepare -DdevelopmentVersion=${NEXT_SNAPSHOT} -DreleaseVersion=${RELEASE_VERSION}
echo "files after release:prepare..."
pwd
ls -l