Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions server/jdk.httpserver/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0"?>
<!--
/*********************************************************************
* 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
**********************************************************************/
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.xmla.server</artifactId>
<version>${revision}</version>
</parent>
<artifactId>org.eclipse.daanse.xmla.server.jdk.httpserver</artifactId>
<dependencies>


<dependency>
<groupId>jakarta.xml.soap</groupId>
<artifactId>jakarta.xml.soap-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.xmla.server.tck</artifactId>
<version>${revision}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>
org.eclipse.daanse.xmla.server.adapter.soapmessage
</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.daanse</groupId>
<artifactId>org.eclipse.daanse.xmla.server.adapter.soapmessage</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* 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
* Stefan Bischof (bipolis.org) - initial
*/
package org.eclipse.daanse.xmla.server.jdk.httpserver;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import jakarta.xml.soap.MessageFactory;
import jakarta.xml.soap.MimeHeader;
import jakarta.xml.soap.MimeHeaders;
import jakarta.xml.soap.SOAPConnection;
import jakarta.xml.soap.SOAPConnectionFactory;
import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

public abstract class AbstractSoapHttpHandler implements HttpHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSoapHttpHandler.class);
private static final String HEADER_DELIMITER = ",";

protected final MessageFactory messageFactory;
protected final SOAPConnection soapConnection;

public AbstractSoapHttpHandler() throws SOAPException {
this.messageFactory = MessageFactory.newInstance();
this.soapConnection = SOAPConnectionFactory.newInstance().createConnection();
LOGGER.debug("MessageFactory: {} – SOAPConnection: {}", messageFactory, soapConnection);
}

protected abstract SOAPMessage onMessage(SOAPMessage soapRequestMessage);

@Override
public final void handle(HttpExchange exchange) throws IOException {
if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) {
exchange.sendResponseHeaders(405, -1);
exchange.close();
return;
}

try {
SOAPMessage requestMessage = createSoapRequest(exchange);

if (LOGGER.isDebugEnabled()) {
LOGGER.debug("SOAPMessage in:\n{}", toString(requestMessage));
}

SOAPMessage responseMessage = onMessage(requestMessage);

if (responseMessage != null) {
writeSoapResponse(exchange, responseMessage);
} else {
exchange.sendResponseHeaders(204, -1);
}
} catch (Exception ex) {
LOGGER.error("Error processing SOAP request", ex);
exchange.sendResponseHeaders(500, -1);
} finally {
exchange.close();
}
}

private SOAPMessage createSoapRequest(HttpExchange exchange) throws IOException, SOAPException {
MimeHeaders mimeHeaders = getMimeHeadersFromExchange(exchange);
try (InputStream requestStream = exchange.getRequestBody()) {
return messageFactory.createMessage(mimeHeaders, requestStream);
}
}

private void writeSoapResponse(HttpExchange exchange, SOAPMessage responseMessage)
throws SOAPException, IOException {

if (responseMessage.saveRequired()) {
responseMessage.saveChanges();
}

setMimeHeadersToExchange(exchange, responseMessage.getMimeHeaders());

ByteArrayOutputStream baos = new ByteArrayOutputStream();
responseMessage.writeTo(baos);
byte[] payload = baos.toByteArray();

exchange.sendResponseHeaders(200, payload.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(payload);
}

if (LOGGER.isDebugEnabled()) {
LOGGER.debug("SOAPMessage out:\n{}", toString(responseMessage));
}
}

private static MimeHeaders getMimeHeadersFromExchange(HttpExchange exchange) {
Headers reqHeaders = exchange.getRequestHeaders();
MimeHeaders mimeHeaders = new MimeHeaders();

for (Map.Entry<String, List<String>> entry : reqHeaders.entrySet()) {
String headerName = entry.getKey();
for (String rawValue : entry.getValue()) {
StringTokenizer tokenizer = new StringTokenizer(rawValue, HEADER_DELIMITER);
while (tokenizer.hasMoreTokens()) {
mimeHeaders.addHeader(headerName, tokenizer.nextToken().trim());
}
}
}
return mimeHeaders;
}

private static void setMimeHeadersToExchange(HttpExchange exchange, MimeHeaders mimeHeaders) {
Headers resHeaders = exchange.getResponseHeaders();
Iterator<MimeHeader> it = mimeHeaders.getAllHeaders();

while (it.hasNext()) {
MimeHeader header = it.next();
String[] values = mimeHeaders.getHeader(header.getName());

if (values.length == 1) {
resHeaders.set(header.getName(), header.getValue());
} else {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (String value : values) {
if (first) {
first = false;
} else {
sb.append(',');
}
sb.append(value);
}
resHeaders.set(header.getName(), sb.toString());
}
}
}

private static String toString(SOAPMessage msg) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
msg.writeTo(baos);
return baos.toString();
} catch (Exception e) {
return "<unable to serialise SOAPMessage>";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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
* Stefan Bischof (bipolis.org) - initial
*/
package org.eclipse.daanse.xmla.server.jdk.httpserver;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.Executors;

import org.eclipse.daanse.xmla.api.XmlaService;
import org.eclipse.daanse.xmla.server.adapter.soapmessage.XmlaApiAdapter;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ServiceScope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.net.httpserver.HttpServer;

import jakarta.xml.soap.SOAPException;

@Component(scope = ServiceScope.PROTOTYPE, immediate = true)
public class JdkHttpServer {

private static Logger LOGGER = LoggerFactory.getLogger(JdkHttpServer.class);
private XmlaApiAdapter wsAdapter;
private HttpServer server = null;

@Reference(cardinality = ReferenceCardinality.MANDATORY)
private XmlaService xmlaService;

@Activate
public void activate(Map<String, Object> map) throws SOAPException, IOException {
LOGGER.debug("Starting JDK HTTP server");
wsAdapter = new XmlaApiAdapter(xmlaService);
XmlaSoapHttpHandler xmlaHandler = new XmlaSoapHttpHandler(wsAdapter);
// Register the handler with the HTTP server

server = HttpServer.create(new InetSocketAddress(8090), 0);
server.createContext("/xmla", xmlaHandler);
server.setExecutor(Executors.newCachedThreadPool());
server.start();
LOGGER.debug("JDK HTTP server started on port 8090");
}

@Deactivate
public void deativate() {
LOGGER.debug("Stopping JDK HTTP server");
server.stop(0);
LOGGER.debug("JDK HTTP server stopped");
}

};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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
* Stefan Bischof (bipolis.org) - initial
*/
package org.eclipse.daanse.xmla.server.jdk.httpserver;

import java.util.Collections;

import org.eclipse.daanse.xmla.server.adapter.soapmessage.XmlaApiAdapter;

import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPMessage;

public class XmlaSoapHttpHandler extends AbstractSoapHttpHandler {
private final XmlaApiAdapter adapter;

XmlaSoapHttpHandler(XmlaApiAdapter xmlaApiAdapter) throws SOAPException {
adapter = xmlaApiAdapter;
}

@Override
protected SOAPMessage onMessage(SOAPMessage req) {
return adapter.handleRequest(req, Collections.emptyMap());
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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
*/
package org.eclipse.daanse.xmla.server.jdk.httpserver;
Loading
Loading