Skip to content

Commit 9927304

Browse files
committed
Restore support for Apache Axiom
Closes gh-1454
2 parents 3ac5ba0 + 2c1abc6 commit 9927304

File tree

76 files changed

+5218
-27
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+5218
-27
lines changed

spring-ws-core/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ dependencies {
2323
exclude(group: "commons-logging", module: "commons-logging")
2424
}
2525
optional("org.apache.httpcomponents.client5:httpclient5")
26+
optional("org.apache.ws.commons.axiom:axiom-impl") {
27+
exclude(group: "commons-logging", module: "commons-logging")
28+
}
29+
optional("org.apache.ws.commons.axiom:axiom-legacy-attachments") {
30+
exclude(group: "commons-logging", module: "commons-logging")
31+
}
2632
optional("org.apache.ws.xmlschema:xmlschema-core")
2733
optional("org.dom4j:dom4j")
2834
optional("org.jdom:jdom2")
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import javax.xml.stream.XMLStreamReader;
20+
import javax.xml.transform.Result;
21+
import javax.xml.transform.Source;
22+
23+
import org.apache.axiom.om.OMElement;
24+
import org.apache.axiom.om.OMException;
25+
import org.apache.axiom.soap.SOAPBody;
26+
import org.apache.axiom.soap.SOAPFactory;
27+
28+
import org.springframework.util.Assert;
29+
import org.springframework.util.xml.StaxUtils;
30+
import org.springframework.ws.soap.axiom.support.AxiomUtils;
31+
32+
/**
33+
* Abstract base class for {@link Payload} implementations.
34+
*
35+
* @author Arjen Poutsma
36+
* @since 2.0
37+
*/
38+
abstract class AbstractPayload extends Payload {
39+
40+
private final SOAPBody axiomBody;
41+
42+
private final SOAPFactory axiomFactory;
43+
44+
protected AbstractPayload(SOAPBody axiomBody, SOAPFactory axiomFactory) {
45+
Assert.notNull(axiomBody, "'axiomBody' must not be null");
46+
Assert.notNull(axiomFactory, "'axiomFactory' must not be null");
47+
this.axiomBody = axiomBody;
48+
this.axiomFactory = axiomFactory;
49+
}
50+
51+
@Override
52+
public final Source getSource() {
53+
try {
54+
OMElement payloadElement = getPayloadElement();
55+
if (payloadElement != null) {
56+
XMLStreamReader streamReader = getStreamReader(payloadElement);
57+
return StaxUtils.createCustomStaxSource(streamReader);
58+
}
59+
else {
60+
return null;
61+
}
62+
}
63+
catch (OMException ex) {
64+
throw new AxiomSoapBodyException(ex);
65+
}
66+
}
67+
68+
protected abstract XMLStreamReader getStreamReader(OMElement payloadElement);
69+
70+
@Override
71+
public final Result getResult() {
72+
AxiomUtils.removeContents(getAxiomBody());
73+
return getResultInternal();
74+
}
75+
76+
protected abstract Result getResultInternal();
77+
78+
public SOAPFactory getAxiomFactory() {
79+
return this.axiomFactory;
80+
}
81+
82+
protected SOAPBody getAxiomBody() {
83+
return this.axiomBody;
84+
}
85+
86+
protected OMElement getPayloadElement() throws OMException {
87+
return getAxiomBody().getFirstElement();
88+
}
89+
90+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
22+
import jakarta.activation.DataHandler;
23+
24+
import org.springframework.util.Assert;
25+
import org.springframework.ws.mime.Attachment;
26+
27+
/**
28+
* Axiom-specific implementation of {@link org.springframework.ws.mime.Attachment}.
29+
*
30+
* @author Arjen Poutsma
31+
* @since 1.0.0
32+
*/
33+
class AxiomAttachment implements Attachment {
34+
35+
private final DataHandler dataHandler;
36+
37+
private final String contentId;
38+
39+
AxiomAttachment(String contentId, DataHandler dataHandler) {
40+
Assert.notNull(contentId, "contentId must not be null");
41+
Assert.notNull(dataHandler, "dataHandler must not be null");
42+
this.contentId = contentId;
43+
this.dataHandler = dataHandler;
44+
}
45+
46+
@Override
47+
public String getContentId() {
48+
return this.contentId;
49+
}
50+
51+
@Override
52+
public String getContentType() {
53+
return this.dataHandler.getContentType();
54+
}
55+
56+
@Override
57+
public InputStream getInputStream() throws IOException {
58+
return this.dataHandler.getInputStream();
59+
}
60+
61+
@Override
62+
public long getSize() {
63+
// Axiom does not support getting the size of attachments.
64+
return -1;
65+
}
66+
67+
@Override
68+
public DataHandler getDataHandler() {
69+
return this.dataHandler;
70+
}
71+
72+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import org.springframework.ws.mime.AttachmentException;
20+
21+
/**
22+
* Exception thrown when a {@link AxiomAttachment} could not be accessed.
23+
*
24+
* @author Arjen Poutsma
25+
*/
26+
@SuppressWarnings("serial")
27+
public class AxiomAttachmentException extends AttachmentException {
28+
29+
public AxiomAttachmentException(String msg) {
30+
super(msg);
31+
}
32+
33+
public AxiomAttachmentException(String msg, Throwable ex) {
34+
super(msg, ex);
35+
}
36+
37+
public AxiomAttachmentException(Throwable ex) {
38+
super(ex);
39+
}
40+
41+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* Copyright 2005-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ws.soap.axiom;
18+
19+
import java.util.Locale;
20+
21+
import javax.xml.namespace.QName;
22+
23+
import org.apache.axiom.om.OMAttribute;
24+
import org.apache.axiom.om.OMNamespace;
25+
import org.apache.axiom.soap.SOAP11Constants;
26+
import org.apache.axiom.soap.SOAPBody;
27+
import org.apache.axiom.soap.SOAPFactory;
28+
import org.apache.axiom.soap.SOAPFault;
29+
import org.apache.axiom.soap.SOAPFaultCode;
30+
import org.apache.axiom.soap.SOAPFaultReason;
31+
import org.apache.axiom.soap.SOAPProcessingException;
32+
33+
import org.springframework.util.Assert;
34+
import org.springframework.util.StringUtils;
35+
import org.springframework.ws.soap.axiom.support.AxiomUtils;
36+
import org.springframework.ws.soap.soap11.Soap11Body;
37+
import org.springframework.ws.soap.soap11.Soap11Fault;
38+
39+
/**
40+
* Axiom-specific version of {@code org.springframework.ws.soap.Soap11Body}.
41+
*
42+
* @author Arjen Poutsma
43+
* @since 1.0.0
44+
*/
45+
class AxiomSoap11Body extends AxiomSoapBody implements Soap11Body {
46+
47+
private final boolean langAttributeOnSoap11FaultString;
48+
49+
AxiomSoap11Body(SOAPBody axiomBody, SOAPFactory axiomFactory, boolean payloadCaching,
50+
boolean langAttributeOnSoap11FaultString) {
51+
super(axiomBody, axiomFactory, payloadCaching);
52+
this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString;
53+
}
54+
55+
@Override
56+
public Soap11Fault addMustUnderstandFault(String faultString, Locale locale) {
57+
SOAPFault fault = addStandardFault(SOAP11Constants.FAULT_CODE_MUST_UNDERSTAND, faultString, locale);
58+
return new AxiomSoap11Fault(fault, getAxiomFactory());
59+
}
60+
61+
@Override
62+
public Soap11Fault addClientOrSenderFault(String faultString, Locale locale) {
63+
SOAPFault fault = addStandardFault(SOAP11Constants.FAULT_CODE_SENDER, faultString, locale);
64+
return new AxiomSoap11Fault(fault, getAxiomFactory());
65+
}
66+
67+
@Override
68+
public Soap11Fault addServerOrReceiverFault(String faultString, Locale locale) {
69+
SOAPFault fault = addStandardFault(SOAP11Constants.FAULT_CODE_RECEIVER, faultString, locale);
70+
return new AxiomSoap11Fault(fault, getAxiomFactory());
71+
}
72+
73+
@Override
74+
public Soap11Fault addVersionMismatchFault(String faultString, Locale locale) {
75+
SOAPFault fault = addStandardFault(SOAP11Constants.FAULT_CODE_VERSION_MISMATCH, faultString, locale);
76+
return new AxiomSoap11Fault(fault, getAxiomFactory());
77+
}
78+
79+
@Override
80+
public Soap11Fault addFault(QName code, String faultString, Locale faultStringLocale) {
81+
Assert.notNull(code, "No faultCode given");
82+
Assert.hasLength(faultString, "faultString cannot be empty");
83+
if (!StringUtils.hasLength(code.getNamespaceURI())) {
84+
throw new IllegalArgumentException(
85+
"A fault code with namespace and local part must be specific for a custom fault code");
86+
}
87+
if (!this.langAttributeOnSoap11FaultString) {
88+
faultStringLocale = null;
89+
}
90+
try {
91+
AxiomUtils.removeContents(getAxiomBody());
92+
SOAPFault fault = getAxiomFactory().createSOAPFault(getAxiomBody());
93+
SOAPFaultCode faultCode = getAxiomFactory().createSOAPFaultCode(fault);
94+
setValueText(code, fault, faultCode);
95+
SOAPFaultReason faultReason = getAxiomFactory().createSOAPFaultReason(fault);
96+
if (faultStringLocale != null) {
97+
addLangAttribute(faultStringLocale, faultReason);
98+
}
99+
faultReason.setText(faultString);
100+
return new AxiomSoap11Fault(fault, getAxiomFactory());
101+
102+
}
103+
catch (SOAPProcessingException ex) {
104+
throw new AxiomSoapFaultException(ex);
105+
}
106+
}
107+
108+
private void setValueText(QName code, SOAPFault fault, SOAPFaultCode faultCode) {
109+
String prefix = code.getPrefix();
110+
if (StringUtils.hasLength(code.getNamespaceURI()) && StringUtils.hasLength(prefix)) {
111+
OMNamespace namespace = fault.findNamespaceURI(prefix);
112+
if (namespace == null) {
113+
fault.declareNamespace(code.getNamespaceURI(), prefix);
114+
}
115+
}
116+
else if (StringUtils.hasLength(code.getNamespaceURI())) {
117+
OMNamespace namespace = fault.findNamespace(code.getNamespaceURI(), null);
118+
if (namespace == null) {
119+
namespace = fault.declareNamespace(code.getNamespaceURI(), "");
120+
}
121+
code = new QName(code.getNamespaceURI(), code.getLocalPart(), namespace.getPrefix());
122+
}
123+
faultCode.setText(code);
124+
}
125+
126+
private SOAPFault addStandardFault(String localName, String faultString, Locale locale) {
127+
Assert.notNull(faultString, "No faultString given");
128+
try {
129+
AxiomUtils.removeContents(getAxiomBody());
130+
SOAPFault fault = getAxiomFactory().createSOAPFault(getAxiomBody());
131+
SOAPFaultCode faultCode = getAxiomFactory().createSOAPFaultCode(fault);
132+
faultCode.setText(
133+
new QName(fault.getNamespace().getNamespaceURI(), localName, fault.getNamespace().getPrefix()));
134+
SOAPFaultReason faultReason = getAxiomFactory().createSOAPFaultReason(fault);
135+
if (locale != null) {
136+
addLangAttribute(locale, faultReason);
137+
}
138+
faultReason.setText(faultString);
139+
return fault;
140+
}
141+
catch (SOAPProcessingException ex) {
142+
throw new AxiomSoapFaultException(ex);
143+
}
144+
}
145+
146+
private void addLangAttribute(Locale locale, SOAPFaultReason faultReason) {
147+
OMNamespace xmlNamespace = getAxiomFactory().createOMNamespace("http://www.w3.org/XML/1998/namespace", "xml");
148+
OMAttribute langAttribute = getAxiomFactory().createOMAttribute("lang", xmlNamespace,
149+
AxiomUtils.toLanguage(locale));
150+
faultReason.addAttribute(langAttribute);
151+
}
152+
153+
@Override
154+
public Soap11Fault getFault() {
155+
SOAPFault axiomFault = getAxiomBody().getFault();
156+
return (axiomFault != null) ? new AxiomSoap11Fault(axiomFault, getAxiomFactory()) : null;
157+
}
158+
159+
}

0 commit comments

Comments
 (0)