diff --git a/config/src/main/java/org/polypheny/db/webui/ConfigServer.java b/config/src/main/java/org/polypheny/db/webui/ConfigService.java similarity index 79% rename from config/src/main/java/org/polypheny/db/webui/ConfigServer.java rename to config/src/main/java/org/polypheny/db/webui/ConfigService.java index 3f5f206632..58502dc0fe 100644 --- a/config/src/main/java/org/polypheny/db/webui/ConfigServer.java +++ b/config/src/main/java/org/polypheny/db/webui/ConfigService.java @@ -17,21 +17,16 @@ package org.polypheny.db.webui; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import io.javalin.Javalin; -import io.javalin.json.JavalinJackson; -import io.javalin.plugin.bundled.CorsPluginConfig; import java.io.IOException; -import java.lang.reflect.Type; import java.math.BigDecimal; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; import org.polypheny.db.config.Config; import org.polypheny.db.config.Config.ConfigListener; import org.polypheny.db.config.ConfigManager; @@ -42,22 +37,19 @@ * RESTful server used by the Web UI to interact with the Config Manager. */ @Slf4j -public class ConfigServer implements ConfigListener { +public class ConfigService implements ConfigListener { - private static final Gson gson = new Gson(); + private static final String PREFIX_TYPE = "/config"; + private static final String PREFIX_VERSION = "/v1"; - public ConfigServer( final int port ) { + private static final String PREFIX = PREFIX_TYPE + PREFIX_VERSION; - Javalin http = Javalin.create( config -> { - config.plugins.enableCors( cors -> cors.add( CorsPluginConfig::anyHost ) ); - config.staticFiles.add( "webapp" ); - config.jsonMapper( new JavalinJackson().updateMapper( mapper -> { - mapper.setSerializationInclusion( JsonInclude.Include.NON_NULL ); - } ) ); - } ).start( port ); + ObjectMapper mapper = new ObjectMapper(); - http.ws( "/configWebSocket", new ConfigWebsocket() ); + + public ConfigService( final Javalin http ) { + http.ws( "/config", new ConfigWebsocket() ); configRoutes( http ); } @@ -68,13 +60,12 @@ public ConfigServer( final int port ) { */ private void configRoutes( final Javalin http ) { String type = "application/json"; - Gson gson = new Gson(); ConfigManager cm = ConfigManager.getInstance(); - http.get( "/getPageList", ctx -> ctx.result( cm.getWebUiPageList() ) ); + http.get( PREFIX + "/getPageList", ctx -> ctx.result( cm.getWebUiPageList() ) ); // get Ui of certain page - http.post( "/getPage", ctx -> { + http.post( PREFIX + "/getPage", ctx -> { //input: req: {pageId: 123} try { ctx.result( cm.getPage( ctx.body() ) ); @@ -85,11 +76,11 @@ private void configRoutes( final Javalin http ) { } ); // Save changes from WebUi - http.post( "/updateConfigs", ctx -> { + http.post( PREFIX + "/updateConfigs", ctx -> { log.trace( ctx.body() ); - Type clazzType = new TypeToken>() { - }.getType(); - Map changes = gson.fromJson( ctx.body(), clazzType ); + TypeReference> typeRef = new TypeReference<>() { + }; + Map changes = mapper.convertValue( ctx.body(), typeRef ); StringBuilder feedback = new StringBuilder(); boolean allValid = true; for ( Map.Entry entry : changes.entrySet() ) { @@ -140,16 +131,22 @@ private void configRoutes( final Javalin http ) { break; case "ConfigClazzList": case "ConfigEnumList": - if ( !c.parseStringAndSetValue( gson.toJson( entry.getValue(), ArrayList.class ) ) ) { + try { + if ( !c.parseStringAndSetValue( mapper.writeValueAsString( entry.getValue() ) ) ) { + allValid = false; + appendError( feedback, entry, c ); + } + } catch ( JsonProcessingException e ) { allValid = false; appendError( feedback, entry, c ); } + break; case "ConfigList": Feedback res = c.setConfigObjectList( (List) entry.getValue(), c.getTemplateClass() ); if ( !res.successful ) { allValid = false; - if ( res.message.trim().equals( "" ) ) { + if ( res.message.trim().isEmpty() ) { appendError( feedback, entry, c ); } else { feedback.append( "Could not set " ) @@ -188,9 +185,8 @@ private static void appendError( StringBuilder feedback, Entry e @Override public void onConfigChange( final Config c ) { - Gson gson = new Gson(); try { - ConfigWebsocket.broadcast( gson.toJson( c ) ); + ConfigWebsocket.broadcast( mapper.writeValueAsString( c ) ); } catch ( IOException e ) { log.error( "Caught exception!", e ); } @@ -202,4 +198,21 @@ public void restart( final Config c ) { } + + @FunctionalInterface + public interface Consumer3 { + + void apply( One one, Two two, Three three ); + + } + + + public enum HandlerType { + POST, + GET, + PUT, + DELETE, + PATCH + } + } diff --git a/config/src/test/java/org/polypheny/db/config/ConfigServerTest.java b/config/src/test/java/org/polypheny/db/config/ConfigServerTest.java index 1b75743172..a17a573c0b 100644 --- a/config/src/test/java/org/polypheny/db/config/ConfigServerTest.java +++ b/config/src/test/java/org/polypheny/db/config/ConfigServerTest.java @@ -21,14 +21,14 @@ import java.util.Random; import java.util.Timer; import java.util.TimerTask; -import org.polypheny.db.webui.ConfigServer; +import org.polypheny.db.webui.ConfigService; public class ConfigServerTest { public static void main( String[] args ) { - ConfigServer s = new ConfigServer( 8081 ); + ConfigService s = new ConfigService( null ); demoData( s ); } @@ -36,7 +36,7 @@ public static void main( String[] args ) { /** * Test data */ - private static void demoData( ConfigServer s ) { + private static void demoData( ConfigService s ) { System.out.println( "demoData()" ); ConfigManager cm = ConfigManager.getInstance(); @@ -145,18 +145,28 @@ public void run() { } + private static class TestClass { + int a; + } + + private static class FooImplementation extends TestClass { + int b; + } + + private static class BarImplementation extends TestClass { int c; } + private enum TestEnum { A, B, C } diff --git a/core/src/main/java/org/polypheny/db/adapter/Adapter.java b/core/src/main/java/org/polypheny/db/adapter/Adapter.java index 85a24ee40d..206a591ae1 100644 --- a/core/src/main/java/org/polypheny/db/adapter/Adapter.java +++ b/core/src/main/java/org/polypheny/db/adapter/Adapter.java @@ -245,7 +245,7 @@ public void enableInformationPage() { * Removes all information objects defined in this adapter from the InformationManager */ public void removeInformationPage() { - if ( informationElements.size() > 0 ) { + if ( !informationElements.isEmpty() ) { InformationManager im = InformationManager.getInstance(); im.removeInformation( informationElements.toArray( new Information[0] ) ); informationGroups.forEach( im::removeGroup ); diff --git a/core/src/main/java/org/polypheny/db/catalog/Catalog.java b/core/src/main/java/org/polypheny/db/catalog/Catalog.java index 5917fe9dd3..3dae09a01e 100644 --- a/core/src/main/java/org/polypheny/db/catalog/Catalog.java +++ b/core/src/main/java/org/polypheny/db/catalog/Catalog.java @@ -19,6 +19,7 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -59,6 +60,9 @@ public abstract class Catalog implements ExtensionPoint { public static String defaultNamespaceName = "public"; public static long defaultNamespaceId = 0; public static boolean resetDocker; + + protected static List afterInit = new ArrayList<>(); + protected final PropertyChangeSupport listeners = new PropertyChangeSupport( this ); public boolean isPersistent = false; private static Catalog INSTANCE = null; @@ -89,6 +93,11 @@ public static Catalog getInstance() { } + public static void afterInit( Runnable action ) { + afterInit.add( action ); + } + + public abstract void init(); public abstract void updateSnapshot(); diff --git a/core/src/main/java/org/polypheny/db/catalog/impl/PolyCatalog.java b/core/src/main/java/org/polypheny/db/catalog/impl/PolyCatalog.java index 7316428914..682c86585a 100644 --- a/core/src/main/java/org/polypheny/db/catalog/impl/PolyCatalog.java +++ b/core/src/main/java/org/polypheny/db/catalog/impl/PolyCatalog.java @@ -150,7 +150,6 @@ public PolyCatalog( this.persister = new Persister(); - } @@ -158,6 +157,8 @@ public PolyCatalog( public void init() { //new DefaultInserter(); updateSnapshot(); + + Catalog.afterInit.forEach( Runnable::run ); } diff --git a/core/src/main/java/org/polypheny/db/config/RuntimeConfig.java b/core/src/main/java/org/polypheny/db/config/RuntimeConfig.java index 66a701c6a1..dfbe7007bf 100644 --- a/core/src/main/java/org/polypheny/db/config/RuntimeConfig.java +++ b/core/src/main/java/org/polypheny/db/config/RuntimeConfig.java @@ -85,7 +85,7 @@ public enum RuntimeConfig { WEBUI_SERVER_PORT( "runtime/webuiServerPort", "The port on which the web ui server should listen.", - 8080, + 7659, ConfigType.INTEGER ), diff --git a/dbms/build.gradle b/dbms/build.gradle index bee02cd998..5c8c9b5635 100644 --- a/dbms/build.gradle +++ b/dbms/build.gradle @@ -41,6 +41,7 @@ dependencies { ////// SLF4J implementation group: 'org.pf4j', name: 'pf4j', version: pf4j_version // Apache 2.0 + implementation group: "io.javalin", name: "javalin", version: javalin_version // Apache 2.0 implementation group: "com.github.rvesse", name: "airline", version: airline_version // Apache 2.0 implementation group: "com.github.oshi", name: "oshi-core", version: oshi_core_version // MIT diff --git a/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java b/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java index 7857ef1671..aa0230ade2 100644 --- a/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java +++ b/dbms/src/main/java/org/polypheny/db/PolyphenyDb.java @@ -80,9 +80,9 @@ import org.polypheny.db.util.PolyphenyHomeDirManager; import org.polypheny.db.view.MaterializedViewManager; import org.polypheny.db.view.MaterializedViewManagerImpl; -import org.polypheny.db.webui.ConfigServer; +import org.polypheny.db.webui.ConfigService; import org.polypheny.db.webui.HttpServer; -import org.polypheny.db.webui.InformationServer; +import org.polypheny.db.webui.InformationService; import org.polypheny.db.webui.UiTestingConfigPage; import org.polypheny.db.webui.UiTestingMonitoringPage; @@ -362,9 +362,14 @@ public void join( final long millis ) throws InterruptedException { final ShutdownHelper sh = new ShutdownHelper(); // shutdownHookId = addShutdownHook( "Component Terminator", sh ); + // Start Polypheny-UI + final Authenticator authenticator = new AuthenticatorImpl(); + final HttpServer server = startHttpServer( authenticator, transactionManager ); + // Start config server and information server - new ConfigServer( RuntimeConfig.CONFIG_SERVER_PORT.getInteger() ); - new InformationServer( RuntimeConfig.INFORMATION_SERVER_PORT.getInteger() ); + + new ConfigService( server.getServer() ); + new InformationService( server.getServer() ); try { new JavaInformation(); @@ -398,9 +403,6 @@ public void join( final long millis ) throws InterruptedException { // Startup and restore catalog Catalog catalog = startCatalog(); - - final Authenticator authenticator = new AuthenticatorImpl(); - // Initialize interface manager QueryInterfaceManager.initialize( transactionManager, authenticator ); @@ -435,16 +437,6 @@ public void join( final long millis ) throws InterruptedException { // Initialize MaterializedViewManager MaterializedViewManager.setAndGetInstance( new MaterializedViewManagerImpl( transactionManager ) ); - // Start Polypheny-UI - final HttpServer httpServer = new HttpServer( transactionManager, authenticator ); - Thread polyphenyUiThread = new Thread( httpServer ); - polyphenyUiThread.start(); - try { - polyphenyUiThread.join(); - } catch ( InterruptedException e ) { - log.warn( "Interrupted on join()", e ); - } - // Initialize DDL Manager DdlManager.setAndGetInstance( new DdlManagerImpl( catalog ) ); @@ -508,6 +500,19 @@ public void join( final long millis ) throws InterruptedException { } + private HttpServer startHttpServer( Authenticator authenticator, TransactionManager transactionManager ) { + final HttpServer httpServer = new HttpServer( transactionManager, authenticator ); + Thread polyphenyUiThread = new Thread( httpServer ); + polyphenyUiThread.start(); + try { + polyphenyUiThread.join(); + } catch ( InterruptedException e ) { + log.warn( "Interrupted on join()", e ); + } + return httpServer; + } + + @NotNull private Catalog startCatalog() { Catalog.resetCatalog = resetCatalog; diff --git a/information/build.gradle b/information/build.gradle index c447e980cb..03c6c8daa3 100644 --- a/information/build.gradle +++ b/information/build.gradle @@ -2,6 +2,7 @@ group "org.polypheny" dependencies { + api project(":config") api group: "org.slf4j", name: "slf4j-api", version: slf4j_api_version // MIT implementation group: "org.apache.logging.log4j", name: "log4j-slf4j2-impl", version: log4j_slf4j_impl_version // Apache 2.0 diff --git a/information/src/main/java/org/polypheny/db/webui/InformationServer.java b/information/src/main/java/org/polypheny/db/webui/InformationService.java similarity index 62% rename from information/src/main/java/org/polypheny/db/webui/InformationServer.java rename to information/src/main/java/org/polypheny/db/webui/InformationService.java index 90fec49d0f..812d6c1184 100644 --- a/information/src/main/java/org/polypheny/db/webui/InformationServer.java +++ b/information/src/main/java/org/polypheny/db/webui/InformationService.java @@ -17,16 +17,7 @@ package org.polypheny.db.webui; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.google.gson.Gson; -import com.google.gson.TypeAdapter; -import com.google.gson.TypeAdapterFactory; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; import io.javalin.Javalin; -import io.javalin.json.JavalinJackson; -import io.javalin.plugin.bundled.CorsPluginConfig; import java.io.IOException; import lombok.extern.slf4j.Slf4j; import org.eclipse.jetty.websocket.api.Session; @@ -42,55 +33,16 @@ * RESTful server for requesting data from the information manager. It is primarily used by the Polypheny-UI. */ @Slf4j -public class InformationServer implements InformationObserver { +public class InformationService implements InformationObserver { - public static final TypeAdapterFactory throwableTypeAdapterFactory; - public static final TypeAdapter throwableTypeAdapter; + private static final String PREFIX_TYPE = "/info"; + private static final String PREFIX_VERSION = "/v1"; - static { - // Adapter factory, which handles generic throwables - throwableTypeAdapterFactory = new TypeAdapterFactory() { - @Override - public TypeAdapter create( Gson gson, TypeToken type ) { - if ( !Throwable.class.isAssignableFrom( type.getRawType() ) ) { - return null; - } - //noinspection unchecked - return (TypeAdapter) throwableTypeAdapter; - } - }; - throwableTypeAdapter = new TypeAdapter<>() { - @Override - public void write( JsonWriter out, Throwable value ) throws IOException { - if ( value == null ) { - out.nullValue(); - return; - } - out.beginObject(); - out.name( "message" ); - out.value( value.getMessage() ); - out.endObject(); - } - - - @Override - public Throwable read( JsonReader in ) throws IOException { - return new Throwable( in.nextString() ); - } - }; - } - + private static final String PREFIX = PREFIX_TYPE + PREFIX_VERSION; - public InformationServer( final int port ) { - Javalin http = Javalin.create( config -> { - config.plugins.enableCors( cors -> cors.add( CorsPluginConfig::anyHost ) ); - config.staticFiles.add( "webapp" ); - config.jsonMapper( new JavalinJackson().updateMapper( mapper -> { - mapper.setSerializationInclusion( JsonInclude.Include.NON_NULL ); - } ) ); - } ).start( port ); + public InformationService( final Javalin http ) { // Needs to be called before defining routes! webSockets( http ); @@ -102,7 +54,7 @@ public InformationServer( final int port ) { private void webSockets( final Javalin http ) { // Websockets need to be defined before the post/get requests - http.ws( "/informationWebSocket", new InformationWebSocket() ); + http.ws( "/info", new InformationWebSocket() ); } @@ -110,9 +62,9 @@ private void informationRoutes( final Javalin http ) { InformationManager im = InformationManager.getInstance(); im.observe( this ); - http.get( "/getPageList", ctx -> ctx.result( im.getPageList() ) ); + http.get( PREFIX + "/getPageList", ctx -> ctx.result( im.getPageList() ) ); - http.post( "/getPage", ctx -> { + http.post( PREFIX + "/getPage", ctx -> { //input: req: {pageId: "page1"} try { InformationPage page = im.getPage( ctx.body() ); @@ -129,7 +81,7 @@ private void informationRoutes( final Javalin http ) { } } ); - http.post( "/executeAction", ctx -> { + http.post( PREFIX + "/executeAction", ctx -> { try { InformationAction action = ctx.bodyAsClass( InformationAction.class ); String msg = im.getInformation( action.getId() ).unwrap( InformationAction.class ).executeAction( action.getParameters() ); @@ -141,7 +93,7 @@ private void informationRoutes( final Javalin http ) { } } ); - http.post( "/refreshPage", ctx -> { + http.post( PREFIX + "/refreshPage", ctx -> { // Refresh not necessary, since getPage already triggers a refresh try { im.getPage( ctx.body() ); @@ -151,7 +103,7 @@ private void informationRoutes( final Javalin http ) { ctx.result( "" ); } ); - http.post( "/refreshGroup", ctx -> { + http.post( PREFIX + "/refreshGroup", ctx -> { try { im.getGroup( ctx.body() ).refresh(); } catch ( Exception e ) { diff --git a/information/src/test/java/org/polypheny/db/information/InformationServerTest.java b/information/src/test/java/org/polypheny/db/information/InformationServerTest.java index 26c194ccee..7c62c37646 100644 --- a/information/src/test/java/org/polypheny/db/information/InformationServerTest.java +++ b/information/src/test/java/org/polypheny/db/information/InformationServerTest.java @@ -27,7 +27,7 @@ import org.junit.Assert; import org.polypheny.db.information.InformationGraph.GraphData; import org.polypheny.db.information.InformationGraph.GraphType; -import org.polypheny.db.webui.InformationServer; +import org.polypheny.db.webui.InformationService; import oshi.SystemInfo; import oshi.hardware.HardwareAbstractionLayer; import oshi.software.os.OSProcess; @@ -40,7 +40,7 @@ public class InformationServerTest { public static void main( String[] args ) { - InformationServer s = new InformationServer( 8082 ); + InformationService s = new InformationService( null ); demoData(); } diff --git a/monitoring/src/main/java/org/polypheny/db/monitoring/core/MonitoringQueueImpl.java b/monitoring/src/main/java/org/polypheny/db/monitoring/core/MonitoringQueueImpl.java index 83232228f1..c50b25efc4 100644 --- a/monitoring/src/main/java/org/polypheny/db/monitoring/core/MonitoringQueueImpl.java +++ b/monitoring/src/main/java/org/polypheny/db/monitoring/core/MonitoringQueueImpl.java @@ -216,9 +216,9 @@ protected void afterExecute( Runnable r, Throwable t ) { } + @Getter class MonitoringWorker implements Runnable { - @Getter private final MonitoringEvent event; diff --git a/monitoring/src/main/java/org/polypheny/db/monitoring/statistics/StatisticQueryProcessor.java b/monitoring/src/main/java/org/polypheny/db/monitoring/statistics/StatisticQueryProcessor.java index 072a6fee4c..af45fdb898 100644 --- a/monitoring/src/main/java/org/polypheny/db/monitoring/statistics/StatisticQueryProcessor.java +++ b/monitoring/src/main/java/org/polypheny/db/monitoring/statistics/StatisticQueryProcessor.java @@ -47,21 +47,19 @@ public class StatisticQueryProcessor { @Getter private final TransactionManager transactionManager; - private final long userId; /** * LowCostQueries can be used to retrieve short answered queries * Idea is to expose a selected list of sql operations with a small list of results and not impact performance */ - public StatisticQueryProcessor( final TransactionManager transactionManager, long userId ) { + public StatisticQueryProcessor( final TransactionManager transactionManager ) { this.transactionManager = transactionManager; - this.userId = userId; } public StatisticQueryProcessor( TransactionManager transactionManager, Authenticator authenticator ) { - this( transactionManager, Catalog.defaultUserId ); + this( transactionManager ); } @@ -147,7 +145,6 @@ private StatisticResult executeColStat( AlgNode node, Transaction transaction, S return result; } - // ----------------------------------------------------------------------- // Helper // ----------------------------------------------------------------------- diff --git a/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreByExamplePlugin.java b/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreByExamplePlugin.java index 9e845f35f0..d4041ca670 100644 --- a/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreByExamplePlugin.java +++ b/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreByExamplePlugin.java @@ -23,8 +23,8 @@ import org.polypheny.db.plugins.PolyPlugin; import org.polypheny.db.processing.TransactionExtension; import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.webui.ConfigService.HandlerType; import org.polypheny.db.webui.HttpServer; -import org.polypheny.db.webui.HttpServer.HandlerType; public class ExploreByExamplePlugin extends PolyPlugin { diff --git a/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreManager.java b/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreManager.java index 3d5a0b4939..df20d37305 100644 --- a/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreManager.java +++ b/plugins/explore-by-example/src/main/java/org/polypheny/db/exploreByExample/ExploreManager.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import lombok.extern.slf4j.Slf4j; +import org.polypheny.db.catalog.Catalog; import org.polypheny.db.config.RuntimeConfig; import org.polypheny.db.exploreByExample.models.RelationalExploreResult; import org.polypheny.db.exploreByExample.models.RelationalExploreResult.RelationalExploreResultBuilder; @@ -303,7 +304,7 @@ public void createInitialExploreQuery( final Context ctx, final Crud crud ) { return; } - Transaction transaction = Crud.getTransaction( queryExplorationRequest.analyze, true, crud.getTransactionManager(), crud.getUserId(), crud.getNamespaceId(), "Explore-by-Example" ); + Transaction transaction = Crud.getTransaction( queryExplorationRequest.analyze, true, crud.getTransactionManager(), Catalog.defaultUserId, Catalog.defaultNamespaceId, "Explore-by-Example" ); Statement statement = transaction.createStatement(); try { String query = explore.getSqlStatement(); diff --git a/plugins/notebooks/src/main/java/org/polypheny/db/notebooks/NotebooksPlugin.java b/plugins/notebooks/src/main/java/org/polypheny/db/notebooks/NotebooksPlugin.java index 06ce3cef1b..e14f47c1c2 100644 --- a/plugins/notebooks/src/main/java/org/polypheny/db/notebooks/NotebooksPlugin.java +++ b/plugins/notebooks/src/main/java/org/polypheny/db/notebooks/NotebooksPlugin.java @@ -38,9 +38,9 @@ import org.polypheny.db.plugins.PluginContext; import org.polypheny.db.plugins.PolyPlugin; import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.webui.ConfigService.HandlerType; import org.polypheny.db.webui.Crud; import org.polypheny.db.webui.HttpServer; -import org.polypheny.db.webui.HttpServer.HandlerType; @Slf4j public class NotebooksPlugin extends PolyPlugin { @@ -239,7 +239,7 @@ private void registerEndpoints() { HttpServer server = HttpServer.getInstance(); final String PATH = "/notebooks"; - server.addWebsocket( PATH + "/webSocket/{kernelId}", new JupyterWebSocket() ); + server.addWebsocketRoute( PATH + "/webSocket/{kernelId}", new JupyterWebSocket() ); server.addSerializedRoute( PATH + "/contents/", fs::contents, HandlerType.GET ); server.addSerializedRoute( PATH + "/sessions", proxyOrEmpty( proxy -> proxy::sessions ), HandlerType.GET ); diff --git a/webui/src/main/java/org/polypheny/db/webui/Crud.java b/webui/src/main/java/org/polypheny/db/webui/Crud.java index a982bc131d..6d315527ea 100644 --- a/webui/src/main/java/org/polypheny/db/webui/Crud.java +++ b/webui/src/main/java/org/polypheny/db/webui/Crud.java @@ -221,10 +221,6 @@ public class Crud implements InformationObserver, PropertyChangeListener { private static final Gson gson = new Gson(); private final TransactionManager transactionManager; - @Getter - private final long namespaceId; - @Getter - private final long userId; public final LanguageCrud languageCrud; public final StatisticCrud statisticCrud; @@ -233,26 +229,22 @@ public class Crud implements InformationObserver, PropertyChangeListener { public final AuthCrud authCrud; - private final Catalog catalog = Catalog.getInstance(); - /** * Constructor * * @param transactionManager The Polypheny-DB transaction manager */ - Crud( final TransactionManager transactionManager, final long userId, final long namespaceId ) { + Crud( final TransactionManager transactionManager ) { this.transactionManager = transactionManager; - this.namespaceId = namespaceId; - this.userId = userId; this.languageCrud = new LanguageCrud( this ); this.statisticCrud = new StatisticCrud( this ); this.catalogCrud = new CatalogCrud( this ); this.authCrud = new AuthCrud( this ); - Catalog.getInstance().addObserver( this ); - } + Catalog.afterInit( () -> Catalog.getInstance().addObserver( this ) ); + } /** * Closes analyzers and deletes temporary files. @@ -317,7 +309,7 @@ RelationalResult getTable( final UIRequest request ) { } // determine if it is a view or a table - LogicalTable table = catalog.getSnapshot().rel().getTable( request.entityId ).orElseThrow(); + LogicalTable table = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); resultBuilder.namespaceType( table.namespaceType ); if ( table.modifiable ) { resultBuilder.type( ResultType.TABLE ); @@ -329,12 +321,12 @@ RelationalResult getTable( final UIRequest request ) { List cols = new ArrayList<>(); List primaryColumns; if ( table.primaryKey != null ) { - LogicalPrimaryKey primaryKey = catalog.getSnapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); + LogicalPrimaryKey primaryKey = Catalog.snapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); primaryColumns = new ArrayList<>( primaryKey.getColumnNames() ); } else { primaryColumns = new ArrayList<>(); } - for ( LogicalColumn logicalColumn : catalog.getSnapshot().rel().getColumns( table.id ) ) { + for ( LogicalColumn logicalColumn : Catalog.snapshot().rel().getColumns( table.id ) ) { String defaultValue = logicalColumn.defaultValue == null ? null : logicalColumn.defaultValue.value; String collectionsType = logicalColumn.collectionsType == null ? "" : logicalColumn.collectionsType.getName(); cols.add( @@ -382,18 +374,18 @@ RelationalResult getTable( final UIRequest request ) { void getEntities( final Context ctx ) { EditTableRequest request = ctx.bodyAsClass( EditTableRequest.class ); long namespaceId = request.namespaceId != null ? request.namespaceId : Catalog.defaultNamespaceId; - LogicalNamespace namespace = catalog.getSnapshot().getNamespace( namespaceId ).orElseThrow(); + LogicalNamespace namespace = Catalog.snapshot().getNamespace( namespaceId ).orElseThrow(); List entities = List.of(); switch ( namespace.namespaceType ) { case RELATIONAL: - entities = catalog.getSnapshot().rel().getTables( namespace.id, null ); + entities = Catalog.snapshot().rel().getTables( namespace.id, null ); break; case DOCUMENT: - entities = catalog.getSnapshot().doc().getCollections( namespace.id, null ); + entities = Catalog.snapshot().doc().getCollections( namespace.id, null ); break; case GRAPH: - entities = catalog.getSnapshot().graph().getGraphs( null ); + entities = Catalog.snapshot().graph().getGraphs( null ); break; } @@ -610,7 +602,7 @@ void insertTuple( final Context ctx ) { long entityId = Long.parseLong( unparsed ); LogicalTable table = Catalog.snapshot().rel().getTable( entityId ).orElseThrow(); - LogicalNamespace namespace = Catalog.snapshot().getNamespace( namespaceId ).orElseThrow(); + LogicalNamespace namespace = Catalog.snapshot().getNamespace( Catalog.defaultNamespaceId ).orElseThrow(); String entityName = String.format( "\"%s\".\"%s\"", namespace.name, table.name ); Transaction transaction = getTransaction(); @@ -618,7 +610,7 @@ void insertTuple( final Context ctx ) { StringJoiner columns = new StringJoiner( ",", "(", ")" ); StringJoiner values = new StringJoiner( ",", "(", ")" ); - List logicalColumns = catalog.getSnapshot().rel().getColumns( table.id ); + List logicalColumns = Catalog.snapshot().rel().getColumns( table.id ); try { int i = 0; for ( LogicalColumn logicalColumn : logicalColumns ) { @@ -896,12 +888,12 @@ public static String uiValueToSql( final String value, final PolyType type, fina */ private String computeWherePK( final LogicalTable table, final Map filter ) { StringJoiner joiner = new StringJoiner( " AND ", "", "" ); - Map columns = this.catalog.getSnapshot().rel().getColumns( table.id ).stream().collect( Collectors.toMap( c -> c.id, c -> c ) ); + Map columns = Catalog.snapshot().rel().getColumns( table.id ).stream().collect( Collectors.toMap( c -> c.id, c -> c ) ); if ( columns.isEmpty() ) { throw new GenericRuntimeException( "Table has no columns" ); } - LogicalPrimaryKey pk = catalog.getSnapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); + LogicalPrimaryKey pk = Catalog.snapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); for ( long colId : pk.columnIds ) { LogicalColumn col = columns.get( colId ); String condition; @@ -971,7 +963,7 @@ void updateTuple( final Context ctx ) throws ServletException, IOException { Statement statement = transaction.createStatement(); StringJoiner setStatements = new StringJoiner( ",", "", "" ); - List logicalColumns = catalog.getSnapshot().rel().getColumns( entityId ); + List logicalColumns = Catalog.snapshot().rel().getColumns( entityId ); int i = 0; for ( LogicalColumn logicalColumn : logicalColumns ) { @@ -1071,12 +1063,12 @@ void getColumns( final Context ctx ) { LogicalTable table = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); List primaryColumns; if ( table.primaryKey != null ) { - LogicalPrimaryKey primaryKey = catalog.getSnapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); + LogicalPrimaryKey primaryKey = Catalog.snapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); primaryColumns = new ArrayList<>( primaryKey.getColumnNames() ); } else { primaryColumns = new ArrayList<>(); } - for ( LogicalColumn logicalColumn : catalog.getSnapshot().rel().getColumns( table.id ) ) { + for ( LogicalColumn logicalColumn : Catalog.snapshot().rel().getColumns( table.id ) ) { String defaultValue = logicalColumn.defaultValue == null ? null : logicalColumn.defaultValue.value; String collectionsType = logicalColumn.collectionsType == null ? "" : logicalColumn.collectionsType.getName(); cols.add( @@ -1108,12 +1100,12 @@ void getColumns( final Context ctx ) { void getDataSourceColumns( final Context ctx ) { UIRequest request = ctx.bodyAsClass( UIRequest.class ); - LogicalTable tablee = catalog.getSnapshot().rel().getTable( request.entityId ).orElseThrow(); + LogicalTable tablee = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); if ( tablee.entityType == EntityType.VIEW ) { List columns = new ArrayList<>(); - List cols = catalog.getSnapshot().rel().getColumns( tablee.id ); + List cols = Catalog.snapshot().rel().getColumns( tablee.id ); for ( LogicalColumn col : cols ) { columns.add( UiColumnDefinition.builder() .name( col.name ) @@ -1132,17 +1124,17 @@ void getDataSourceColumns( final Context ctx ) { } ctx.json( RelationalResult.builder().header( columns.toArray( new UiColumnDefinition[0] ) ).type( ResultType.VIEW ).build() ); } else { - List allocs = catalog.getSnapshot().alloc().getFromLogical( tablee.id ); - if ( catalog.getSnapshot().alloc().getFromLogical( tablee.id ).size() != 1 ) { + List allocs = Catalog.snapshot().alloc().getFromLogical( tablee.id ); + if ( Catalog.snapshot().alloc().getFromLogical( tablee.id ).size() != 1 ) { throw new RuntimeException( "The table has an unexpected number of placements!" ); } long adapterId = allocs.get( 0 ).adapterId; - LogicalPrimaryKey primaryKey = catalog.getSnapshot().rel().getPrimaryKey( tablee.primaryKey ).orElseThrow(); + LogicalPrimaryKey primaryKey = Catalog.snapshot().rel().getPrimaryKey( tablee.primaryKey ).orElseThrow(); List pkColumnNames = primaryKey.getColumnNames(); List columns = new ArrayList<>(); - for ( AllocationColumn ccp : catalog.getSnapshot().alloc().getColumnPlacementsOnAdapterPerTable( adapterId, tablee.id ) ) { - LogicalColumn col = catalog.getSnapshot().rel().getColumn( ccp.columnId ).orElseThrow(); + for ( AllocationColumn ccp : Catalog.snapshot().alloc().getColumnPlacementsOnAdapterPerTable( adapterId, tablee.id ) ) { + LogicalColumn col = Catalog.snapshot().rel().getColumn( ccp.columnId ).orElseThrow(); columns.add( UiColumnDefinition.builder().name( col.name ).dataType( col.type.getName() ).collectionsType( @@ -1166,11 +1158,11 @@ void getDataSourceColumns( final Context ctx ) { void getAvailableSourceColumns( final Context ctx ) { UIRequest request = ctx.bodyAsClass( UIRequest.class ); - LogicalTable table = catalog.getSnapshot().rel().getTable( request.entityId ).orElseThrow(); - Map> placements = catalog.getSnapshot().alloc().getColumnPlacementsByAdapters( table.id ); + LogicalTable table = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); + Map> placements = Catalog.snapshot().alloc().getColumnPlacementsByAdapters( table.id ); Set adapterIds = placements.keySet(); if ( adapterIds.size() > 1 ) { - LogicalNamespace namespace = catalog.getSnapshot().getNamespace( table.namespaceId ).orElseThrow(); + LogicalNamespace namespace = Catalog.snapshot().getNamespace( table.namespaceId ).orElseThrow(); log.warn( String.format( "The number of sources of an entity should not be > 1 (%s.%s)", namespace.name, table.name ) ); } List exportedColumns = new ArrayList<>(); @@ -1240,7 +1232,7 @@ void getMaterializedInfo( final Context ctx ) { private LogicalTable getLogicalTable( String namespace, String table ) { - return catalog.getSnapshot().rel().getTable( namespace, table ).orElseThrow(); + return Catalog.snapshot().rel().getTable( namespace, table ).orElseThrow(); } @@ -1534,11 +1526,11 @@ void getConstraints( final Context ctx ) { List resultList = new ArrayList<>(); Map> temp = new HashMap<>(); - LogicalTable table = catalog.getSnapshot().rel().getTable( request.entityId ).orElseThrow(); + LogicalTable table = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); // get primary key if ( table.primaryKey != null ) { - LogicalPrimaryKey primaryKey = catalog.getSnapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); + LogicalPrimaryKey primaryKey = Catalog.snapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); for ( String columnName : primaryKey.getColumnNames() ) { if ( !temp.containsKey( "" ) ) { temp.put( "", new ArrayList<>() ); @@ -1552,7 +1544,7 @@ void getConstraints( final Context ctx ) { // get unique constraints. temp.clear(); - List constraints = catalog.getSnapshot().rel().getConstraints( table.id ); + List constraints = Catalog.snapshot().rel().getConstraints( table.id ); for ( LogicalConstraint logicalConstraint : constraints ) { if ( logicalConstraint.type == ConstraintType.UNIQUE ) { temp.put( logicalConstraint.name, new ArrayList<>( logicalConstraint.key.getColumnNames() ) ); @@ -1691,7 +1683,7 @@ void getIndexes( final Context ctx ) { Pair namespaceTable = getNamespaceTable( request ); LogicalTable table = getLogicalTable( namespaceTable.left.name, namespaceTable.right.name ); - List logicalIndices = catalog.getSnapshot().rel().getIndexes( table.id, false ); + List logicalIndices = Catalog.snapshot().rel().getIndexes( table.id, false ); UiColumnDefinition[] header = { UiColumnDefinition.builder().name( "Name" ).build(), @@ -1710,7 +1702,7 @@ void getIndexes( final Context ctx ) { // a polystore index storeUniqueName = "Polypheny-DB"; } else { - storeUniqueName = catalog.getSnapshot().getAdapter( logicalIndex.location ).orElseThrow().uniqueName; + storeUniqueName = Catalog.snapshot().getAdapter( logicalIndex.location ).orElseThrow().uniqueName; } arr[0] = logicalIndex.name; arr[1] = String.join( ", ", logicalIndex.key.getColumnNames() ); @@ -1721,7 +1713,7 @@ void getIndexes( final Context ctx ) { } // Get functional indexes - List allocs = catalog.getSnapshot().alloc().getFromLogical( table.id ); + List allocs = Catalog.snapshot().alloc().getFromLogical( table.id ); for ( AllocationEntity alloc : allocs ) { Adapter adapter = AdapterManager.getInstance().getAdapter( alloc.adapterId ); DataStore store; @@ -1817,7 +1809,7 @@ void createIndex( final Context ctx ) { void getUnderlyingTable( final Context ctx ) { UIRequest request = ctx.bodyAsClass( UIRequest.class ); - LogicalTable table = catalog.getSnapshot().rel().getTable( request.entityId ).orElseThrow(); + LogicalTable table = Catalog.snapshot().rel().getTable( request.entityId ).orElseThrow(); if ( table.entityType == EntityType.VIEW ) { ImmutableMap> underlyingTableOriginal = table.unwrap( LogicalView.class ).underlyingTables; @@ -1825,9 +1817,9 @@ void getUnderlyingTable( final Context ctx ) { for ( Entry> entry : underlyingTableOriginal.entrySet() ) { List columns = new ArrayList<>(); for ( Long ids : entry.getValue() ) { - columns.add( catalog.getSnapshot().rel().getColumn( ids ).orElseThrow().name ); + columns.add( Catalog.snapshot().rel().getColumn( ids ).orElseThrow().name ); } - underlyingTable.put( catalog.getSnapshot().rel().getTable( entry.getKey() ).orElseThrow().name, columns ); + underlyingTable.put( Catalog.snapshot().rel().getTable( entry.getKey() ).orElseThrow().name, columns ); } ctx.json( new UnderlyingTables( underlyingTable ) ); } else { @@ -2382,7 +2374,7 @@ void addQueryInterface( final Context ctx ) { QueryInterfaceInformationRequest request = ctx.bodyAsClass( QueryInterfaceInformationRequest.class ); String generatedQuery = String.format( "ALTER INTERFACES ADD \"%s\" USING '%s' WITH '%s'", request.uniqueName, request.clazzName, gson.toJson( request.currentSettings ) ); try { - qim.addQueryInterface( catalog, request.clazzName, request.uniqueName, request.currentSettings ); + qim.addQueryInterface( Catalog.getInstance(), request.clazzName, request.uniqueName, request.currentSettings ); ctx.json( RelationalResult.builder().affectedTuples( 1 ).query( generatedQuery ).build() ); } catch ( RuntimeException e ) { log.error( "Exception while deploying query interface", e ); @@ -2408,7 +2400,7 @@ void removeQueryInterface( final Context ctx ) { QueryInterfaceManager qim = QueryInterfaceManager.getInstance(); String generatedQuery = String.format( "ALTER INTERFACES DROP \"%s\"", uniqueName ); try { - qim.removeQueryInterface( catalog, uniqueName ); + qim.removeQueryInterface( Catalog.getInstance(), uniqueName ); ctx.json( RelationalResult.builder().affectedTuples( 1 ).query( generatedQuery ).build() ); } catch ( RuntimeException e ) { log.error( "Could not remove query interface {}", ctx.body(), e ); @@ -2425,15 +2417,15 @@ void getUml( final Context ctx ) { List fKeys = new ArrayList<>(); List tables = new ArrayList<>(); - LogicalRelSnapshot relSnapshot = catalog.getSnapshot().rel(); + LogicalRelSnapshot relSnapshot = Catalog.snapshot().rel(); long namespaceId = request.namespaceId == null ? Catalog.defaultNamespaceId : request.namespaceId; - LogicalNamespace namespace = catalog.getSnapshot().getNamespace( namespaceId ).orElseThrow(); + LogicalNamespace namespace = Catalog.snapshot().getNamespace( namespaceId ).orElseThrow(); List entities = relSnapshot.getTablesFromNamespace( namespace.id ); for ( LogicalTable table : entities ) { if ( table.entityType == EntityType.ENTITY || table.entityType == EntityType.SOURCE ) { // get foreign keys - List foreignKeys = catalog.getSnapshot().rel().getForeignKeys( table.id ); + List foreignKeys = Catalog.snapshot().rel().getForeignKeys( table.id ); for ( LogicalForeignKey logicalForeignKey : foreignKeys ) { for ( int i = 0; i < logicalForeignKey.getReferencedKeyColumnNames().size(); i++ ) { fKeys.add( ForeignKey.builder() @@ -2459,14 +2451,14 @@ void getUml( final Context ctx ) { // get primary key with its columns if ( table.primaryKey != null ) { - LogicalPrimaryKey primaryKey = catalog.getSnapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); + LogicalPrimaryKey primaryKey = Catalog.snapshot().rel().getPrimaryKey( table.primaryKey ).orElseThrow(); for ( String columnName : primaryKey.getColumnNames() ) { dbTable.addPrimaryKeyField( columnName ); } } // get unique constraints - List logicalConstraints = catalog.getSnapshot().rel().getConstraints( table.id ); + List logicalConstraints = Catalog.snapshot().rel().getConstraints( table.id ); for ( LogicalConstraint logicalConstraint : logicalConstraints ) { if ( logicalConstraint.type == ConstraintType.UNIQUE ) { // TODO: unique constraints can be over multiple columns. @@ -2480,7 +2472,7 @@ void getUml( final Context ctx ) { } // get unique indexes - List logicalIndices = catalog.getSnapshot().rel().getIndexes( table.id, true ); + List logicalIndices = Catalog.snapshot().rel().getIndexes( table.id, true ); for ( LogicalIndex logicalIndex : logicalIndices ) { // TODO: unique indexes can be over multiple columns. if ( logicalIndex.key.getColumnNames().size() == 1 && @@ -2793,7 +2785,7 @@ void namespaceRequest( final Context ctx ) { // drop namespace else if ( !namespace.isCreate() && namespace.isDrop() ) { if ( type == null ) { - List namespaces = catalog.getSnapshot().getNamespaces( new org.polypheny.db.catalog.logistic.Pattern( namespace.getName() ) ); + List namespaces = Catalog.snapshot().getNamespaces( new org.polypheny.db.catalog.logistic.Pattern( namespace.getName() ) ); assert namespaces.size() == 1; } @@ -3062,7 +3054,7 @@ void getDirectory( File dir, Context ctx ) { // Get column default values if ( table != null ) { - Optional logicalColumn = crud.catalog.getSnapshot().rel().getColumn( table.id, columnName ); + Optional logicalColumn = Catalog.snapshot().rel().getColumn( table.id, columnName ); if ( logicalColumn.isPresent() ) { if ( logicalColumn.get().defaultValue != null ) { dbCol.defaultValue( logicalColumn.get().defaultValue.value ); @@ -3441,7 +3433,7 @@ public static Transaction getTransaction( boolean analyze, boolean useCache, Tra public static Transaction getTransaction( boolean analyze, boolean useCache, Crud crud ) { - return getTransaction( analyze, useCache, crud.transactionManager, crud.userId, crud.namespaceId ); + return getTransaction( analyze, useCache, crud.transactionManager, Catalog.defaultUserId, Catalog.defaultNamespaceId ); } @@ -3456,7 +3448,7 @@ private Map getColumns( String namespaceName, String tabl Map dataTypes = new HashMap<>(); LogicalTable table = getLogicalTable( namespaceName, tableName ); - List logicalColumns = catalog.getSnapshot().rel().getColumns( table.id ); + List logicalColumns = Catalog.snapshot().rel().getColumns( table.id ); for ( LogicalColumn logicalColumn : logicalColumns ) { dataTypes.put( logicalColumn.name, logicalColumn ); } diff --git a/webui/src/main/java/org/polypheny/db/webui/HttpServer.java b/webui/src/main/java/org/polypheny/db/webui/HttpServer.java index 10434d45ce..1cd04250de 100644 --- a/webui/src/main/java/org/polypheny/db/webui/HttpServer.java +++ b/webui/src/main/java/org/polypheny/db/webui/HttpServer.java @@ -20,11 +20,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.SerializationFeature; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; import io.javalin.Javalin; import io.javalin.http.Context; import io.javalin.json.JavalinJackson; @@ -42,11 +37,12 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.polypheny.db.StatusService; -import org.polypheny.db.catalog.Catalog; import org.polypheny.db.catalog.exceptions.GenericRuntimeException; import org.polypheny.db.config.RuntimeConfig; import org.polypheny.db.iface.Authenticator; import org.polypheny.db.transaction.TransactionManager; +import org.polypheny.db.webui.ConfigService.Consumer3; +import org.polypheny.db.webui.ConfigService.HandlerType; import org.polypheny.db.webui.crud.LanguageCrud; import org.polypheny.db.webui.models.results.RelationalResult; @@ -60,53 +56,6 @@ public class HttpServer implements Runnable { private final TransactionManager transactionManager; private final Authenticator authenticator; - private final Gson gsonExpose = new GsonBuilder() - .excludeFieldsWithoutExposeAnnotation() - .enableComplexMapKeySerialization() - .setPrettyPrinting() - .create(); - - public static final TypeAdapter throwableTypeAdapter; - - - static { - throwableTypeAdapter = new TypeAdapter<>() { - @Override - public void write( JsonWriter out, Throwable value ) throws IOException { - if ( value == null ) { - out.nullValue(); - return; - } - out.beginObject(); - out.name( "message" ); - out.value( value.getMessage() ); - out.endObject(); - } - - - @Override - public Throwable read( JsonReader in ) throws IOException { - return new Throwable( in.nextString() ); - } - }; - /*gson = new GsonBuilder() - .enableComplexMapKeySerialization() - .registerTypeHierarchyAdapter( DataSource.class, DataSource.getSerializer() ) - .registerTypeHierarchyAdapter( DataStore.class, DataStore.getSerializer() ) - .registerTypeHierarchyAdapter( Throwable.class, throwableTypeAdapter ) - .registerTypeAdapter( AdapterInformation.class, AdapterInformation.getSerializer() ) - .registerTypeAdapter( AbstractAdapterSetting.class, new AdapterSettingDeserializer() ) - .registerTypeAdapter( InformationDuration.class, InformationDuration.getSerializer() ) - .registerTypeAdapter( Duration.class, Duration.getSerializer() ) - //.registerTypeAdapter( RelationalResult.class, RelationalResult.getSerializer() ) - .registerTypeAdapter( InformationPage.class, InformationPage.getSerializer() ) - .registerTypeAdapter( InformationGroup.class, InformationGroup.getSerializer() ) - .registerTypeAdapter( InformationStacktrace.class, InformationStacktrace.getSerializer() ) - .registerTypeAdapter( PluginStatus.class, PluginStatus.getSerializer() ) - .create();*/ - } - - private static HttpServer INSTANCE = null; @Getter private WebSocket webSocketHandler; @@ -120,12 +69,13 @@ public static HttpServer getInstance() { } + @Getter private Javalin server; private Crud crud; - public HttpServer( final TransactionManager transactionManager, final Authenticator authenticator ) { - this.transactionManager = transactionManager; + public HttpServer( TransactionManager manager, final Authenticator authenticator ) { + this.transactionManager = manager; this.authenticator = authenticator; } @@ -147,11 +97,6 @@ public void run() { } ) ); } ).start( RuntimeConfig.WEBUI_SERVER_PORT.getInteger() ); - this.crud = new Crud( - transactionManager, - Catalog.defaultUserId, - Catalog.defaultNamespaceId ); - this.webSocketHandler = new WebSocket( crud ); webSockets( server, this.webSocketHandler ); @@ -166,16 +111,28 @@ public void run() { } } ); - attachExceptions( server ); + this.crud = new Crud( this.transactionManager ); - crudRoutes( server, crud ); + attachRoutes( server, crud ); - StatusService.printInfo( String.format( "Polypheny-UI started and is listening on port %d.", RuntimeConfig.WEBUI_SERVER_PORT.getInteger() ) ); + StatusService.printInfo( + String.format( "Polypheny-UI started and is listening on port %d.", RuntimeConfig.WEBUI_SERVER_PORT.getInteger() ) ); + attachExceptions( server ); INSTANCE = this; } + public Consumer3, HandlerType> getRouteRegisterer() { + return this::addSerializedRoute; + } + + + public BiConsumer> getWebSocketRegisterer() { + return this::addWebsocketRoute; + } + + private void attachExceptions( Javalin server ) { server.exception( SocketException.class, ( e, ctx ) -> { ctx.status( 400 ).result( "Error: Could not determine IP address." ); @@ -193,13 +150,19 @@ private void defaultException( Class exceptionClass, Javali /** - * Defines the routes for this Server + * Defines the routes for this server */ - private void crudRoutes( Javalin webuiServer, Crud crud ) { + private void attachRoutes( Javalin webuiServer, Crud crud ) { attachCatalogMetaRoutes( webuiServer, crud ); attachPartnerRoutes( webuiServer, crud ); + attachStatisticRoutes( webuiServer, crud ); + + attachPluginRoutes( webuiServer, crud ); + + attachDockerRoutes( webuiServer, crud ); + webuiServer.post( "/anyQuery", LanguageCrud::anyQuery ); webuiServer.post( "/insertTuple", crud::insertTuple ); @@ -210,14 +173,6 @@ private void crudRoutes( Javalin webuiServer, Crud crud ) { webuiServer.post( "/batchUpdate", crud::batchUpdate ); - webuiServer.post( "/allStatistics", ( ctx ) -> crud.statisticCrud.getStatistics( ctx, gsonExpose ) ); - - webuiServer.post( "/getTableStatistics", crud.statisticCrud::getTableStatistics ); - - webuiServer.post( "/getDashboardInformation", crud.statisticCrud::getDashboardInformation ); - - webuiServer.post( "/getDashboardDiagram", crud.statisticCrud::getDashboardDiagram ); - webuiServer.post( "/getColumns", crud::getColumns ); webuiServer.post( "/getDataSourceColumns", crud::getDataSourceColumns ); @@ -322,6 +277,14 @@ private void crudRoutes( Javalin webuiServer, Crud crud ) { webuiServer.get( "/getFile/{file}", crud::getFile ); + webuiServer.get( "/getDocumentDatabases", crud.languageCrud::getDocumentDatabases ); + + webuiServer.get( "/product", ctx -> ctx.result( "Polypheny-DB" ) ); + + } + + + private static void attachDockerRoutes( Javalin webuiServer, Crud crud ) { webuiServer.post( "/addDockerInstance", crud::addDockerInstance ); webuiServer.post( "/testDockerInstance/{dockerId}", crud::testDockerInstance ); @@ -349,21 +312,30 @@ private void crudRoutes( Javalin webuiServer, Crud crud ) { webuiServer.get( "/getDockerSettings", crud::getDockerSettings ); webuiServer.post( "/changeDockerSettings", crud::changeDockerSettings ); + } - webuiServer.get( "/getDocumentDatabases", crud.languageCrud::getDocumentDatabases ); - - webuiServer.get( "/product", ctx -> ctx.result( "Polypheny-DB" ) ); + private static void attachPluginRoutes( Javalin webuiServer, Crud crud ) { webuiServer.post( "/loadPlugins", crud::loadPlugins ); webuiServer.post( "/unloadPlugin", crud::unloadPlugin ); webuiServer.get( "/getAvailablePlugins", crud::getAvailablePlugins ); + } + + + private static void attachStatisticRoutes( Javalin webuiServer, Crud crud ) { + webuiServer.post( "/allStatistics", crud.statisticCrud::getStatistics ); + + webuiServer.post( "/getTableStatistics", crud.statisticCrud::getTableStatistics ); + + webuiServer.post( "/getDashboardInformation", crud.statisticCrud::getDashboardInformation ); + webuiServer.post( "/getDashboardDiagram", crud.statisticCrud::getDashboardDiagram ); } - private void attachPartnerRoutes( Javalin webuiServer, Crud crud ) { + private static void attachPartnerRoutes( Javalin webuiServer, Crud crud ) { webuiServer.get( "/auth/deregister", crud.authCrud::deregister ); } @@ -449,53 +421,15 @@ private void webSockets( Javalin webuiServer, Consumer handler ) { } - public void addWebsocket( String route, Consumer handler ) { + public void addWebsocketRoute( String route, Consumer handler ) { server.ws( route, handler ); } - /** - * To avoid the CORS problem, when the ConfigServer receives requests from the Web UI. - * See https://gist.github.com/saeidzebardast/e375b7d17be3e0f4dddf - */ - private static void enableCORS( Javalin webuiServer ) { - //staticFiles.header("Access-Control-Allow-Origin", "*"); - - webuiServer.options( "/*", ctx -> { - String accessControlRequestHeaders = ctx.req().getHeader( "Access-Control-Request-Headers" ); - if ( accessControlRequestHeaders != null ) { - ctx.res().setHeader( "Access-Control-Allow-Headers", accessControlRequestHeaders ); - } - - String accessControlRequestMethod = ctx.req().getHeader( "Access-Control-Request-Method" ); - if ( accessControlRequestMethod != null ) { - ctx.res().setHeader( "Access-Control-Allow-Methods", accessControlRequestMethod ); - } - - ctx.result( "OK" ); - } ); - - webuiServer.before( ctx -> { - //res.header("Access-Control-Allow-Origin", "*"); - ctx.res().setHeader( "Access-Control-Allow-Origin", "*" ); - ctx.res().setHeader( "Access-Control-Allow-Credentials", "true" ); - ctx.res().setHeader( "Access-Control-Allow-Headers", "*" ); - ctx.res().setContentType( "application/json" ); - } ); - } - - public void removeRoute( String route, HandlerType type ) { addRoute( route, ( ctx, crud ) -> null, Object.class, type ); } - public enum HandlerType { - POST, - GET, - PUT, - DELETE, - PATCH - } } diff --git a/webui/src/main/java/org/polypheny/db/webui/WebSocket.java b/webui/src/main/java/org/polypheny/db/webui/WebSocket.java index ba885639d9..23af5f6b3d 100644 --- a/webui/src/main/java/org/polypheny/db/webui/WebSocket.java +++ b/webui/src/main/java/org/polypheny/db/webui/WebSocket.java @@ -121,9 +121,8 @@ public void onMessage( final WsMessageContext ctx ) { ctx.session, queryRequest, crud.getTransactionManager(), - crud.getUserId(), - crud.getNamespaceId() - ); + Catalog.defaultUserId, + Catalog.defaultNamespaceId ); for ( Result result : results ) { if ( !(result instanceof RelationalResult) ) { diff --git a/webui/src/main/java/org/polypheny/db/webui/crud/CatalogCrud.java b/webui/src/main/java/org/polypheny/db/webui/crud/CatalogCrud.java index 76862e6c54..e102fb7b8f 100644 --- a/webui/src/main/java/org/polypheny/db/webui/crud/CatalogCrud.java +++ b/webui/src/main/java/org/polypheny/db/webui/crud/CatalogCrud.java @@ -43,8 +43,6 @@ public class CatalogCrud { private static Crud crud; - private final Catalog catalog = Catalog.getInstance(); - public CatalogCrud( Crud crud ) { CatalogCrud.crud = crud; @@ -53,7 +51,7 @@ public CatalogCrud( Crud crud ) { public void getNamespaces( Context context ) { NamespaceRequest request = context.bodyAsClass( NamespaceRequest.class ); - List namespaces = catalog + List namespaces = Catalog.getInstance() .getSnapshot() .getNamespaces( request.pattern != null ? Pattern.of( request.pattern ) : null ) .stream().map( NamespaceModel::from ).collect( Collectors.toList() ); @@ -62,9 +60,8 @@ public void getNamespaces( Context context ) { public void getTypeNamespaces( final Context ctx ) { - ctx.json( catalog - .getSnapshot(). - getNamespaces( null ) + ctx.json( Catalog.snapshot() + .getNamespaces( null ) .stream() .collect( Collectors.toMap( LogicalNamespace::getName, LogicalNamespace::getNamespaceType ) ) ); } @@ -79,7 +76,7 @@ public void getSchemaTree( final Context ctx ) { ctx.json( new ArrayList<>() ); } - List namespaces = catalog.getSnapshot().getNamespaces( null ); + List namespaces = Catalog.snapshot().getNamespaces( null ); // remove unwanted namespaces namespaces = namespaces.stream().filter( s -> request.dataModels.contains( s.namespaceType ) ).collect( Collectors.toList() ); for ( LogicalNamespace namespace : namespaces ) { @@ -108,7 +105,7 @@ public void getSchemaTree( final Context ctx ) { private void attachDocumentTreeElements( LogicalNamespace namespace, SchemaTreeRequest request, SidebarElement schemaTree ) { List collectionTree = new ArrayList<>(); - List collections = catalog.getSnapshot().doc().getCollections( namespace.id, null ); + List collections = Catalog.snapshot().doc().getCollections( namespace.id, null ); for ( LogicalCollection collection : collections ) { SidebarElement tableElement = attachCollectionElement( namespace, request, collection ); @@ -149,7 +146,7 @@ private static SidebarElement attachCollectionElement( LogicalNamespace namespac private void attachTreeElements( LogicalNamespace namespace, SchemaTreeRequest request, SidebarElement schemaTree ) { List collectionTree = new ArrayList<>(); - List tables = catalog.getSnapshot().rel().getTables( namespace.id, null ); + List tables = Catalog.snapshot().rel().getTables( namespace.id, null ); for ( LogicalTable table : tables ) { String icon = "fa fa-table"; if ( table.entityType == EntityType.SOURCE ) { @@ -163,7 +160,7 @@ private void attachTreeElements( LogicalNamespace namespace, SchemaTreeRequest r SidebarElement tableElement = new SidebarElement( namespace.name + "." + table.name, table.name, namespace.namespaceType, request.routerLinkRoot, icon ); if ( request.depth > 2 ) { - List columns = catalog.getSnapshot().rel().getColumns( table.id ); + List columns = Catalog.snapshot().rel().getColumns( table.id ); for ( LogicalColumn column : columns ) { tableElement.addChild( new SidebarElement( namespace.name + "." + table.name + "." + column.name, column.name, namespace.namespaceType, request.routerLinkRoot, icon ).setCssClass( "sidebarColumn" ) ); } @@ -209,7 +206,7 @@ public void getSnapshot( Context context ) { public void getCurrentSnapshot( Context context ) { - context.json( catalog.getSnapshot().id() ); + context.json( Catalog.snapshot().id() ); } diff --git a/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java b/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java index 6f724aa521..2844375b17 100644 --- a/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java +++ b/webui/src/main/java/org/polypheny/db/webui/crud/LanguageCrud.java @@ -91,7 +91,7 @@ public LanguageCrud( Crud crud ) { public static void anyQuery( Context ctx ) { QueryRequest request = ctx.bodyAsClass( QueryRequest.class ); QueryLanguage language = QueryLanguage.from( request.language ); - Result result = anyQuery( language, null, request, crud.getTransactionManager(), crud.getUserId(), crud.getNamespaceId() ).get( 0 ); + Result result = anyQuery( language, null, request, crud.getTransactionManager(), Catalog.defaultUserId, Catalog.defaultNamespaceId ).get( 0 ); ctx.json( result ); } diff --git a/webui/src/main/java/org/polypheny/db/webui/crud/StatisticCrud.java b/webui/src/main/java/org/polypheny/db/webui/crud/StatisticCrud.java index fef5bf83ab..d713b9557e 100644 --- a/webui/src/main/java/org/polypheny/db/webui/crud/StatisticCrud.java +++ b/webui/src/main/java/org/polypheny/db/webui/crud/StatisticCrud.java @@ -16,7 +16,6 @@ package org.polypheny.db.webui.crud; -import com.google.gson.Gson; import io.javalin.http.Context; import java.sql.Timestamp; import java.util.List; @@ -47,7 +46,6 @@ public class StatisticCrud { private static Crud crud; @Getter private boolean activeTracking = false; - private final StatisticsManager statisticsManager = StatisticsManager.getInstance(); public StatisticCrud( Crud crud ) { @@ -87,16 +85,16 @@ public void getTableStatistics( Context ctx ) { UIRequest request = ctx.bodyAsClass( UIRequest.class ); LogicalTable table = Catalog.getInstance().getSnapshot().rel().getTable( request.entityId ).orElseThrow(); - ctx.json( statisticsManager.getTableStatistic( table.namespaceId, table.id ) ); + ctx.json( StatisticsManager.getInstance().getTableStatistic( table.namespaceId, table.id ) ); } /** * Return all available statistics to the client */ - public void getStatistics( final Context ctx, Gson gsonExpose ) { + public void getStatistics( final Context ctx ) { if ( RuntimeConfig.DYNAMIC_QUERYING.getBoolean() ) { - ctx.result( gsonExpose.toJson( statisticsManager.getQualifiedStatisticMap() ) ); + ctx.json( StatisticsManager.getInstance().getQualifiedStatisticMap() ); } else { ctx.json( new ConcurrentHashMap<>() ); } @@ -107,7 +105,7 @@ public void getStatistics( final Context ctx, Gson gsonExpose ) { * General information for the UI dashboard. */ public void getDashboardInformation( Context ctx ) { - ctx.json( statisticsManager.getDashboardInformation() ); + ctx.json( StatisticsManager.getInstance().getDashboardInformation() ); }