diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapElement.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapElement.java
index bb23168f..4bb9e7c1 100644
--- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapElement.java
+++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapElement.java
@@ -36,6 +36,8 @@ class SaajSoapElement implements SoapElement {
private final SOAPElement element;
+ private SaajImplementation implementation;
+
SaajSoapElement(SOAPElement element) {
Assert.notNull(element, "element must not be null");
this.element = element;
@@ -94,17 +96,20 @@ class SaajSoapElement implements SoapElement {
}
protected final SaajImplementation getImplementation() {
- if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_13) {
- return Saaj13Implementation.getInstance();
- }
- else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) {
- return Saaj12Implementation.getInstance();
- }
- else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) {
- return Saaj11Implementation.getInstance();
- }
- else {
- throw new IllegalStateException("Could not find SAAJ on the classpath");
+ if (implementation == null) {
+ if (SaajUtils.getSaajVersion(element) == SaajUtils.SAAJ_13) {
+ implementation = Saaj13Implementation.getInstance();
+ }
+ else if (SaajUtils.getSaajVersion(element) == SaajUtils.SAAJ_12) {
+ implementation = Saaj12Implementation.getInstance();
+ }
+ else if (SaajUtils.getSaajVersion(element) == SaajUtils.SAAJ_11) {
+ implementation = Saaj11Implementation.getInstance();
+ }
+ else {
+ throw new IllegalStateException("Could not find SAAJ on the classpath");
+ }
}
+ return implementation;
}
}
diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java
index 8ec092f7..a25266aa 100644
--- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java
+++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessage.java
@@ -59,6 +59,8 @@ public class SaajSoapMessage extends AbstractSoapMessage {
private final boolean langAttributeOnSoap11FaulString;
+ private SaajImplementation implementation;
+
/**
* Create a new SaajSoapMessage based on the given SAAJ SOAPMessage.
*
@@ -77,12 +79,12 @@ public class SaajSoapMessage extends AbstractSoapMessage {
*/
public SaajSoapMessage(SOAPMessage soapMessage, boolean langAttributeOnSoap11FaulString) {
Assert.notNull(soapMessage, "soapMessage must not be null");
+ saajMessage = soapMessage;
+ this.langAttributeOnSoap11FaulString = langAttributeOnSoap11FaulString;
MimeHeaders headers = getImplementation().getMimeHeaders(soapMessage);
if (ObjectUtils.isEmpty(headers.getHeader(TransportConstants.HEADER_SOAP_ACTION))) {
headers.addHeader(TransportConstants.HEADER_SOAP_ACTION, "\"\"");
}
- saajMessage = soapMessage;
- this.langAttributeOnSoap11FaulString = langAttributeOnSoap11FaulString;
}
/** Return the SAAJ SOAPMessage that this SaajSoapMessage is based on. */
@@ -169,7 +171,7 @@ public class SaajSoapMessage extends AbstractSoapMessage {
}
public boolean isXopPackage() {
- if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
+ if (SaajUtils.getSaajVersion(saajMessage) >= SaajUtils.SAAJ_13) {
SOAPPart saajPart = saajMessage.getSOAPPart();
String[] contentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
for (int i = 0; i < contentTypes.length; i++) {
@@ -182,7 +184,7 @@ public class SaajSoapMessage extends AbstractSoapMessage {
}
public boolean convertToXopPackage() {
- if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
+ if (SaajUtils.getSaajVersion(saajMessage) >= SaajUtils.SAAJ_13) {
convertMessageToXop();
convertPartToXop();
return true;
@@ -244,19 +246,22 @@ public class SaajSoapMessage extends AbstractSoapMessage {
return new SaajAttachment(saajAttachment);
}
- protected SaajImplementation getImplementation() {
- if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_13) {
- return Saaj13Implementation.getInstance();
- }
- else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) {
- return Saaj12Implementation.getInstance();
- }
- else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) {
- return Saaj11Implementation.getInstance();
- }
- else {
- throw new IllegalStateException("Could not find SAAJ on the classpath");
+ protected final SaajImplementation getImplementation() {
+ if (implementation == null) {
+ if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_13) {
+ implementation = Saaj13Implementation.getInstance();
+ }
+ else if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_12) {
+ implementation = Saaj12Implementation.getInstance();
+ }
+ else if (SaajUtils.getSaajVersion(saajMessage) == SaajUtils.SAAJ_11) {
+ implementation = Saaj11Implementation.getInstance();
+ }
+ else {
+ throw new IllegalStateException("Could not find SAAJ on the classpath");
+ }
}
+ return implementation;
}
public String toString() {
diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java b/core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java
index 1527650e..921becda 100644
--- a/core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java
+++ b/core/src/main/java/org/springframework/ws/soap/saaj/support/SaajUtils.java
@@ -18,7 +18,12 @@ package org.springframework.ws.soap.saaj.support;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
@@ -29,13 +34,16 @@ import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
+import org.w3c.dom.Element;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.xml.namespace.QNameUtils;
-import org.w3c.dom.Element;
/**
* Collection of generic utility methods to work with SAAJ. Includes conversion from SAAJ {@link Name} objects to {@link
@@ -48,6 +56,11 @@ import org.w3c.dom.Element;
*/
public abstract class SaajUtils {
+ // The exception message thrown by WebLogic 9
+ private static final String WEBLOGIC_9_SAAJ_EXCEPTION_MESSAGE = "This class does not support SAAJ 1.1";
+
+ private static final Log logger = LogFactory.getLog(SaajUtils.class);
+
public static final int SAAJ_11 = 0;
public static final int SAAJ_12 = 1;
@@ -56,6 +69,9 @@ public abstract class SaajUtils {
private static final String SAAJ_13_CLASS_NAME = "javax.xml.soap.SAAJMetaFactory";
+ // Maps SOAPElement class names to Integer SAAJ versions (SAAJ_11, SAAJ_12, SAAJ_13)
+ private static final Map saajVersions = Collections.synchronizedMap(new HashMap());
+
private static int saajVersion = SAAJ_12;
static {
@@ -127,6 +143,112 @@ public abstract class SaajUtils {
return saajVersion;
}
+ /**
+ * Gets the SAAJ version for the specified {@link SOAPMessage}.
+ *
+ * @return a code comparable to the SAAJ_XX codes in this class
+ * @see #SAAJ_11
+ * @see #SAAJ_12
+ * @see #SAAJ_13
+ */
+ public static int getSaajVersion(SOAPMessage soapMessage) {
+ Assert.notNull(soapMessage, "'soapMessage' must not be null");
+ try {
+ return getSaajVersion(soapMessage.getSOAPPart().getEnvelope());
+ }
+ catch (SOAPException e) {
+ return SAAJ_11;
+ }
+ }
+
+ /**
+ * Gets the SAAJ version for the specified {@link javax.xml.soap.SOAPElement}.
+ *
+ * @return a code comparable to the SAAJ_XX codes in this class
+ * @see #SAAJ_11
+ * @see #SAAJ_12
+ * @see #SAAJ_13
+ */
+ public static int getSaajVersion(SOAPElement soapElement) {
+ Assert.notNull(soapElement, "'soapElement' must not be null");
+ Class soapElementClass = soapElement.getClass();
+ Integer saajVersion = (Integer) saajVersions.get(soapElementClass.getName());
+ if (saajVersion == null) {
+ if (isSaaj12(soapElement)) {
+ if (isSaaj13(soapElement)) {
+ saajVersion = new Integer(SAAJ_13);
+ }
+ else {
+ saajVersion = new Integer(SAAJ_12);
+ }
+ } else {
+ saajVersion = new Integer(SAAJ_11);
+ }
+ saajVersions.put(soapElementClass.getName(), saajVersion);
+ if (logger.isTraceEnabled()) {
+ logger.trace("SOAPElement [" + soapElement.getClass().getName() + "] implements " +
+ getSaajVersionString(saajVersion.intValue()));
+ }
+ }
+ return saajVersion.intValue();
+ }
+
+ private static boolean isSaaj13(SOAPElement soapElement) {
+ try {
+ Method m = soapElement.getClass().getMethod("getElementQName", new Class[0]);
+ // we might be using the SAAJ 1.3 API, while the impl is 1.2
+ // let's see if the method is not abstract
+ if (Modifier.isAbstract(m.getModifiers())) {
+ logger.warn("Detected SAAJ API version 1.3, while implementation provides version 1.2. " +
+ "Please replace the SAAJ API jar with a version that corresponds to your runtime" +
+ " implementation (which might be provided by your app server).");
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ catch (NoSuchMethodException e) {
+ // getElementQName not found
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether we can find a SAAJ 1.2 implementation, being aware of the broken WebLogic 9 SAAJ implementation.
+ *
SAAJ 1.3", "SAAJ
* 1.2", or "SAAJ 1.1".
@@ -135,6 +257,10 @@ public abstract class SaajUtils {
* @see #getSaajVersion()
*/
public static String getSaajVersionString() {
+ return getSaajVersionString(saajVersion);
+ }
+
+ private static String getSaajVersionString(int saajVersion) {
if (saajVersion >= SaajUtils.SAAJ_13) {
return "SAAJ 1.3";
}
@@ -166,7 +292,7 @@ public abstract class SaajUtils {
}
else if (StringUtils.hasLength(qName.getNamespaceURI())) {
Iterator prefixes;
- if (getSaajVersion() == SAAJ_11) {
+ if (getSaajVersion(resolveElement) == SAAJ_11) {
prefixes = resolveElement.getNamespacePrefixes();
}
else {
diff --git a/core/src/test/java/org/springframework/ws/soap/saaj/support/SaajUtilsTest.java b/core/src/test/java/org/springframework/ws/soap/saaj/support/SaajUtilsTest.java
index 3ccc0642..5c119ea6 100644
--- a/core/src/test/java/org/springframework/ws/soap/saaj/support/SaajUtilsTest.java
+++ b/core/src/test/java/org/springframework/ws/soap/saaj/support/SaajUtilsTest.java
@@ -25,9 +25,10 @@ import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import org.custommonkey.xmlunit.XMLTestCase;
+import org.w3c.dom.Document;
+
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Document;
public class SaajUtilsTest extends XMLTestCase {
@@ -114,4 +115,5 @@ public class SaajUtilsTest extends XMLTestCase {
public void testGetSaajVersion() throws Exception {
assertEquals("Invalid SAAJ version", SaajUtils.SAAJ_13, SaajUtils.getSaajVersion());
}
+
}
\ No newline at end of file