All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.bdeploy.bhive.cli.ServeTool Maven / Gradle / Ivy

Go to download

Public API including dependencies, ready to be used for integrations and plugins.

There is a newer version: 7.3.6
Show newest version
package io.bdeploy.bhive.cli;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.util.Map;
import java.util.TreeMap;

import org.glassfish.hk2.utilities.binding.AbstractBinder;

import io.bdeploy.bhive.BHive;
import io.bdeploy.bhive.cli.ServeTool.ServeConfig;
import io.bdeploy.bhive.remote.jersey.BHiveJacksonModule;
import io.bdeploy.bhive.remote.jersey.BHiveLocatorImpl;
import io.bdeploy.bhive.remote.jersey.BHiveRegistry;
import io.bdeploy.common.cfg.Configuration.Help;
import io.bdeploy.common.cfg.Configuration.Validator;
import io.bdeploy.common.cfg.ExistingPathValidator;
import io.bdeploy.common.cli.ToolBase.CliTool.CliName;
import io.bdeploy.common.cli.ToolBase.ConfiguredCliTool;
import io.bdeploy.common.cli.ToolCategory;
import io.bdeploy.common.cli.data.RenderableResult;
import io.bdeploy.common.security.SecurityHelper;
import io.bdeploy.jersey.JerseyServer;
import io.bdeploy.jersey.JerseySessionConfiguration;
import io.bdeploy.jersey.ws.change.ObjectChangeBroadcaster;
import io.bdeploy.jersey.ws.change.ObjectChangeWebSocket;

/**
 * Starts a HTTP(S) server which serves given {@link BHive}s other the network.
 */
@Help("Serve given BHives over the network.")
@ToolCategory(BHiveCli.SERVER_TOOLS)
@CliName("serve")
public class ServeTool extends ConfiguredCliTool {

    public @interface ServeConfig {

        @Help("Mapping from context path to BHive directory, ':' separated. E.g. 'myhive:/path/to/hive' will serve on 'https://host:port/api/hives/myhive'")
        String[] serve();

        @Help("Private KeyStore containing the server certificate and private key")
        @Validator(ExistingPathValidator.class)
        String keystore();

        @Help("Passphrase for the private KeyStore")
        String passphrase();

        @Help("Port to serve on")
        short port() default 7700;
    }

    public ServeTool() {
        super(ServeConfig.class);
    }

    @Override
    protected RenderableResult run(ServeConfig config) {
        helpAndFailIfMissing(config.serve(), "Missing --serve");
        helpAndFailIfMissing(config.keystore(), "Missing --keystore");

        Map hives = new TreeMap<>();
        try {
            for (String s : config.serve()) {
                int index = s.indexOf(':');
                String path = s.substring(0, index);
                String hive = s.substring(index + 1);

                Path hPath = Paths.get(hive);

                if (!Files.isDirectory(hPath)) {
                    out().println("WARNING: Skipping non-existant: " + hPath);
                    continue;
                }

                hives.put(path, new BHive(hPath.toUri(), getAuditorFactory().apply(hPath), getActivityReporter()));
            }
            Path storePath = Paths.get(config.keystore());

            char[] passphrase = config.passphrase() == null ? null : config.passphrase().toCharArray();
            KeyStore ks = SecurityHelper.getInstance().loadPrivateKeyStore(storePath, passphrase);

            out().println("Serving " + hives.size() + " hive" + (hives.size() == 1 ? "" : "s") + " on port " + config.port());

            runServer(config.port(), hives, ks, passphrase);
        } catch (Exception e) {
            throw new IllegalStateException("Error while preparing or running server", e);
        } finally {
            hives.forEach((k, v) -> v.close());
        }

        return null; // usually not reached.
    }

    private void runServer(short port, Map hives, KeyStore ks, char[] passphrase) {
        try (JerseyServer server = new JerseyServer(port, ks, null, passphrase, JerseySessionConfiguration.noSessions())) {
            BHiveRegistry reg = new BHiveRegistry(getActivityReporter());

            for (Map.Entry entry : hives.entrySet()) {
                reg.register(entry.getKey(), entry.getValue());
            }

            // WebSocket activity reporter bridge
            ObjectChangeWebSocket ocws = new ObjectChangeWebSocket(server.getKeyStore());
            server.registerWebsocketApplication(ObjectChangeWebSocket.OCWS_PATH, ocws);

            // locator will create nested resources on demand.
            server.registerResource(reg);
            server.register(reg.binder());
            server.register(new BHiveJacksonModule().binder());
            server.register(BHiveLocatorImpl.class);
            server.register(new AbstractBinder() {

                @Override
                protected void configure() {
                    bind(ocws).to(ObjectChangeBroadcaster.class);
                }
            });

            server.start();
            server.join();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy