From 07a3d8a517c0f1b838970c5888fda4bf7a367a81 Mon Sep 17 00:00:00 2001 From: Stefan Bischof Date: Sat, 9 Aug 2025 16:53:00 +0200 Subject: [PATCH] Refactor XMLA Servlet and add localization with improved modularity... - Replaced old `XmlaServlet` with new implementation using metatype annotations. - Added `Constants` class for reusable definitions and servlet properties. - Introduced `ServletOCD` interface for configuration definitions. - Implemented `XmlaServletOCD` with localization and OCD support. - Updated `pom.xml` to include OSGi metatype annotations dependency. - Added `package-info.java` for `impl` package with versioning annotations. - Removed `package-info.java` from root `jakarta.saaj` package. - Added localization properties for servlet configuration in resource files. - Defined OCD names and descriptions in localization file. - Improved project structure for better modularity and maintainability. --- server/jakarta.saaj/pom.xml | 7 ++ .../server/jakarta/saaj/api/Constants.java | 75 +++++++++++++++++++ .../server/jakarta/saaj/api/package-info.java | 18 +++++ .../server/jakarta/saaj/impl/ServletOCD.java | 37 +++++++++ .../jakarta/saaj/{ => impl}/XmlaServlet.java | 19 +++-- .../jakarta/saaj/impl/XmlaServletOCD.java | 38 ++++++++++ .../jakarta/saaj/{ => impl}/package-info.java | 2 +- ...se.xmla.server.jakarta.saaj.ocd.properties | 21 ++++++ .../daanse/xmla/server/tck/TestSetup.java | 28 +++++++ 9 files changed, 237 insertions(+), 8 deletions(-) create mode 100644 server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/Constants.java create mode 100644 server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/package-info.java create mode 100644 server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/ServletOCD.java rename server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/{ => impl}/XmlaServlet.java (80%) create mode 100644 server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServletOCD.java rename server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/{ => impl}/package-info.java (85%) create mode 100644 server/jakarta.saaj/src/main/resources/OSGI-INF/l10n/org.eclipse.daanse.xmla.server.jakarta.saaj.ocd.properties create mode 100644 server/tck/src/main/java/org/eclipse/daanse/xmla/server/tck/TestSetup.java diff --git a/server/jakarta.saaj/pom.xml b/server/jakarta.saaj/pom.xml index cb80183..73d27bc 100644 --- a/server/jakarta.saaj/pom.xml +++ b/server/jakarta.saaj/pom.xml @@ -32,6 +32,13 @@ org.osgi org.osgi.service.servlet + + + org.osgi + org.osgi.service.metatype.annotations + compile + + org.apache.felix org.apache.felix.http.servlet-api diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/Constants.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/Constants.java new file mode 100644 index 0000000..2511e1c --- /dev/null +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/Constants.java @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2024 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.xmla.server.jakarta.saaj.api; + +import org.osgi.framework.Bundle; + +/** + * Constants of this {@link Bundle}. + */ +public class Constants { + + private Constants() { + } + + /** + * Constant for the {@link org.osgi.framework.Constants#SERVICE_PID} of the XMLA Servlet Service. + */ + public static final String PID_XMLA_SERVLET = "daanse.xmla.server.jakarta.saaj.XmlaServlet"; + + /** + * Constant for the reference attribute name for the XMLA service. This is used as a service filter + * for selecting the XMLA service. + */ + public static final String REFERENCE_XMLA_SERVICE = "xmlaService"; + + /** + * Constant for the OSGi HTTP Whiteboard servlet pattern property. Service property specifying the + * request mappings for a Servlet service. This allows specifying paths or patterns that the servlet + * should listen to according to the Jakarta Servlet specification. + */ + public static final String SERVLET_PATTERN_PROPERTY = "osgi.http.whiteboard.servlet.pattern"; + + /** + * Default value for the servlet pattern property. + */ + public static final String DEFAULT_SERVLET_PATTERN = "/xmla"; + + /** + * Constant for the OSGi HTTP Whiteboard context select property. Service property referencing a + * ServletContextHelper service. For servlet, listener, servlet filter, or resource services, this + * service property refers to the associated ServletContextHelper service. The value of this + * property is a filter expression which is matched against the service registration properties of + * the ServletContextHelper service. If this service property is not specified, the default context + * is used. + */ + public static final String SERVLET_CONTEXT_SELECT_PROPERTY = "osgi.http.whiteboard.context.select"; + + /** + * Constant for the OSGi HTTP Whiteboard servlet name property. Service property specifying the + * servlet name of a Servlet service. The servlet is registered with this name and the name can be + * used as a reference to the servlet for filtering or request dispatching. This name is in addition + * used as the value for the ServletConfig.getServletName() method. If this service property is not + * specified, the fully qualified name of the service object's class is used as the servlet name. + * Servlet names should be unique among all servlet services associated with a single + * ServletContextHelper. + */ + public static final String SERVLET_NAME_PROPERTY = "osgi.http.whiteboard.servlet.name"; + + /** + * Default value for the servlet name property. + */ + public static final String DEFAULT_SERVLET_NAME = "XMLA Servlet"; + +} diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/package-info.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/package-info.java new file mode 100644 index 0000000..2dafdc2 --- /dev/null +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/api/package-info.java @@ -0,0 +1,18 @@ +/* +* Copyright (c) 2023 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 +*/ +@Export +@Version("0.0.1") +package org.eclipse.daanse.xmla.server.jakarta.saaj.api; + +import org.osgi.annotation.bundle.Export; +import org.osgi.annotation.versioning.Version; diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/ServletOCD.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/ServletOCD.java new file mode 100644 index 0000000..8b03d6e --- /dev/null +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/ServletOCD.java @@ -0,0 +1,37 @@ +package org.eclipse.daanse.xmla.server.jakarta.saaj.impl; + +import org.eclipse.daanse.xmla.server.jakarta.saaj.api.Constants; +import org.osgi.service.metatype.annotations.AttributeDefinition; + +public interface ServletOCD { + + String L10N_SERVLET_NAME_NAME = XmlaServletOCD.L10N_PREFIX + Constants.SERVLET_NAME_PROPERTY + + XmlaServletOCD.L10N_POSTFIX_NAME; + String L10N_SERVLET_NAME_DESCRIPTION = XmlaServletOCD.L10N_PREFIX + Constants.SERVLET_NAME_PROPERTY + + XmlaServletOCD.L10N_POSTFIX_DESCRIPTION; + + String L10N_SERVLET_CONTEXT_SELECT_NAME = XmlaServletOCD.L10N_PREFIX + Constants.SERVLET_CONTEXT_SELECT_PROPERTY + + XmlaServletOCD.L10N_POSTFIX_NAME; + + String L10N_SERVLET_CONTEXT_SELECT_DESCRIPTION = XmlaServletOCD.L10N_PREFIX + + Constants.SERVLET_CONTEXT_SELECT_PROPERTY + XmlaServletOCD.L10N_POSTFIX_DESCRIPTION; + + String L10N_SERVLET_PATTERN_NAME = XmlaServletOCD.L10N_PREFIX + Constants.SERVLET_PATTERN_PROPERTY + + XmlaServletOCD.L10N_POSTFIX_NAME; + String L10N_SERVLET_PATTERN_DESCRIPTION = XmlaServletOCD.L10N_PREFIX + Constants.SERVLET_PATTERN_PROPERTY + + XmlaServletOCD.L10N_POSTFIX_DESCRIPTION; + + @AttributeDefinition(name = L10N_SERVLET_NAME_NAME, description = L10N_SERVLET_NAME_DESCRIPTION, defaultValue = Constants.DEFAULT_SERVLET_NAME) + default String osgi_http_whiteboard_servlet_name() { + return Constants.DEFAULT_SERVLET_NAME; + } + + @AttributeDefinition(name = L10N_SERVLET_PATTERN_NAME, description = L10N_SERVLET_PATTERN_DESCRIPTION, defaultValue = Constants.DEFAULT_SERVLET_PATTERN) + default String osgi_http_whiteboard_servlet_pattern() { + return Constants.DEFAULT_SERVLET_PATTERN; + } + + @AttributeDefinition(name = L10N_SERVLET_CONTEXT_SELECT_NAME, description = L10N_SERVLET_CONTEXT_SELECT_DESCRIPTION, required = false) + String osgi_http_whiteboard_context_select(); + +} diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/XmlaServlet.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServlet.java similarity index 80% rename from server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/XmlaServlet.java rename to server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServlet.java index b7055d9..9764074 100644 --- a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/XmlaServlet.java +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServlet.java @@ -10,7 +10,7 @@ * Contributors: * SmartCity Jena - initial */ -package org.eclipse.daanse.xmla.server.jakarta.saaj; +package org.eclipse.daanse.xmla.server.jakarta.saaj.impl; import jakarta.servlet.Servlet; import jakarta.xml.soap.MimeHeader; @@ -18,10 +18,12 @@ import org.eclipse.daanse.jakarta.servlet.soap.AbstractSoapServlet; import org.eclipse.daanse.xmla.api.XmlaService; import org.eclipse.daanse.xmla.server.adapter.soapmessage.XmlaApiAdapter; +import org.eclipse.daanse.xmla.server.jakarta.saaj.api.Constants; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.servlet.whiteboard.propertytypes.HttpWhiteboardServletPattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,18 +38,20 @@ import java.util.stream.StreamSupport; @HttpWhiteboardServletPattern("/xmla") -@Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE) +@Designate(ocd = XmlaServletOCD.class, factory = true) +@Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE, configurationPid = Constants.PID_XMLA_SERVLET) public class XmlaServlet extends AbstractSoapServlet { + private static final long serialVersionUID = 1L; private static Logger LOGGER = LoggerFactory.getLogger(XmlaServlet.class); - private XmlaApiAdapter wsAdapter; + private XmlaApiAdapter xmlaAdapter; - @Reference + @Reference(name = Constants.REFERENCE_XMLA_SERVICE) private XmlaService xmlaService; @Activate public void activate() { - wsAdapter = new XmlaApiAdapter(xmlaService); + xmlaAdapter = new XmlaApiAdapter(xmlaService); } @Override @@ -57,9 +61,10 @@ public SOAPMessage onMessage(SOAPMessage soapMessage) { LOGGER.debug("SoapMessage in:", prettyPrint(soapMessage).toString()); } Iterable iterable = () -> soapMessage.getMimeHeaders().getAllHeaders(); - Map map = StreamSupport.stream(iterable.spliterator(), true).collect(Collectors.toMap(MimeHeader::getName, MimeHeader::getValue, (oldValue, newValue) -> oldValue)); + Map map = StreamSupport.stream(iterable.spliterator(), true).collect( + Collectors.toMap(MimeHeader::getName, MimeHeader::getValue, (oldValue, newValue) -> oldValue)); - SOAPMessage returnMessage = wsAdapter.handleRequest(soapMessage, map); + SOAPMessage returnMessage = xmlaAdapter.handleRequest(soapMessage, map); LOGGER.debug("SoapMessage out:", prettyPrint(returnMessage).toString()); diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServletOCD.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServletOCD.java new file mode 100644 index 0000000..ac851c2 --- /dev/null +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/XmlaServletOCD.java @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2024 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.xmla.server.jakarta.saaj.impl; + +import org.eclipse.daanse.xmla.server.jakarta.saaj.api.Constants; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(name = XmlaServletOCD.L10N_OCD_NAME, description = XmlaServletOCD.L10N_OCD_DESCRIPTION, localization = XmlaServletOCD.OCD_LOCALIZATION) +public interface XmlaServletOCD extends ServletOCD { + + String OCD_LOCALIZATION = "OSGI-INF/l10n/org.eclipse.daanse.xmla.server.jakarta.saaj.ocd"; + String L10N_PREFIX = "%"; + String L10N_POSTFIX_DESCRIPTION = ".description"; + String L10N_POSTFIX_NAME = ".name"; + + String L10N_OCD_NAME = L10N_PREFIX + "ocd.xmlaservlet" + L10N_POSTFIX_NAME; + String L10N_OCD_DESCRIPTION = L10N_PREFIX + "ocd.xmlaservlet" + L10N_POSTFIX_DESCRIPTION; + + String L10N_XMLA_SERVICE_TARGET_NAME = L10N_PREFIX + Constants.REFERENCE_XMLA_SERVICE + ".target" + + L10N_POSTFIX_NAME; + String L10N_XMLA_SERVICE_TARGET_DESCRIPTION = L10N_PREFIX + Constants.REFERENCE_XMLA_SERVICE + ".target" + + L10N_POSTFIX_DESCRIPTION; + + @AttributeDefinition(name = L10N_XMLA_SERVICE_TARGET_NAME, description = L10N_XMLA_SERVICE_TARGET_DESCRIPTION) + String xmlaService_target(); +} diff --git a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/package-info.java b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/package-info.java similarity index 85% rename from server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/package-info.java rename to server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/package-info.java index 9ab9bf8..c660408 100644 --- a/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/package-info.java +++ b/server/jakarta.saaj/src/main/java/org/eclipse/daanse/xmla/server/jakarta/saaj/impl/package-info.java @@ -10,4 +10,4 @@ * Contributors: * SmartCity Jena - initial */ -package org.eclipse.daanse.xmla.server.jakarta.saaj; +package org.eclipse.daanse.xmla.server.jakarta.saaj.impl; diff --git a/server/jakarta.saaj/src/main/resources/OSGI-INF/l10n/org.eclipse.daanse.xmla.server.jakarta.saaj.ocd.properties b/server/jakarta.saaj/src/main/resources/OSGI-INF/l10n/org.eclipse.daanse.xmla.server.jakarta.saaj.ocd.properties new file mode 100644 index 0000000..fb87e0b --- /dev/null +++ b/server/jakarta.saaj/src/main/resources/OSGI-INF/l10n/org.eclipse.daanse.xmla.server.jakarta.saaj.ocd.properties @@ -0,0 +1,21 @@ +# XMLA Jakarta SAAJ Servlet Configuration Localization + +# OCD Names and Descriptions +ocd.xmlaservlet.name=XMLA Jakarta SAAJ Servlet +ocd.xmlaservlet.description=XMLA web interface based on a Jakarta SAAJ Servlet. This can easily be integrated as a servlet into the Servlet Whiteboard. Further details can be found in the OSGi Servlet Specification. + +# Servlet Pattern Property +osgi.http.whiteboard.servlet.pattern.name=Servlet Pattern +osgi.http.whiteboard.servlet.pattern.description=Service property specifying the request mappings for a Servlet service. Allows specifying paths or patterns that the servlet should listen to according to the Jakarta Servlet specification. + +# Servlet Name Property +osgi.http.whiteboard.servlet.name.name=Servlet Name +osgi.http.whiteboard.servlet.name.description=Service property specifying the servlet name. The servlet is registered with this name and can be used as a reference for filtering or request dispatching. If not specified, the fully qualified class name is used. Servlet names should be unique among all servlet services associated with a single ServletContextHelper. + +# Servlet Context Select Property +osgi.http.whiteboard.context.select.name=Servlet Context Select +osgi.http.whiteboard.context.select.description=Service property referencing a ServletContextHelper service. The value is a filter expression matched against service registration properties of the ServletContextHelper service. If not specified, the default context is used. Examples: "(osgi.http.whiteboard.context.name=Admin)" or "(osgi.http.whiteboard.context.name=*)". + +# XMLA Service Target Property +xmlaService.target.name=XMLA Service Target +xmlaService.target.description=Service filter for selecting the XMLA Service that will be provided under the servlet URL diff --git a/server/tck/src/main/java/org/eclipse/daanse/xmla/server/tck/TestSetup.java b/server/tck/src/main/java/org/eclipse/daanse/xmla/server/tck/TestSetup.java new file mode 100644 index 0000000..abde4d5 --- /dev/null +++ b/server/tck/src/main/java/org/eclipse/daanse/xmla/server/tck/TestSetup.java @@ -0,0 +1,28 @@ +package org.eclipse.daanse.xmla.server.tck; + +import java.io.IOException; + +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.cm.annotations.RequireConfigurationAdmin; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.test.common.dictionary.Dictionaries; + +@Component(immediate = true) +@RequireConfigurationAdmin +public class TestSetup { + + @Reference + ConfigurationAdmin ca; + + @Activate + void activate() throws IOException { + Configuration c = ca.getFactoryConfiguration("daanse.xmla.server.jakarta.saaj.XmlaServlet", "0815", "?"); + + c.update(Dictionaries.dictionaryOf("osgi.http.whiteboard.servlet.name", "TestXmlaServlet", + "osgi.http.whiteboard.servlet.pattern", "/xmla")); + System.out.println("TestSetup activated and configuration created."); + } +}