mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
project restructuring
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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(","));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
io.nosqlbench.nb.annotations.ServiceProcessor
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user