2020import javax .xml .parsers .DocumentBuilderFactory ;
2121import javax .xml .parsers .ParserConfigurationException ;
2222import javax .xml .transform .Source ;
23+ import javax .xml .transform .TransformerException ;
2324import javax .xml .transform .dom .DOMResult ;
2425import javax .xml .transform .dom .DOMSource ;
2526
26- import org .springframework .xml .transform .TransformerObjectSupport ;
2727import org .w3c .dom .Document ;
2828import org .w3c .dom .Element ;
29+ import org .w3c .dom .Node ;
30+
31+ import org .springframework .xml .transform .TransformerObjectSupport ;
2932
3033/**
3134 * Abstract base class for endpoints that handle the message payload as DOM elements.
3235 * <p/>
33- * <p> Offers the message payload as a DOM <code>Element</code>, and allows subclasses to create a response by returning
34- * an <code>Element</code>.
36+ * Offers the message payload as a DOM <code>Element</code>, and allows subclasses to create a response by returning an
37+ * <code>Element</code>.
3538 * <p/>
36- * <p> An <code>AbstractDomPayloadEndpoint</code> only accept <i >one</i > payload element. Multiple payload elements are
39+ * An <code>AbstractDomPayloadEndpoint</code> only accept <em >one</em > payload element. Multiple payload elements are
3740 * not in accordance with WS-I.
3841 *
3942 * @author Arjen Poutsma
@@ -49,6 +52,8 @@ public abstract class AbstractDomPayloadEndpoint extends TransformerObjectSuppor
4952
5053 private boolean namespaceAware = true ;
5154
55+ private boolean alwaysTransform = false ;
56+
5257 /** Set whether or not the XML parser should be XML namespace aware. Default is <code>true</code>. */
5358 public void setNamespaceAware (boolean namespaceAware ) {
5459 this .namespaceAware = namespaceAware ;
@@ -59,26 +64,24 @@ public void setValidating(boolean validating) {
5964 this .validating = validating ;
6065 }
6166
67+ /**
68+ * Set if the request {@link Source} should always be transformed into a new {@link DOMResult}.
69+ * <p/>
70+ * Default is {@code false}, which is faster.
71+ */
72+ public void setAlwaysTransform (boolean alwaysTransform ) {
73+ this .alwaysTransform = alwaysTransform ;
74+ }
75+
6276 public final Source invoke (Source request ) throws Exception {
6377 if (documentBuilderFactory == null ) {
6478 documentBuilderFactory = createDocumentBuilderFactory ();
6579 }
6680 DocumentBuilder documentBuilder = createDocumentBuilder (documentBuilderFactory );
67- Element requestElement = null ;
68- if (request != null ) {
69- Document requestDocument = documentBuilder .newDocument ();
70- DOMResult domResult = new DOMResult (requestDocument );
71- transform (request , domResult );
72- requestElement = (Element ) requestDocument .getFirstChild ();
73- }
81+ Element requestElement = getDocumentElement (request , documentBuilder );
7482 Document responseDocument = documentBuilder .newDocument ();
7583 Element responseElement = invokeInternal (requestElement , responseDocument );
76- if (responseElement != null ) {
77- return new DOMSource (responseElement );
78- }
79- else {
80- return null ;
81- }
84+ return responseElement != null ? new DOMSource (responseElement ) : null ;
8285 }
8386
8487 /**
@@ -109,6 +112,39 @@ protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserCon
109112 return factory ;
110113 }
111114
115+ /**
116+ * Returns the payload element of the given source.
117+ * <p/>
118+ * Default implementation checks whether the source is a {@link DOMSource}, and returns the {@linkplain
119+ * DOMSource#getNode() node} of that. In all other cases, or when {@linkplain #setAlwaysTransform(boolean)
120+ * alwaysTransform} is {@code true}, the source is transformed into a {@link DOMResult}, which is more expensive. If
121+ * the passed source is {@code null}, {@code null} is returned.
122+ *
123+ * @param source the source to return the root element of; can be {@code null}
124+ * @param documentBuilder the document builder to be used for transformations
125+ * @return the document element
126+ * @throws TransformerException in case of errors
127+ */
128+ protected Element getDocumentElement (Source source , DocumentBuilder documentBuilder ) throws TransformerException {
129+ if (source == null ) {
130+ return null ;
131+ }
132+ if (!alwaysTransform && source instanceof DOMSource ) {
133+ Node node = ((DOMSource ) source ).getNode ();
134+ if (node .getNodeType () == Node .ELEMENT_NODE ) {
135+ return (Element ) node ;
136+ }
137+ else if (node .getNodeType () == Node .DOCUMENT_NODE ) {
138+ return ((Document ) node ).getDocumentElement ();
139+ }
140+ }
141+ // we have no other option than to transform
142+ Document requestDocument = documentBuilder .newDocument ();
143+ DOMResult domResult = new DOMResult (requestDocument );
144+ transform (source , domResult );
145+ return requestDocument .getDocumentElement ();
146+ }
147+
112148 /**
113149 * Template method that subclasses must implement to process the request.
114150 * <p/>
@@ -123,4 +159,5 @@ protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserCon
123159 * @return the response element. Can be <code>null</code> to specify no response.
124160 */
125161 protected abstract Element invokeInternal (Element requestElement , Document responseDocument ) throws Exception ;
162+
126163}
0 commit comments