1+ /*
2+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
3+ *
4+ * This program and the accompanying materials are made
5+ * available under the terms of the Eclipse Public License 2.0
6+ * which is available at https://www.eclipse.org/legal/epl-2.0/
7+ *
8+ * SPDX-License-Identifier: EPL-2.0
9+ *
10+ * Contributors:
11+ * SmartCity Jena - initial
12+ * Stefan Bischof (bipolis.org) - initial
13+ */
14+ package org .eclipse .daanse .xmla .server .jdk .httpserver ;
15+
16+ import com .sun .net .httpserver .Headers ;
17+ import com .sun .net .httpserver .HttpExchange ;
18+ import com .sun .net .httpserver .HttpHandler ;
19+ import jakarta .xml .soap .MessageFactory ;
20+ import jakarta .xml .soap .MimeHeader ;
21+ import jakarta .xml .soap .MimeHeaders ;
22+ import jakarta .xml .soap .SOAPConnection ;
23+ import jakarta .xml .soap .SOAPConnectionFactory ;
24+ import jakarta .xml .soap .SOAPException ;
25+ import jakarta .xml .soap .SOAPMessage ;
26+ import org .slf4j .Logger ;
27+ import org .slf4j .LoggerFactory ;
28+
29+ import java .io .ByteArrayOutputStream ;
30+ import java .io .IOException ;
31+ import java .io .InputStream ;
32+ import java .io .OutputStream ;
33+ import java .util .Iterator ;
34+ import java .util .List ;
35+ import java .util .Map ;
36+ import java .util .StringTokenizer ;
37+
38+ public abstract class AbstractSoapHttpHandler implements HttpHandler {
39+
40+ private static final Logger LOGGER = LoggerFactory .getLogger (AbstractSoapHttpHandler .class );
41+ private static final String HEADER_DELIMITER = "," ;
42+
43+ protected final MessageFactory messageFactory ;
44+ protected final SOAPConnection soapConnection ;
45+
46+ public AbstractSoapHttpHandler () throws SOAPException {
47+ this .messageFactory = MessageFactory .newInstance ();
48+ this .soapConnection = SOAPConnectionFactory .newInstance ().createConnection ();
49+ LOGGER .debug ("MessageFactory: {} – SOAPConnection: {}" , messageFactory , soapConnection );
50+ }
51+
52+ protected abstract SOAPMessage onMessage (SOAPMessage soapRequestMessage );
53+
54+ @ Override
55+ public final void handle (HttpExchange exchange ) throws IOException {
56+ if (!"POST" .equalsIgnoreCase (exchange .getRequestMethod ())) {
57+ exchange .sendResponseHeaders (405 , -1 );
58+ exchange .close ();
59+ return ;
60+ }
61+
62+ try {
63+ SOAPMessage requestMessage = createSoapRequest (exchange );
64+
65+ if (LOGGER .isDebugEnabled ()) {
66+ LOGGER .debug ("SOAPMessage in:\n {}" , toString (requestMessage ));
67+ }
68+
69+ SOAPMessage responseMessage = onMessage (requestMessage );
70+
71+ if (responseMessage != null ) {
72+ writeSoapResponse (exchange , responseMessage );
73+ } else {
74+ exchange .sendResponseHeaders (204 , -1 );
75+ }
76+ } catch (Exception ex ) {
77+ LOGGER .error ("Error processing SOAP request" , ex );
78+ exchange .sendResponseHeaders (500 , -1 );
79+ } finally {
80+ exchange .close ();
81+ }
82+ }
83+
84+ private SOAPMessage createSoapRequest (HttpExchange exchange ) throws IOException , SOAPException {
85+ MimeHeaders mimeHeaders = getMimeHeadersFromExchange (exchange );
86+ try (InputStream requestStream = exchange .getRequestBody ()) {
87+ return messageFactory .createMessage (mimeHeaders , requestStream );
88+ }
89+ }
90+
91+ private void writeSoapResponse (HttpExchange exchange , SOAPMessage responseMessage )
92+ throws SOAPException , IOException {
93+
94+ if (responseMessage .saveRequired ()) {
95+ responseMessage .saveChanges ();
96+ }
97+
98+ setMimeHeadersToExchange (exchange , responseMessage .getMimeHeaders ());
99+
100+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
101+ responseMessage .writeTo (baos );
102+ byte [] payload = baos .toByteArray ();
103+
104+ exchange .sendResponseHeaders (200 , payload .length );
105+ try (OutputStream os = exchange .getResponseBody ()) {
106+ os .write (payload );
107+ }
108+
109+ if (LOGGER .isDebugEnabled ()) {
110+ LOGGER .debug ("SOAPMessage out:\n {}" , toString (responseMessage ));
111+ }
112+ }
113+
114+ private static MimeHeaders getMimeHeadersFromExchange (HttpExchange exchange ) {
115+ Headers reqHeaders = exchange .getRequestHeaders ();
116+ MimeHeaders mimeHeaders = new MimeHeaders ();
117+
118+ for (Map .Entry <String , List <String >> entry : reqHeaders .entrySet ()) {
119+ String headerName = entry .getKey ();
120+ for (String rawValue : entry .getValue ()) {
121+ StringTokenizer tokenizer = new StringTokenizer (rawValue , HEADER_DELIMITER );
122+ while (tokenizer .hasMoreTokens ()) {
123+ mimeHeaders .addHeader (headerName , tokenizer .nextToken ().trim ());
124+ }
125+ }
126+ }
127+ return mimeHeaders ;
128+ }
129+
130+ private static void setMimeHeadersToExchange (HttpExchange exchange , MimeHeaders mimeHeaders ) {
131+ Headers resHeaders = exchange .getResponseHeaders ();
132+ Iterator <MimeHeader > it = mimeHeaders .getAllHeaders ();
133+
134+ while (it .hasNext ()) {
135+ MimeHeader header = it .next ();
136+ String [] values = mimeHeaders .getHeader (header .getName ());
137+
138+ if (values .length == 1 ) {
139+ resHeaders .set (header .getName (), header .getValue ());
140+ } else {
141+ StringBuilder sb = new StringBuilder ();
142+ boolean first = true ;
143+ for (String value : values ) {
144+ if (first ) {
145+ first = false ;
146+ } else {
147+ sb .append (',' );
148+ }
149+ sb .append (value );
150+ }
151+ resHeaders .set (header .getName (), sb .toString ());
152+ }
153+ }
154+ }
155+
156+ private static String toString (SOAPMessage msg ) {
157+ try {
158+ ByteArrayOutputStream baos = new ByteArrayOutputStream ();
159+ msg .writeTo (baos );
160+ return baos .toString ();
161+ } catch (Exception e ) {
162+ return "<unable to serialise SOAPMessage>" ;
163+ }
164+ }
165+ }
0 commit comments