project restructuring

This commit is contained in:
Jonathan Shook
2024-04-11 22:50:13 -05:00
parent 7810178f0c
commit 4358344029
2892 changed files with 1134 additions and 821 deletions

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys;
import io.nosqlbench.nb.api.docsapi.Docs;
import io.nosqlbench.nb.api.docsapi.DocsBinder;
import io.nosqlbench.docsys.api.DocsysStaticManifest;
//@Service(DocsysStaticManifest.class)
public class DocsysDefaultAppPath implements DocsysStaticManifest {
@Override
public DocsBinder getDocs() {
return new Docs().namespace("docsys-default-app").addFirstFoundPath(
"docsys/src/main/resources/docsys-guidebook/",
"docsys-guidebook/")
.setEnabledByDefault(true)
.asDocsBinder();
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.api;
import io.nosqlbench.nb.api.docsapi.DocsBinder;
public interface DocsysDynamicManifest {
DocsBinder getDocs();
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.api;
import io.nosqlbench.nb.api.docsapi.DocsBinder;
/**
* At runtime, any instances of this service will be used to find
* paths to be hosted as static content.
*/
public interface DocsysStaticManifest {
DocsBinder getDocs();
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.api;
/**
* Any class which is annotated with <pre>{@code @Service(WebServiceObject.class)}</pre>
* will be found and loaded as a service.
*
* For the methods used to configure these objects, consult the
* references below:
*
* @see <A href="https://eclipse-ee4j.github.io/jersey.github
* .io/documentation/latest/jaxrs-resources.html#d0e2040">Jersey jax-rs
* resources documentation</A>
*
* @see <A href="https://repo1.maven.org/maven2/org/glassfish/jersey/jersey-documentation/2.5
* .1/jersey-documentation-2.5.1-user-guide.pdf">Jersey 2.5.1 user guide</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 {
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.core;
import io.nosqlbench.nb.api.docsapi.Docs;
import io.nosqlbench.nb.api.docsapi.DocsBinder;
import io.nosqlbench.nb.api.docsapi.DocsNameSpaceImpl;
import io.nosqlbench.docsys.api.DocsysDynamicManifest;
import io.nosqlbench.docsys.api.DocsysStaticManifest;
import java.util.ServiceLoader;
/**
* The standard way to load and use all of the {@link DocsNameSpaceImpl}
* instances which are present in the runtime via SPI.
*
* This implementation ensures that names space collisions are known.
*/
public class DocsysPathLoader {
public static DocsBinder loadStaticPaths() {
ServiceLoader<DocsysStaticManifest> loader = ServiceLoader.load(DocsysStaticManifest.class);
Docs docs = new Docs();
for (DocsysStaticManifest docPathInfos : loader) {
docs.merge(docPathInfos.getDocs());
}
return docs;
}
public static DocsBinder loadDynamicPaths() {
ServiceLoader<DocsysDynamicManifest> loader = ServiceLoader.load(DocsysDynamicManifest.class);
Docs docs = new Docs();
for (DocsysDynamicManifest docPathInfos : loader) {
docs.merge(docPathInfos.getDocs());
}
return docs;
}
}

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.core;
import io.nosqlbench.docsys.DocsysDefaultAppPath;
import io.nosqlbench.nb.api.docsapi.Docs;
import io.nosqlbench.docsys.api.WebServiceObject;
import io.nosqlbench.docsys.handlers.FavIconHandler;
import io.nosqlbench.nb.annotations.Maturity;
import io.nosqlbench.nb.api.spi.SimpleServiceLoader;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletRegistration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.model.ResourceMethod;
import org.glassfish.jersey.servlet.ServletContainer;
import java.awt.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.AccessMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* For examples, see <a href="https://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/examples/embedded/src/main/java/org/eclipse/jetty/embedded/">embedded examples</a>
*/
public class NBWebServer implements Runnable {
private final static Logger logger = LogManager.getLogger(NBWebServer.class);
private final List<Path> basePaths = new ArrayList<>();
private final List<Class> servletClasses = new ArrayList<>();
private ServletContextHandler contextHandler;
private ServletHolder servletHolder;
private HandlerList handlers;
private String bindScheme = "http";
private String bindHost = "localhost";
private int bindPort = 12345;
private final Map<String, Object> contextParams = new LinkedHashMap<>();
public NBWebServer withContextParams(Map<String, Object> cp) {
this.contextParams.putAll(cp);
return this;
}
public NBWebServer withContextParam(String name, Object object) {
this.contextParams.put(name, object);
return this;
}
public NBWebServer withHost(String bindHost) {
this.bindHost = bindHost;
return this;
}
public NBWebServer withPort(int bindPort) {
this.bindPort = bindPort;
return this;
}
public NBWebServer withURL(String urlSpec) {
try {
URL url = new URL(urlSpec);
this.bindPort = url.getPort();
this.bindHost = url.getHost();
this.bindScheme = url.getProtocol();
if (url.getPath() != null && !url.getPath().equals("/") && !url.getPath().equals("")) {
throw new UnsupportedOperationException("You may not specify a path for the hosting URL. (specified '" + url.getPath() + "')");
}
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
return this;
}
public NBWebServer withScheme(String scheme) {
this.bindScheme = scheme;
return this;
}
private void addWebObject(Class<?>... objects) {
servletClasses.addAll(Arrays.asList(objects));
// String servletClasses = this.servletClasses
// .stream()
// .map(Class::getCanonicalName)
// .collect(Collectors.joining(","));
//
// getServletHolder().setInitParameter(
// "jersey.config.server.provider.classnames",
// servletClasses
// );
// return this;
}
private void loadDynamicEndpoints() {
List<Pattern> includeApps = List.of(Pattern.compile(".*"));
if (contextParams.containsKey("include-apps")) {
includeApps = Arrays.asList(contextParams.get("include-apps").toString().split(", *"))
.stream()
.map(Pattern::compile)
.collect(Collectors.toList());
}
SimpleServiceLoader<WebServiceObject> svcLoader = new SimpleServiceLoader<>(WebServiceObject.class, Maturity.Any);
svcLoader.getNamedProviders().stream().map(p -> p.provider)
.forEach(p -> {
Class<? extends WebServiceObject> c = p.type();
logger.info(() -> "Adding web service object: " + c.getSimpleName());
this.addWebObject(c);
});
logger.debug(() -> "Loaded " + this.servletClasses.size() + " root resources.");
}
private ServletContextHandler getContextHandler() {
if (contextHandler == null) {
contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/*");
}
return contextHandler;
}
private ServletHolder getServletHolder() {
if (servletHolder == null) {
servletHolder = getContextHandler().addServlet(
ServletContainer.class,
"/apps"
);
servletHolder.setInitOrder(0);
}
return servletHolder;
}
public NBWebServer addPaths(Path... paths) {
for (Path path : paths) {
try {
path.getFileSystem().provider().checkAccess(path, AccessMode.READ);
this.basePaths.add(path);
} catch (Exception e) {
logger.error(() -> "Unable to access path " + path.toString());
throw new RuntimeException(e);
}
}
return this;
}
public void run() {
//new InetSocketAddress("")
Server server = new Server(bindPort);
handlers = new HandlerList();
if (this.basePaths.size() == 0 && this.servletClasses.size() == 0) {
logger.warn("No service endpoints or doc paths have been added. Loading dynamically.");
}
RewriteHandler rh = new RewriteHandler();
// rh.addRule(new RedirectRegexRule("/","/docs/"));
// rh.addRule(new RedirectPatternRule("/","/docs/"));
handlers.addHandler(rh);
// ShutdownHandler shutdownHandler; // for easy recycles
// Favicon
for (Path basePath : basePaths) {
Path icon = basePath.resolve("/favicon.ico");
if (Files.exists(icon)) {
FavIconHandler favIconHandler = new FavIconHandler(basePaths.get(0) + "/favicon.ico", false);
handlers.addHandler(favIconHandler);
break;
}
}
if (basePaths.size() == 0) {
Docs docs = new Docs();
// Load static path contexts which are published within the runtime.
docs.merge(DocsysPathLoader.loadStaticPaths());
// If none claims the "docsys-app" namespace, then install the
// default static copy of the docs app
if (!docs.getPathMap().containsKey("docsys-app")) {
docs.merge(new DocsysDefaultAppPath().getDocs());
}
basePaths.addAll(docs.getPaths());
}
for (Path basePath : basePaths) {
logger.info(() -> "Adding path to server: " + basePath.toString());
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setDirAllowed(true);
resourceHandler.setAcceptRanges(true);
resourceHandler.setWelcomeFiles(new String[]{"index.html"});
resourceHandler.setRedirectWelcome(false);
Resource baseResource = new PathResource(basePath);
if (basePath.toUri().toString().startsWith("jar:")) {
try {
baseResource = JarResource.newResource(basePath.toUri());
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
resourceHandler.setBaseResource(baseResource);
resourceHandler.setCacheControl("no-cache");
handlers.addHandler(resourceHandler);
}
// ResourceConfig statusResourceCfg = new ResourceConfig(DocServerStatusEndpoint.class);
// statusResourceCfg.property("server", this);
// ServletContainer statusResourceContainer = new ServletContainer(statusResourceCfg);
// ServletHolder statusResourceServletHolder = new ServletHolder(statusResourceContainer);
// getContextHandler().addServlet(statusResourceServletHolder, "/_");
logger.info(() -> "adding " + servletClasses.size() + " context handlers...");
loadDynamicEndpoints();
ResourceConfig rc = new ResourceConfig();
rc.addProperties(contextParams);
rc.property("server", this);
ServletContainer container = new ServletContainer(rc);
ServletHolder servlets = new ServletHolder(container);
String classnames = this.servletClasses
.stream()
.map(Class::getCanonicalName)
.collect(Collectors.joining(","));
rc.property(ServerProperties.PROVIDER_CLASSNAMES, classnames);
// servlets.setInitParameter(ServerProperties.PROVIDER_CLASSNAMES,
// classnames
// );
ServletContextHandler sch = new ServletContextHandler();
sch.setContextPath("/*");
sch.addServlet(servlets, "/*");
FilterHolder filter = new FilterHolder();
filter.setInitParameter("allowedOrigins", "*");
filter.setInitParameter("allowedMethods", "POST,GET,OPTIONS,PUT,DELETE,HEAD");
filter.setInitParameter("allowedHeaders", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
filter.setInitParameter("preflightMaxAge", "1800");
filter.setInitParameter("allowCredentials", "true");
CrossOriginFilter corsFilter = new CrossOriginFilter();
filter.setFilter(corsFilter);
FilterMapping filterMapping = new FilterMapping();
filterMapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
filterMapping.setPathSpec("/*");
filterMapping.setServletName("cross-origin");
sch.addFilter(filter, "/*", EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC));
handlers.addHandler(sch);
// Show contexts
DefaultHandler defaultHandler = new DefaultHandler();
defaultHandler.setShowContexts(true);
defaultHandler.setServeIcon(false);
handlers.addHandler(defaultHandler);
// FilterMapping corsMapping = new FilterMapping();
// corsMapping.set
//
// ServletHandler CorsHandler = new ServletHandler();
// CorsHandler.setH
server.setHandler(handlers);
for (Connector connector : server.getConnectors()) {
if (connector instanceof AbstractConnector) {
logger.debug(() -> "Setting idle timeout for " + connector + " to 300,000ms");
((AbstractConnector) connector).setIdleTimeout(300000);
}
}
try {
List<Connector> connectors = new ArrayList<>();
if (bindScheme.equals("http")) {
ServerConnector sc = new ServerConnector(server);
sc.setPort(bindPort);
sc.setHost(bindHost);
// sc.setDefaultProtocol(bindScheme);
connectors.add(sc);
} else if (bindScheme.equals("https")) {
SslContextFactory.Server server1 = new SslContextFactory.Server();
ServerConnector sc = new ServerConnector(server, server1);
sc.setPort(bindPort);
sc.setHost(bindHost);
// sc.setDefaultProtocol(bindScheme);
connectors.add(sc);
}
server.setConnectors(connectors.toArray(new Connector[0]));
server.start();
System.out.println("Started documentation server at " + bindScheme + "://" + bindHost + ":" + bindPort + "/");
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
System.out.println("Browsing to documentation server at " + bindScheme + "://" + bindHost + ":" + bindPort + "/");
Desktop.getDesktop().browse(new URI(bindScheme + "://" + bindHost + ":" + bindPort + "/"));
System.out.println("If the docs app did not open automatically in your browser, open to the the url above.");
}
server.join();
} catch (Exception e) {
throw new RuntimeException("error while starting doc server: "+ e,e);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Class servletClass : this.servletClasses) {
sb.append("- ").append(servletClass.getCanonicalName()).append("\n");
ResourceConfig rc = new ResourceConfig(servletClass);
Set<org.glassfish.jersey.server.model.Resource> resources = rc.getResources();
for (org.glassfish.jersey.server.model.Resource resource : resources) {
sb.append("resource name:").append(resource.getName()).append("\n");
List<ResourceMethod> resourceMethods = resource.getResourceMethods();
for (ResourceMethod resourceMethod : resourceMethods) {
String rm = resourceMethod.toString();
sb.append("rm:").append(rm);
}
}
}
sb.append("- - - -\n");
for (Handler handler : handlers.getHandlers()) {
String summary = handlerSummary(handler);
sb.append(summary == null ? "NULL SUMMARY" : summary);
sb.append("\n");
}
return sb.toString();
}
private String handlerSummary(Handler handler) {
StringBuilder sb = new StringBuilder();
sb.append("----> handler type ").append(handler.getClass().getSimpleName()).append("\n");
if (handler instanceof ResourceHandler h) {
sb.append(" base resource: ").append(h.getBaseResource().toString())
.append("\n");
sb.append(h.dump());
} else if (handler instanceof ServletContextHandler h) {
sb.append(h.dump()).append("\n");
h.getServletContext().getServletRegistrations().forEach(
(k, v) -> {
sb.append("==> servlet type ").append(k).append("\n");
sb.append(getServletSummary(v)).append("\n");
}
);
sb.append("context path:").append(h.getContextPath());
} else if (handler instanceof DefaultHandler h) {
sb.append(h.dump());
}
return sb.toString();
}
private String getServletSummary(ServletRegistration v) {
return v.getClassName() + "('" + v.getName() + "')" + v.getInitParameters().keySet().stream().map(
k -> k + "=" + v.getInitParameters().get(k)).collect(Collectors.joining(","));
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.core;
import io.nosqlbench.nb.api.apps.BundledApp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
//@Service(value=NBWebServerApp.class,selector="appserver")
public class NBWebServerApp implements BundledApp {
private static final Logger logger = LogManager.getLogger(NBWebServerApp.class);
public static void main(String[] args) {
new NBWebServerApp().applyAsInt(args);
}
private static boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
private static void generate(String[] args) throws IOException {
Path dirpath = args.length == 0 ?
Path.of("docs") :
Path.of(args[0]);
StandardOpenOption[] OVERWRITE = {StandardOpenOption.TRUNCATE_EXISTING,StandardOpenOption.CREATE,StandardOpenOption.WRITE};
logger.info(() -> "generating to directory " + dirpath);
}
private static void runServer(String[] serverArgs) {
NBWebServer server = new NBWebServer();
server.withContextParam("logpath", Path.of("logs")); // default
for (int i = 0; i < serverArgs.length; i++) {
String arg = serverArgs[i];
if (arg.matches(".*://.*")) {
if (!arg.toLowerCase().contains("http://")) {
String suggested = arg.toLowerCase().replaceAll("https", "http");
throw new RuntimeException("ERROR:\nIn this release, only 'http://' URLs are supported.\nTLS will be added in a future release.\nSee https://github.com/nosqlbench/nosqlbench/issues/35\n" +
"Consider using " + suggested);
}
server.withURL(arg);
} else if (Files.exists(Path.of(arg))) {
server.addPaths(Path.of(arg));
} else if (arg.matches("\\d+")) {
server.withPort(Integer.parseInt(arg));
} else if (arg.matches("--public")) {
int nextidx = i+1;
String net_addr = "0.0.0.0";
if (
serverArgs.length>nextidx+1 &&
serverArgs[nextidx].matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
) {
i++;
net_addr = serverArgs[nextidx];
}
logger.info("running public server on interface with address " + net_addr);
server.withHost(net_addr);
} else if (arg.matches("--workspaces")) {
String workspaces_root = serverArgs[i + 1];
logger.info("Setting workspace directory to workspace_dir");
server.withContextParam("workspaces_root", workspaces_root);
} else if (arg.matches("--logdir")) {
String logdir_path = serverArgs[i + 1];
logger.info(() -> "Setting docserver logdir to " + logdir_path);
server.withContextParam("logpath", Path.of(logdir_path));
}
}
//
server.run();
}
private static void showHelp(String... helpArgs) {
System.out.println(
"Usage: appserver " +
" [url] " +
" [path]... " + "\n" +
"\n" +
"If [url] is provided, then the scheme, address and port are all taken from it.\n" +
"Any additional paths are served from the filesystem, in addition to the internal ones.\n" +
"\n" +
"For now, only http:// is supported."
);
}
private static void search(String[] searchArgs) {
}
private static void listTopics() {
}
@Override
public int applyAsInt(String[] args) {
if (args.length > 0 && args[0].contains("help")) {
showHelp();
} else if (args.length > 0 && args[0].contains("generate")) {
try {
String[] genargs = Arrays.copyOfRange(args, 1, args.length);
logger.info(() -> "Generating with args [" + String.join("][", args) + "]");
generate(genargs);
} catch (IOException e) {
logger.error(() -> "could not generate files with command " + String.join(" ", args));
e.printStackTrace();
}
} else {
runServer(args);
}
return 0;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.core;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.spi.FileSystemProvider;
import java.util.ArrayList;
import java.util.List;
public class PathWalker {
private final static Logger logger = LogManager.getLogger(PathWalker.class);
public static void walk(Path p, PathVisitor v) {
walk(p,v,PathWalker.WALK_ALL);
}
public static List<Path> findAll(Path p) {
Collect fileCollector = new Collect(true, false);
walk(p, fileCollector);
return fileCollector.get();
}
public static void walk(Path p, PathVisitor v, DirectoryStream.Filter<Path> filter) {
try {
FileSystemProvider provider = p.getFileSystem().provider();
DirectoryStream<Path> paths = provider.newDirectoryStream(p, (Path r) -> true);
List<Path> pathlist = new ArrayList<>();
for (Path path : paths) {
pathlist.add(path);
}
for (Path path : pathlist) {
if (path.getFileSystem().provider().readAttributes(path, BasicFileAttributes.class).isDirectory()) {
v.preVisitDir(path);
walk(path, v, filter);
v.postVisitDir(path);
} else if (filter.accept(path)) {
v.preVisitFile(path);
v.visit(path);
v.postVisitFile(path);
} else {
logger.error("error");
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public interface PathVisitor {
void visit(Path p);
default void preVisitFile(Path path) {}
default void postVisitFile(Path path) {}
default void preVisitDir(Path path) {}
default void postVisitDir(Path path) {}
}
public static DirectoryStream.Filter<Path> WALK_ALL = entry -> true;
public static class Collect implements PathVisitor {
private final List<Path> listing = new ArrayList<>();
private final boolean collectFiles;
private final boolean collectDirectories;
public Collect(boolean collectFiles, boolean collectDirectories) {
this.collectFiles = collectFiles;
this.collectDirectories = collectDirectories;
}
public List<Path> get() {
return listing;
}
@Override
public void visit(Path p) {
}
@Override
public void preVisitFile(Path path) {
if (this.collectFiles) {
listing.add(path);
}
}
@Override
public void preVisitDir(Path path) {
if (this.collectDirectories) {
listing.add(path);
}
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.handlers;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.servlet.ServletHandler;
import java.io.IOException;
public class EndpointsHandler extends ServletHandler {
@Override
public void doHandle(
String target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException
{
if (request.getServletPath().equals("/status.json")) {
response.setContentType("text/json");
response.setStatus(HttpStatus.OK_200);
response.getWriter().println("" +
"{" +
" 'status': 'OK'" +
"}" +
"");
baseRequest.setHandled(true);
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.handlers;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.security.InvalidParameterException;
public class FavIconHandler extends AbstractHandler {
private final static Logger logger = LogManager.getLogger(FavIconHandler.class);
private final Path faviconPath;
byte[] iconData;
private long lastModified = 0L;
public FavIconHandler(String faviconPath, boolean requireFile) {
this.faviconPath = Path.of(faviconPath);
if (!this.faviconPath.toFile().exists() && requireFile) {
throw new InvalidParameterException("favicon faviconPath " + this.faviconPath + " does not exist.");
}
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (baseRequest.isHandled() || response.isCommitted()) {
return;
}
if (!HttpMethod.GET.is(request.getMethod()) || !target.equals("/favicon.ico")) {
return;
}
if (!this.faviconPath.toFile().exists()) {
return;
}
lastModified = faviconPath.toFile().lastModified();
if (request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString()) == lastModified) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
baseRequest.setHandled(true);
URL fav = this.getClass().getClassLoader().getResource("org/eclipse/jetty/favicon.ico");
if (fav != null) {
Resource r = Resource.newResource(fav);
iconData = IO.readBytes(r.getInputStream());
}
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("image/x-icon");
response.setContentLength(iconData.length);
response.setDateHeader(HttpHeader.LAST_MODIFIED.toString(), lastModified);
response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "max-age=360000,public");
response.getOutputStream().write(iconData);
}
}

View File

@@ -0,0 +1 @@
io.nosqlbench.nb.annotations.ServiceProcessor

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.docsys.core;
import io.nosqlbench.docsys.api.WebServiceObject;
import jakarta.inject.Singleton;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Map;
import java.util.Set;
//@Service(value=WebServiceObject.class, selector="test", maturity=Stability.Stable)
@Singleton
@Path("test1")
public class TestServlet1 implements WebServiceObject {
private final static Logger logger =
LogManager.getLogger(TestServlet1.class);
// @Context
// private Configuration config;
// private String name;
@GET
@Path("list")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getStats() {
return List.of("one","two","three");
}
@GET
@Path("map")
@Produces(MediaType.APPLICATION_JSON)
public Map<String,String> getMap() {
return Map.of("key1","value1","key2","value2");
}
@GET
@Path("set")
@Produces(MediaType.APPLICATION_JSON)
public Set<String> getSet() {
return Set.of("one", "two", "three");
}
}