diff --git a/xmla/bridge/pom.xml b/xmla/bridge/pom.xml index da74dd5..98d4c84 100644 --- a/xmla/bridge/pom.xml +++ b/xmla/bridge/pom.xml @@ -68,5 +68,11 @@ 0.0.1-SNAPSHOT test + + org.eclipse.daanse + org.eclipse.daanse.xmla.csdl.model.v2.edm + 0.0.1-SNAPSHOT + compile + diff --git a/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/CSDLUtils.java b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/CSDLUtils.java new file mode 100644 index 0000000..596eb12 --- /dev/null +++ b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/CSDLUtils.java @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2025 Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * SmartCity Jena - initial + * Stefan Bischof (bipolis.org) - initial + */ +package org.eclipse.daanse.olap.xmla.bridge.discover; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.eclipse.daanse.olap.api.element.Catalog; +import org.eclipse.daanse.olap.api.element.Cube; +import org.eclipse.daanse.olap.api.element.Dimension; +import org.eclipse.daanse.olap.api.element.Hierarchy; +import org.eclipse.daanse.olap.api.element.Level; +import org.eclipse.daanse.olap.api.element.Member; +import org.eclipse.daanse.olap.common.StandardProperty; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.BiFactory; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.TEntityContainer; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.TEntitySet; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.TEntityType; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.THierarchy; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.TLevel; +import org.eclipse.daanse.xmla.csdl.model.v2.bi.TMeasure; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.EdmFactory; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.EntityContainerType; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.EntitySetType; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.TEntityKeyElement; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.TEntityProperty; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.TPropertyRef; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.TSchema; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.XMLResource; + +public class CSDLUtils { + private static EdmFactory edmFactory = EdmFactory.eINSTANCE; + private static BiFactory biFactory = BiFactory.eINSTANCE; + + private static final String csdlMd3 = """ + + + + %s + + %s + + + %s + + """; + + private static final String csdlMd4 = """ + + + + + + """; + + public static TSchema getCSDLModel(Catalog catalog, Optional perspectiveName) { + if (perspectiveName.isPresent()) { + String cubeName = perspectiveName.get(); + Optional oCube = catalog.getCubes().stream().filter(c -> cubeName.equals(c.getName())).findFirst(); + if (oCube.isPresent()) { + Cube cube = oCube.get(); + TSchema schema = edmFactory.createTSchema(); + schema.setNamespace("Model"); + schema.setAlias("Model"); + + EntityContainerType container = edmFactory.createEntityContainerType(); + container.setName(catalog.getName()); + + TEntityContainer biContainer = biFactory.createTEntityContainer(); + biContainer.setCaption(cube.getName()); + biContainer.setCulture("de-DE"); + container.setBiEntityContainer(biContainer); + + + List measures = cube.getMeasures(); + if (measures != null) { + for (Member member : measures) { + EntitySetType entitySet = edmFactory.createEntitySetType(); + entitySet.setName(member.getUniqueName()); + entitySet.setEntityType("Model." + member.getUniqueName()); + TEntitySet biEntitySet = biFactory.createTEntitySet(); + biEntitySet.setCaption(member.getCaption()); + entitySet.setBiEntitySet(biEntitySet); + container.getEntitySet().add(entitySet); + + org.eclipse.daanse.xmla.csdl.model.v2.edm.TEntityType measureSumType = edmFactory.createTEntityType(); + measureSumType.setName(member.getUniqueName()); + + TEntityType biMeasureSumType = biFactory.createTEntityType(); + biMeasureSumType.setContents(member.getUniqueName()); + measureSumType.setBiEntityType(biMeasureSumType); + + TEntityProperty valueProperty = edmFactory.createTEntityProperty(); + valueProperty.setName(member.getUniqueName()); + String type = getType(member.getPropertyValue(StandardProperty.DATATYPE.getName())); + valueProperty.setType(type); + valueProperty.setNullable(false); + + TMeasure biValueMeasure = biFactory.createTMeasure(); + biValueMeasure.setCaption(member.getUniqueName()); + biValueMeasure.setHidden(false); + valueProperty.setBiMeasure(biValueMeasure); + + measureSumType.getProperty().add(valueProperty); + schema.getEntityType().add(measureSumType); + } + } + + List hierarchies = cube.getHierarchies(); + if (hierarchies != null) { + for (Hierarchy hierarchy : hierarchies) { + EntitySetType entitySetHierarchy = edmFactory.createEntitySetType(); + entitySetHierarchy.setName(hierarchy.getUniqueName()); + entitySetHierarchy.setEntityType("Model." + hierarchy.getUniqueName()); + + TEntitySet biEntitySetHierarchy = biFactory.createTEntitySet(); + biEntitySetHierarchy.setCaption(hierarchy.getCaption()); + + entitySetHierarchy.setBiEntitySet(biEntitySetHierarchy); + + container.getEntitySet().add(entitySetHierarchy); + + org.eclipse.daanse.xmla.csdl.model.v2.edm.TEntityType hierarchyType = edmFactory.createTEntityType(); + hierarchyType.setName(hierarchy.getUniqueName()); + + List levels = new ArrayList<>(); + + List ls = hierarchy.getLevels(); + if (ls != null) { + for (Level l : ls) { + TLevel tLevel = biFactory.createTLevel(); + tLevel.setName(l.getUniqueName()); + tLevel.setCaption(l.getCaption()); + tLevel.setReferenceName(l.getUniqueName()); + levels.add(tLevel); + + TEntityProperty levelProperty = edmFactory.createTEntityProperty(); + levelProperty.setName(l.getUniqueName()); + levelProperty.setType("String"); //TODO need get type from level + levelProperty.setNullable(false); + hierarchyType.getProperty().add(levelProperty); + } + } + + THierarchy hierarchyTHierarchy = biFactory.createTHierarchy(); + hierarchyTHierarchy.setCaption(hierarchy.getCaption()); + hierarchyTHierarchy.setName(hierarchy.getUniqueName()); + hierarchyTHierarchy.setReferenceName(hierarchy.getUniqueName()); + + hierarchyTHierarchy.getLevel().addAll(levels); + + TEntityType hierarchyTEntityType = biFactory.createTEntityType(); + hierarchyTEntityType.setContents(hierarchy.getUniqueName()); + hierarchyTEntityType.getHierarchy().add(hierarchyTHierarchy); + + hierarchyType.setBiEntityType(hierarchyTEntityType); + + TEntityProperty hierarchyKeyProperty = edmFactory.createTEntityProperty(); + hierarchyKeyProperty.setName(hierarchy.getUniqueName()); + hierarchyKeyProperty.setType("Int32"); + hierarchyKeyProperty.setNullable(false); + + TPropertyRef hierarchyPropertyRef = edmFactory.createTPropertyRef(); + hierarchyPropertyRef.setName(hierarchy.getUniqueName()); + + TEntityKeyElement key = edmFactory.createTEntityKeyElement(); + key.getPropertyRef().add(hierarchyPropertyRef); + + hierarchyType.getProperty().add(hierarchyKeyProperty); + + schema.getEntityType().add(hierarchyType); + } + } + return schema; + } + } + return edmFactory.createTSchema(); + } + + private static String getType(Object propertyValue) { + if (propertyValue != null && propertyValue instanceof String value) { + switch (value) { + case "UNDEFINED": + case "String": + return "String"; + case "NUMERIC": + return "Numeric"; + case "Integer": + return "Int32"; + case "Boolean": + return "Boolean"; + case "Date": + return "Date"; + case "Time": + return "Time"; + case "Timestamp": + return "Timestamp"; + default: + return "String"; + } + } + return "String"; + } + + public static String getCSDLModelAsString(TSchema schema) { + try { + return serializeToXml(schema); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String getCSDL(Catalog catalog, Optional perspectiveName) { + if (perspectiveName.isPresent()) { + String cubeName = perspectiveName.get(); + Optional oCube = catalog.getCubes().stream().filter(c -> cubeName.equals(c.getName())).findFirst(); + if (oCube.isPresent()) { + return String.format(csdlMd3, cubeName, getEntitySets(oCube.get()), getEntityTypes(oCube.get())); + } + } + return String.format(csdlMd4); + } + + private static String serializeToXml(EObject eObject) throws IOException { + ResourceSetImpl resourceSet = new ResourceSetImpl(); + Resource resource = resourceSet.createResource(URI.createURI("temp.xml")); + resource.getContents().add(eObject); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Map options = new HashMap<>(); + options.put(XMLResource.OPTION_ENCODING, "UTF-8"); + options.put(XMLResource.OPTION_FORMATTED, Boolean.TRUE); + options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); + + resource.save(baos, options); + + resource.getContents().clear(); + resourceSet.getResources().remove(resource); + + return baos.toString("UTF-8"); + } + + private static String getEntityTypes(Cube cube) { + StringBuilder sb = new StringBuilder(); + boolean flag = true; + for (Dimension dimension : cube.getDimensions()) { + for (Hierarchy hierarchy : dimension.getHierarchies()) { + if (flag) { + flag = false; + } else { + sb.append(System.lineSeparator()); + } + sb.append("") + .append(System.lineSeparator()); + sb.append(" ") + .append(System.lineSeparator()) + .append(" ") + .append(System.lineSeparator()) + .append(" ") + .append(System.lineSeparator()); + + sb.append(" ") + .append(System.lineSeparator()) + .append("") + .append(System.lineSeparator()); + + for (Level level : hierarchy.getLevels()) { + sb.append(" ") + .append(System.lineSeparator()) + .append(""); + } + sb.append(System.lineSeparator()); + sb.append(" "); + sb.append(System.lineSeparator()); + for (Level level : hierarchy.getLevels()) { + sb.append(" "); + sb.append(System.lineSeparator()); + sb.append(" "); + sb.append(System.lineSeparator()); + sb.append(" "); + sb.append(System.lineSeparator()); + sb.append(" "); + sb.append(System.lineSeparator()); + sb.append(" "); + sb.append(System.lineSeparator()); + } + sb.append(" "); + sb.append(System.lineSeparator()); + sb.append(""); + + } + } + for (Member member : cube.getMeasures()) { + if (flag) { + flag = false; + } else { + sb.append(System.lineSeparator()); + } + sb.append("") + .append(System.lineSeparator()); + sb.append(" ") + .append(System.lineSeparator()) + .append(" ") + .append(System.lineSeparator()) + .append(" ") + .append(System.lineSeparator()); + + sb.append(" ") + //.append(System.lineSeparator()) + //.append(" ") + .append(System.lineSeparator()) + .append(""); + sb.append(System.lineSeparator()) + .append(""); + } + return sb.toString(); + } + + private static String getEntitySets(Cube cube) { + StringBuilder sb = new StringBuilder(); + boolean flag = true; + for (Dimension dimension : cube.getDimensions()) { + for (Hierarchy hierarchy : dimension.getHierarchies()) { + if (flag) { + flag = false; + } else { + sb.append(System.lineSeparator()); + } + sb.append("") + .append(System.lineSeparator()) + .append(""); + } + } + if (cube.getMeasures() != null && cube.getMeasures().size() > 0) { + for (Member member : cube.getMeasures()) { + if (flag) { + flag = false; + } else { + sb.append(System.lineSeparator()); + } + sb.append("") + .append(System.lineSeparator()) + .append(""); + } + } + return sb.toString(); + } + +} diff --git a/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/DelegatingDiscoverService.java b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/DelegatingDiscoverService.java index e4c02b8..e2d44f3 100644 --- a/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/DelegatingDiscoverService.java +++ b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/DelegatingDiscoverService.java @@ -272,10 +272,8 @@ public List xmlMetaData(DiscoverXmlMetaDataReque @Override public List csdlMetaData(DiscoverCsdlMetaDataRequest request, RequestMetaData metaData) { - //return otherSchemaService.csdlMetaData(request, metaData); - //TODO - return null; + return otherSchemaService.csdlMetaData(request, metaData); } } diff --git a/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/OtherDiscoverService.java b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/OtherDiscoverService.java index 8f67c9d..bd548a8 100644 --- a/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/OtherDiscoverService.java +++ b/xmla/bridge/src/main/java/org/eclipse/daanse/olap/xmla/bridge/discover/OtherDiscoverService.java @@ -26,7 +26,11 @@ import java.util.Set; import org.eclipse.daanse.olap.api.Context; +import org.eclipse.daanse.olap.api.DataTypeJdbc; import org.eclipse.daanse.olap.api.element.Catalog; +import org.eclipse.daanse.olap.api.element.DatabaseColumn; +import org.eclipse.daanse.olap.api.element.DatabaseSchema; +import org.eclipse.daanse.olap.api.element.DatabaseTable; import org.eclipse.daanse.olap.xmla.bridge.ContextGroupXmlaServiceConfig; import org.eclipse.daanse.olap.xmla.bridge.ContextListSupplyer; import org.eclipse.daanse.xmla.api.PropertyDefinition; @@ -47,6 +51,7 @@ import org.eclipse.daanse.xmla.api.discover.dbschema.tables.DbSchemaTablesRequest; import org.eclipse.daanse.xmla.api.discover.dbschema.tablesinfo.DbSchemaTablesInfoRequest; import org.eclipse.daanse.xmla.api.discover.discover.csdlmetadata.DiscoverCsdlMetaDataRequest; +import org.eclipse.daanse.xmla.api.discover.discover.csdlmetadata.DiscoverCsdlMetaDataResponseRow; import org.eclipse.daanse.xmla.api.discover.discover.datasources.DiscoverDataSourcesRequest; import org.eclipse.daanse.xmla.api.discover.discover.datasources.DiscoverDataSourcesResponseRow; import org.eclipse.daanse.xmla.api.discover.discover.enumerators.DiscoverEnumeratorsRequest; @@ -75,6 +80,8 @@ import org.eclipse.daanse.xmla.api.discover.mdschema.properties.MdSchemaPropertiesRequest; import org.eclipse.daanse.xmla.api.discover.mdschema.sets.MdSchemaSetsRequest; import org.eclipse.daanse.xmla.api.xmla.Restriction; +import org.eclipse.daanse.xmla.csdl.model.v2.edm.TSchema; +import org.eclipse.daanse.xmla.model.record.discover.discover.csdlmetadata.DiscoverCsdlMetaDataResponseRowR; import org.eclipse.daanse.xmla.model.record.discover.discover.datasources.DiscoverDataSourcesResponseRowR; import org.eclipse.daanse.xmla.model.record.discover.discover.enumerators.DiscoverEnumeratorsResponseRowR; import org.eclipse.daanse.xmla.model.record.discover.discover.keywords.DiscoverKeywordsResponseRowR; @@ -288,7 +295,7 @@ public List discoverSchemaRowsets(DiscoverSche } } result.add(new DiscoverSchemaRowsetsResponseRowR(o.name(), Optional.ofNullable(o.guid()), - Optional.ofNullable(restrictions), Optional.of((desc == null) ? "" : desc), Optional.empty())); + Optional.ofNullable(restrictions), Optional.ofNullable(desc), Optional.of(7l))); } } return result; @@ -328,6 +335,37 @@ public List xmlMetaData(DiscoverXmlMetaDataReque return result; } + public List csdlMetaData(DiscoverCsdlMetaDataRequest request, + RequestMetaData metaData) { + List result = new ArrayList<>(); + Optional catalogName = request.restrictions().catalogName(); + Optional perspectiveName = request.restrictions().perspectiveName(); + if (!catalogName.isPresent()) { + catalogName = request.properties().catalog(); + } + if (catalogName.isPresent()) { + Optional oCatalog = contextsListSupplyer.tryGetFirstByName(catalogName.get(), metaData.sessionId()); + if (oCatalog.isPresent()) { + Catalog catalog = oCatalog.get(); + + if (catalog != null) { + TSchema schema = CSDLUtils.getCSDLModel(catalog, perspectiveName); + //result.add(new DiscoverCsdlMetaDataResponseRowR(CSDLUtils.getCSDL(catalog, perspectiveName))); + result.add(new DiscoverCsdlMetaDataResponseRowR(CSDLUtils.getCSDLModelAsString(schema))); + } + } + } else { + List cs = contextsListSupplyer.get(metaData.sessionId()); + if (cs != null) { + Catalog catalog = cs.get(0); + TSchema schema = CSDLUtils.getCSDLModel(catalog, Optional.empty()); + //result.add(new DiscoverCsdlMetaDataResponseRowR(CSDLUtils.getCSDL(catalog, Optional.empty()))); + + } + } + return result; + } + private String getOperationDescription(String name) { switch (name) { case "DBSCHEMA_CATALOGS": diff --git a/xmla/bridge/test.bndrun b/xmla/bridge/test.bndrun index 8241254..b504317 100644 --- a/xmla/bridge/test.bndrun +++ b/xmla/bridge/test.bndrun @@ -73,11 +73,20 @@ org.eclipse.daanse.olap.xmla.bridge-tests;version='[0.0.1,0.0.2)',\ org.eclipse.daanse.sql.guard.api;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.mockito.junit-jupiter;version='[4.9.0,4.9.1)',\ - org.mockito.mockito-core;version='[4.9.0,4.9.1)',\ + 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.api;version='[1.0.0,1.0.1)',\ + org.mockito.junit-jupiter;version='[5.18.0,5.18.1)',\ + org.mockito.mockito-core;version='[5.18.0,5.18.1)',\ org.objenesis;version='[3.3.0,3.3.1)',\ org.opentest4j;version='[1.3.0,1.3.1)',\ + org.osgi.service.cm;version='[1.6.1,1.6.2)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.test.common;version='[1.3.0,1.3.1)',\ org.osgi.test.junit5;version='[1.3.0,1.3.1)',\