diff --git a/application/probe/daanse.probe.bndrun b/application/probe/daanse.probe.bndrun index 466fbbe..93b447e 100644 --- a/application/probe/daanse.probe.bndrun +++ b/application/probe/daanse.probe.bndrun @@ -30,17 +30,19 @@ -runrequires: \ bnd.identity;id='${project.artifactId}',\ - bnd.identity;id='org.glassfish.hk2.osgi-resource-locator',\ - bnd.identity;id='com.sun.xml.messaging.saaj.impl',\ bnd.identity;id='org.apache.felix.metatype',\ - bnd.identity;id='org.eclipse.daanse.olap.xmla.bridge',\ - bnd.identity;id='org.eclipse.daanse.xmla.server.jakarta.saaj',\ + bnd.identity;id='org.eclipse.daanse.olap.xmla.connector',\ + bnd.identity;id='org.eclipse.daanse.xmla.server.jdk.httpserver',\ + bnd.identity;id='org.eclipse.daanse.xmla.server.auth.dummy',\ + bnd.identity;id='org.eclipse.daanse.xmla.server.auth.roles',\ bnd.identity;id='ch.qos.logback.classic',\ bnd.identity;id='org.eclipse.daanse.jdbc.datasource.h2',\ + bnd.identity;id='org.eclipse.daanse.jdbc.datasource.pools.hikari',\ bnd.identity;id='org.eclipse.daanse.sql.dialect.db.h2',\ bnd.identity;id='org.eclipse.daanse.sql.jdbc.impl',\ bnd.identity;id='org.eclipse.daanse.mdx.parser.api',\ bnd.identity;id='org.eclipse.daanse.mdx.parser.ccc',\ + bnd.identity;id='org.eclipse.daanse.dmv.parser.ccc',\ bnd.identity;id='org.eclipse.daanse.rolap.mapping.model',\ bnd.identity;id='org.eclipse.daanse.sql.jdbc.importer.csv',\ bnd.identity;id='org.eclipse.daanse.sql.guard.api',\ @@ -76,12 +78,11 @@ -runbundles: \ ai.starlake.transpiler;version='[1.8.0,1.8.1)',\ ch.qos.logback.classic;version='[1.5.6,1.5.7)',\ + com.fasterxml.woodstox.woodstox-core;version='[7.1.1,7.1.2)',\ com.github.ben-manes.caffeine;version='[3.1.2,3.1.3)',\ com.h2database;version='[2.3.230,2.3.231)',\ - com.sun.xml.messaging.saaj.impl;version='[3.0.4,3.0.5)',\ + com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\ de.siegmar.fastcsv;version='[3.1.0,3.1.1)',\ - jakarta.activation-api;version='[2.1.3,2.1.4)',\ - jakarta.xml.soap-api;version='[3.0.2,3.0.3)',\ net.sf.jsqlparser;version='[5.3.167,5.3.168)',\ org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\ org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\ @@ -92,15 +93,24 @@ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.10,2.2.11)',\ - org.eclipse.daanse.cwm.model.cwm;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.cwm.util;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.foundation.datatypes;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.foundation.keysindexes;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.objectmodel.behavioral;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.objectmodel.core;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.objectmodel.instance;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.cwm.model.cwm.resource.relational;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.dmv.model.api;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.dmv.model.record;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.dmv.parser.api;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.dmv.parser.ccc;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.io.fs.watcher.api;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.io.fs.watcher.watchservice;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.jakarta.servlet.filter.auth.dummy.role;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.jakarta.servlet.filter.cors;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.jakarta.servlet.soap;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.jdbc.datasource.common;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.jdbc.datasource.h2;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.jdbc.datasource.pools.api;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.jdbc.datasource.pools.hikari;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.lcid.api;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.lcid.basic;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.mdx.model.api;version='[0.0.1,0.0.2)',\ @@ -120,7 +130,7 @@ org.eclipse.daanse.olap.odc;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.olap.xmla.bridge;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.rolap.core;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.rolap.documentation.api;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.rolap.documentation.common;version='[0.0.1,0.0.2)',\ @@ -142,19 +152,36 @@ org.eclipse.daanse.sql.statement.api;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.sql.statement.impl;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.xmla.api;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.csdl.model.v2.an;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.csdl.model.v2.bi;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.csdl.model.v2.cg;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.csdl.model.v2.edm;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.model.record;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.server.adapter.soapmessage;version='[0.0.1,0.0.2)',\ - org.eclipse.daanse.xmla.server.jakarta.saaj;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.csdl.v2.an;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.csdl.v2.bi;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.csdl.v2.cg;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.csdl.v2.edm;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.empty;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.engine;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.engine200;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.engine300;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.engine300_300;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.exception;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.ext;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.io;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.mddataset;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.msxmla;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.multipleresults;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.rowset.core;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.rowset.mining;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.rowset.multidimensional;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.rowset.relational;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.rowset.server;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.soap;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.model.xmla;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.server.adapter.emf;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.server.auth.dummy;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.server.auth.roles;version='[0.0.1,0.0.2)',\ + org.eclipse.daanse.xmla.server.jdk.httpserver;version='[0.0.1,0.0.2)',\ org.eclipse.emf.common;version='[2.44.0,2.44.1)',\ org.eclipse.emf.ecore;version='[2.41.0,2.41.1)',\ org.eclipse.emf.ecore.xmi;version='[2.39.0,2.39.1)',\ org.eclipse.fennec.emf.osgi.component;version='[0.1.1,0.1.2)',\ - org.glassfish.hk2.osgi-resource-locator;version='[2.5.0,2.5.1)',\ - org.jvnet.staxex.stax-ex;version='[2.1.0,2.1.1)',\ org.objectweb.asm;version='[9.9.0,9.9.1)',\ org.objectweb.asm.commons;version='[9.9.0,9.9.1)',\ org.objectweb.asm.tree;version='[9.9.0,9.9.1)',\ @@ -166,4 +193,5 @@ org.osgi.util.converter;version='[1.0.9,1.0.10)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ - org.osgi.util.pushstream;version='[1.1.0,1.1.1)' + org.osgi.util.pushstream;version='[1.1.0,1.1.1)',\ + stax2-api;version='[4.2.2,4.2.3)' diff --git a/application/probe/pom.xml b/application/probe/pom.xml index 5e80fcd..331032f 100644 --- a/application/probe/pom.xml +++ b/application/probe/pom.xml @@ -23,6 +23,24 @@ + + biz.aQute.bnd + bnd-resolver-maven-plugin + ${bnd.version} + + false + + daanse.probe.bndrun + + true + false + + compile + runtime + test + + + biz.aQute.bnd bnd-export-maven-plugin @@ -86,6 +104,20 @@ compile + + org.eclipse.daanse + org.eclipse.daanse.jdbc.datasource.pools.api + 0.0.1-SNAPSHOT + compile + + + + org.eclipse.daanse + org.eclipse.daanse.jdbc.datasource.pools.hikari + 0.0.1-SNAPSHOT + compile + + org.eclipse.daanse org.eclipse.daanse.jakarta.servlet.filter.cors diff --git a/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/Probe.java b/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/Probe.java index eccff45..76fa8e9 100644 --- a/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/Probe.java +++ b/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/Probe.java @@ -43,16 +43,21 @@ public class Probe { private static final String CONFIG_IDENT = "probe"; private static final String TARGET_EXT = ".target"; - private static final String PID_MS_SOAP_MSG_SAAJ = "daanse.xmla.server.jakarta.saaj.XmlaServlet"; - private static final String PID_XMLA_SERVICE = "daanse.olap.xmla.bridge.ContextGroupXmlaService"; + // The EMF-native stack: the connector serves the SPI, the JDK HTTP server fronts it on + // its own port (8090, /xmla). + private static final String PID_XMLA_SERVICE = "daanse.olap.xmla.connector.OlapXmlaConnector"; + private static final String PID_XMLA_HTTP = + "org.eclipse.daanse.xmla.server.jdk.httpserver.JdkHttpServer"; private static final String PID_CONTEXT_GROUP = "daanse.olap.core.BasicContextGroup"; + private static final String PID_FIXED_IDENTITY = + "org.eclipse.daanse.xmla.server.auth.dummy.FixedIdentityAuthenticator"; @Reference ConfigurationAdmin ca; - private Configuration configXmlaEndpoint; - private Configuration confSoapLoggingHandler; private Configuration confContextGroupXmlaService; + private Configuration configXmlaHttp; + private Configuration configFixedIdentity; private Configuration confDataSource; private Configuration confContextGroup; private Configuration configAuthFilter; @@ -72,9 +77,10 @@ public class Probe { public void activate() throws IOException { logger.info("Activating ProbeSetup"); - initXmlaEndPoint(); initRoleAuthFilter(); initCorsFilter(); + initXmlaHttp(); + initFixedIdentity(); initXmlaService(); initFileListener(); initContextGroup(); @@ -107,6 +113,37 @@ private void initContextGroup() throws IOException { confContextGroup.update(propsCG); } + /** + * The XMLA port. Mechanisms are services rather than configuration, so this + * only states the endpoint's policy and its CORS. + */ + private void initXmlaHttp() throws IOException { + configXmlaHttp = ca.getConfiguration(PID_XMLA_HTTP, "?"); + Dictionary dict = new Hashtable<>(); + dict.put("corsAllowedOrigins", "*"); + // The fixed identity below names every caller but proves nothing about them, and + // a stand-in deliberately does not satisfy a demand for a login. Demanding one + // here would refuse every request; this probe is a development server and says so. + dict.put("requirePrincipal", Boolean.FALSE); + configXmlaHttp.update(dict); + } + + /** + * The probe is a development server and authenticates nobody: every caller + * becomes the same configured user, which is enough to exercise the roles a + * catalog defines without a directory to talk to. + */ + private void initFixedIdentity() throws IOException { + configFixedIdentity = ca.getConfiguration(PID_FIXED_IDENTITY, "?"); + Dictionary dict = new Hashtable<>(); + // This names every caller without verifying anything, which the component makes + // the deployment say out loud. + dict.put("acknowledgeUnauthenticated", Boolean.TRUE); + dict.put("userName", "probe"); + dict.put("roles", new String[] { "Admin" }); + configFixedIdentity.update(dict); + } + private void initXmlaService() throws IOException { confContextGroupXmlaService = ca.getFactoryConfiguration(PID_XMLA_SERVICE, CONFIG_IDENT, "?"); @@ -145,18 +182,6 @@ private void initCorsFilter() throws IOException { } - private void initXmlaEndPoint() throws IOException { - - configXmlaEndpoint = ca.getFactoryConfiguration(PID_MS_SOAP_MSG_SAAJ, CONFIG_IDENT, "?"); - - Dictionary dict = new Hashtable<>(); - dict.put("xmlaService.target", "(service.pid=*)"); - dict.put("osgi.http.whiteboard.servlet.pattern", "/xmla"); - - configXmlaEndpoint.update(dict); - - } - private void initDocumenter() throws IOException { configDocumenterMarkdown = ca.getFactoryConfiguration( @@ -177,7 +202,7 @@ private void initODC() throws IOException { CONFIG_IDENT, "?"); Dictionary dict = new Hashtable<>(); dict.put(org.eclipse.daanse.olap.odc.simple.api.Constants.CREATOR_PROPERTY_DATASOURCE, - "http://localhost:8080/xmla"); + "http://localhost:8090/xmla"); configOdcWriter.update(dict); configAutoODC = ca.getFactoryConfiguration(org.eclipse.daanse.olap.odc.simple.api.Constants.AUTO_ODC_PID, @@ -198,19 +223,18 @@ private void initCheckReporter() throws IOException { public void deactivate() throws IOException { logger.info("Deactivating ProbeSetup"); - if (configXmlaEndpoint != null) { - configXmlaEndpoint.delete(); - } if (configAuthFilter != null) { configAuthFilter.delete(); } + if (configFixedIdentity != null) { + configFixedIdentity.delete(); + } + if (configXmlaHttp != null) { + configXmlaHttp.delete(); + } if (configCorsFilter != null) { configCorsFilter.delete(); } - if (confSoapLoggingHandler != null) { - confSoapLoggingHandler.delete(); - } - if (configDocumenterMarkdown != null) { configDocumenterMarkdown.delete(); } diff --git a/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/ProbeFileListener.java b/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/ProbeFileListener.java index 82bed95..4a911ba 100644 --- a/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/ProbeFileListener.java +++ b/application/probe/src/main/java/org/eclipse/daanse/server/application/probe/ProbeFileListener.java @@ -17,10 +17,12 @@ import static org.eclipse.daanse.jdbc.datasource.h2.api.Constants.DATASOURCE_PROPERTY_PLUGABLE_FILESYSTEM; import static org.eclipse.daanse.jdbc.datasource.h2.api.Constants.OPTION_PLUGABLE_FILESYSTEM_MEM_FS; import static org.eclipse.daanse.jdbc.datasource.h2.api.Constants.PID_DATASOURCE; +import static org.eclipse.daanse.jdbc.datasource.pools.api.Constants.POOL_PROPERTY_DATASOURCE_TARGET; +import static org.eclipse.daanse.jdbc.datasource.pools.hikari.api.Constants.PID_CONNECTION_POOL; import static org.eclipse.daanse.sql.jdbc.importer.csv.api.Constants.PID_CSV_DATA_IMPORTER; import static org.eclipse.daanse.rolap.core.api.Constants.BASIC_CONTEXT_PID; import static org.eclipse.daanse.rolap.core.api.Constants.BASIC_CONTEXT_REF_NAME_CATALOG_MAPPING_SUPPLIER; -import static org.eclipse.daanse.rolap.core.api.Constants.BASIC_CONTEXT_REF_NAME_DATA_SOURCE; +import static org.eclipse.daanse.rolap.core.api.Constants.BASIC_CONTEXT_REF_NAME_CONNECTION_POOL; import static org.eclipse.daanse.rolap.core.api.Constants.BASIC_CONTEXT_REF_NAME_DIALECT_FACTORY; import java.io.IOException; @@ -68,6 +70,7 @@ public class ProbeFileListener implements FileSystemWatcherListener { ConfigurationAdmin ca; private Map catalogFolderConfigsDS = new ConcurrentHashMap<>(); + private Map catalogFolderConfigsPool = new ConcurrentHashMap<>(); private Map catalogFolderConfigsCSV = new ConcurrentHashMap<>(); private Map catalogFolderConfigsContext = new ConcurrentHashMap<>(); private Map catalogFolderConfigsMapping = new ConcurrentHashMap<>(); @@ -122,6 +125,15 @@ private void removePath(Path path) { logger.error("Failed to delete context configuration for path: {}", path, e); } + try { + Configuration c = catalogFolderConfigsPool.remove(path); + if (c != null) { + c.delete(); + } + } catch (IOException e) { + logger.error("Failed to delete connection pool configuration for path: {}", path, e); + } + try { Configuration c = catalogFolderConfigsMapping.remove(path); c.delete(); @@ -151,6 +163,7 @@ private void addPath(Path path) { try { createH2DataSource(path, matcherKey); + createConnectionPool(path, matcherKey); createCsvDatabaseImporter(path, matcherKey); createMapping(path, matcherKey); createCheckSuite(path, matcherKey); @@ -209,7 +222,7 @@ private void createContext(Path path, String matcherKey) throws IOException { Configuration configContext = ca.getFactoryConfiguration(BASIC_CONTEXT_PID, UUID.randomUUID().toString(), "?"); Dictionary props = new Hashtable<>(); - props.put(BASIC_CONTEXT_REF_NAME_DATA_SOURCE + TARGET_EXT, filterOfMatcherKey(matcherKey)); + props.put(BASIC_CONTEXT_REF_NAME_CONNECTION_POOL + TARGET_EXT, filterOfMatcherKey(matcherKey)); props.put(BASIC_CONTEXT_REF_NAME_DIALECT_FACTORY + TARGET_EXT, "(org.eclipse.daanse.dialect.name=H2)"); props.put(BASIC_CONTEXT_REF_NAME_CATALOG_MAPPING_SUPPLIER + TARGET_EXT, filterOfMatcherKey(matcherKey)); @@ -250,12 +263,32 @@ private void createH2DataSource(Path path, String matcherKey) throws IOException propsH2.put(DATASOURCE_PROPERTY_IDENTIFIER, UUID.randomUUID().toString()); propsH2.put(DATASOURCE_PROPERTY_PLUGABLE_FILESYSTEM, OPTION_PLUGABLE_FILESYSTEM_MEM_FS); + // Without this, H2 discards the in-memory database as soon as the last connection + // closes - the CSV importer finishes, closes, and the pool later opens a fresh empty + // database of the same name. -1 keeps it for the lifetime of the JVM. + propsH2.put(org.eclipse.daanse.jdbc.datasource.h2.api.Constants + .DATASOURCE_PROPERTY_DB_CLOSE_DELAY, "-1"); propsH2.put(KEY_FILE_CONTEXT_MATCHER, matcherKey); configH2.update(propsH2); catalogFolderConfigsDS.put(path, configH2); } + /** + * The pool between the folder's DataSource and its context. The context binds + * a pool, never a DataSource, so every catalog folder needs one of its own. + */ + private void createConnectionPool(Path path, String matcherKey) throws IOException { + Configuration configPool = ca.getFactoryConfiguration(PID_CONNECTION_POOL, UUID.randomUUID().toString(), "?"); + + Dictionary props = new Hashtable<>(); + props.put(POOL_PROPERTY_DATASOURCE_TARGET, filterOfMatcherKey(matcherKey)); + props.put(KEY_FILE_CONTEXT_MATCHER, matcherKey); + configPool.update(props); + + catalogFolderConfigsPool.put(path, configPool); + } + private static final String filterOfMatcherKey(String matcherKey) { return "(" + KEY_FILE_CONTEXT_MATCHER + "=" + matcherKey + ")"; }