/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.soap.saaj.support;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.ws.transport.TransportConstants;
/**
* Collection of generic utility methods to work with SAAJ. Includes conversion from SAAJ {@link Name} objects to {@link
* QName}s and vice-versa, and SAAJ version checking.
*
* @author Arjen Poutsma
* @see Name
* @see QName
* @since 1.0.0
*/
public abstract class SaajUtils {
public static final int SAAJ_11 = 0;
public static final int SAAJ_12 = 1;
public static final int SAAJ_13 = 2;
private static int saajVersion = SAAJ_13;
/**
* Gets the SAAJ version.
* Returns {@link #SAAJ_13} as of Spring-WS 2.2.
*
* @return a code comparable to the SAAJ_XX codes in this class
*/
public static int getSaajVersion() {
return saajVersion;
}
/**
* Gets the SAAJ version for the specified {@link SOAPMessage}.
* Returns {@link #SAAJ_13} as of Spring-WS 2.2.
*
* @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) throws SOAPException {
Assert.notNull(soapMessage, "'soapMessage' must not be null");
SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
return getSaajVersion(soapEnvelope);
}
/**
* Gets the SAAJ version for the specified {@link javax.xml.soap.SOAPElement}.
* Returns {@link #SAAJ_13} as of Spring-WS 2.2.
*
* @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) {
return SAAJ_13;
}
/**
* Returns the SAAJ version as a String. The returned string will be "{@code SAAJ 1.3}", "{@code SAAJ
* 1.2}", or "{@code SAAJ 1.1}".
*
* @return a string representation of the SAAJ version
* @see #getSaajVersion()
*/
public static String getSaajVersionString() {
return getSaajVersionString(saajVersion);
}
private static String getSaajVersionString(int saajVersion) {
if (saajVersion >= SaajUtils.SAAJ_13) {
return "SAAJ 1.3";
}
else if (saajVersion == SaajUtils.SAAJ_12) {
return "SAAJ 1.2";
}
else if (saajVersion == SaajUtils.SAAJ_11) {
return "SAAJ 1.1";
}
else {
return "";
}
}
/**
* Converts a {@link QName} to a {@link Name}. A {@link SOAPElement} is required to resolve namespaces.
*
* @param qName the {@code QName} to convert
* @param resolveElement a {@code SOAPElement} used to resolve namespaces to prefixes
* @return the converted SAAJ Name
* @throws SOAPException if conversion is unsuccessful
* @throws IllegalArgumentException if {@code qName} is not fully qualified
*/
public static Name toName(QName qName, SOAPElement resolveElement) throws SOAPException {
String qNamePrefix = qName.getPrefix();
SOAPEnvelope envelope = getEnvelope(resolveElement);
if (StringUtils.hasLength(qName.getNamespaceURI()) && StringUtils.hasLength(qNamePrefix)) {
return envelope.createName(qName.getLocalPart(), qNamePrefix, qName.getNamespaceURI());
}
else if (StringUtils.hasLength(qName.getNamespaceURI())) {
Iterator<?> prefixes;
if (getSaajVersion(resolveElement) == SAAJ_11) {
prefixes = resolveElement.getNamespacePrefixes();
}
else {
prefixes = resolveElement.getVisibleNamespacePrefixes();
}
while (prefixes.hasNext()) {
String prefix = (String) prefixes.next();
if (qName.getNamespaceURI().equals(resolveElement.getNamespaceURI(prefix))) {
return envelope.createName(qName.getLocalPart(), prefix, qName.getNamespaceURI());
}
}
return envelope.createName(qName.getLocalPart(), "", qName.getNamespaceURI());
}
else {
return envelope.createName(qName.getLocalPart());
}
}
/**
* Converts a {@code javax.xml.soap.Name} to a {@code javax.xml.namespace.QName}.
*
* @param name the {@code Name} to convert
* @return the converted {@code QName}
*/
public static QName toQName(Name name) {
if (StringUtils.hasLength(name.getURI()) && StringUtils.hasLength(name.getPrefix())) {
return new QName(name.getURI(), name.getLocalName(), name.getPrefix());
}
else if (StringUtils.hasLength(name.getURI())) {
return new QName(name.getURI(), name.getLocalName());
}
else {
return new QName(name.getLocalName());
}
}
/**
* Loads a SAAJ {@code SOAPMessage} from the given resource with a given message factory.
*
* @param resource the resource to read from
* @param messageFactory SAAJ message factory used to construct the message
* @return the loaded SAAJ message
* @throws SOAPException if the message cannot be constructed
* @throws IOException if the input stream resource cannot be loaded
*/
public static SOAPMessage loadMessage(Resource resource, MessageFactory messageFactory)
throws SOAPException, IOException {
InputStream is = resource.getInputStream();
try {
MimeHeaders mimeHeaders = new MimeHeaders();
mimeHeaders.addHeader(TransportConstants.HEADER_CONTENT_TYPE, "text/xml");
mimeHeaders.addHeader(TransportConstants.HEADER_CONTENT_LENGTH, Long.toString(resource.getFile().length()));
return messageFactory.createMessage(mimeHeaders, is);
}
finally {
is.close();
}
}
/**
* Returns the SAAJ {@code SOAPEnvelope} for the given element.
*
* @param element the element to return the envelope from
* @return the envelope, or {@code null} if not found
*/
public static SOAPEnvelope getEnvelope(SOAPElement element) {
Assert.notNull(element, "Element should not be null");
do {
if (element instanceof SOAPEnvelope) {
return (SOAPEnvelope) element;
}
element = element.getParentElement();
}
while (element != null);
return null;
}
/**
* Returns the first child element of the given body.
*/
public static SOAPElement getFirstBodyElement(SOAPBody body) {
for (Iterator<?> iterator = body.getChildElements(); iterator.hasNext(); ) {
Object child = iterator.next();
if (child instanceof SOAPElement) {
return (SOAPElement) child;
}
}
return null;
}
}