001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.ws.soap.saaj.support;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.util.Iterator;
022: import javax.xml.namespace.QName;
023: import javax.xml.soap.MessageFactory;
024: import javax.xml.soap.MimeHeaders;
025: import javax.xml.soap.Name;
026: import javax.xml.soap.SOAPElement;
027: import javax.xml.soap.SOAPEnvelope;
028: import javax.xml.soap.SOAPException;
029: import javax.xml.soap.SOAPMessage;
030:
031: import org.springframework.core.io.Resource;
032: import org.springframework.util.Assert;
033: import org.springframework.util.ClassUtils;
034: import org.springframework.util.StringUtils;
035: import org.springframework.xml.namespace.QNameUtils;
036: import org.w3c.dom.Element;
037:
038: /**
039: * Collection of generic utility methods to work with SAAJ. Includes conversion from <code>Name</code>s to
040: * <code>QName</code>s and vice-versa, and SAAJ version checking.
041: *
042: * @author Arjen Poutsma
043: * @see Name
044: * @see QName
045: * @since 1.0.0
046: */
047: public abstract class SaajUtils {
048:
049: public static final int SAAJ_11 = 0;
050:
051: public static final int SAAJ_12 = 1;
052:
053: public static final int SAAJ_13 = 2;
054:
055: private static final String SAAJ_13_CLASS_NAME = "javax.xml.soap.SAAJMetaFactory";
056:
057: private static int saajVersion = SAAJ_12;
058:
059: static {
060: try {
061: ClassUtils.forName(SAAJ_13_CLASS_NAME);
062: saajVersion = SAAJ_13;
063: } catch (ClassNotFoundException ex) {
064: if (Element.class.isAssignableFrom(SOAPElement.class)
065: && !isWebLogic9Implementation()) {
066: saajVersion = SAAJ_12;
067: } else {
068: saajVersion = SAAJ_11;
069: }
070: }
071: }
072:
073: /**
074: * Checks whether we are dealing with a WebLogic 9 implementation of SAAJ. WebLogic 9 does implement SAAJ 1.2, but
075: * throws UnsupportedOperationExceptions when a SAAJ 1.2 method is called.
076: */
077: private static boolean isWebLogic9Implementation() {
078: try {
079: MessageFactory messageFactory = MessageFactory
080: .newInstance();
081: SOAPMessage message = messageFactory.createMessage();
082: try {
083: message.getSOAPBody();
084: } catch (UnsupportedOperationException ex) {
085: return true;
086: }
087: return false;
088: } catch (SOAPException e) {
089: return false;
090: }
091: }
092:
093: /**
094: * Gets the SAAJ version.
095: *
096: * @return a code comparable to the SAAJ_XX codes in this class
097: * @see #SAAJ_11
098: * @see #SAAJ_12
099: * @see #SAAJ_13
100: */
101: public static int getSaajVersion() {
102: return saajVersion;
103: }
104:
105: /**
106: * Returns the SAAJ version as a String. The returned string will be "<code>SAAJ 1.3</code>", "<code>SAAJ
107: * 1.2</code>", or "<code>SAAJ 1.1</code>".
108: *
109: * @return a string representation of the SAAJ version
110: * @see #getSaajVersion()
111: */
112: public static String getSaajVersionString() {
113: if (saajVersion >= SaajUtils.SAAJ_13) {
114: return "SAAJ 1.3";
115: } else if (saajVersion == SaajUtils.SAAJ_12) {
116: return "SAAJ 1.2";
117: } else if (saajVersion == SaajUtils.SAAJ_11) {
118: return "SAAJ 1.1";
119: } else {
120: return "";
121: }
122: }
123:
124: /**
125: * Converts a {@link QName} to a {@link Name}. A {@link SOAPElement} is required to resolve namespaces.
126: *
127: * @param qName the <code>QName</code> to convert
128: * @param resolveElement a <code>SOAPElement</code> used to resolve namespaces to prefixes
129: * @return the converted SAAJ Name
130: * @throws SOAPException if conversion is unsuccessful
131: * @throws IllegalArgumentException if <code>qName</code> is not fully qualified
132: */
133: public static Name toName(QName qName, SOAPElement resolveElement)
134: throws SOAPException {
135: String qNamePrefix = QNameUtils.getPrefix(qName);
136: SOAPEnvelope envelope = getEnvelope(resolveElement);
137: if (StringUtils.hasLength(qName.getNamespaceURI())
138: && StringUtils.hasLength(qNamePrefix)) {
139: return envelope.createName(qName.getLocalPart(),
140: qNamePrefix, qName.getNamespaceURI());
141: } else if (StringUtils.hasLength(qName.getNamespaceURI())) {
142: Iterator prefixes;
143: if (getSaajVersion() == SAAJ_11) {
144: prefixes = resolveElement.getNamespacePrefixes();
145: } else {
146: prefixes = resolveElement.getVisibleNamespacePrefixes();
147: }
148: while (prefixes.hasNext()) {
149: String prefix = (String) prefixes.next();
150: if (qName.getNamespaceURI().equals(
151: resolveElement.getNamespaceURI(prefix))) {
152: return envelope.createName(qName.getLocalPart(),
153: prefix, qName.getNamespaceURI());
154: }
155: }
156: return envelope.createName(qName.getLocalPart(), "", qName
157: .getNamespaceURI());
158: } else {
159: return envelope.createName(qName.getLocalPart());
160: }
161: }
162:
163: /**
164: * Converts a <code>javax.xml.soap.Name</code> to a <code>javax.xml.namespace.QName</code>.
165: *
166: * @param name the <code>Name</code> to convert
167: * @return the converted <code>QName</code>
168: */
169: public static QName toQName(Name name) {
170: if (StringUtils.hasLength(name.getURI())
171: && StringUtils.hasLength(name.getPrefix())) {
172: return QNameUtils.createQName(name.getURI(), name
173: .getLocalName(), name.getPrefix());
174: } else if (StringUtils.hasLength(name.getURI())) {
175: return new QName(name.getURI(), name.getLocalName());
176: } else {
177: return new QName(name.getLocalName());
178: }
179: }
180:
181: /**
182: * Loads a SAAJ <code>SOAPMessage</code> from the given resource with a given message factory.
183: *
184: * @param resource the resource to read from
185: * @param messageFactory SAAJ message factory used to construct the message
186: * @return the loaded SAAJ message
187: * @throws SOAPException if the message cannot be constructed
188: * @throws IOException if the input stream resource cannot be loaded
189: */
190: public static SOAPMessage loadMessage(Resource resource,
191: MessageFactory messageFactory) throws SOAPException,
192: IOException {
193: InputStream is = resource.getInputStream();
194: try {
195: MimeHeaders mimeHeaders = new MimeHeaders();
196: mimeHeaders.addHeader("Content-Type", "text/xml");
197: mimeHeaders.addHeader("Content-Length", Long
198: .toString(resource.getFile().length()));
199: return messageFactory.createMessage(mimeHeaders, is);
200: } finally {
201: is.close();
202: }
203: }
204:
205: /**
206: * Returns the SAAJ <code>SOAPEnvelope</code> for the given element.
207: *
208: * @param element the element to return the envelope from
209: * @return the envelope, or <code>null</code> if not found
210: */
211: public static SOAPEnvelope getEnvelope(SOAPElement element) {
212: Assert.notNull(element, "Element should not be null");
213: do {
214: if (element instanceof SOAPEnvelope) {
215: return (SOAPEnvelope) element;
216: }
217: element = element.getParentElement();
218: } while (element != null);
219: return null;
220: }
221: }
|