Migrated to Gradle build

This commit migrates from a Maven-based build system to a Gradle-based
one. Changes include:

- Removed archetype & parent
- Renamed core, support, test, security and xml directories to
  spring-ws-core, spring-ws-test, spring-ws-security, spring-xml
  respectively.
- Moved samples to separate project
  (https://github.com/spring-projects/spring-ws-samples)
This commit is contained in:
Arjen Poutsma
2013-11-05 10:55:44 +01:00
committed by Arjen Poutsma
parent a8c1d2ad97
commit 843ca6d2ef
1362 changed files with 798 additions and 13079 deletions

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2005-2010 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;
/**
* Sub-interface of {@link WebServiceMessage} that can contain special Fault messages. Fault messages (such as {@link
* org.springframework.ws.soap.SoapFault} SOAP Faults) often require different processing rules.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.SoapMessage
* @since 1.0.0
*/
public interface FaultAwareWebServiceMessage extends WebServiceMessage {
/**
* Does this message have a fault?
*
* @return <code>true</code> if the message has a fault.
* @see #getFaultReason()
*/
boolean hasFault();
/**
* Returns the fault reason message.
*
* @return the fault reason message, if any; returns <code>null</code> when no fault is present.
* @see #hasFault()
*/
String getFaultReason();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2005-2012 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;
/**
* Exception thrown when a {@link WebServiceMessageFactory} cannot parse the XML passed on to
* {@link WebServiceMessageFactory#createWebServiceMessage(java.io.InputStream)}.
*
* @author Arjen Poutsma
* @since 2.0.4
*/
public final class InvalidXmlException extends WebServiceException {
public InvalidXmlException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2005 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;
/**
* Exception thrown when an endpoint cannot be resolved for an incoming message request.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public final class NoEndpointFoundException extends WebServiceException {
public NoEndpointFoundException(WebServiceMessage request) {
super("No endpoint can be found for request [" + request + "]");
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2005-2007 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;
import org.springframework.core.NestedRuntimeException;
/**
* Root of the hierarchy of Web Service exceptions.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class WebServiceException extends NestedRuntimeException {
/**
* Create a new instance of the <code>WebServiceException</code> class.
*
* @param msg the detail message
*/
public WebServiceException(String msg) {
super(msg);
}
/**
* Create a new instance of the <code>WebServiceException</code> class.
*
* @param msg the detail message
* @param ex the root {@link Throwable exception}
*/
public WebServiceException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2005-2007 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;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
/**
* Represents a protocol-agnostic XML message.
* <p/>
* <p>Contains methods that provide access to the payload of the message.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.SoapMessage
* @see WebServiceMessageFactory
* @since 1.0.0
*/
public interface WebServiceMessage {
/**
* Returns the contents of the message as a {@link Source}. <p> Depending on the implementation, this can be
* retrieved multiple times, or just a single time.
*
* @return the message contents
*/
Source getPayloadSource();
/**
* Returns the contents of the message as a {@link Result}.
* <p/>
* Calling this method removes the current payload.
* <p/>
* Implementations that are read-only will throw an {@link UnsupportedOperationException}.
*
* @return the message contents
* @throws UnsupportedOperationException if the message is read-only
*/
Result getPayloadResult();
/**
* Writes the entire message to the given output stream. <p>If the given stream is an instance of {@link
* org.springframework.ws.transport.TransportOutputStream}, the corresponding headers will be written as well.
*
* @param outputStream the stream to write to
* @throws IOException if an I/O exception occurs
*/
void writeTo(OutputStream outputStream) throws IOException;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2005 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;
/**
* Base class for all web service message exceptions.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class WebServiceMessageException extends WebServiceException {
/** Constructor for <code>WebServiceMessageException</code>. */
public WebServiceMessageException(String msg) {
super(msg);
}
/** Constructor for <code>WebServiceMessageException</code>. */
public WebServiceMessageException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2005-2012 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;
import java.io.IOException;
import java.io.InputStream;
/**
* The <code>WebServiceMessageFactory</code> serves as a factory for {@link org.springframework.ws.WebServiceMessage
* WebServiceMessages}.
* <p/>
* <p>Allows the creation of empty messages, or messages based on <code>InputStream</code>s.
*
* @author Arjen Poutsma
* @see org.springframework.ws.WebServiceMessage
* @since 1.0.0
*/
public interface WebServiceMessageFactory {
/**
* Creates a new, empty <code>WebServiceMessage</code>.
*
* @return the empty message
*/
WebServiceMessage createWebServiceMessage();
/**
* Reads a {@link WebServiceMessage} from the given input stream.
* <p/>
* If the given stream is an instance of {@link org.springframework.ws.transport.TransportInputStream
* TransportInputStream}, the headers will be read from the request.
*
* @param inputStream the input stream to read the message from
* @return the created message
* @throws InvalidXmlException if the XML read from the input stream is invalid
* @throws IOException if an I/O exception occurs
*/
WebServiceMessage createWebServiceMessage(InputStream inputStream) throws InvalidXmlException, IOException;
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 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.client;
import org.springframework.ws.WebServiceException;
/**
* Exception thrown whenever an error occurs on the client-side.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class WebServiceClientException extends WebServiceException {
/**
* Create a new instance of the <code>WebServiceClientException</code> class.
*
* @param msg the detail message
*/
public WebServiceClientException(String msg) {
super(msg);
}
/**
* Create a new instance of the <code>WebServiceClientException</code> class.
*
* @param msg the detail message
* @param ex the root {@link Throwable exception}
*/
public WebServiceClientException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2007 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.client;
import org.springframework.ws.FaultAwareWebServiceMessage;
/**
* Thrown by <code>SimpleFaultMessageResolver</code> when the response message has a fault.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class WebServiceFaultException extends WebServiceClientException {
private final FaultAwareWebServiceMessage faultMessage;
/** Create a new instance of the <code>WebServiceFaultException</code> class. */
public WebServiceFaultException(String msg) {
super(msg);
faultMessage = null;
}
/**
* Create a new instance of the <code>WebServiceFaultException</code> class.
*
* @param faultMessage the fault message
*/
public WebServiceFaultException(FaultAwareWebServiceMessage faultMessage) {
super(faultMessage.getFaultReason());
this.faultMessage = faultMessage;
}
/** Returns the fault message. */
public FaultAwareWebServiceMessage getWebServiceMessage() {
return faultMessage;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 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.client;
import java.io.IOException;
/**
* Exception thrown whenever an I/O error occurs on the client-side.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class WebServiceIOException extends WebServiceClientException {
/**
* Create a new instance of the <code>WebServiceIOException</code> class.
*
* @param msg the detail message
*/
public WebServiceIOException(String msg) {
super(msg);
}
/**
* Create a new instance of the <code>WebServiceIOException</code> class.
*
* @param msg the detail message
* @param ex the root {@link IOException}
*/
public WebServiceIOException(String msg, IOException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 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.client;
import javax.xml.transform.TransformerException;
/**
* Exception thrown whenever a transformation error occurs <i>on the client-side</i>.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class WebServiceTransformerException extends WebServiceClientException {
/**
* Create a new instance of the <code>WebServiceTransformerException</code> class.
*
* @param msg the detail message
*/
public WebServiceTransformerException(String msg) {
super(msg);
}
/**
* Create a new instance of the <code>WebServiceTransformerException</code> class.
*
* @param msg the detail message
* @param ex the root {@link Throwable exception}
*/
public WebServiceTransformerException(String msg, TransformerException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2007 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.client;
import org.springframework.ws.transport.TransportException;
/**
* Exception thrown whenever a transport error occurs on the client-side.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class WebServiceTransportException extends WebServiceIOException {
/**
* Create a new instance of the <code>WebServiceTransportException</code> class.
*
* @param msg the detail message
*/
public WebServiceTransportException(String msg) {
super(msg);
}
/**
* Create a new instance of the <code>WebServiceTransportException</code> class.
*
* @param msg the detail message
* @param ex the root {@link TransportException}
*/
public WebServiceTransportException(String msg, TransportException ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2007 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.client.core;
import java.io.IOException;
import org.springframework.ws.WebServiceMessage;
/**
* Defines the interface for objects than can resolve fault {@link WebServiceMessage}s.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface FaultMessageResolver {
/**
* Try to resolve the given fault message that got received.
*
* @param message the fault message
*/
void resolveFault(WebServiceMessage message) throws IOException;
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2007 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.client.core;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceFaultException;
/**
* Simple fault resolver that simply throws a {@link WebServiceFaultException} when a fault occurs.
*
* @author Arjen Poutsma
* @see WebServiceFaultException
* @since 1.0.0
*/
public class SimpleFaultMessageResolver implements FaultMessageResolver {
/** Throws a new <code>WebServiceFaultException</code>. */
public void resolveFault(WebServiceMessage message) {
if (message instanceof FaultAwareWebServiceMessage) {
throw new WebServiceFaultException((FaultAwareWebServiceMessage) message);
}
else {
throw new WebServiceFaultException("Message has unknown fault: " + message);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2005-2010 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.client.core;
import java.io.IOException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
/**
* Callback interface for extracting a result object from a {@link javax.xml.transform.Source} instance.
* <p/>
* Used for output object creation in {@link WebServiceTemplate}. Alternatively, output sources can also be returned to
* client code as-is. In case of a source as execution result, you will almost always want to implement a
* <code>SourceExtractor</code>, to be able to read the message content in a managed fashion, with the connection still
* open while reading the message.
* <p/>
* Implementations of this interface perform the actual work of extracting results, but don't need to worry about
* exception handling, or resource handling.
*
* @author Arjen Poutsma
* @see org.springframework.ws.client.core.WebServiceTemplate
* @since 1.0.0
*/
public interface SourceExtractor<T> {
/**
* Process the data in the given <code>Source</code>, creating a corresponding result object.
*
* @param source the message payload to extract data from
* @return an arbitrary result object, or <code>null</code> if none (the extractor will typically be stateful in the
* latter case)
* @throws IOException in case of I/O errors
*/
T extractData(Source source) throws IOException, TransformerException;
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2007 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.client.core;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import org.springframework.ws.WebServiceMessage;
/**
* Generic callback interface for code that operates on a {@link WebServiceMessage}.
* <p/>
* Implementations can execute any number of operations on the message, such as set the contents of the message, or set
* the <code>SOAPAction</code> header.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface WebServiceMessageCallback {
/**
* Execute any number of operations on the supplied <code>message</code>.
*
* @param message the message
* @throws IOException in case of I/O errors
* @throws TransformerException in case of transformation errors
*/
void doWithMessage(WebServiceMessage message) throws IOException, TransformerException;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2005-2010 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.client.core;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import org.springframework.ws.WebServiceMessage;
/**
* Callback interface for extracting a result object from a {@link WebServiceMessage} instance.
* <p/>
* Used for output object creation in {@link WebServiceTemplate}. Alternatively, output messages can also be returned to
* client code as-is. In case of a message as execution result, you will almost always want to implement a
* <code>WebServiceMessageExtractor</code>, to be able to read the message in a managed fashion, with the connection
* still open while reading the message.
* <p/>
* Implementations of this interface perform the actual work of extracting results, but don't need to worry about
* exception handling, or resource handling.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface WebServiceMessageExtractor<T> {
/**
* Process the data in the given <code>WebServiceMessage</code>, creating a corresponding result object.
*
* @param message the message to extract data from (possibly a <code>SoapMessage</code>)
* @return an arbitrary result object, or <code>null</code> if none (the extractor will typically be stateful in the
* latter case)
* @throws IOException in case of I/O errors
* @throws TransformerException in case of transformation errors
*/
T extractData(WebServiceMessage message) throws IOException, TransformerException;
}

View File

@@ -0,0 +1,293 @@
/*
* Copyright 2005-2011 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.client.core;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import org.springframework.oxm.XmlMappingException;
import org.springframework.ws.client.WebServiceClientException;
/**
* Specifies a basic set of Web service operations. Implemented by {@link WebServiceTemplate}. Not often used directly,
* but a useful option to enhance testability, as it can easily be mocked or stubbed.
*
* @author Arjen Poutsma
* @see WebServiceTemplate
* @since 1.0.0
*/
public interface WebServiceOperations {
/**
* Sends a web service message that can be manipulated with the given callback, reading the result with a
* <code>WebServiceMessageExtractor</code>.
* <p/>
* This will only work with a default uri specified!
*
* @param requestCallback the requestCallback to be used for manipulating the request message
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>WebServiceMessageExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageExtractor<T> responseExtractor)
throws WebServiceClientException;
/**
* Sends a web service message that can be manipulated with the given callback, reading the result with a
* <code>WebServiceMessageExtractor</code>.
*
* @param uri the URI to send the message to
* @param requestCallback the requestCallback to be used for manipulating the request message
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>WebServiceMessageExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageExtractor<T> responseExtractor) throws WebServiceClientException;
/**
* Sends a web service message that can be manipulated with the given request callback, handling the response with a
* response callback.
* <p/>
* This will only work with a default uri specified!
*
* @param requestCallback the callback to be used for manipulating the request message
* @param responseCallback the callback to be used for manipulating the response message
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendAndReceive(WebServiceMessageCallback requestCallback, WebServiceMessageCallback responseCallback)
throws WebServiceClientException;
/**
* Sends a web service message that can be manipulated with the given request callback, handling the response with a
* response callback.
*
* @param uri the URI to send the message to
* @param requestCallback the callback to be used for manipulating the request message
* @param responseCallback the callback to be used for manipulating the response message
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) throws WebServiceClientException;
//-----------------------------------------------------------------------------------------------------------------
// Convenience methods for sending and receiving marshalled messages
//-----------------------------------------------------------------------------------------------------------------
/**
* Sends a web service message that contains the given payload, marshalled by the configured
* <code>Marshaller</code>. Returns the unmarshalled payload of the response message, if any.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the object to marshal into the request message payload
* @return the unmarshalled payload of the response message, or <code>null</code> if no response is given
* @throws XmlMappingException if there is a problem marshalling or unmarshalling
* @throws WebServiceClientException if there is a problem sending or receiving the message
* @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller)
* @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
Object marshalSendAndReceive(Object requestPayload) throws XmlMappingException, WebServiceClientException;
/**
* Sends a web service message that contains the given payload, marshalled by the configured
* <code>Marshaller</code>. Returns the unmarshalled payload of the response message, if any.
*
* @param uri the URI to send the message to
* @param requestPayload the object to marshal into the request message payload
* @return the unmarshalled payload of the response message, or <code>null</code> if no response is given
* @throws XmlMappingException if there is a problem marshalling or unmarshalling
* @throws WebServiceClientException if there is a problem sending or receiving the message
* @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller)
* @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
Object marshalSendAndReceive(String uri, Object requestPayload)
throws XmlMappingException, WebServiceClientException;
/**
* Sends a web service message that contains the given payload, marshalled by the configured
* <code>Marshaller</code>. Returns the unmarshalled payload of the response message, if any. The given callback
* allows changing of the request message after the payload has been marshalled to it.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the object to marshal into the request message payload
* @param requestCallback callback to change message, can be <code>null</code>
* @return the unmarshalled payload of the response message, or <code>null</code> if no response is given
* @throws XmlMappingException if there is a problem marshalling or unmarshalling
* @throws WebServiceClientException if there is a problem sending or receiving the message
* @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller)
* @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
Object marshalSendAndReceive(Object requestPayload, WebServiceMessageCallback requestCallback)
throws XmlMappingException, WebServiceClientException;
/**
* Sends a web service message that contains the given payload, marshalled by the configured
* <code>Marshaller</code>. Returns the unmarshalled payload of the response message, if any. The given callback
* allows changing of the request message after the payload has been marshalled to it.
*
* @param uri the URI to send the message to
* @param requestPayload the object to marshal into the request message payload
* @param requestCallback callback to change message, can be <code>null</code>
* @return the unmarshalled payload of the response message, or <code>null</code> if no response is given
* @throws XmlMappingException if there is a problem marshalling or unmarshalling
* @throws WebServiceClientException if there is a problem sending or receiving the message
* @see WebServiceTemplate#setMarshaller(org.springframework.oxm.Marshaller)
* @see WebServiceTemplate#setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
Object marshalSendAndReceive(String uri, Object requestPayload, WebServiceMessageCallback requestCallback)
throws XmlMappingException, WebServiceClientException;
//-----------------------------------------------------------------------------------------------------------------
// Convenience methods for sending Sources
//-----------------------------------------------------------------------------------------------------------------
/**
* Sends a web service message that contains the given payload, reading the result with a
* <code>SourceExtractor</code>.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the payload of the request message
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>SourceExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendSourceAndReceive(Source requestPayload, SourceExtractor<T> responseExtractor)
throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload, reading the result with a
* <code>SourceExtractor</code>.
*
* @param uri the URI to send the message to
* @param requestPayload the payload of the request message
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>SourceExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendSourceAndReceive(String uri, Source requestPayload, SourceExtractor<T> responseExtractor)
throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload, reading the result with a
* <code>SourceExtractor</code>.
* <p/>
* The given callback allows changing of the request message after the payload has been written to it.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>SourceExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendSourceAndReceive(Source requestPayload,
WebServiceMessageCallback requestCallback,
SourceExtractor<T> responseExtractor) throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload, reading the result with a
* <code>SourceExtractor</code>.
* <p/>
* The given callback allows changing of the request message after the payload has been written to it.
*
* @param uri the URI to send the message to
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>SourceExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
<T> T sendSourceAndReceive(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
SourceExtractor<T> responseExtractor) throws WebServiceClientException;
//-----------------------------------------------------------------------------------------------------------------
// Convenience methods for sending Sources and receiving to Results
//-----------------------------------------------------------------------------------------------------------------
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
* <code>Result</code>.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the payload of the request message
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendSourceAndReceiveToResult(Source requestPayload, Result responseResult) throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
* <code>Result</code>.
*
* @param uri the URI to send the message to
* @param requestPayload the payload of the request message
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendSourceAndReceiveToResult(String uri, Source requestPayload, Result responseResult)
throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
* <code>Result</code>.
* <p/>
* The given callback allows changing of the request message after the payload has been written to it.
* <p/>
* This will only work with a default uri specified!
*
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendSourceAndReceiveToResult(Source requestPayload,
WebServiceMessageCallback requestCallback,
Result responseResult) throws WebServiceClientException;
/**
* Sends a web service message that contains the given payload. Writes the response, if any, to the given
* <code>Result</code>.
* <p/>
* The given callback allows changing of the request message after the payload has been written to it.
*
* @param uri the URI to send the message to
* @param requestPayload the payload of the request message
* @param requestCallback callback to change message, can be <code>null</code>
* @param responseResult the result to write the response payload to
* @return <code>true</code> if a response was received; <code>false</code> otherwise
* @throws WebServiceClientException if there is a problem sending or receiving the message
*/
boolean sendSourceAndReceiveToResult(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
Result responseResult) throws WebServiceClientException;
}

View File

@@ -0,0 +1,813 @@
/*
* Copyright 2005-2011 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.client.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.client.WebServiceTransformerException;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.client.support.WebServiceAccessor;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.client.core.SoapFaultMessageResolver;
import org.springframework.ws.support.DefaultStrategiesHelper;
import org.springframework.ws.support.MarshallingUtils;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.TransportException;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.context.DefaultTransportContext;
import org.springframework.ws.transport.context.TransportContext;
import org.springframework.ws.transport.context.TransportContextHolder;
import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;
import org.springframework.ws.transport.support.TransportUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* <strong>The central class for client-side Web services.</strong> It provides a message-driven approach to sending and
* receiving {@link WebServiceMessage} instances.
* <p/>
* Code using this class need only implement callback interfaces, provide {@link Source} objects to read data from, or
* use the pluggable {@link Marshaller} support. For invoking the {@link #marshalSendAndReceive marshalling methods},
* the {@link #setMarshaller(Marshaller) marshaller} and {@link #setUnmarshaller(Unmarshaller) unmarshaller} properties
* must be set.
* <p/>
* This template uses a {@link SoapFaultMessageResolver} to handle fault response messages. Another {@link
* FaultMessageResolver} can be defined with with {@link #setFaultMessageResolver(FaultMessageResolver)
* faultMessageResolver} property. If this property is set to <code>null</code>, no fault resolving is performed.
* <p/>
* This template uses the following algorithm for sending and receiving. <ol> <li>Call {@link #createConnection(URI)
* createConnection()}.</li> <li>Call {@link WebServiceMessageFactory#createWebServiceMessage()
* createWebServiceMessage()} on the registered message factory to create a request message.</li> <li>Invoke {@link
* WebServiceMessageCallback#doWithMessage(WebServiceMessage) doWithMessage()} on the request callback, if any. This
* step stores content in the request message, based on <code>Source</code>, marshalling, etc.</li> <li>Invoke {@link
* ClientInterceptor#handleRequest(MessageContext) handleRequest()} on the registered {@link
* #setInterceptors(ClientInterceptor[]) interceptors}. Interceptors are executed in order. If any of the interceptors
* creates a response message in the message context, skip to step 7.</li> <li>Call {@link
* WebServiceConnection#send(WebServiceMessage) send()} on the connection.</li> <li>Call {@link
* #hasError(WebServiceConnection,WebServiceMessage) hasError()} to check if the connection has an error. For an HTTP
* transport, a status code other than <code>2xx</code> indicates an error. However, since a status code of 500 can also
* indicate a SOAP fault, the template verifies whether the error is not a fault.</li> <ul> <li>If the connection has an
* error, call the {@link #handleError handleError()} method, which by default throws a {@link
* WebServiceTransportException}.</li> <li>If the connection has no error, continue with the next step.</li> </ul>
* <li>Invoke {@link WebServiceConnection#receive(WebServiceMessageFactory) receive} on the connection to read the
* response message, if any.</li> <ul> <li>If no response was received, return <code>null</code> or
* <code>false</code></li> <li>Call {@link #hasFault(WebServiceConnection,WebServiceMessage) hasFault()} to determine
* whether the response has a fault. If it has, call {@link ClientInterceptor#handleFault(MessageContext)} and the
* {@link #handleFault handleFault()} method.</li> <li>Otherwise, invoke {@link ClientInterceptor#handleResponse(MessageContext)}
* and {@link WebServiceMessageExtractor#extractData(WebServiceMessage) extractData()} on the response extractor, or
* {@link WebServiceMessageCallback#doWithMessage(WebServiceMessage) doWithMessage} on the response callback.</li> </ul>
* <li>Call to {@link WebServiceConnection#close() close} on the connection.</li> </ol>
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class WebServiceTemplate extends WebServiceAccessor implements WebServiceOperations {
/** Log category to use for message tracing. */
public static final String MESSAGE_TRACING_LOG_CATEGORY = "org.springframework.ws.client.MessageTracing";
/** Additional logger to use for sent message tracing. */
protected static final Log sentMessageTracingLogger =
LogFactory.getLog(WebServiceTemplate.MESSAGE_TRACING_LOG_CATEGORY + ".sent");
/** Additional logger to use for received message tracing. */
protected static final Log receivedMessageTracingLogger =
LogFactory.getLog(WebServiceTemplate.MESSAGE_TRACING_LOG_CATEGORY + ".received");
private Marshaller marshaller;
private Unmarshaller unmarshaller;
private FaultMessageResolver faultMessageResolver;
private boolean checkConnectionForError = true;
private boolean checkConnectionForFault = true;
private ClientInterceptor[] interceptors;
private DestinationProvider destinationProvider;
/** Creates a new <code>WebServiceTemplate</code> using default settings. */
public WebServiceTemplate() {
initDefaultStrategies();
}
/**
* Creates a new <code>WebServiceTemplate</code> based on the given message factory.
*
* @param messageFactory the message factory to use
*/
public WebServiceTemplate(WebServiceMessageFactory messageFactory) {
setMessageFactory(messageFactory);
initDefaultStrategies();
}
/**
* Creates a new <code>WebServiceTemplate</code> with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
* @since 2.0.3
*/
public WebServiceTemplate(Marshaller marshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
if (!(marshaller instanceof Unmarshaller)) {
throw new IllegalArgumentException("Marshaller [" + marshaller + "] does not implement the Unmarshaller " +
"interface. Please set an Unmarshaller explicitly by using the " +
"WebServiceTemplate(Marshaller, Unmarshaller) constructor.");
}
else {
this.setMarshaller(marshaller);
this.setUnmarshaller((Unmarshaller) marshaller);
}
initDefaultStrategies();
}
/**
* Creates a new <code>MarshallingMethodEndpointAdapter</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
* @since 2.0.3
*/
public WebServiceTemplate(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.notNull(unmarshaller, "unmarshaller must not be null");
this.setMarshaller(marshaller);
this.setUnmarshaller(unmarshaller);
initDefaultStrategies();
}
/** Returns the default URI to be used on operations that do not have a URI parameter. */
public String getDefaultUri() {
if (destinationProvider != null) {
URI uri = destinationProvider.getDestination();
return uri != null ? uri.toString() : null;
}
else {
return null;
}
}
/**
* Set the default URI to be used on operations that do not have a URI parameter.
* <p/>
* Typically, either this property is set, or {@link #setDestinationProvider(DestinationProvider)}, but not both.
*
* @see #marshalSendAndReceive(Object)
* @see #marshalSendAndReceive(Object,WebServiceMessageCallback)
* @see #sendSourceAndReceiveToResult(Source,Result)
* @see #sendSourceAndReceiveToResult(Source,WebServiceMessageCallback,Result)
* @see #sendSourceAndReceive(Source,SourceExtractor)
* @see #sendSourceAndReceive(Source,WebServiceMessageCallback,SourceExtractor)
* @see #sendAndReceive(WebServiceMessageCallback,WebServiceMessageCallback)
*/
public void setDefaultUri(final String uri) {
destinationProvider = new DestinationProvider() {
public URI getDestination() {
return URI.create(uri);
}
};
}
/** Returns the destination provider used on operations that do not have a URI parameter. */
public DestinationProvider getDestinationProvider() {
return destinationProvider;
}
/**
* Set the destination provider URI to be used on operations that do not have a URI parameter.
* <p/>
* Typically, either this property is set, or {@link #setDefaultUri(String)}, but not both.
*
* @see #marshalSendAndReceive(Object)
* @see #marshalSendAndReceive(Object,WebServiceMessageCallback)
* @see #sendSourceAndReceiveToResult(Source,Result)
* @see #sendSourceAndReceiveToResult(Source,WebServiceMessageCallback,Result)
* @see #sendSourceAndReceive(Source,SourceExtractor)
* @see #sendSourceAndReceive(Source,WebServiceMessageCallback,SourceExtractor)
* @see #sendAndReceive(WebServiceMessageCallback,WebServiceMessageCallback)
*/
public void setDestinationProvider(DestinationProvider destinationProvider) {
this.destinationProvider = destinationProvider;
}
/** Returns the marshaller for this template. */
public Marshaller getMarshaller() {
return marshaller;
}
/** Sets the marshaller for this template. */
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/** Returns the unmarshaller for this template. */
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
/** Sets the unmarshaller for this template. */
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
/** Returns the fault message resolver for this template. */
public FaultMessageResolver getFaultMessageResolver() {
return faultMessageResolver;
}
/**
* Sets the fault resolver for this template. Default is the
* {@link org.springframework.ws.soap.client.core.SoapFaultMessageResolver, SoapFaultMessageResolver}, but may be
* set to {@code null} to disable fault handling.
*/
public void setFaultMessageResolver(FaultMessageResolver faultMessageResolver) {
this.faultMessageResolver = faultMessageResolver;
}
/**
* Indicates whether the {@linkplain WebServiceConnection#hasError() connection} should be checked for error
* indicators (<code>true</code>), or whether these should be ignored (<code>false</code>). The default is
* <code>true</code>.
* <p/>
* When using an HTTP transport, this property defines whether to check the HTTP response status code is in the 2xx
* Successful range. Both the SOAP specification and the WS-I Basic Profile define that a Web service must return a
* "200 OK" or "202 Accepted" HTTP status code for a normal response. Setting this property to <code>false</code>
* allows this template to deal with non-conforming services.
*
* @see #hasError(WebServiceConnection, WebServiceMessage)
* @see <a href="http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383529">SOAP 1.1 specification</a>
* @see <a href="http://www.ws-i.org/Profiles/BasicProfile-1.1.html#HTTP_Success_Status_Codes">WS-I Basic
* Profile</a>
*/
public void setCheckConnectionForError(boolean checkConnectionForError) {
this.checkConnectionForError = checkConnectionForError;
}
/**
* Indicates whether the {@linkplain FaultAwareWebServiceConnection#hasFault() connection} should be checked for
* fault indicators (<code>true</code>), or whether we should rely on the {@link
* FaultAwareWebServiceMessage#hasFault() message} only (<code>false</code>). The default is <code>true</code>.
* <p/>
* When using an HTTP transport, this property defines whether to check the HTTP response status code for fault
* indicators. Both the SOAP specification and the WS-I Basic Profile define that a Web service must return a "500
* Internal Server Error" HTTP status code if the response envelope is a Fault. Setting this property to
* <code>false</code> allows this template to deal with non-conforming services.
*
* @see #hasFault(WebServiceConnection,WebServiceMessage)
* @see <a href="http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383529">SOAP 1.1 specification</a>
* @see <a href="http://www.ws-i.org/Profiles/BasicProfile-1.1.html#HTTP_Server_Error_Status_Codes">WS-I Basic
* Profile</a>
*/
public void setCheckConnectionForFault(boolean checkConnectionForFault) {
this.checkConnectionForFault = checkConnectionForFault;
}
/**
* Returns the client interceptors to apply to all web service invocations made by this template.
*
* @return array of endpoint interceptors, or <code>null</code> if none
*/
public ClientInterceptor[] getInterceptors() {
return interceptors;
}
/**
* Sets the client interceptors to apply to all web service invocations made by this template.
*
* @param interceptors array of endpoint interceptors, or <code>null</code> if none
*/
public final void setInterceptors(ClientInterceptor[] interceptors) {
this.interceptors = interceptors;
}
/**
* Initialize the default implementations for the template's strategies: {@link SoapFaultMessageResolver}, {@link
* org.springframework.ws.soap.saaj.SaajSoapMessageFactory}, and {@link HttpUrlConnectionMessageSender}.
*
* @throws BeanInitializationException in case of initalization errors
* @see #setFaultMessageResolver(FaultMessageResolver)
* @see #setMessageFactory(WebServiceMessageFactory)
* @see #setMessageSender(WebServiceMessageSender)
*/
protected void initDefaultStrategies() {
DefaultStrategiesHelper strategiesHelper = new DefaultStrategiesHelper(WebServiceTemplate.class);
if (getMessageFactory() == null) {
initMessageFactory(strategiesHelper);
}
if (ObjectUtils.isEmpty(getMessageSenders())) {
initMessageSenders(strategiesHelper);
}
if (getFaultMessageResolver() == null) {
initFaultMessageResolver(strategiesHelper);
}
}
private void initMessageFactory(DefaultStrategiesHelper helper) throws BeanInitializationException {
WebServiceMessageFactory messageFactory = helper.getDefaultStrategy(WebServiceMessageFactory.class);
setMessageFactory(messageFactory);
}
private void initMessageSenders(DefaultStrategiesHelper helper) {
List<WebServiceMessageSender> messageSenders = helper.getDefaultStrategies(WebServiceMessageSender.class);
setMessageSenders(messageSenders.toArray(new WebServiceMessageSender[messageSenders.size()]));
}
private void initFaultMessageResolver(DefaultStrategiesHelper helper) throws BeanInitializationException {
FaultMessageResolver faultMessageResolver = helper.getDefaultStrategy(FaultMessageResolver.class);
setFaultMessageResolver(faultMessageResolver);
}
//
// Marshalling methods
//
public Object marshalSendAndReceive(final Object requestPayload) {
return marshalSendAndReceive(requestPayload, null);
}
public Object marshalSendAndReceive(String uri, final Object requestPayload) {
return marshalSendAndReceive(uri, requestPayload, null);
}
public Object marshalSendAndReceive(final Object requestPayload, final WebServiceMessageCallback requestCallback) {
return marshalSendAndReceive(getDefaultUri(), requestPayload, requestCallback);
}
public Object marshalSendAndReceive(String uri,
final Object requestPayload,
final WebServiceMessageCallback requestCallback) {
return sendAndReceive(uri, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage request) throws IOException, TransformerException {
if (requestPayload != null) {
Marshaller marshaller = getMarshaller();
if (marshaller == null) {
throw new IllegalStateException(
"No marshaller registered. Check configuration of WebServiceTemplate.");
}
MarshallingUtils.marshal(marshaller, requestPayload, request);
if (requestCallback != null) {
requestCallback.doWithMessage(request);
}
}
}
}, new WebServiceMessageExtractor<Object>() {
public Object extractData(WebServiceMessage response) throws IOException {
Unmarshaller unmarshaller = getUnmarshaller();
if (unmarshaller == null) {
throw new IllegalStateException(
"No unmarshaller registered. Check configuration of WebServiceTemplate.");
}
return MarshallingUtils.unmarshal(unmarshaller, response);
}
});
}
//
// Result-handling methods
//
public boolean sendSourceAndReceiveToResult(Source requestPayload, Result responseResult) {
return sendSourceAndReceiveToResult(requestPayload, null, responseResult);
}
public boolean sendSourceAndReceiveToResult(String uri, Source requestPayload, Result responseResult) {
return sendSourceAndReceiveToResult(uri, requestPayload, null, responseResult);
}
public boolean sendSourceAndReceiveToResult(Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
return sendSourceAndReceiveToResult(getDefaultUri(), requestPayload, requestCallback, responseResult);
}
public boolean sendSourceAndReceiveToResult(String uri,
Source requestPayload,
WebServiceMessageCallback requestCallback,
final Result responseResult) {
try {
final Transformer transformer = createTransformer();
Boolean retVal = doSendAndReceive(uri, transformer, requestPayload, requestCallback,
new SourceExtractor<Boolean>() {
public Boolean extractData(Source source) throws IOException, TransformerException {
if (source != null) {
transformer.transform(source, responseResult);
}
return Boolean.TRUE;
}
});
return retVal != null && retVal;
}
catch (TransformerConfigurationException ex) {
throw new WebServiceTransformerException("Could not create transformer", ex);
}
}
//
// Source-handling methods
//
public <T> T sendSourceAndReceive(final Source requestPayload, final SourceExtractor<T> responseExtractor) {
return sendSourceAndReceive(requestPayload, null, responseExtractor);
}
public <T> T sendSourceAndReceive(String uri,
final Source requestPayload,
final SourceExtractor<T> responseExtractor) {
return sendSourceAndReceive(uri, requestPayload, null, responseExtractor);
}
public <T> T sendSourceAndReceive(final Source requestPayload,
final WebServiceMessageCallback requestCallback,
final SourceExtractor<T> responseExtractor) {
return sendSourceAndReceive(getDefaultUri(), requestPayload, requestCallback, responseExtractor);
}
public <T> T sendSourceAndReceive(String uri,
final Source requestPayload,
final WebServiceMessageCallback requestCallback,
final SourceExtractor<T> responseExtractor) {
try {
return doSendAndReceive(uri, createTransformer(), requestPayload, requestCallback, responseExtractor);
}
catch (TransformerConfigurationException ex) {
throw new WebServiceTransformerException("Could not create transformer", ex);
}
}
private <T> T doSendAndReceive(String uri,
final Transformer transformer,
final Source requestPayload,
final WebServiceMessageCallback requestCallback,
final SourceExtractor<T> responseExtractor) {
Assert.notNull(responseExtractor, "responseExtractor must not be null");
return sendAndReceive(uri, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
transformer.transform(requestPayload, message.getPayloadResult());
if (requestCallback != null) {
requestCallback.doWithMessage(message);
}
}
}, new SourceExtractorMessageExtractor<T>(responseExtractor));
}
//
// WebServiceMessage-handling methods
//
public boolean sendAndReceive(WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) {
return sendAndReceive(getDefaultUri(), requestCallback, responseCallback);
}
public boolean sendAndReceive(String uri,
WebServiceMessageCallback requestCallback,
WebServiceMessageCallback responseCallback) {
Assert.notNull(responseCallback, "responseCallback must not be null");
Boolean result = sendAndReceive(uri, requestCallback,
new WebServiceMessageCallbackMessageExtractor(responseCallback));
return result != null && result;
}
public <T> T sendAndReceive(WebServiceMessageCallback requestCallback,
WebServiceMessageExtractor<T> responseExtractor) {
return sendAndReceive(getDefaultUri(), requestCallback, responseExtractor);
}
public <T> T sendAndReceive(String uriString,
WebServiceMessageCallback requestCallback,
WebServiceMessageExtractor<T> responseExtractor) {
Assert.notNull(responseExtractor, "'responseExtractor' must not be null");
Assert.hasLength(uriString, "'uri' must not be empty");
TransportContext previousTransportContext = TransportContextHolder.getTransportContext();
WebServiceConnection connection = null;
try {
connection = createConnection(URI.create(uriString));
TransportContextHolder.setTransportContext(new DefaultTransportContext(connection));
MessageContext messageContext = new DefaultMessageContext(getMessageFactory());
return doSendAndReceive(messageContext, connection, requestCallback, responseExtractor);
}
catch (TransportException ex) {
throw new WebServiceTransportException("Could not use transport: " + ex.getMessage(), ex);
}
catch (IOException ex) {
throw new WebServiceIOException("I/O error: " + ex.getMessage(), ex);
}
finally {
TransportUtils.closeConnection(connection);
TransportContextHolder.setTransportContext(previousTransportContext);
}
}
/**
* Sends and receives a {@link MessageContext}. Sends the {@link MessageContext#getRequest() request message}, and
* received to the {@link MessageContext#getResponse() repsonse message}. Invocates the defined {@link
* #setInterceptors(ClientInterceptor[]) interceptors} as part of the process.
*
* @param messageContext the message context
* @param connection the connection to use
* @param requestCallback the requestCallback to be used for manipulating the request message
* @param responseExtractor object that will extract results
* @return an arbitrary result object, as returned by the <code>WebServiceMessageExtractor</code>
* @throws WebServiceClientException if there is a problem sending or receiving the message
* @throws IOException in case of I/O errors
*/
@SuppressWarnings("unchecked")
protected <T> T doSendAndReceive(MessageContext messageContext,
WebServiceConnection connection,
WebServiceMessageCallback requestCallback,
WebServiceMessageExtractor<T> responseExtractor) throws IOException {
try {
if (requestCallback != null) {
requestCallback.doWithMessage(messageContext.getRequest());
}
// Apply handleRequest of registered interceptors
int interceptorIndex = -1;
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
interceptorIndex = i;
if (!interceptors[i].handleRequest(messageContext)) {
break;
}
}
}
// if an interceptor has set a response, we don't send/receive
if (!messageContext.hasResponse()) {
sendRequest(connection, messageContext.getRequest());
if (hasError(connection, messageContext.getRequest())) {
return (T)handleError(connection, messageContext.getRequest());
}
WebServiceMessage response = connection.receive(getMessageFactory());
messageContext.setResponse(response);
}
logResponse(messageContext);
if (messageContext.hasResponse()) {
if (!hasFault(connection, messageContext.getResponse())) {
triggerHandleResponse(interceptorIndex, messageContext);
return responseExtractor.extractData(messageContext.getResponse());
}
else {
triggerHandleFault(interceptorIndex, messageContext);
return (T)handleFault(connection, messageContext);
}
}
else {
return null;
}
}
catch (TransformerException ex) {
throw new WebServiceTransformerException("Transformation error: " + ex.getMessage(), ex);
}
}
/** Sends the request in the given message context over the connection. */
private void sendRequest(WebServiceConnection connection, WebServiceMessage request) throws IOException {
if (sentMessageTracingLogger.isTraceEnabled()) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
request.writeTo(os);
sentMessageTracingLogger.trace("Sent request [" + os.toString("UTF-8") + "]");
}
else if (sentMessageTracingLogger.isDebugEnabled()) {
sentMessageTracingLogger.debug("Sent request [" + request + "]");
}
connection.send(request);
}
/**
* Determines whether the given connection or message context has an error.
* <p/>
* This implementation checks the {@link WebServiceConnection#hasError() connection} first. If it indicates an
* error, it makes sure that it is not a {@link FaultAwareWebServiceConnection#hasFault() fault}.
*
* @param connection the connection (possibly a {@link FaultAwareWebServiceConnection}
* @param request the response message (possibly a {@link FaultAwareWebServiceMessage}
* @return <code>true</code> if the connection has an error; <code>false</code> otherwise
* @throws IOException in case of I/O errors
*/
protected boolean hasError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
if (checkConnectionForError && connection.hasError()) {
// could be a fault
if (checkConnectionForFault && connection instanceof FaultAwareWebServiceConnection) {
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
return !(faultConnection.hasFault() && request instanceof FaultAwareWebServiceMessage);
}
else {
return true;
}
}
return false;
}
/**
* Handles an error on the given connection. The default implementation throws a {@link
* WebServiceTransportException}.
*
* @param connection the erroneous connection
* @param request the corresponding request message
* @return the object to be returned from {@link #sendAndReceive(String,WebServiceMessageCallback,
* WebServiceMessageExtractor)}, if any
*/
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Received error for request [" + request + "]");
}
throw new WebServiceTransportException(connection.getErrorMessage());
}
private void logResponse(MessageContext messageContext) throws IOException {
if (messageContext.hasResponse()) {
if (receivedMessageTracingLogger.isTraceEnabled()) {
ByteArrayOutputStream requestStream = new ByteArrayOutputStream();
messageContext.getRequest().writeTo(requestStream);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
messageContext.getResponse().writeTo(responseStream);
receivedMessageTracingLogger
.trace("Received response [" + responseStream.toString("UTF-8") + "] for request [" +
requestStream.toString("UTF-8") + "]");
}
else if (receivedMessageTracingLogger.isDebugEnabled()) {
receivedMessageTracingLogger
.debug("Received response [" + messageContext.getResponse() + "] for request [" +
messageContext.getRequest() + "]");
}
}
else {
if (logger.isDebugEnabled()) {
receivedMessageTracingLogger
.debug("Received no response for request [" + messageContext.getRequest() + "]");
}
}
}
/**
* Determines whether the given connection or message has a fault.
* <p/>
* This implementation checks the {@link FaultAwareWebServiceConnection#hasFault() connection} if the {@link
* #setCheckConnectionForFault(boolean) checkConnectionForFault} property is true, and defaults to the {@link
* FaultAwareWebServiceMessage#hasFault() message} otherwise.
*
* @param connection the connection (possibly a {@link FaultAwareWebServiceConnection}
* @param response the response message (possibly a {@link FaultAwareWebServiceMessage}
* @return <code>true</code> if either the connection or the message has a fault; <code>false</code> otherwise
* @throws IOException in case of I/O errors
*/
protected boolean hasFault(WebServiceConnection connection, WebServiceMessage response) throws IOException {
if (checkConnectionForFault && connection instanceof FaultAwareWebServiceConnection) {
// check whether the connection has a fault (i.e. status code 500 in HTTP)
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
if (!faultConnection.hasFault()) {
return false;
}
}
if (response instanceof FaultAwareWebServiceMessage) {
// either the connection has a fault, or checkConnectionForFault is false: let's verify the fault
FaultAwareWebServiceMessage faultMessage = (FaultAwareWebServiceMessage) response;
return faultMessage.hasFault();
}
return false;
}
/**
* Trigger handleResponse on the defined ClientInterceptors. Will just invoke said method on all interceptors whose
* handleRequest invocation returned <code>true</code>, in addition to the last interceptor who returned
* <code>false</code>.
*
* @param interceptorIndex index of last interceptor that was called
* @param messageContext the message context, whose request and response are filled
* @see ClientInterceptor#handleResponse(MessageContext)
* @see ClientInterceptor#handleFault(MessageContext)
*/
private void triggerHandleResponse(int interceptorIndex, MessageContext messageContext) {
if (messageContext.hasResponse() && interceptors != null) {
for (int i = interceptorIndex; i >= 0; i--) {
if (!interceptors[i].handleResponse(messageContext)) {
break;
}
}
}
}
/**
* Trigger handleFault on the defined ClientInterceptors. Will just invoke said method on all interceptors whose
* handleRequest invocation returned <code>true</code>, in addition to the last interceptor who returned
* <code>false</code>.
*
* @param interceptorIndex index of last interceptor that was called
* @param messageContext the message context, whose request and response are filled
* @see ClientInterceptor#handleResponse(MessageContext)
* @see ClientInterceptor#handleFault(MessageContext)
*/
private void triggerHandleFault(int interceptorIndex, MessageContext messageContext) {
if (messageContext.hasResponse() && interceptors != null) {
for (int i = interceptorIndex; i >= 0; i--) {
if (!interceptors[i].handleFault(messageContext)) {
break;
}
}
}
}
/**
* Handles an fault in the given response message. The default implementation invokes the {@link
* FaultMessageResolver fault resolver} if registered, or invokes {@link #handleError(WebServiceConnection,
* WebServiceMessage)} otherwise.
*
* @param connection the faulty connection
* @param messageContext the message context
* @return the object to be returned from {@link #sendAndReceive(String,WebServiceMessageCallback,
* WebServiceMessageExtractor)}, if any
*/
protected Object handleFault(WebServiceConnection connection, MessageContext messageContext) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Received Fault message for request [" + messageContext.getRequest() + "]");
}
if (getFaultMessageResolver() != null) {
getFaultMessageResolver().resolveFault(messageContext.getResponse());
return null;
}
else {
return handleError(connection, messageContext.getRequest());
}
}
/** Adapter to enable use of a WebServiceMessageCallback inside a WebServiceMessageExtractor. */
private static class WebServiceMessageCallbackMessageExtractor implements WebServiceMessageExtractor<Boolean> {
private final WebServiceMessageCallback callback;
private WebServiceMessageCallbackMessageExtractor(WebServiceMessageCallback callback) {
this.callback = callback;
}
public Boolean extractData(WebServiceMessage message) throws IOException, TransformerException {
callback.doWithMessage(message);
return Boolean.TRUE;
}
}
/** Adapter to enable use of a SourceExtractor inside a WebServiceMessageExtractor. */
private static class SourceExtractorMessageExtractor<T> implements WebServiceMessageExtractor<T> {
private final SourceExtractor<T> sourceExtractor;
private SourceExtractorMessageExtractor(SourceExtractor<T> sourceExtractor) {
this.sourceExtractor = sourceExtractor;
}
public T extractData(WebServiceMessage message) throws IOException, TransformerException {
return sourceExtractor.extractData(message.getPayloadSource());
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Core package of the Spring-WS client-side support. Provides a WebServiceTemplate class and various callback interfaces.
</body>
</html>

View File

@@ -0,0 +1,194 @@
/*
* Copyright 2007 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.client.core.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.transport.WebServiceMessageSender;
/**
* Convenient super class for application classes that need Web service access.
* <p/>
* Requires a {@link WebServiceMessageFactory} or a {@link WebServiceTemplate} instance to be set. It will create its
* own <code>WebServiceTemplate</code> if <code>WebServiceMessageFactory</code> is passed in.
* <p/>
* In addition to the message factory property, this gateway offers {@link Marshaller} and {@link Unmarshaller}
* properties. Setting these is required when the {@link WebServiceTemplate#marshalSendAndReceive(Object) marshalling
* methods} of the template are to be used.
* <p/>
* Note that when {@link #setWebServiceTemplate(WebServiceTemplate) injecting a <code>WebServiceTemplate</code>}
* directly, the convenience setters ({@link #setMarshaller(Marshaller)}, {@link #setUnmarshaller(Unmarshaller)}, {@link
* #setMessageSender(WebServiceMessageSender)}, {@link #setMessageSenders(WebServiceMessageSender[])}, and {@link
* #setDefaultUri(String)}) should not be used on this class, but on the template directly.
*
* @author Arjen Poutsma
* @see #setMessageFactory(WebServiceMessageFactory)
* @see WebServiceTemplate
* @see #setMarshaller(Marshaller)
* @since 1.0.0
*/
public abstract class WebServiceGatewaySupport implements InitializingBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private WebServiceTemplate webServiceTemplate;
/**
* Creates a new instance of the <code>WebServiceGatewaySupport</code> class, with a default
* <code>WebServiceTemplate</code>.
*/
protected WebServiceGatewaySupport() {
webServiceTemplate = new WebServiceTemplate();
}
/**
* Creates a new <code>WebServiceGatewaySupport</code> instance based on the given message factory.
*
* @param messageFactory the message factory to use
*/
protected WebServiceGatewaySupport(WebServiceMessageFactory messageFactory) {
webServiceTemplate = new WebServiceTemplate(messageFactory);
}
/** Returns the <code>WebServiceMessageFactory</code> used by the gateway. */
public final WebServiceMessageFactory getMessageFactory() {
return webServiceTemplate.getMessageFactory();
}
/** Set the <code>WebServiceMessageFactory</code> to be used by the gateway. */
public final void setMessageFactory(WebServiceMessageFactory messageFactory) {
webServiceTemplate.setMessageFactory(messageFactory);
}
/** Returns the default URI used by the gateway. */
public final String getDefaultUri() {
return webServiceTemplate.getDefaultUri();
}
/** Sets the default URI used by the gateway. */
public final void setDefaultUri(String uri) {
webServiceTemplate.setDefaultUri(uri);
}
/** Returns the destination provider used by the gateway. */
public final DestinationProvider getDestinationProvider() {
return webServiceTemplate.getDestinationProvider();
}
/** Set the destination provider URI used by the gateway. */
public final void setDestinationProvider(DestinationProvider destinationProvider) {
webServiceTemplate.setDestinationProvider(destinationProvider);
}
/** Sets a single <code>WebServiceMessageSender</code> to be used by the gateway. */
public final void setMessageSender(WebServiceMessageSender messageSender) {
webServiceTemplate.setMessageSender(messageSender);
}
/** Returns the <code>WebServiceMessageSender</code>s used by the gateway. */
public final WebServiceMessageSender[] getMessageSenders() {
return webServiceTemplate.getMessageSenders();
}
/** Sets multiple <code>WebServiceMessageSender</code> to be used by the gateway. */
public final void setMessageSenders(WebServiceMessageSender[] messageSenders) {
webServiceTemplate.setMessageSenders(messageSenders);
}
/** Returns the <code>WebServiceTemplate</code> for the gateway. */
public final WebServiceTemplate getWebServiceTemplate() {
return webServiceTemplate;
}
/**
* Sets the <code>WebServiceTemplate</code> to be used by the gateway.
* <p/>
* When using this property, the convenience setters ({@link #setMarshaller(Marshaller)}, {@link
* #setUnmarshaller(Unmarshaller)}, {@link #setMessageSender(WebServiceMessageSender)}, {@link
* #setMessageSenders(WebServiceMessageSender[])}, and {@link #setDefaultUri(String)}) should not be set on this
* class, but on the template directly.
*/
public final void setWebServiceTemplate(WebServiceTemplate webServiceTemplate) {
Assert.notNull(webServiceTemplate, "'webServiceTemplate' must not be null");
this.webServiceTemplate = webServiceTemplate;
}
/** Returns the <code>Marshaller</code> used by the gateway. */
public final Marshaller getMarshaller() {
return webServiceTemplate.getMarshaller();
}
/**
* Sets the <code>Marshaller</code> used by the gateway. Setting this property is only required if the marshalling
* functionality of <code>WebServiceTemplate</code> is to be used.
*
* @see WebServiceTemplate#marshalSendAndReceive
*/
public final void setMarshaller(Marshaller marshaller) {
webServiceTemplate.setMarshaller(marshaller);
}
/** Returns the <code>Unmarshaller</code> used by the gateway. */
public final Unmarshaller getUnmarshaller() {
return webServiceTemplate.getUnmarshaller();
}
/**
* Sets the <code>Unmarshaller</code> used by the gateway. Setting this property is only required if the marshalling
* functionality of <code>WebServiceTemplate</code> is to be used.
*
* @see WebServiceTemplate#marshalSendAndReceive
*/
public final void setUnmarshaller(Unmarshaller unmarshaller) {
webServiceTemplate.setUnmarshaller(unmarshaller);
}
/** Returns the <code>ClientInterceptors</code> used by the template. */
public final ClientInterceptor[] getInterceptors() {
return webServiceTemplate.getInterceptors();
}
/** Sets the <code>ClientInterceptors</code> used by the gateway. */
public final void setInterceptors(ClientInterceptor[] interceptors) {
webServiceTemplate.setInterceptors(interceptors);
}
public final void afterPropertiesSet() throws Exception {
webServiceTemplate.afterPropertiesSet();
initGateway();
}
/**
* Subclasses can override this for custom initialization behavior. Gets called after population of this instance's
* bean properties.
*
* @throws java.lang.Exception if initialization fails
*/
protected void initGateway() throws Exception {
}
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Convenient super class for application classes that need Web service access. Contains a base class for
WebServiceTemplate usage.
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains classes for client-side Spring-WS support, allowing for Spring-style Web service access.
</body>
</html>

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2005-2010 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.client.support;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Base class for <code>WebServiceTemplate</code> and other WS-accessing helpers. Defines common properties like the
* {@link WebServiceMessageFactory} and {@link WebServiceMessageSender}.
* <p/>
* Not intended to be used directly. See {@link org.springframework.ws.client.core.WebServiceTemplate}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.client.core.WebServiceTemplate
* @since 1.0.0
*/
public abstract class WebServiceAccessor extends TransformerObjectSupport implements InitializingBean {
private WebServiceMessageFactory messageFactory;
private WebServiceMessageSender[] messageSenders;
/** Returns the message factory used for creating messages. */
public WebServiceMessageFactory getMessageFactory() {
return messageFactory;
}
/** Sets the message factory used for creating messages. */
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
this.messageFactory = messageFactory;
}
/** Returns the message senders used for sending messages. */
public WebServiceMessageSender[] getMessageSenders() {
return messageSenders;
}
/**
* Sets the single message sender used for sending messages.
* <p/>
* This message sender will be used to resolve an URI to a {@link WebServiceConnection}.
*
* @see #createConnection(URI)
*/
public void setMessageSender(WebServiceMessageSender messageSender) {
Assert.notNull(messageSender, "'messageSender' must not be null");
messageSenders = new WebServiceMessageSender[]{messageSender};
}
/**
* Sets the message senders used for sending messages.
* <p/>
* These message senders will be used to resolve an URI to a {@link WebServiceConnection}.
*
* @see #createConnection(URI)
*/
public void setMessageSenders(WebServiceMessageSender[] messageSenders) {
Assert.notEmpty(messageSenders, "'messageSenders' must not be empty");
this.messageSenders = messageSenders;
}
public void afterPropertiesSet() {
Assert.notNull(getMessageFactory(), "Property 'messageFactory' is required");
Assert.notEmpty(getMessageSenders(), "Property 'messageSenders' is required");
}
/**
* Creates a connection to the given URI, or throws an exception when it cannot be resolved.
* <p/>
* Default implementation iterates over all configured {@link WebServiceMessageSender} objects, and calls {@link
* WebServiceMessageSender#supports(URI)} for each of them. If the sender supports the parameter URI, it creates a
* connection using {@link WebServiceMessageSender#createConnection(URI)} .
*
* @param uri the URI to open a connection to
* @return the created connection
* @throws IllegalArgumentException when the uri cannot be resolved
* @throws IOException when an I/O error occurs
*/
protected WebServiceConnection createConnection(URI uri) throws IOException {
Assert.notEmpty(getMessageSenders(), "Property 'messageSenders' is required");
WebServiceMessageSender[] messageSenders = getMessageSenders();
for (WebServiceMessageSender messageSender : messageSenders) {
if (messageSender.supports(uri)) {
WebServiceConnection connection = messageSender.createConnection(uri);
if (logger.isDebugEnabled()) {
try {
logger.debug("Opening [" + connection + "] to [" + connection.getUri() + "]");
}
catch (URISyntaxException e) {
// ignore
}
}
return connection;
}
}
throw new IllegalArgumentException("Could not resolve [" + uri + "] to a WebServiceMessageSender");
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2008 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.client.support.destination;
import java.net.URI;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract base class for {@link DestinationProvider} implementations that cache destination URI.
* <p/>
* Caching can be disabled by setting the {@link #setCache(boolean) cache} property to <code>false</code>; forcing a
* destination lookup for every call.
*
* @author Arjen Poutsma
* @since 1.5.4
*/
public abstract class AbstractCachingDestinationProvider implements DestinationProvider {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private URI cachedUri;
private boolean cache = true;
/**
* Set whether to cache resolved destinations. Default is <code>true</code>. This flag can be turned off to
* re-lookup a destination for each operation, which allows for hot restarting of destinations. This is mainly
* useful during development.
*/
public void setCache(boolean cache) {
this.cache = cache;
}
public final URI getDestination() {
if (cache) {
if (cachedUri == null) {
cachedUri = lookupDestination();
}
return cachedUri;
}
else {
return lookupDestination();
}
}
/**
* Abstract template method that looks up the URI.
* <p/>
* If {@linkplain #setCache(boolean) caching} is enabled, this method will only be called once.
*
* @return the destination URI
*/
protected abstract URI lookupDestination();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2008 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.client.support.destination;
import java.net.URI;
/**
* Strategy interface for providing a {@link org.springframework.ws.client.core.WebServiceTemplate} destination URI at
* runtime.
* <p/>
* Typically implemented by providers that use WSDL, a UDDI registry, or some other form to determine the destination
* URI.
*
* @author Arjen Poutsma
* @see org.springframework.ws.client.core.WebServiceTemplate#setDestinationProvider(DestinationProvider)
* @since 1.5.4
*/
public interface DestinationProvider {
/**
* Return the destination URI.
*
* @return the destination URI
*/
URI getDestination();
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2008 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.client.support.destination;
import org.springframework.ws.client.WebServiceClientException;
/**
* Thrown by a {@link DestinationProvider} when it cannot provide a destination.
*
* @author Arjen Poutsma
* @since 1.5.4
*/
public class DestinationProvisionException extends WebServiceClientException {
public DestinationProvisionException(String msg) {
super(msg);
}
public DestinationProvisionException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2005-2010 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.client.support.destination;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import org.w3c.dom.Document;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.client.WebServiceTransformerException;
import org.springframework.xml.transform.ResourceSource;
import org.springframework.xml.xpath.XPathExpression;
import org.springframework.xml.xpath.XPathExpressionFactory;
/**
* Implementation of the {@link DestinationProvider} that resolves a destination URI from a WSDL file.
* <p/>
* The extraction relies on an XPath expression to locate the URI. By default, the {@link
* #DEFAULT_WSDL_LOCATION_EXPRESSION} will be used, but this expression can be overridden by setting the {@link
* #setLocationExpression(String) locationExpression} property.
*
* @author Tareq Abed Rabbo
* @author Arjen Poutsma
* @since 1.5.4
*/
public class Wsdl11DestinationProvider extends AbstractCachingDestinationProvider {
/** Default XPath expression used for extracting all <code>location</code> attributes from the WSDL definition. */
public static final String DEFAULT_WSDL_LOCATION_EXPRESSION =
"/wsdl:definitions/wsdl:service/wsdl:port/soap:address/@location";
private static TransformerFactory transformerFactory = TransformerFactory.newInstance();
private Map<String, String> expressionNamespaces = new HashMap<String, String>();
private XPathExpression locationXPathExpression;
private Resource wsdlResource;
public Wsdl11DestinationProvider() {
expressionNamespaces.put("wsdl", "http://schemas.xmlsoap.org/wsdl/");
expressionNamespaces.put("soap", "http://schemas.xmlsoap.org/wsdl/soap/");
expressionNamespaces.put("soap12", "http://schemas.xmlsoap.org/wsdl/soap12/");
locationXPathExpression = XPathExpressionFactory
.createXPathExpression(DEFAULT_WSDL_LOCATION_EXPRESSION, expressionNamespaces);
}
/** Sets a WSDL location from which the service destination <code>URI</code> will be resolved. */
public void setWsdl(Resource wsdlResource) {
Assert.notNull(wsdlResource, "'wsdl' must not be null");
Assert.isTrue(wsdlResource.exists(), wsdlResource + " does not exist");
this.wsdlResource = wsdlResource;
}
/**
* Sets the XPath expression to use when extracting the service location <code>URI</code> from a WSDL.
* <p/>
* The expression can use the following bound prefixes: <blockquote> <table> <tr><th>Prefix</th><th>Namespace</th></tr>
* <tr><td><code>wsdl</code></td><td><code>http://schemas.xmlsoap.org/wsdl/</code></td></tr>
* <tr><td><code>soap</code></td><td><code>http://schemas.xmlsoap.org/wsdl/soap/</code></td></tr>
* <tr><td><code>soap12</code></td><td><code>http://schemas.xmlsoap.org/wsdl/soap12/</code></td></tr>
* </table></blockquote>
* <p/>
* Defaults to {@link #DEFAULT_WSDL_LOCATION_EXPRESSION}.
*/
public void setLocationExpression(String expression) {
Assert.hasText(expression, "'expression' must not be empty");
locationXPathExpression = XPathExpressionFactory
.createXPathExpression(expression, expressionNamespaces);
}
@Override
protected URI lookupDestination() {
try {
DOMResult result = new DOMResult();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new ResourceSource(wsdlResource), result);
Document definitionDocument = (Document) result.getNode();
String location = locationXPathExpression.evaluateAsString(definitionDocument);
if (logger.isDebugEnabled()) {
logger.debug("Found location [" + location + "] in " + wsdlResource);
}
return location != null ? URI.create(location) : null;
}
catch (IOException ex) {
throw new WebServiceIOException("Error extracting location from WSDL [" + wsdlResource + "]", ex);
}
catch (TransformerException ex) {
throw new WebServiceTransformerException("Error extracting location from WSDL [" + wsdlResource + "]", ex);
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Provides the <code>DestinationProvider</code> interface.
</body>
</html>

View File

@@ -0,0 +1,275 @@
/*
* Copyright 2005-2010 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.client.support.interceptor;
import java.io.IOException;
import javax.xml.transform.Source;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.WebServiceIOException;
import org.springframework.ws.context.MessageContext;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.xml.validation.XmlValidator;
import org.springframework.xml.validation.XmlValidatorFactory;
import org.springframework.xml.xsd.XsdSchema;
import org.springframework.xml.xsd.XsdSchemaCollection;
import org.xml.sax.SAXParseException;
/**
* Abstract base class for {@link ClientInterceptor} implementations that validate part of the message using a schema.
* The exact message part is determined by the {@link #getValidationRequestSource(WebServiceMessage)} and {@link
* #getValidationResponseSource(WebServiceMessage)} template methods.
* <p/>
* By default, only the request message is validated, but this behaviour can be changed using the
* <code>validateRequest</code> and <code>validateResponse</code> properties.
*
* @author Arjen Poutsma
* @see #getValidationRequestSource(WebServiceMessage)
* @see #getValidationResponseSource(WebServiceMessage)
* @since 1.5.4
*/
public abstract class AbstractValidatingInterceptor extends TransformerObjectSupport
implements ClientInterceptor, InitializingBean {
private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML;
private Resource[] schemas;
private boolean validateRequest = true;
private boolean validateResponse = false;
private XmlValidator validator;
public String getSchemaLanguage() {
return schemaLanguage;
}
/**
* Sets the schema language. Default is the W3C XML Schema: <code>http://www.w3.org/2001/XMLSchema"</code>.
*
* @see XmlValidatorFactory#SCHEMA_W3C_XML
* @see XmlValidatorFactory#SCHEMA_RELAX_NG
*/
public void setSchemaLanguage(String schemaLanguage) {
this.schemaLanguage = schemaLanguage;
}
/** Returns the schema resources to use for validation. */
public Resource[] getSchemas() {
return schemas;
}
/**
* Sets the schema resource to use for validation. Setting this property, {@link
* #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link
* #setSchemas(Resource[]) schemas} is required.
*/
public void setSchema(Resource schema) {
setSchemas(new Resource[]{schema});
}
/**
* Sets the schema resources to use for validation. Setting this property, {@link
* #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link
* #setSchemas(Resource[]) schemas} is required.
*/
public void setSchemas(Resource[] schemas) {
Assert.notEmpty(schemas, "schemas must not be empty or null");
for (Resource schema : schemas) {
Assert.notNull(schema, "schema must not be null");
Assert.isTrue(schema.exists(), "schema \"" + schema + "\" does not exit");
}
this.schemas = schemas;
}
/**
* Sets the {@link XsdSchema} to use for validation. Setting this property, {@link
* #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link
* #setSchemas(Resource[]) schemas} is required.
*
* @param schema the xsd schema to use
* @throws java.io.IOException in case of I/O errors
*/
public void setXsdSchema(XsdSchema schema) throws IOException {
this.validator = schema.createValidator();
}
/**
* Sets the {@link XsdSchemaCollection} to use for validation. Setting this property, {@link
* #setXsdSchema(XsdSchema) xsdSchema}, {@link #setSchema(Resource) schema}, or {@link #setSchemas(Resource[])
* schemas} is required.
*
* @param schemaCollection the xsd schema collection to use
* @throws java.io.IOException in case of I/O errors
*/
public void setXsdSchemaCollection(XsdSchemaCollection schemaCollection) throws IOException {
this.validator = schemaCollection.createValidator();
}
/** Indicates whether the request should be validated against the schema. Default is <code>true</code>. */
public void setValidateRequest(boolean validateRequest) {
this.validateRequest = validateRequest;
}
/** Indicates whether the response should be validated against the schema. Default is <code>false</code>. */
public void setValidateResponse(boolean validateResponse) {
this.validateResponse = validateResponse;
}
public void afterPropertiesSet() throws Exception {
if (validator == null && !ObjectUtils.isEmpty(schemas)) {
Assert.hasLength(schemaLanguage, "schemaLanguage is required");
for (Resource schema : schemas) {
Assert.isTrue(schema.exists(), "schema [" + schema + "] does not exist");
}
if (logger.isInfoEnabled()) {
logger.info("Validating using " + StringUtils.arrayToCommaDelimitedString(schemas));
}
validator = XmlValidatorFactory.createValidator(schemas, schemaLanguage);
}
Assert.notNull(validator, "Setting 'schema', 'schemas', 'xsdSchema', or 'xsdSchemaCollection' is required");
}
/**
* Validates the request message in the given message context. Validation only occurs if {@link
* #setValidateRequest(boolean) validateRequest} is set to <code>true</code>, which is the default.
* <p/>
* Returns <code>true</code> if the request is valid, or <code>false</code> if it isn't.
*
* @param messageContext the message context
* @return <code>true</code> if the message is valid; <code>false</code> otherwise
* @see #setValidateRequest(boolean)
*/
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
if (validateRequest) {
Source requestSource = getValidationRequestSource(messageContext.getRequest());
if (requestSource != null) {
SAXParseException[] errors;
try {
errors = validator.validate(requestSource);
}
catch (IOException e) {
throw new WebServiceIOException("Could not validate response: " + e.getMessage(), e);
}
if (!ObjectUtils.isEmpty(errors)) {
return handleRequestValidationErrors(messageContext, errors);
}
else if (logger.isDebugEnabled()) {
logger.debug("Request message validated");
}
}
}
return true;
}
/**
* Template method that is called when the request message contains validation errors.
* <p/>
* Default implementation logs all errors, and throws a {@link WebServiceValidationException}. Subclasses can
* override this method to customize this behavior.
*
* @param messageContext the message context
* @param errors the validation errors
* @return <code>true</code> to continue processing the request, <code>false</code> otherwise
*/
protected boolean handleRequestValidationErrors(MessageContext messageContext, SAXParseException[] errors) {
for (SAXParseException error : errors) {
logger.error("XML validation error on request: " + error.getMessage());
}
throw new WebServiceValidationException(errors);
}
/**
* Validates the response message in the given message context. Validation only occurs if {@link
* #setValidateResponse(boolean) validateResponse} is set to <code>true</code>, which is <strong>not</strong> the
* default.
* <p/>
* Returns <code>true</code> if the request is valid, or <code>false</code> if it isn't.
*
* @param messageContext the message context.
* @return <code>true</code> if the response is valid; <code>false</code> otherwise
* @see #setValidateResponse(boolean)
*/
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
if (validateResponse) {
Source responseSource = getValidationResponseSource(messageContext.getResponse());
if (responseSource != null) {
SAXParseException[] errors;
try {
errors = validator.validate(responseSource);
}
catch (IOException e) {
throw new WebServiceIOException("Could not validate response: " + e.getMessage(), e);
}
if (!ObjectUtils.isEmpty(errors)) {
return handleResponseValidationErrors(messageContext, errors);
}
else if (logger.isDebugEnabled()) {
logger.debug("Response message validated");
}
}
}
return true;
}
/**
* Template method that is called when the response message contains validation errors.
* <p/>
* Default implementation logs all errors, and returns <code>false</code>, i.e. do not cot continue to process the
* respone interceptor chain.
*
* @param messageContext the message context
* @param errors the validation errors
* @return <code>true</code> to continue the reponse interceptor chain, <code>false</code> (the default) otherwise
*/
protected boolean handleResponseValidationErrors(MessageContext messageContext, SAXParseException[] errors)
throws WebServiceValidationException {
for (SAXParseException error : errors) {
logger.warn("XML validation error on response: " + error.getMessage());
}
return false;
}
/** Does nothing by default. Faults are not validated. */
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
return true;
}
/**
* Abstract template method that returns the part of the request message that is to be validated.
*
* @param request the request message
* @return the part of the message that is to validated, or <code>null</code> not to validate anything
*/
protected abstract Source getValidationRequestSource(WebServiceMessage request);
/**
* Abstract template method that returns the part of the response message that is to be validated.
*
* @param response the response message
* @return the part of the message that is to validated, or <code>null</code> not to validate anything
*/
protected abstract Source getValidationResponseSource(WebServiceMessage response);
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2008 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.client.support.interceptor;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.transport.WebServiceConnection;
/**
* Workflow interface that allows for customized client-side message interception. Applications can register any number
* of existing or custom interceptors on a {@link org.springframework.ws.client.core.WebServiceTemplate}, to add common
* pre- and postprocessing behavior without needing to modify payload handling code.
* <p/>
* A <code>ClientInterceptor</code> gets called after payload creation (using {@link
* org.springframework.ws.client.core.WebServiceTemplate#marshalSendAndReceive(Object)} or similar methods, and after
* {@link org.springframework.ws.client.core.WebServiceMessageCallback callback} invocation, but before the message is
* sent over the {@link WebServiceConnection}. This mechanism can be used for a large field of preprocessing aspects,
* e.g. for authorization checks, or message header checks. Its main purpose is to allow for factoring out meta-data
* (i.e. {@link SoapHeader}) related code.
* <p/>
* Client interceptors are defined on a {@link org.springframework.ws.client.core.WebServiceTemplate}, using the {@link
* org.springframework.ws.client.core.WebServiceTemplate#setInterceptors(ClientInterceptor[]) interceptors} property.
*
* @author Giovanni Cuccu
* @author Arjen Poutsma
* @see org.springframework.ws.client.core.WebServiceTemplate#setInterceptors(ClientInterceptor[])
* @since 1.5.0
*/
public interface ClientInterceptor {
/**
* Processes the outgoing request message. Called after payload creation and callback invocation, but before the
* message is sent.
*
* @param messageContext contains the outgoing request message
* @return <code>true</code> to continue processing of the request interceptors; <code>false</code> to indicate
* blocking of the request endpoint chain
* @throws WebServiceClientException in case of errors
* @see MessageContext#getRequest()
*/
boolean handleRequest(MessageContext messageContext) throws WebServiceClientException;
/**
* Processes the incoming response message. Called for non-fault response messages before payload handling in the
* {@link org.springframework.ws.client.core.WebServiceTemplate}.
*
* @param messageContext contains the outgoing request message
* @return <code>true</code> to continue processing of the request interceptors; <code>false</code> to indicate
* blocking of the response endpoint chain
* @throws WebServiceClientException in case of errors
* @see MessageContext#getResponse()
*/
boolean handleResponse(MessageContext messageContext) throws WebServiceClientException;
/**
* Processes the incoming response fault. Called for response fault messages before payload handling in the {@link
* org.springframework.ws.client.core.WebServiceTemplate}.
*
* @param messageContext contains the outgoing request message
* @return <code>true</code> to continue processing of the request interceptors; <code>false</code> to indicate
* blocking of the request endpoint chain
* @throws WebServiceClientException in case of errors
* @see MessageContext#getResponse()
* @see org.springframework.ws.FaultAwareWebServiceMessage#hasFault()
*/
boolean handleFault(MessageContext messageContext) throws WebServiceClientException;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2005-2010 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.client.support.interceptor;
import javax.xml.transform.Source;
import org.springframework.ws.WebServiceMessage;
/**
* Client-side interceptor that validates the contents of <code>WebServiceMessage</code>s using a schema. Allows for
* both W3C XML and RELAX NG schemas.
* <p/>
* When the payload is invalid, this interceptor stops processing of the interceptor chain.
* <p/>
* The schema to validate against is set with the <code>schema</code> property or <code>schemas</code> property. By
* default, only the request message is validated, but this behaviour can be changed using the
* <code>validateRequest</code> and <code>validateResponse</code> properties. Responses that contains faults are not
* validated.
*
* @author Stefan Schmidt
* @author Arjen Poutsma
* @see #setSchema(org.springframework.core.io.Resource)
* @see #setSchemas(org.springframework.core.io.Resource[])
* @see #setValidateRequest(boolean)
* @see #setValidateResponse(boolean)
* @since 1.5.4
*/
public class PayloadValidatingInterceptor extends AbstractValidatingInterceptor {
/**
* Returns the part of the request message that is to be validated. Default
*
* @param request the request message
* @return the part of the message that is to validated, or <code>null</code> not to validate anything
*/
@Override
protected Source getValidationRequestSource(WebServiceMessage request) {
return request.getPayloadSource();
}
/**
* Returns the part of the response message that is to be validated.
*
* @param response the response message
* @return the part of the message that is to validated, or <code>null</code> not to validate anything
*/
@Override
protected Source getValidationResponseSource(WebServiceMessage response) {
return response.getPayloadSource();
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2005-2010 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.client.support.interceptor;
import org.springframework.ws.client.WebServiceClientException;
import org.xml.sax.SAXParseException;
/**
* Exception thrown whenever a validation error occurs on the client-side.
*
* @author Stefan Schmidt
* @author Arjen Poutsma
* @since 1.5.4
*/
public class WebServiceValidationException extends WebServiceClientException {
private SAXParseException[] validationErrors;
/**
* Create a new instance of the <code>WebServiceValidationException</code> class.
*/
public WebServiceValidationException(SAXParseException[] validationErrors) {
super(createMessage(validationErrors));
this.validationErrors = validationErrors;
}
private static String createMessage(SAXParseException[] validationErrors) {
StringBuilder builder = new StringBuilder("XML validation error on response: ");
for (SAXParseException validationError : validationErrors) {
builder.append(validationError.getMessage());
}
return builder.toString();
}
/** Returns the validation errors. */
public SAXParseException[] getValidationErrors() {
return validationErrors;
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Provides the <code>ClientInterceptor</code> interface, and validating interceptors.
</body>
</html>

View File

@@ -0,0 +1,6 @@
<html>
<body>
Classes supporting the org.springframework.ws.client.core package.
Contains a base class for WebServiceTemplate usage.
</body>
</html>

View File

@@ -0,0 +1,213 @@
/*
* Copyright 2005-2012 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.config;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Ordered;
import org.springframework.util.ClassUtils;
import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter;
import org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.addressing.server.AnnotationActionEndpointMapping;
import org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver;
import org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver;
import org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver;
import org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver;
import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping;
import org.w3c.dom.Element;
/**
* {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring WS application.
*
* @author Arjen Poutsma
* @since 2.0
*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
private static final boolean dom4jPresent =
ClassUtils.isPresent("org.dom4j.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean jdomPresent =
ClassUtils.isPresent("org.jdom2.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean staxPresent = ClassUtils
.isPresent("javax.xml.stream.XMLInputFactory", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
private static final boolean xomPresent =
ClassUtils.isPresent("nu.xom.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
registerEndpointMappings(source, parserContext);
registerEndpointAdapters(element, source, parserContext);
registerEndpointExceptionResolvers(source, parserContext);
parserContext.popAndRegisterContainingComponent();
return null;
}
private void registerEndpointMappings(Object source, ParserContext parserContext) {
RootBeanDefinition payloadRootMappingDef =
createBeanDefinition(PayloadRootAnnotationMethodEndpointMapping.class, source);
payloadRootMappingDef.getPropertyValues().add("order", 0);
parserContext.getReaderContext().registerWithGeneratedName(payloadRootMappingDef);
RootBeanDefinition soapActionMappingDef =
createBeanDefinition(SoapActionAnnotationMethodEndpointMapping.class, source);
soapActionMappingDef.getPropertyValues().add("order", 1);
parserContext.getReaderContext().registerWithGeneratedName(soapActionMappingDef);
RootBeanDefinition annActionMappingDef =
createBeanDefinition(AnnotationActionEndpointMapping.class, source);
annActionMappingDef.getPropertyValues().add("order", 2);
parserContext.getReaderContext().registerWithGeneratedName(annActionMappingDef);
}
private void registerEndpointAdapters(Element element, Object source, ParserContext parserContext) {
RootBeanDefinition adapterDef = createBeanDefinition(DefaultMethodEndpointAdapter.class, source);
ManagedList<BeanMetadataElement> argumentResolvers = new ManagedList<BeanMetadataElement>();
argumentResolvers.setSource(source);
ManagedList<BeanMetadataElement> returnValueHandlers = new ManagedList<BeanMetadataElement>();
returnValueHandlers.setSource(source);
argumentResolvers.add(createBeanDefinition(MessageContextMethodArgumentResolver.class, source));
argumentResolvers.add(createBeanDefinition(XPathParamMethodArgumentResolver.class, source));
argumentResolvers.add(createBeanDefinition(SoapMethodArgumentResolver.class, source));
argumentResolvers.add(createBeanDefinition(SoapHeaderElementMethodArgumentResolver.class, source));
RuntimeBeanReference domProcessor = createBeanReference(DomPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(domProcessor);
returnValueHandlers.add(domProcessor);
RuntimeBeanReference sourceProcessor =
createBeanReference(SourcePayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(sourceProcessor);
returnValueHandlers.add(sourceProcessor);
if (dom4jPresent) {
RuntimeBeanReference dom4jProcessor =
createBeanReference(Dom4jPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(dom4jProcessor);
returnValueHandlers.add(dom4jProcessor);
}
if (jaxb2Present) {
RuntimeBeanReference xmlRootElementProcessor =
createBeanReference(XmlRootElementPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(xmlRootElementProcessor);
returnValueHandlers.add(xmlRootElementProcessor);
RuntimeBeanReference jaxbElementProcessor =
createBeanReference(JaxbElementPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(jaxbElementProcessor);
returnValueHandlers.add(jaxbElementProcessor);
}
if (jdomPresent) {
RuntimeBeanReference jdomProcessor =
createBeanReference(JDomPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(jdomProcessor);
returnValueHandlers.add(jdomProcessor);
}
if (staxPresent) {
argumentResolvers.add(createBeanDefinition(StaxPayloadMethodArgumentResolver.class, source));
}
if (xomPresent) {
RuntimeBeanReference xomProcessor =
createBeanReference(XomPayloadMethodProcessor.class, source, parserContext);
argumentResolvers.add(xomProcessor);
returnValueHandlers.add(xomProcessor);
}
if (element.hasAttribute("marshaller")) {
RuntimeBeanReference marshallerReference = new RuntimeBeanReference(element.getAttribute("marshaller"));
RuntimeBeanReference unmarshallerReference;
if (element.hasAttribute("unmarshaller")) {
unmarshallerReference = new RuntimeBeanReference(element.getAttribute("unmarshaller"));
}
else {
unmarshallerReference = marshallerReference;
}
RootBeanDefinition marshallingProcessorDef =
createBeanDefinition(MarshallingPayloadMethodProcessor.class, source);
marshallingProcessorDef.getPropertyValues().add("marshaller", marshallerReference);
marshallingProcessorDef.getPropertyValues().add("unmarshaller", unmarshallerReference);
argumentResolvers.add(marshallingProcessorDef);
returnValueHandlers.add(marshallingProcessorDef);
}
adapterDef.getPropertyValues().add("methodArgumentResolvers", argumentResolvers);
adapterDef.getPropertyValues().add("methodReturnValueHandlers", returnValueHandlers);
parserContext.getReaderContext().registerWithGeneratedName(adapterDef);
}
private void registerEndpointExceptionResolvers(Object source, ParserContext parserContext) {
RootBeanDefinition annotationResolverDef =
createBeanDefinition(SoapFaultAnnotationExceptionResolver.class, source);
annotationResolverDef.getPropertyValues().add("order", 0);
parserContext.getReaderContext().registerWithGeneratedName(annotationResolverDef);
RootBeanDefinition simpleResolverDef =
createBeanDefinition(SimpleSoapExceptionResolver.class, source);
simpleResolverDef.getPropertyValues().add("order", Ordered.LOWEST_PRECEDENCE);
parserContext.getReaderContext().registerWithGeneratedName(simpleResolverDef);
}
private RuntimeBeanReference createBeanReference(Class<?> beanClass, Object source, ParserContext parserContext) {
RootBeanDefinition beanDefinition = createBeanDefinition(beanClass, source);
String beanName = parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, beanName));
return new RuntimeBeanReference(beanName);
}
private RootBeanDefinition createBeanDefinition(Class<?> beanClass, Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
return beanDefinition;
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2005-2010 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.config;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection;
import org.w3c.dom.Element;
/**
* Parser for the {@code &lt;sws:dynamic-wsdl/&gt;} element.
*
* @author Arjen Poutsma
* @since 2.0
*/
class DynamicWsdlBeanDefinitionParser extends AbstractBeanDefinitionParser {
private static final boolean commonsSchemaPresent = ClassUtils.isPresent("org.apache.ws.commons.schema.XmlSchema",
DynamicWsdlBeanDefinitionParser.class.getClassLoader());
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
BeanDefinitionBuilder wsdlBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultWsdl11Definition.class);
wsdlBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
wsdlBuilder.getRawBeanDefinition().setSource(source);
addProperty(element, wsdlBuilder, "portTypeName");
addProperty(element, wsdlBuilder, "targetNamespace");
addProperty(element, wsdlBuilder, "requestSuffix");
addProperty(element, wsdlBuilder, "responseSuffix");
addProperty(element, wsdlBuilder, "faultSuffix");
addProperty(element, wsdlBuilder, "createSoap11Binding");
addProperty(element, wsdlBuilder, "createSoap12Binding");
addProperty(element, wsdlBuilder, "transportUri");
addProperty(element, wsdlBuilder, "locationUri");
addProperty(element, wsdlBuilder, "serviceName");
List<Element> schemas = DomUtils.getChildElementsByTagName(element, "xsd");
if (commonsSchemaPresent) {
RootBeanDefinition collectionDef = createBeanDefinition(CommonsXsdSchemaCollection.class, source);
collectionDef.getPropertyValues().addPropertyValue("inline", "true");
ManagedList<String> xsds = new ManagedList<String>();
xsds.setSource(source);
for (Element schema : schemas) {
xsds.add(schema.getAttribute("location"));
}
collectionDef.getPropertyValues().addPropertyValue("xsds", xsds);
String collectionName = parserContext.getReaderContext().registerWithGeneratedName(collectionDef);
wsdlBuilder.addPropertyReference("schemaCollection", collectionName);
}
else {
if (schemas.size() > 1) {
throw new IllegalArgumentException(
"Multiple <xsd/> elements requires Commons XMLSchema." +
"Please put Commons XMLSchema on the classpath.");
}
RootBeanDefinition schemaDef = createBeanDefinition(SimpleXsdSchema.class, source);
Element schema = schemas.iterator().next();
schemaDef.getPropertyValues().addPropertyValue("xsd", schema.getAttribute("location"));
String schemaName = parserContext.getReaderContext().registerWithGeneratedName(schemaDef);
wsdlBuilder.addPropertyReference("schema", schemaName);
}
return wsdlBuilder.getBeanDefinition();
}
private void addProperty(Element element, BeanDefinitionBuilder builder, String propertyName) {
String propertyValue = element.getAttribute(propertyName);
if (StringUtils.hasText(propertyValue)) {
builder.addPropertyValue(propertyName, propertyValue);
}
}
private RootBeanDefinition createBeanDefinition(Class<?> beanClass, Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
return beanDefinition;
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright 2005-2011 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.config;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.ws.server.SmartEndpointInterceptor;
import org.springframework.ws.soap.server.endpoint.interceptor.DelegatingSmartSoapEndpointInterceptor;
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadRootSmartSoapEndpointInterceptor;
import org.springframework.ws.soap.server.endpoint.interceptor.SoapActionSmartEndpointInterceptor;
import org.w3c.dom.Element;
/**
* Parser for the {@code &lt;sws:interceptors/&gt;} element.
*
* @author Arjen Poutsma
* @since 2.0
*/
class InterceptorsBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compDefinition =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compDefinition);
List<Element> childElements = DomUtils.getChildElements(element);
for (Element childElement : childElements) {
if ("bean".equals(childElement.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(DelegatingSmartSoapEndpointInterceptor.class, childElement,
parserContext);
BeanDefinitionHolder interceptorDef = createInterceptorDefinition(parserContext, childElement);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorDef);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
else if ("ref".equals(childElement.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(DelegatingSmartSoapEndpointInterceptor.class, childElement,
parserContext);
BeanReference interceptorRef = createInterceptorReference(parserContext, childElement);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorRef);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
else if ("payloadRoot".equals(childElement.getLocalName())) {
List<Element> payloadRootChildren = DomUtils.getChildElements(childElement);
for (Element payloadRootChild : payloadRootChildren) {
if ("bean".equals(payloadRootChild.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(PayloadRootSmartSoapEndpointInterceptor.class,
childElement, parserContext);
BeanDefinitionHolder interceptorDef =
createInterceptorDefinition(parserContext, payloadRootChild);
String namespaceUri = childElement.getAttribute("namespaceUri");
String localPart = childElement.getAttribute("localPart");
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorDef);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, namespaceUri);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, localPart);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
else if ("ref".equals(payloadRootChild.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(PayloadRootSmartSoapEndpointInterceptor.class,
childElement, parserContext);
BeanReference interceptorRef = createInterceptorReference(parserContext, payloadRootChild);
String namespaceUri = childElement.getAttribute("namespaceUri");
String localPart = childElement.getAttribute("localPart");
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorRef);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, namespaceUri);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(2, localPart);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
}
}
else if ("soapAction".equals(childElement.getLocalName())) {
List<Element> soapActionChildren = DomUtils.getChildElements(childElement);
for (Element soapActionChild : soapActionChildren) {
if ("bean".equals(soapActionChild.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(SoapActionSmartEndpointInterceptor.class, childElement,
parserContext);
BeanDefinitionHolder interceptorDef =
createInterceptorDefinition(parserContext, soapActionChild);
String soapAction = childElement.getAttribute("value");
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorDef);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, soapAction);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
else if ("ref".equals(soapActionChild.getLocalName())) {
RootBeanDefinition smartInterceptorDef =
createSmartInterceptorDefinition(SoapActionSmartEndpointInterceptor.class, childElement,
parserContext);
BeanReference interceptorRef = createInterceptorReference(parserContext, soapActionChild);
String soapAction = childElement.getAttribute("value");
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, interceptorRef);
smartInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, soapAction);
registerSmartInterceptor(parserContext, smartInterceptorDef);
}
}
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
private void registerSmartInterceptor(ParserContext parserContext, RootBeanDefinition smartInterceptorDef) {
String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(smartInterceptorDef);
parserContext.registerComponent(new BeanComponentDefinition(smartInterceptorDef, mappedInterceptorName));
}
private BeanDefinitionHolder createInterceptorDefinition(ParserContext parserContext, Element element) {
BeanDefinitionHolder interceptorDef = parserContext.getDelegate().parseBeanDefinitionElement(element);
interceptorDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(element, interceptorDef);
return interceptorDef;
}
private BeanReference createInterceptorReference(ParserContext parserContext, Element element) {
// A generic reference to any name of any bean.
String refName = element.getAttribute("bean");
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = element.getAttribute("local");
if (!StringUtils.hasLength(refName)) {
error(parserContext, "Either 'bean' or 'local' is required for <ref> element", element);
return null;
}
}
if (!StringUtils.hasText(refName)) {
error(parserContext, "<ref> element contains empty target attribute", element);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(parserContext.extractSource(element));
return ref;
}
private RootBeanDefinition createSmartInterceptorDefinition(Class<? extends SmartEndpointInterceptor> interceptorClass,
Element element,
ParserContext parserContext) {
RootBeanDefinition smartInterceptorDef = new RootBeanDefinition(interceptorClass);
smartInterceptorDef.setSource(parserContext.extractSource(element));
smartInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
return smartInterceptorDef;
}
private void error(ParserContext parserContext, String message, Object source) {
parserContext.getDelegate().getReaderContext().error(message, source);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2005-2010 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.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for the <code>&lt;sws:marshalling-endpoints/&gt; element.
*
* @author Arjen Poutsma
* @since 1.5.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link AnnotationDrivenBeanDefinitionParser}
*/
@Deprecated
class MarshallingEndpointsBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
private static final String GENERIC_MARSHALLING_METHOD_ENDPOINT_ADAPTER_CLASS_NAME =
"org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter";
private static final boolean genericAdapterPresent =
ClassUtils.isPresent(GENERIC_MARSHALLING_METHOD_ENDPOINT_ADAPTER_CLASS_NAME,
MarshallingEndpointsBeanDefinitionParser.class.getClassLoader());
private static final String MARSHALLING_METHOD_ENDPOINT_ADAPTER_CLASS_NAME =
"org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter";
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected String getBeanClassName(Element element) {
if (genericAdapterPresent) {
return GENERIC_MARSHALLING_METHOD_ENDPOINT_ADAPTER_CLASS_NAME;
}
return MARSHALLING_METHOD_ENDPOINT_ADAPTER_CLASS_NAME;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) {
String marshallerName = element.getAttribute("marshaller");
if (StringUtils.hasText(marshallerName)) {
beanDefinitionBuilder.addPropertyReference("marshaller", marshallerName);
}
String unmarshallerName = element.getAttribute("unmarshaller");
if (StringUtils.hasText(unmarshallerName)) {
beanDefinitionBuilder.addPropertyReference("unmarshaller", unmarshallerName);
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2005-2010 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.config;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Parser for the {@code &lt;sws:static-wsdl/&gt;} element.
*
* @author Arjen Poutsma
* @since 2.0
*/
class StaticWsdlBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
private static final String CLASS_NAME = "org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition";
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected String getBeanClassName(Element element) {
return CLASS_NAME;
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
String id = element.getAttribute(ID_ATTRIBUTE);
if (StringUtils.hasLength(id)) {
return id;
}
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
String filename = StringUtils.stripFilenameExtension(StringUtils.getFilename(location));
if (StringUtils.hasLength(filename)) {
return filename;
}
}
return parserContext.getReaderContext().generateBeanName(definition);
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) {
String location = element.getAttribute("location");
beanDefinitionBuilder.addPropertyValue("wsdl", location);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2005-2010 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.config;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* {@link NamespaceHandler} for the '<code>web-services</code>' namespace.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public class WebServicesNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("static-wsdl", new StaticWsdlBeanDefinitionParser());
registerBeanDefinitionParser("dynamic-wsdl", new DynamicWsdlBeanDefinitionParser());
registerBeanDefinitionParser("marshalling-endpoints", new MarshallingEndpointsBeanDefinitionParser());
registerBeanDefinitionParser("xpath-endpoints", new XPathEndpointsBeanDefinitionParser());
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2005-2010 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.config;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser for the <code>&lt;sws:xpath-endpoints/&gt; element.
*
* @author Arjen Poutsma
* @since 1.5.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link AnnotationDrivenBeanDefinitionParser}
*/
@Deprecated
class XPathEndpointsBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
private static final String XPATH_PARAM_ANNOTATION_METHOD_ENDPOINT_ADAPTER_CLASS_NAME =
"org.springframework.ws.server.endpoint.adapter.XPathParamAnnotationMethodEndpointAdapter";
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected String getBeanClassName(Element element) {
return XPATH_PARAM_ANNOTATION_METHOD_ENDPOINT_ADAPTER_CLASS_NAME;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) {
List<Element> namespaceElements = DomUtils.getChildElementsByTagName(element, "namespace");
if (!namespaceElements.isEmpty()) {
Properties namespaces = new Properties();
for (Element namespaceElement : namespaceElements) {
String prefix = namespaceElement.getAttribute("prefix");
String uri = namespaceElement.getAttribute("uri");
namespaces.setProperty(prefix, uri);
}
beanDefinitionBuilder.addPropertyValue("namespaces", namespaces);
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Provides an namespace handler for the Spring Web Services namespace.
</body>
</html>

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2005-2010 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.context;
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.StringUtils;
/**
* Abstract base class for {@link MessageContext} instances.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractMessageContext implements MessageContext {
/**
* Keys are <code>Strings</code>, values are <code>Objects</code>. Lazily initialized by
* <code>getProperties()</code>.
*/
private Map<String, Object> properties;
public boolean containsProperty(String name) {
return getProperties().containsKey(name);
}
public Object getProperty(String name) {
return getProperties().get(name);
}
public String[] getPropertyNames() {
return StringUtils.toStringArray(getProperties().keySet());
}
public void removeProperty(String name) {
getProperties().remove(name);
}
public void setProperty(String name, Object value) {
getProperties().put(name, value);
}
private Map<String, Object> getProperties() {
if (properties == null) {
properties = new HashMap<String, Object>();
}
return properties;
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2006 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.context;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
/**
* Default implementation of <code>MessageContext</code>.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class DefaultMessageContext extends AbstractMessageContext {
private final WebServiceMessageFactory messageFactory;
private final WebServiceMessage request;
private WebServiceMessage response;
/** Construct a new, empty instance of the <code>DefaultMessageContext</code> with the given message factory. */
public DefaultMessageContext(WebServiceMessageFactory messageFactory) {
this(messageFactory.createWebServiceMessage(), messageFactory);
}
/**
* Construct a new instance of the <code>DefaultMessageContext</code> with the given request message and message
* factory.
*/
public DefaultMessageContext(WebServiceMessage request, WebServiceMessageFactory messageFactory) {
Assert.notNull(request, "request must not be null");
Assert.notNull(messageFactory, "messageFactory must not be null");
this.request = request;
this.messageFactory = messageFactory;
}
public WebServiceMessage getRequest() {
return request;
}
public boolean hasResponse() {
return response != null;
}
public WebServiceMessage getResponse() {
if (response == null) {
response = messageFactory.createWebServiceMessage();
}
return response;
}
public void setResponse(WebServiceMessage response) {
checkForResponse();
this.response = response;
}
public void clearResponse() {
response = null;
}
public void readResponse(InputStream inputStream) throws IOException {
checkForResponse();
response = messageFactory.createWebServiceMessage(inputStream);
}
public WebServiceMessageFactory getMessageFactory() {
return messageFactory;
}
private void checkForResponse() throws IllegalStateException {
if (response != null) {
throw new IllegalStateException("Response message already created");
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2005 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.context;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.server.EndpointInterceptor;
/**
* Context holder for message requests.
* <p/>
* Contains both the message request as well as the response. Response message are usually lazily created (but do not
* have to be).
* <p/>
* Also contains properties, which can be used to by {@link EndpointInterceptor interceptors} to pass information on to
* endpoints.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface MessageContext {
/**
* Returns the request message.
*
* @return the request message
*/
WebServiceMessage getRequest();
/**
* Indicates whether this context has a response.
*
* @return <code>true</code> if this context has a response; <code>false</code> otherwise
*/
boolean hasResponse();
/**
* Returns the response message. Creates a new response if no response is present.
*
* @return the response message
* @see #hasResponse()
*/
WebServiceMessage getResponse();
/**
* Sets the response message.
*
* @param response the response message
* @throws IllegalStateException if a response has already been created
* @since 1.5.0
*/
void setResponse(WebServiceMessage response);
/**
* Removes the response message, if any.
*
* @since 1.5.0
*/
void clearResponse();
/**
* Reads a response message from the given input stream.
*
* @param inputStream the stream to read the response from
* @throws IOException in case of I/O errors
* @throws IllegalStateException if a response has already been created
*/
void readResponse(InputStream inputStream) throws IOException;
/**
* Sets the name and value of a property associated with the <code>MessageContext</code>. If the
* <code>MessageContext</code> contains a value of the same property, the old value is replaced.
*
* @param name name of the property associated with the value
* @param value value of the property
*/
void setProperty(String name, Object value);
/**
* Gets the value of a specific property from the <code>MessageContext</code>.
*
* @param name name of the property whose value is to be retrieved
* @return value of the property
*/
Object getProperty(String name);
/**
* Removes a property from the <code>MessageContext</code>.
*
* @param name name of the property to be removed
*/
void removeProperty(String name);
/**
* Check if this message context contains a property with the given name.
*
* @param name the name of the property to look for
* @return <code>true</code> if the <code>MessageContext</code> contains the property; <code>false</code> otherwise
*/
boolean containsProperty(String name);
/**
* Return the names of all properties in this <code>MessageContext</code>.
*
* @return the names of all properties in this context, or an empty array if none defined
*/
String[] getPropertyNames();
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains the <code>MessageContext</code> interface and implementations thereof.
</body>
</html>

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2007 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.mime;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
/**
* Abstract implementation of the {@link MimeMessage} interface. Contains convenient default implementations.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractMimeMessage implements MimeMessage {
public final Attachment addAttachment(String contentId, File file) throws AttachmentException {
Assert.hasLength(contentId, "contentId must not be empty");
Assert.notNull(file, "File must not be null");
DataHandler dataHandler = new DataHandler(new FileDataSource(file));
return addAttachment(contentId, dataHandler);
}
public final Attachment addAttachment(String contentId, InputStreamSource inputStreamSource, String contentType) {
Assert.hasLength(contentId, "contentId must not be empty");
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
throw new IllegalArgumentException("Passed-in Resource contains an open stream: invalid argument. " +
"MIME requires an InputStreamSource that creates a fresh stream for every call.");
}
DataHandler dataHandler = new DataHandler(new InputStreamSourceDataSource(inputStreamSource, contentType));
return addAttachment(contentId, dataHandler);
}
/**
* Activation framework <code>DataSource</code> that wraps a Spring <code>InputStreamSource</code>.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
private static class InputStreamSourceDataSource implements DataSource {
private final InputStreamSource inputStreamSource;
private final String contentType;
public InputStreamSourceDataSource(InputStreamSource inputStreamSource, String contentType) {
this.inputStreamSource = inputStreamSource;
this.contentType = contentType;
}
public InputStream getInputStream() throws IOException {
return inputStreamSource.getInputStream();
}
public OutputStream getOutputStream() {
throw new UnsupportedOperationException("Read-only javax.activation.DataSource");
}
public String getContentType() {
return contentType;
}
public String getName() {
if (inputStreamSource instanceof Resource) {
Resource resource = (Resource) inputStreamSource;
return resource.getFilename();
}
else {
throw new UnsupportedOperationException("DataSource name not available");
}
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2006 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.mime;
import java.io.IOException;
import java.io.InputStream;
import javax.activation.DataHandler;
/**
* Represents an attachment to a {@link org.springframework.ws.mime.MimeMessage}
*
* @author Arjen Poutsma
* @see MimeMessage#getAttachments()
* @see MimeMessage#addAttachment
* @since 1.0.0
*/
public interface Attachment {
/**
* Returns the content identifier of the attachment.
*
* @return the content id, or <code>null</code> if empty or not defined
*/
String getContentId();
/**
* Returns the content type of the attachment.
*
* @return the content type, or <code>null</code> if empty or not defined
*/
String getContentType();
/**
* Return an <code>InputStream</code> to read the contents of the attachment from. The user is responsible for
* closing the stream.
*
* @return the contents of the file as stream, or an empty stream if empty
* @throws IOException in case of access I/O errors
*/
InputStream getInputStream() throws IOException;
/**
* Returns the size of the attachment in bytes. Returns <code>-1</code> if the size cannot be determined.
*
* @return the size of the attachment, <code>0</code> if empty, or <code>-1</code> if the size cannot be determined
*/
long getSize();
/**
* Returns the data handler of the attachment.
*
* @return the data handler of the attachment
*/
DataHandler getDataHandler();
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2006 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.mime;
import org.springframework.ws.WebServiceMessageException;
/**
* Exception thrown when a MIME attachment could not be accessed.
*
* @author Arjen Poutsma
* @see Attachment
* @since 1.0.0
*/
public class AttachmentException extends WebServiceMessageException {
public AttachmentException(String msg) {
super(msg);
}
public AttachmentException(String msg, Throwable ex) {
super(msg, ex);
}
public AttachmentException(Throwable ex) {
super("Could not access body: " + ex.getMessage(), ex);
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2005-2010 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.mime;
import java.io.File;
import java.util.Iterator;
import javax.activation.DataHandler;
import org.springframework.core.io.InputStreamSource;
import org.springframework.ws.WebServiceMessage;
/**
* Represents a Web service message with MIME attachments. Attachments can be added as a file, an {@link
* InputStreamSource}, or a {@link DataHandler}.
*
* @author Arjen Poutsma
* @see Attachment
* @since 1.0.0
*/
public interface MimeMessage extends WebServiceMessage {
/**
* Indicates whether this message is a XOP package.
*
* @return <code>true</code> when the constraints specified in <a href="http://www.w3.org/TR/2005/REC-xop10-20050125/#identifying_xop_documents">Identifying
* XOP Documents</a> are met.
* @see <a href="http://www.w3.org/TR/2005/REC-xop10-20050125/#xop_packages">XOP Packages</a>
*/
boolean isXopPackage();
/**
* Turns this message into a XOP package.
*
* @return <code>true</code> when the message is a XOP package
* @see <a href="http://www.w3.org/TR/2005/REC-xop10-20050125/#xop_packages">XOP Packages</a>
*/
boolean convertToXopPackage();
/**
* Returns the {@link Attachment} with the specified content Id.
*
* @return the attachment with the specified content id; or <code>null</code> if it cannot be found
* @throws AttachmentException in case of errors
*/
Attachment getAttachment(String contentId) throws AttachmentException;
/**
* Returns an <code>Iterator</code> over all {@link Attachment} objects that are part of this message.
*
* @return an iterator over all attachments
* @throws AttachmentException in case of errors
* @see Attachment
*/
Iterator<Attachment> getAttachments() throws AttachmentException;
/**
* Add an attachment to the message, taking the content from a {@link File}.
* <p/>
* The content type will be determined by the name of the given content file. Do not use this for temporary files
* with arbitrary filenames (possibly ending in ".tmp" or the like)!
*
* @param contentId the content Id of the attachment
* @param file the file to take the content from
* @return the added attachment
* @throws AttachmentException in case of errors
*/
Attachment addAttachment(String contentId, File file) throws AttachmentException;
/**
* Add an attachment to the message, taking the content from an {@link InputStreamSource}.
* <p/>
* Note that the stream returned by the source needs to be a <em>fresh one on each call</em>, as underlying
* implementations can invoke {@link InputStreamSource#getInputStream()} multiple times.
*
* @param contentId the content Id of the attachment
* @param inputStreamSource the resource to take the content from (all of Spring's Resource implementations can be
* passed in here)
* @param contentType the content type to use for the element
* @return the added attachment
* @throws AttachmentException in case of errors
* @see org.springframework.core.io.Resource
*/
Attachment addAttachment(String contentId, InputStreamSource inputStreamSource, String contentType);
/**
* Add an attachment to the message, taking the content from a {@link DataHandler}.
*
* @param dataHandler the data handler to take the content from
* @return the added attachment
* @throws AttachmentException in case of errors
*/
Attachment addAttachment(String contentId, DataHandler dataHandler);
}

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides MIME functionality for use the Spring Web Services framework. Contains the Attachment and MimeMessage and
related interfaces.
</body>
</html>

View File

@@ -0,0 +1,5 @@
<html>
<body>
Provides the core functionality of the Spring Web Services framework.
</body>
</html>

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2006 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.pox;
import org.springframework.ws.WebServiceMessage;
/**
* Defines the contract for Plain Old XML messages. Currently only a tagging interface.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface PoxMessage extends WebServiceMessage {
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2006 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.pox;
import org.springframework.ws.WebServiceMessageException;
/**
* Specific subclass of <code>WebServiceMessageException</code> for Plain Old XML messages.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class PoxMessageException extends WebServiceMessageException {
public PoxMessageException(String msg) {
super(msg);
}
public PoxMessageException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2005-2010 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.pox.dom;
import java.io.IOException;
import java.io.OutputStream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.springframework.util.Assert;
import org.springframework.ws.pox.PoxMessage;
import org.springframework.ws.transport.TransportConstants;
import org.springframework.ws.transport.TransportOutputStream;
import org.springframework.xml.namespace.QNameUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Implementation of the <code>PoxMessage</code> interface that is based on a DOM Document.
*
* @author Arjen Poutsma
* @see Document
* @since 1.0.0
*/
public class DomPoxMessage implements PoxMessage {
private final String contentType;
private final Document document;
private final Transformer transformer;
/**
* Constructs a new instance of the <code>DomPoxMessage</code> with the given document.
*
* @param document the document to base the message on
*/
public DomPoxMessage(Document document, Transformer transformer, String contentType) {
Assert.notNull(document, "'document' must not be null");
Assert.notNull(transformer, "'transformer' must not be null");
Assert.hasLength(contentType, "'contentType' must not be empty");
this.document = document;
this.transformer = transformer;
this.contentType = contentType;
}
/** Returns the document underlying this message. */
public Document getDocument() {
return document;
}
public Result getPayloadResult() {
NodeList children = document.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
document.removeChild(children.item(i));
}
return new DOMResult(document);
}
public Source getPayloadSource() {
return new DOMSource(document);
}
public boolean hasFault() {
return false;
}
public String getFaultReason() {
return null;
}
public String toString() {
StringBuilder builder = new StringBuilder("DomPoxMessage ");
Element root = document.getDocumentElement();
if (root != null) {
builder.append(' ');
builder.append(QNameUtils.getQNameForNode(root));
}
return builder.toString();
}
public void writeTo(OutputStream outputStream) throws IOException {
try {
if (outputStream instanceof TransportOutputStream) {
TransportOutputStream transportOutputStream = (TransportOutputStream) outputStream;
transportOutputStream.addHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType);
}
transformer.transform(getPayloadSource(), new StreamResult(outputStream));
}
catch (TransformerException ex) {
throw new DomPoxMessageException("Could write document: " + ex.getMessage(), ex);
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2006 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.pox.dom;
import org.springframework.ws.pox.PoxMessageException;
/**
* Specific subclass of <code>PoxMessageException</code> for DOM Plain Old XML messages.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class DomPoxMessageException extends PoxMessageException {
public DomPoxMessageException(String msg) {
super(msg);
}
public DomPoxMessageException(String msg, Throwable ex) {
super(msg, ex);
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2002-2013 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.pox.dom;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Implementation of the {@link WebServiceMessageFactory} interface that creates a {@link DomPoxMessage}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.pox.dom.DomPoxMessage
* @since 1.0.0
*/
public class DomPoxMessageFactory extends TransformerObjectSupport implements WebServiceMessageFactory {
/** The default content type for the POX messages. */
public static final String DEFAULT_CONTENT_TYPE = "application/xml";
private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
private String contentType = DEFAULT_CONTENT_TYPE;
public DomPoxMessageFactory() {
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(false);
documentBuilderFactory.setExpandEntityReferences(false);
}
/** Sets the content-type for the {@link DomPoxMessage}. */
public void setContentType(String contentType) {
Assert.hasLength(contentType, "'contentType' must not be empty");
this.contentType = contentType;
}
/** Set whether or not the XML parser should be XML namespace aware. Default is <code>true</code>. */
public void setNamespaceAware(boolean namespaceAware) {
documentBuilderFactory.setNamespaceAware(namespaceAware);
}
/** Set if the XML parser should validate the document. Default is <code>false</code>. */
public void setValidating(boolean validating) {
documentBuilderFactory.setValidating(validating);
}
/**
* Set if the XML parser should expand entity reference nodes. Default is
* {@code false}.
*/
public void setExpandEntityReferences(boolean expandEntityRef) {
documentBuilderFactory.setExpandEntityReferences(expandEntityRef);
}
public DomPoxMessage createWebServiceMessage() {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document request = documentBuilder.newDocument();
return new DomPoxMessage(request, createTransformer(), contentType);
}
catch (ParserConfigurationException ex) {
throw new DomPoxMessageException("Could not create message context", ex);
}
catch (TransformerConfigurationException ex) {
throw new DomPoxMessageException("Could not create transformer", ex);
}
}
public DomPoxMessage createWebServiceMessage(InputStream inputStream) throws IOException {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document request = documentBuilder.parse(inputStream);
return new DomPoxMessage(request, createTransformer(), contentType);
}
catch (ParserConfigurationException ex) {
throw new DomPoxMessageException("Could not create message context", ex);
}
catch (SAXException ex) {
throw new DomPoxMessageException("Could not parse request message", ex);
}
catch (TransformerConfigurationException ex) {
throw new DomPoxMessageException("Could not create transformer", ex);
}
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
Contains an implementation of the POX interfaces that is based on DOM.
</body>
</html>

View File

@@ -0,0 +1,6 @@
<html>
<body>
Provides the Plain Old XML (POX) functionality of the Spring Web Services framework. Contains the PoxMessage and related
interfaces.
</body>
</html>

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2005 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.server;
import org.springframework.ws.context.MessageContext;
/**
* Interface that must be implemented for each endpoint type to handle a message request. This interface is used to
* allow the <code>MessageDispatcher</code> to be indefinitely extensible. It accesses all installed endpoints through
* this interface, meaning that is does not contain code specific to any endpoint type.
* <p/>
* <p>This interface is not intended for application developers. It is available for those who want to develop their own
* message flow.
*
* @author Arjen Poutsma
* @see MessageDispatcher
* @since 1.0.0
*/
public interface EndpointAdapter {
/**
* Does this <code>EndpointAdapter</code> support the given <code>endpoint</code>?
* <p/>
* <p>Typical <code>EndpointAdapters</code> will base the decision on the endpoint type.
*
* @param endpoint endpoint object to check
* @return <code>true</code> if this <code>EndpointAdapter</code> supports the supplied <code>endpoint</code>
*/
boolean supports(Object endpoint);
/**
* Use the given <code>endpoint</code> to handle the request.
*
* @param messageContext the current message context
* @param endpoint the endpoint to use. This object must have previously been passed to the {@link
* #supports(Object)} method of this interface, which must have returned <code>true</code>
* @throws Exception in case of errors
*/
void invoke(MessageContext messageContext, Object endpoint) throws Exception;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2005-2011 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.server;
import org.springframework.ws.context.MessageContext;
/**
* Defines the interface for objects than can resolve exceptions thrown during endpoint execution.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface EndpointExceptionResolver {
/**
* Try to resolve the given exception that got thrown during on endpoint execution.
*
* @param messageContext current message context
* @param endpoint the executed endpoint, or null if none chosen at the time of the exception
* @param ex the exception that got thrown during endpoint execution
* @return <code>true</code> if resolved; <code>false</code> otherwise
*/
boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex);
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2005-2011 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.server;
import org.springframework.ws.context.MessageContext;
/**
* Workflow interface that allows for customized endpoint invocation chains. Applications can register any number of
* existing or custom interceptors for certain groups of endpoints, to add common preprocessing behavior without needing
* to modify each endpoint implementation.
* <p/>
* An {@code EndpointInterceptor} gets called before the appropriate {@link EndpointAdapter} triggers the
* invocation of the endpoint itself. This mechanism can be used for a large field of preprocessing aspects, e.g. for
* authorization checks, or message header checks. Its main purpose is to allow for factoring out repetitive endpoint
* code.
* <p/>
* Typically an interceptor chain is defined per {@link EndpointMapping} bean, sharing its granularity. To be able to
* apply a certain interceptor chain to a group of handlers, one needs to map the desired handlers via one
* {@code EndpointMapping} bean. The interceptors themselves are defined as beans in the application context,
* referenced by the mapping bean definition via its {@code interceptors} property (in XML: a &lt;list&gt; of
* &lt;ref&gt;).
*
* @author Arjen Poutsma
* @see EndpointInvocationChain#getInterceptors()
* @see org.springframework.ws.server.endpoint.interceptor.EndpointInterceptorAdapter
* @see org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping#setInterceptors(EndpointInterceptor[])
* @since 1.0.0
*/
public interface EndpointInterceptor {
/**
* Processes the incoming request message. Called after {@link EndpointMapping} determined an appropriate endpoint
* object, but before {@link EndpointAdapter} invokes the endpoint.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can decide to abort the chain, typically
* creating a custom response.
*
* @param messageContext contains the incoming request message
* @param endpoint chosen endpoint to invoke
* @return {@code true} to continue processing of the request interceptor chain; {@code false} to indicate
* blocking of the request endpoint chain, <em>without invoking the endpoint</em>
* @throws Exception in case of errors
* @see MessageContext#getRequest()
*/
boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Processes the outgoing response message. Called after {@link EndpointAdapter} actually invoked the endpoint. Can
* manipulate the response, if any, by adding new headers, etc.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can post-process an invocation, getting
* applied in inverse order of the execution chain.
* <p/>
* Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed.
*
* @param messageContext contains both request and response messages
* @param endpoint chosen endpoint to invoke
* @return {@code true} to continue processing of the response interceptor chain; {@code false} to indicate
* blocking of the response endpoint chain.
* @throws Exception in case of errors
* @see MessageContext#getRequest()
* @see MessageContext#hasResponse()
* @see MessageContext#getResponse()
*/
boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Processes the outgoing response fault. Called after {@link EndpointAdapter} actually invoked the endpoint. Can
* manipulate the response, if any, by adding new headers, etc.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can post-process an invocation, getting
* applied in inverse order of the execution chain.
* <p/>
* Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed.
*
* @param messageContext contains both request and response messages, the response should contains a Fault
* @param endpoint chosen endpoint to invoke
* @return {@code true} to continue processing of the response interceptor chain; {@code false} to indicate
* blocking of the response handler chain.
*/
boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Callback after completion of request and response (fault) processing. Will be called on any outcome of endpoint
* invocation, thus allows for proper resource cleanup.
* <p/>
* Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed.
* <p/>
* As with the {@link #handleResponse} method, the method will be invoked on each interceptor in the chain in
* reverse order, so the first interceptor will be the last to be invoked.
*
* @param messageContext contains both request and response messages, the response should contains a Fault
* @param endpoint chosen endpoint to invoke
* @param ex exception thrown on handler execution, if any
* @throws Exception in case of errors
* @since 2.0.2
*/
void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception;
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2005 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.server;
/**
* Endpoint invocation chain, consisting of an endpoint object and any preprocessing interceptors.
*
* @author Arjen Poutsma
* @see EndpointInterceptor
* @since 1.0.0
*/
public class EndpointInvocationChain {
private Object endpoint;
private EndpointInterceptor[] interceptors;
/**
* Create new <code>EndpointInvocationChain</code>.
*
* @param endpoint the endpoint object to invoke
*/
public EndpointInvocationChain(Object endpoint) {
this.endpoint = endpoint;
}
/**
* Create new <code>EndpointInvocationChain</code>.
*
* @param endpoint the endpoint object to invoke
* @param interceptors the array of interceptors to apply
*/
public EndpointInvocationChain(Object endpoint, EndpointInterceptor[] interceptors) {
this.endpoint = endpoint;
this.interceptors = interceptors;
}
/**
* Returns the endpoint object to invoke.
*
* @return the endpoint object
*/
public Object getEndpoint() {
return endpoint;
}
/**
* Returns the array of interceptors to apply before the handler executes.
*
* @return the array of interceptors
*/
public EndpointInterceptor[] getInterceptors() {
return interceptors;
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2005 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.server;
import org.springframework.ws.context.MessageContext;
/**
* Defines a mapping between message requests and endpoint objects.
* <p/>
* This class can be implemented by application developers, although this is not always necessary, as
* <code>PayloadRootQNameEndpointMapping</code> and <code>SoapActionEndpointMapping</code> are included.
* <p/>
* HandlerMapping implementations can support mapped interceptors but do not have to. An endpoint will always be wrapped
* in a <code>EndpointExecutionChain</code> instance, optionally accompanied by some <code>EndpointInterceptor</code>
* instances. The <code>MessageDispacher</code> will first call each <code>EndpointInterceptor</code>'s
* <code>handlerRequest</code> method in the given order, finally invoking the endpoint itself if all
* <code>handlerRequest</code> methods have returned <code>true</code>.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping
* @see org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping
* @see org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping
* @since 1.0.0
*/
public interface EndpointMapping {
/**
* Returns an endpoint and any interceptors for this message context. The choice may be made on message contents,
* transport request url, a routing table, or any factor the implementing class chooses.
* <p/>
* The returned <code>EndpointExecutionChain</code> contains an endpoint Object, rather than even a tag interface,
* so that endpoints are not constrained in any way. For example, a <code>EndpointAdapter</code> could be written to
* allow another framework's endpoint objects to be used.
* <p/>
* Returns <code>null</code> if no match was found. This is by design. The <code>MessageDispatcher</code> will query
* all registered <code>EndpointMapping</code> beans to find a match, and only decide there is an error if none can
* find an endpoint.
*
* @return a HandlerExecutionChain instance containing endpoint object and any interceptors, or <code>null</code> if
* no mapping is found
* @throws Exception if there is an internal error
*/
EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception;
}

View File

@@ -0,0 +1,482 @@
/*
* Copyright 2005-2012 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.server;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.OrderComparator;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.ws.FaultAwareWebServiceMessage;
import org.springframework.ws.NoEndpointFoundException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.PayloadEndpoint;
import org.springframework.ws.server.endpoint.adapter.MessageEndpointAdapter;
import org.springframework.ws.server.endpoint.adapter.PayloadEndpointAdapter;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.ws.support.DefaultStrategiesHelper;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Central dispatcher for use within Spring-WS, dispatching Web service messages to registered endpoints.
* <p/>
* This dispatcher is quite similar to Spring MVCs {@link DispatcherServlet}. Just like its counterpart, this dispatcher
* is very flexible. This class is SOAP agnostic; in typical SOAP Web Services, the {@link SoapMessageDispatcher}
* subclass is used.
* <ul>
* <li>It can use any {@link EndpointMapping} implementation - whether standard, or provided as
* part of an application - to control the routing of request messages to endpoint objects. Endpoint mappings can be
* registered using the {@link #setEndpointMappings(List) endpointMappings} property.</li>
* <li>It can use any {@link EndpointAdapter}; this allows one to use any endpoint interface or form. Defaults to
* the {@link MessageEndpointAdapter} and {@link PayloadEndpointAdapter}, for {@link MessageEndpoint} and
* {@link PayloadEndpoint}, respectively, and the
* {@link org.springframework.ws.server.endpoint.adapter.MessageMethodEndpointAdapter MessageMethodEndpointAdapter} and
* {@link org.springframework.ws.server.endpoint.adapter.PayloadMethodEndpointAdapter PayloadMethodEndpointAdapter}.
* Additional endpoint adapters can be added through the {@link #setEndpointAdapters(List) endpointAdapters} property.</li>
* <li>Its exception resolution strategy can be specified via a
* {@link EndpointExceptionResolver}, for example mapping certain exceptions to SOAP Faults. Default is none. Additional
* exception resolvers can be added through the {@link #setEndpointExceptionResolvers(List) endpointExceptionResolvers}
* property.</li>
* </ul>
*
* @author Arjen Poutsma
* @see EndpointMapping
* @see EndpointAdapter
* @see EndpointExceptionResolver
* @see org.springframework.web.servlet.DispatcherServlet
* @since 1.0.0
*/
public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAware, ApplicationContextAware {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
/** Log category to use when no mapped endpoint is found for a request. */
public static final String ENDPOINT_NOT_FOUND_LOG_CATEGORY = "org.springframework.ws.server.EndpointNotFound";
/** Additional logger to use when no mapped endpoint is found for a request. */
protected static final Log endpointNotFoundLogger =
LogFactory.getLog(MessageDispatcher.ENDPOINT_NOT_FOUND_LOG_CATEGORY);
/** Log category to use for message tracing. */
public static final String MESSAGE_TRACING_LOG_CATEGORY = "org.springframework.ws.server.MessageTracing";
/** Additional logger to use for sent message tracing. */
protected static final Log sentMessageTracingLogger =
LogFactory.getLog(MessageDispatcher.MESSAGE_TRACING_LOG_CATEGORY + ".sent");
/** Additional logger to use for received message tracing. */
protected static final Log receivedMessageTracingLogger =
LogFactory.getLog(MessageDispatcher.MESSAGE_TRACING_LOG_CATEGORY + ".received");
private final DefaultStrategiesHelper defaultStrategiesHelper;
/** The registered bean name for this dispatcher. */
private String beanName;
/** List of EndpointAdapters used in this dispatcher. */
private List<EndpointAdapter> endpointAdapters;
/** List of EndpointExceptionResolvers used in this dispatcher. */
private List<EndpointExceptionResolver> endpointExceptionResolvers;
/** List of EndpointMappings used in this dispatcher. */
private List<EndpointMapping> endpointMappings;
/** Initializes a new instance of the <code>MessageDispatcher</code>. */
public MessageDispatcher() {
defaultStrategiesHelper = new DefaultStrategiesHelper(getClass());
}
/** Returns the <code>EndpointAdapter</code>s to use by this <code>MessageDispatcher</code>. */
public List<EndpointAdapter> getEndpointAdapters() {
return endpointAdapters;
}
/** Sets the <code>EndpointAdapter</code>s to use by this <code>MessageDispatcher</code>. */
public void setEndpointAdapters(List<EndpointAdapter> endpointAdapters) {
this.endpointAdapters = endpointAdapters;
}
/** Returns the <code>EndpointExceptionResolver</code>s to use by this <code>MessageDispatcher</code>. */
public List<EndpointExceptionResolver> getEndpointExceptionResolvers() {
return endpointExceptionResolvers;
}
/** Sets the <code>EndpointExceptionResolver</code>s to use by this <code>MessageDispatcher</code>. */
public void setEndpointExceptionResolvers(List<EndpointExceptionResolver> endpointExceptionResolvers) {
this.endpointExceptionResolvers = endpointExceptionResolvers;
}
/** Returns the <code>EndpointMapping</code>s to use by this <code>MessageDispatcher</code>. */
public List<EndpointMapping> getEndpointMappings() {
return endpointMappings;
}
/** Sets the <code>EndpointMapping</code>s to use by this <code>MessageDispatcher</code>. */
public void setEndpointMappings(List<EndpointMapping> endpointMappings) {
this.endpointMappings = endpointMappings;
}
public final void setBeanName(String beanName) {
this.beanName = beanName;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
initEndpointAdapters(applicationContext);
initEndpointExceptionResolvers(applicationContext);
initEndpointMappings(applicationContext);
}
public void receive(MessageContext messageContext) throws Exception {
// Let's keep a reference to the request content as it came in, it might be changed by interceptors in dispatch()
String requestContent = "";
if (receivedMessageTracingLogger.isTraceEnabled() || sentMessageTracingLogger.isTraceEnabled()) {
requestContent = getMessageContent(messageContext.getRequest());
}
if (receivedMessageTracingLogger.isTraceEnabled()) {
receivedMessageTracingLogger.trace("Received request [" + requestContent + "]");
}
else if (receivedMessageTracingLogger.isDebugEnabled()) {
receivedMessageTracingLogger.debug("Received request [" + messageContext.getRequest() + "]");
}
dispatch(messageContext);
if (messageContext.hasResponse()) {
WebServiceMessage response = messageContext.getResponse();
if (sentMessageTracingLogger.isTraceEnabled()) {
String responseContent = getMessageContent(response);
sentMessageTracingLogger.trace("Sent response [" + responseContent + "] for request [" +
requestContent + "]");
}
else if (sentMessageTracingLogger.isDebugEnabled()) {
sentMessageTracingLogger.debug("Sent response [" + response + "] for request [" +
messageContext.getRequest() + "]");
}
}
else if (sentMessageTracingLogger.isDebugEnabled()) {
sentMessageTracingLogger
.debug("MessageDispatcher with name '" + beanName + "' sends no response for request [" +
messageContext.getRequest() + "]");
}
}
private String getMessageContent(WebServiceMessage message) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
message.writeTo(bos);
return bos.toString("UTF-8");
}
/**
* Dispatches the request in the given MessageContext according to the configuration.
*
* @param messageContext the message context
* @throws org.springframework.ws.NoEndpointFoundException
* thrown when an endpoint cannot be resolved for the incoming message
*/
protected final void dispatch(MessageContext messageContext) throws Exception {
EndpointInvocationChain mappedEndpoint = null;
int interceptorIndex = -1;
try {
try {
// Determine endpoint for the current context
mappedEndpoint = getEndpoint(messageContext);
if (mappedEndpoint == null || mappedEndpoint.getEndpoint() == null) {
throw new NoEndpointFoundException(messageContext.getRequest());
}
if (!handleRequest(mappedEndpoint, messageContext)) {
return;
}
// Apply handleRequest of registered interceptors
if (mappedEndpoint.getInterceptors() != null) {
for (int i = 0; i < mappedEndpoint.getInterceptors().length; i++) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
interceptorIndex = i;
if (!interceptor.handleRequest(messageContext, mappedEndpoint.getEndpoint())) {
triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext);
triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null);
return;
}
}
}
// Actually invoke the endpoint
EndpointAdapter endpointAdapter = getEndpointAdapter(mappedEndpoint.getEndpoint());
endpointAdapter.invoke(messageContext, mappedEndpoint.getEndpoint());
// Apply handleResponse methods of registered interceptors
triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext);
}
catch (NoEndpointFoundException ex) {
// No triggering of interceptors if no endpoint is found
if (endpointNotFoundLogger.isWarnEnabled()) {
endpointNotFoundLogger.warn("No endpoint mapping found for [" + messageContext.getRequest() + "]");
}
throw ex;
}
catch (Exception ex) {
Object endpoint = mappedEndpoint != null ? mappedEndpoint.getEndpoint() : null;
processEndpointException(messageContext, endpoint, ex);
triggerHandleResponse(mappedEndpoint, interceptorIndex, messageContext);
}
triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, null);
}
catch (NoEndpointFoundException ex) {
throw ex;
}
catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedEndpoint, interceptorIndex, messageContext, ex);
throw ex;
}
}
/**
* Returns the endpoint for this request. All endpoint mappings are tried, in order.
*
* @return the <code>EndpointInvocationChain</code>, or <code>null</code> if no endpoint could be found.
*/
protected EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception {
for (EndpointMapping endpointMapping : getEndpointMappings()) {
EndpointInvocationChain endpoint = endpointMapping.getEndpoint(messageContext);
if (endpoint != null) {
if (logger.isDebugEnabled()) {
logger.debug("Endpoint mapping [" + endpointMapping + "] maps request to endpoint [" +
endpoint.getEndpoint() + "]");
}
return endpoint;
}
else if (logger.isDebugEnabled()) {
logger.debug("Endpoint mapping [" + endpointMapping + "] has no mapping for request");
}
}
return null;
}
/**
* Returns the <code>EndpointAdapter</code> for the given endpoint.
*
* @param endpoint the endpoint to find an adapter for
* @return the adapter
*/
protected EndpointAdapter getEndpointAdapter(Object endpoint) {
for (EndpointAdapter endpointAdapter : getEndpointAdapters()) {
if (logger.isDebugEnabled()) {
logger.debug("Testing endpoint adapter [" + endpointAdapter + "]");
}
if (endpointAdapter.supports(endpoint)) {
return endpointAdapter;
}
}
throw new IllegalStateException("No adapter for endpoint [" + endpoint + "]: Is your endpoint annotated with " +
"@Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?");
}
/**
* Callback for pre-processing of given invocation chain and message context. Gets called before invocation of
* <code>handleRequest</code> on the interceptors.
* <p/>
* Default implementation does nothing, and returns <code>true</code>.
*
* @param mappedEndpoint the mapped <code>EndpointInvocationChain</code>
* @param messageContext the message context
* @return <code>true</code> if processing should continue; <code>false</code> otherwise
*/
protected boolean handleRequest(EndpointInvocationChain mappedEndpoint, MessageContext messageContext) {
return true;
}
/**
* Determine an error <code>SOAPMessage</code> response via the registered <code>EndpointExceptionResolvers</code>.
* Most likely, the response contains a <code>SOAPFault</code>. If no suitable resolver was found, the exception is
* rethrown.
*
* @param messageContext current SOAPMessage request
* @param endpoint the executed endpoint, or null if none chosen at the time of the exception
* @param ex the exception that got thrown during handler execution
* @throws Exception if no suitable resolver is found
*/
protected void processEndpointException(MessageContext messageContext, Object endpoint, Exception ex)
throws Exception {
if (!CollectionUtils.isEmpty(getEndpointExceptionResolvers())) {
for (EndpointExceptionResolver resolver : getEndpointExceptionResolvers()) {
if (resolver.resolveException(messageContext, endpoint, ex)) {
if (logger.isDebugEnabled()) {
logger.debug("Endpoint invocation resulted in exception - responding with Fault", ex);
}
return;
}
}
}
// exception not resolved
throw ex;
}
/**
* Trigger handleResponse or handleFault on the mapped EndpointInterceptors. Will just invoke said method on all
* interceptors whose handleRequest invocation returned <code>true</code>, in addition to the last interceptor who
* returned <code>false</code>.
*
* @param mappedEndpoint the mapped EndpointInvocationChain
* @param interceptorIndex index of last interceptor that was called
* @param messageContext the message context, whose request and response are filled
* @see EndpointInterceptor#handleResponse(MessageContext,Object)
* @see EndpointInterceptor#handleFault(MessageContext, Object)
*/
private void triggerHandleResponse(EndpointInvocationChain mappedEndpoint,
int interceptorIndex,
MessageContext messageContext) throws Exception {
if (mappedEndpoint != null && messageContext.hasResponse() &&
!ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) {
boolean hasFault = false;
WebServiceMessage response = messageContext.getResponse();
if (response instanceof FaultAwareWebServiceMessage) {
hasFault = ((FaultAwareWebServiceMessage) response).hasFault();
}
boolean resume = true;
for (int i = interceptorIndex; resume && i >= 0; i--) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
if (!hasFault) {
resume = interceptor.handleResponse(messageContext, mappedEndpoint.getEndpoint());
}
else {
resume = interceptor.handleFault(messageContext, mappedEndpoint.getEndpoint());
}
}
}
}
/**
* Trigger afterCompletion callbacks on the mapped EndpointInterceptors.
* Will just invoke afterCompletion for all interceptors whose handleRequest invocation
* has successfully completed and returned true, in addition to the last interceptor who
* returned <code>false</code>.
*
* @param mappedEndpoint the mapped EndpointInvocationChain
* @param interceptorIndex index of last interceptor that successfully completed
* @param ex Exception thrown on handler execution, or <code>null</code> if none
* @see EndpointInterceptor#afterCompletion
*/
private void triggerAfterCompletion(EndpointInvocationChain mappedEndpoint,
int interceptorIndex,
MessageContext messageContext,
Exception ex) throws Exception {
// Apply afterCompletion methods of registered interceptors.
if (mappedEndpoint != null) {
EndpointInterceptor[] interceptors = mappedEndpoint.getInterceptors();
if (interceptors != null) {
for (int i = interceptorIndex; i >= 0; i--) {
EndpointInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(messageContext, mappedEndpoint.getEndpoint(), ex);
}
catch (Throwable ex2) {
logger.error("EndpointInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
}
/**
* Initialize the <code>EndpointAdapters</code> used by this class. If no adapter beans are explicitly set by using
* the <code>endpointAdapters</code> property, we use the default strategies.
*
* @see #setEndpointAdapters(java.util.List)
*/
private void initEndpointAdapters(ApplicationContext applicationContext) throws BeansException {
if (endpointAdapters == null) {
Map<String, EndpointAdapter> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(applicationContext, EndpointAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
endpointAdapters = new ArrayList<EndpointAdapter>(matchingBeans.values());
Collections.sort(endpointAdapters, new OrderComparator());
}
else {
endpointAdapters =
defaultStrategiesHelper.getDefaultStrategies(EndpointAdapter.class, applicationContext);
if (logger.isDebugEnabled()) {
logger.debug("No EndpointAdapters found, using defaults");
}
}
}
}
/**
* Initialize the <code>EndpointExceptionResolver</code> used by this class. If no resolver beans are explicitly set
* by using the <code>endpointExceptionResolvers</code> property, we use the default strategies.
*
* @see #setEndpointExceptionResolvers(java.util.List)
*/
private void initEndpointExceptionResolvers(ApplicationContext applicationContext) throws BeansException {
if (endpointExceptionResolvers == null) {
Map<String, EndpointExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(applicationContext, EndpointExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
endpointExceptionResolvers = new ArrayList<EndpointExceptionResolver>(matchingBeans.values());
Collections.sort(endpointExceptionResolvers, new OrderComparator());
}
else {
endpointExceptionResolvers = defaultStrategiesHelper
.getDefaultStrategies(EndpointExceptionResolver.class, applicationContext);
if (logger.isDebugEnabled()) {
logger.debug("No EndpointExceptionResolvers found, using defaults");
}
}
}
}
/**
* Initialize the <code>EndpointMappings</code> used by this class. If no mapping beans are explictely set by using
* the <code>endpointMappings</code> property, we use the default strategies.
*
* @see #setEndpointMappings(java.util.List)
*/
private void initEndpointMappings(ApplicationContext applicationContext) throws BeansException {
if (endpointMappings == null) {
Map<String, EndpointMapping> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(applicationContext, EndpointMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
endpointMappings = new ArrayList<EndpointMapping>(matchingBeans.values());
Collections.sort(endpointMappings, new OrderComparator());
}
else {
endpointMappings =
defaultStrategiesHelper.getDefaultStrategies(EndpointMapping.class, applicationContext);
if (logger.isDebugEnabled()) {
logger.debug("No EndpointMappings found, using defaults");
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2005-2010 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.server;
import org.springframework.ws.context.MessageContext;
/**
* Extension of the {@link EndpointInterceptor} interface that adds a way to
* decide whether the interceptor should intercept a given message context.
* @author Arjen Poutsma
* @since 2.0
*/
public interface SmartEndpointInterceptor extends EndpointInterceptor {
/**
* Indicates whether this interceptor should intercept the given message context.
*
* @param messageContext contains the incoming request message
* @param endpoint chosen endpoint to invoke
* @return {@code true} to indicate that this interceptor applies; {@code false} otherwise
*/
boolean shouldIntercept(MessageContext messageContext, Object endpoint);
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.DOMReader;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
import org.w3c.dom.Node;
/**
* Abstract base class for endpoints that handle the message payload as dom4j elements. Offers the message payload as a
* dom4j <code>Element</code>, and allows subclasses to create a response by returning an <code>Element</code>.
* <p/>
* An <code>AbstractDom4JPayloadEndpoint</code> only accept one payload element. Multiple payload elements are not in
* accordance with WS-I.
*
* @author Arjen Poutsma
* @see org.dom4j.Element
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractDom4jPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
private boolean alwaysTransform = false;
/**
* Set if the request {@link Source} should always be transformed into a new {@link DocumentResult}.
* <p/>
* Default is {@code false}, which is faster.
*/
public void setAlwaysTransform(boolean alwaysTransform) {
this.alwaysTransform = alwaysTransform;
}
public final Source invoke(Source request) throws Exception {
Element requestElement = null;
if (request != null) {
DocumentResult dom4jResult = new DocumentResult();
transform(request, dom4jResult);
requestElement = dom4jResult.getDocument().getRootElement();
}
Document responseDocument = DocumentHelper.createDocument();
Element responseElement = invokeInternal(requestElement, responseDocument);
return responseElement != null ? new DocumentSource(responseElement) : null;
}
/**
* Returns the payload element of the given source.
* <p/>
* Default implementation checks whether the source is a {@link javax.xml.transform.dom.DOMSource}, and uses a
* {@link org.jdom.input.DOMBuilder} to create a JDOM {@link org.jdom.Element}. In all other cases, or when
* {@linkplain #setAlwaysTransform(boolean) alwaysTransform} is {@code true}, the source is transformed into a
* {@link org.jdom.transform.JDOMResult}, which is more expensive. If the passed source is {@code null}, {@code
* null} is returned.
*
* @param source the source to return the root element of; can be {@code null}
* @return the document element
* @throws javax.xml.transform.TransformerException
* in case of errors
*/
protected Element getDocumentElement(Source source) throws TransformerException {
if (source == null) {
return null;
}
if (!alwaysTransform && source instanceof DOMSource) {
Node node = ((DOMSource) source).getNode();
if (node.getNodeType() == Node.DOCUMENT_NODE) {
DOMReader domReader = new DOMReader();
Document document = domReader.read((org.w3c.dom.Document) node);
return document.getRootElement();
}
}
// we have no other option than to transform
DocumentResult dom4jResult = new DocumentResult();
transform(source, dom4jResult);
return dom4jResult.getDocument().getRootElement();
}
/**
* Template method. Subclasses must implement this. Offers the request payload as a dom4j <code>Element</code>, and
* allows subclasses to return a response <code>Element</code>.
* <p/>
* The given dom4j <code>Document</code> is to be used for constructing a response element, by using
* <code>addElement</code>.
*
* @param requestElement the contents of the SOAP message as dom4j elements
* @param responseDocument a dom4j document to be used for constructing a response
* @return the response element. Can be <code>null</code> to specify no response.
*/
protected abstract Element invokeInternal(Element requestElement, Document responseDocument) throws Exception;
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2002-2013 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.server.endpoint;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for endpoints that handle the message payload as DOM elements.
* <p/>
* Offers the message payload as a DOM <code>Element</code>, and allows subclasses to create a response by returning an
* <code>Element</code>.
* <p/>
* An <code>AbstractDomPayloadEndpoint</code> only accept <em>one</em> payload element. Multiple payload elements are
* not in accordance with WS-I.
*
* @author Arjen Poutsma
* @author Alef Arendsen
* @see #invokeInternal(org.w3c.dom.Element,org.w3c.dom.Document)
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractDomPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
private DocumentBuilderFactory documentBuilderFactory;
private boolean validating = false;
private boolean namespaceAware = true;
private boolean expandEntityReferences = false;
private boolean alwaysTransform = false;
/** Set whether or not the XML parser should be XML namespace aware. Default is <code>true</code>. */
public void setNamespaceAware(boolean namespaceAware) {
this.namespaceAware = namespaceAware;
}
/** Set if the XML parser should validate the document. Default is <code>false</code>. */
public void setValidating(boolean validating) {
this.validating = validating;
}
/**
* Set if the XML parser should expand entity reference nodes. Default is
* {@code false}.
*/
public void setExpandEntityReferences(boolean expandEntityRef) {
documentBuilderFactory.setExpandEntityReferences(expandEntityRef);
}
/**
* Set if the request {@link Source} should always be transformed into a new {@link DOMResult}.
* <p/>
* Default is {@code false}, which is faster.
*/
public void setAlwaysTransform(boolean alwaysTransform) {
this.alwaysTransform = alwaysTransform;
}
public final Source invoke(Source request) throws Exception {
if (documentBuilderFactory == null) {
documentBuilderFactory = createDocumentBuilderFactory();
}
DocumentBuilder documentBuilder = createDocumentBuilder(documentBuilderFactory);
Element requestElement = getDocumentElement(request, documentBuilder);
Document responseDocument = documentBuilder.newDocument();
Element responseElement = invokeInternal(requestElement, responseDocument);
return responseElement != null ? new DOMSource(responseElement) : null;
}
/**
* Create a <code>DocumentBuilder</code> that this endpoint will use for parsing XML documents. Can be overridden in
* subclasses, adding further initialization of the builder.
*
* @param factory the <code>DocumentBuilderFactory</code> that the DocumentBuilder should be created with
* @return the <code>DocumentBuilder</code>
* @throws ParserConfigurationException if thrown by JAXP methods
*/
protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
throws ParserConfigurationException {
return factory.newDocumentBuilder();
}
/**
* Create a <code>DocumentBuilderFactory</code> that this endpoint will use for constructing XML documents. Can be
* overridden in subclasses, adding further initialization of the factory. The resulting
* <code>DocumentBuilderFactory</code> is cached, so this method will only be called once.
*
* @return the DocumentBuilderFactory
* @throws ParserConfigurationException if thrown by JAXP methods
*/
protected DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validating);
factory.setNamespaceAware(namespaceAware);
factory.setExpandEntityReferences(expandEntityReferences);
return factory;
}
/**
* Returns the payload element of the given source.
* <p/>
* Default implementation checks whether the source is a {@link DOMSource}, and returns the {@linkplain
* DOMSource#getNode() node} of that. In all other cases, or when {@linkplain #setAlwaysTransform(boolean)
* alwaysTransform} is {@code true}, the source is transformed into a {@link DOMResult}, which is more expensive. If
* the passed source is {@code null}, {@code null} is returned.
*
* @param source the source to return the root element of; can be {@code null}
* @param documentBuilder the document builder to be used for transformations
* @return the document element
* @throws TransformerException in case of errors
*/
protected Element getDocumentElement(Source source, DocumentBuilder documentBuilder) throws TransformerException {
if (source == null) {
return null;
}
if (!alwaysTransform && source instanceof DOMSource) {
Node node = ((DOMSource) source).getNode();
if (node.getNodeType() == Node.ELEMENT_NODE) {
return (Element) node;
}
else if (node.getNodeType() == Node.DOCUMENT_NODE) {
return ((Document) node).getDocumentElement();
}
}
// we have no other option than to transform
Document requestDocument = documentBuilder.newDocument();
DOMResult domResult = new DOMResult(requestDocument);
transform(source, domResult);
return requestDocument.getDocumentElement();
}
/**
* Template method that subclasses must implement to process the request.
* <p/>
* <p>Offers the request payload as a DOM <code>Element</code>, and allows subclasses to return a response
* <code>Element</code>.
* <p/>
* <p>The given DOM <code>Document</code> is to be used for constructing <code>Node</code>s, by using the various
* <code>create</code> methods.
*
* @param requestElement the contents of the SOAP message as DOM elements
* @param responseDocument a DOM document to be used for constructing <code>Node</code>s
* @return the response element. Can be <code>null</code> to specify no response.
*/
protected abstract Element invokeInternal(Element requestElement, Document responseDocument) throws Exception;
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import java.util.Set;
import org.springframework.core.Ordered;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointExceptionResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract base class for {@link EndpointExceptionResolver EndpointExceptionResolvers}.
* <p/>
* <p>Provides a set of mapped endpoints that the resolver should map.
*
* @author Arjen Poutsma
* @author Tareq Abed Rabbo
* @since 1.0.0
*/
public abstract class AbstractEndpointExceptionResolver implements EndpointExceptionResolver, Ordered {
/** Shared {@link Log} for subclasses to use. */
protected final Log logger = LogFactory.getLog(getClass());
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
private Set<?> mappedEndpoints;
private Log warnLogger;
/**
* Specify the set of endpoints that this exception resolver should map. <p>The exception mappings and the default
* fault will only apply to the specified endpoints.
* <p/>
* If no endpoints are set, both the exception mappings and the default fault will apply to all handlers. This means
* that a specified default fault will be used as fallback for all exceptions; any further
* <code>EndpointExceptionResolvers</code> in the chain will be ignored in this case.
*/
public void setMappedEndpoints(Set<?> mappedEndpoints) {
this.mappedEndpoints = mappedEndpoints;
}
/**
* Set the log category for warn logging. The name will be passed to the underlying logger implementation through
* Commons Logging, getting interpreted as log category according to the logger's configuration.
* <p/>
* Default is no warn logging. Specify this setting to activate warn logging into a specific category.
* Alternatively, override the {@link #logException} method for custom logging.
*
* @see org.apache.commons.logging.LogFactory#getLog(String)
* @see org.apache.log4j.Logger#getLogger(String)
* @see java.util.logging.Logger#getLogger(String)
*/
public void setWarnLogCategory(String loggerName) {
this.warnLogger = LogFactory.getLog(loggerName);
}
/**
* Specify the order value for this mapping.
* <p/>
* Default value is {@link Integer#MAX_VALUE}, meaning that it's non-ordered.
*
* @see org.springframework.core.Ordered#getOrder()
*/
public final void setOrder(int order) {
this.order = order;
}
public final int getOrder() {
return order;
}
/**
* Default implementation that checks whether the given <code>endpoint</code> is in the set of {@link
* #setMappedEndpoints mapped endpoints}.
*
* @see #resolveExceptionInternal(MessageContext,Object,Exception)
*/
public final boolean resolveException(MessageContext messageContext, Object endpoint, Exception ex) {
Object mappedEndpoint = endpoint instanceof MethodEndpoint ? ((MethodEndpoint) endpoint).getBean() : endpoint;
if (mappedEndpoints != null && !mappedEndpoints.contains(mappedEndpoint)) {
return false;
}
// Log exception, both at debug log level and at warn level, if desired.
if (logger.isDebugEnabled()) {
logger.debug("Resolving exception from endpoint [" + endpoint + "]: " + ex);
}
logException(ex, messageContext);
return resolveExceptionInternal(messageContext, endpoint, ex);
}
/**
* Log the given exception at warn level, provided that warn logging has been activated through the {@link
* #setWarnLogCategory "warnLogCategory"} property.
* <p/>
* Calls {@link #buildLogMessage} in order to determine the concrete message to log. Always passes the full
* exception to the logger.
*
* @param ex the exception that got thrown during handler execution
* @param messageContext current message context request
* @see #setWarnLogCategory
* @see #buildLogMessage
* @see org.apache.commons.logging.Log#warn(Object, Throwable)
*/
protected void logException(Exception ex, MessageContext messageContext) {
if (this.warnLogger != null && this.warnLogger.isWarnEnabled()) {
this.warnLogger.warn(buildLogMessage(ex, messageContext), ex);
}
}
/**
* Build a log message for the given exception, occured during processing the given message context.
*
* @param ex the exception that got thrown during handler execution
* @param messageContext the message context
* @return the log message to use
*/
protected String buildLogMessage(Exception ex, MessageContext messageContext) {
return "Endpoint execution resulted in exception";
}
/**
* Template method for resolving exceptions that is called by {@link #resolveException}.
*
* @param messageContext current message context
* @param endpoint the executed endpoint, or <code>null</code> if none chosen at the time of the exception
* @param ex the exception that got thrown during endpoint execution
* @return <code>true</code> if resolved; <code>false</code> otherwise
* @see #resolveException(MessageContext,Object,Exception)
*/
protected abstract boolean resolveExceptionInternal(MessageContext messageContext, Object endpoint, Exception ex);
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright 2005-2012 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.server.endpoint;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.DOMBuilder;
import org.jdom2.transform.JDOMResult;
import org.jdom2.transform.JDOMSource;
import org.w3c.dom.Node;
/**
* Abstract base class for endpoints that handle the message payload as JDOM elements.
* <p/>
* <p>Offers the message payload as a JDOM {@link Element}, and allows subclasses to create a response by returning an
* <code>Element</code>.
* <p/>
* <pAn <code>AbstractJDomPayloadEndpoint</code> can accept only <i>one</i> payload element. Multiple payload elements
* are not in accordance with WS-I.
*
* @author Arjen Poutsma
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractJDomPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
private boolean alwaysTransform = false;
/**
* Set if the request {@link Source} should always be transformed into a new {@link JDOMResult}.
* <p/>
* Default is {@code false}, which is faster.
*/
public void setAlwaysTransform(boolean alwaysTransform) {
this.alwaysTransform = alwaysTransform;
}
public final Source invoke(Source request) throws Exception {
Element requestElement = getDocumentElement(request);
Element responseElement = invokeInternal(requestElement);
return responseElement != null ? new JDOMSource(responseElement) : null;
}
/**
* Returns the payload element of the given source.
* <p/>
* Default implementation checks whether the source is a {@link DOMSource}, and uses a {@link DOMBuilder} to create
* a JDOM {@link Element}. In all other cases, or when {@linkplain #setAlwaysTransform(boolean) alwaysTransform} is
* {@code true}, the source is transformed into a {@link JDOMResult}, which is more expensive. If the passed source
* is {@code null}, {@code null} is returned.
*
* @param source the source to return the root element of; can be {@code null}
* @return the document element
* @throws TransformerException in case of errors
*/
protected Element getDocumentElement(Source source) throws TransformerException {
if (source == null) {
return null;
}
if (!alwaysTransform && source instanceof DOMSource) {
Node node = ((DOMSource) source).getNode();
DOMBuilder domBuilder = new DOMBuilder();
if (node.getNodeType() == Node.ELEMENT_NODE) {
return domBuilder.build((org.w3c.dom.Element) node);
}
else if (node.getNodeType() == Node.DOCUMENT_NODE) {
Document document = domBuilder.build((org.w3c.dom.Document) node);
return document.getRootElement();
}
}
// we have no other option than to transform
JDOMResult jdomResult = new JDOMResult();
transform(source, jdomResult);
return jdomResult.getDocument().getRootElement();
}
/**
* Template method. Subclasses must implement this. Offers the request payload as a JDOM <code>Element</code>, and
* allows subclasses to return a response <code>Element</code>.
*
* @param requestElement the contents of the SOAP message as JDOM element
* @return the response element. Can be <code>null</code> to specify no response.
*/
protected abstract Element invokeInternal(Element requestElement) throws Exception;
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright 2005-2011 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.server.endpoint;
import java.io.StringWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Abstract base class for <code>EndpointInterceptor</code> instances that log a part of a
* <code>WebServiceMessage</code>. By default, both request and response messages are logged, but this behaviour can be
* changed using the <code>logRequest</code> and <code>logResponse</code> properties.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractLoggingInterceptor extends TransformerObjectSupport implements EndpointInterceptor {
/**
* The default <code>Log</code> instance used to write trace messages. This instance is mapped to the implementing
* <code>Class</code>.
*/
protected transient Log logger = LogFactory.getLog(getClass());
private boolean logRequest = true;
private boolean logResponse = true;
/** Indicates whether the request should be logged. Default is <code>true</code>. */
public final void setLogRequest(boolean logRequest) {
this.logRequest = logRequest;
}
/** Indicates whether the response should be logged. Default is <code>true</code>. */
public final void setLogResponse(boolean logResponse) {
this.logResponse = logResponse;
}
/**
* Set the name of the logger to use. The name will be passed to the underlying logger implementation through
* Commons Logging, getting interpreted as log category according to the logger's configuration.
* <p/>
* This can be specified to not log into the category of a class but rather into a specific named category.
*
* @see org.apache.commons.logging.LogFactory#getLog(String)
* @see org.apache.log4j.Logger#getLogger(String)
* @see java.util.logging.Logger#getLogger(String)
*/
public void setLoggerName(String loggerName) {
this.logger = LogFactory.getLog(loggerName);
}
/**
* Logs the request message payload. Logging only occurs if <code>logRequest</code> is set to <code>true</code>,
* which is the default.
*
* @param messageContext the message context
* @return <code>true</code>
* @throws TransformerException when the payload cannot be transformed to a string
*/
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws TransformerException {
if (logRequest && isLogEnabled()) {
logMessageSource("Request: ", getSource(messageContext.getRequest()));
}
return true;
}
/**
* Logs the response message payload. Logging only occurs if <code>logResponse</code> is set to <code>true</code>,
* which is the default.
*
* @param messageContext the message context
* @return <code>true</code>
* @throws TransformerException when the payload cannot be transformed to a string
*/
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
if (logResponse && isLogEnabled()) {
logMessageSource("Response: ", getSource(messageContext.getResponse()));
}
return true;
}
/** Does nothing by default. Faults are not logged. */
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
/** Does nothing by default*/
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) {
}
/**
* Determine whether the {@link #logger} field is enabled.
* <p/>
* Default is <code>true</code> when the "debug" level is enabled. Subclasses can override this to change the level
* under which logging occurs.
*/
protected boolean isLogEnabled() {
return logger.isDebugEnabled();
}
private Transformer createNonIndentingTransformer() throws TransformerConfigurationException {
Transformer transformer = createTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
return transformer;
}
/**
* Logs the given {@link Source source} to the {@link #logger}, using the message as a prefix.
* <p/>
* By default, this message creates a string representation of the given source, and delegates to {@link
* #logMessage(String)}.
*
* @param logMessage the log message
* @param source the source to be logged
* @throws TransformerException in case of errors
*/
protected void logMessageSource(String logMessage, Source source) throws TransformerException {
if (source != null) {
Transformer transformer = createNonIndentingTransformer();
StringWriter writer = new StringWriter();
transformer.transform(source, new StreamResult(writer));
String message = logMessage + writer.toString();
logMessage(message);
}
}
/**
* Logs the given string message.
* <p/>
* By default, this method uses a "debug" level of logging. Subclasses can override this method to change the level
* of logging used by the logger.
*
* @param message the message
*/
protected void logMessage(String message) {
logger.debug(message);
}
/**
* Abstract template method that returns the <code>Source</code> for the given <code>WebServiceMessage</code>.
*
* @param message the message
* @return the source of the message
*/
protected abstract Source getSource(WebServiceMessage message);
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import java.io.IOException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.support.MarshallingUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Endpoint that unmarshals the request payload, and marshals the response object. This endpoint needs a
* <code>Marshaller</code> and <code>Unmarshaller</code>, both of which can be set using properties. An abstract
* template method is invoked using the request object as a parameter, and allows for a response object to be returned.
*
* @author Arjen Poutsma
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see Marshaller
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
* @see Unmarshaller
* @see #invokeInternal(Object)
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpoint, InitializingBean {
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private Marshaller marshaller;
private Unmarshaller unmarshaller;
/**
* Creates a new <code>AbstractMarshallingPayloadEndpoint</code>. The {@link Marshaller} and {@link Unmarshaller}
* must be injected using properties.
*
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
protected AbstractMarshallingPayloadEndpoint() {
}
/**
* Creates a new <code>AbstractMarshallingPayloadEndpoint</code> with the given marshaller. The given {@link
* Marshaller} should also implements the {@link Unmarshaller}, since it is used for both marshalling and
* unmarshalling. If it is not, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring-WS also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
* @see #AbstractMarshallingPayloadEndpoint(Marshaller,Unmarshaller)
*/
protected AbstractMarshallingPayloadEndpoint(Marshaller marshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
if (!(marshaller instanceof Unmarshaller)) {
throw new IllegalArgumentException("Marshaller [" + marshaller + "] does not implement the Unmarshaller " +
"interface. Please set an Unmarshaller explicitly by using the " +
"AbstractMarshallingPayloadEndpoint(Marshaller, Unmarshaller) constructor.");
}
else {
setMarshaller(marshaller);
setUnmarshaller((Unmarshaller) marshaller);
}
}
/**
* Creates a new <code>AbstractMarshallingPayloadEndpoint</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
protected AbstractMarshallingPayloadEndpoint(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.notNull(unmarshaller, "unmarshaller must not be null");
setMarshaller(marshaller);
setUnmarshaller(unmarshaller);
}
/** Returns the marshaller used for transforming objects into XML. */
public Marshaller getMarshaller() {
return marshaller;
}
/** Sets the marshaller used for transforming objects into XML. */
public final void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/** Returns the unmarshaller used for transforming XML into objects. */
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
/** Sets the unmarshaller used for transforming XML into objects. */
public final void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public void afterPropertiesSet() throws Exception {
afterMarshallerSet();
}
public final void invoke(MessageContext messageContext) throws Exception {
WebServiceMessage request = messageContext.getRequest();
Object requestObject = unmarshalRequest(request);
if (onUnmarshalRequest(messageContext, requestObject)) {
Object responseObject = invokeInternal(requestObject);
if (responseObject != null) {
WebServiceMessage response = messageContext.getResponse();
marshalResponse(responseObject, response);
onMarshalResponse(messageContext, requestObject, responseObject);
}
}
}
private Object unmarshalRequest(WebServiceMessage request) throws IOException {
Unmarshaller unmarshaller = getUnmarshaller();
Assert.notNull(unmarshaller, "No unmarshaller registered. Check configuration of endpoint.");
Object requestObject = MarshallingUtils.unmarshal(unmarshaller, request);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
}
return requestObject;
}
/**
* Callback for post-processing in terms of unmarshalling. Called on each message request, after standard
* unmarshalling.
* <p/>
* Default implementation returns <code>true</code>.
*
* @param messageContext the message context
* @param requestObject the object unmarshalled from the {@link MessageContext#getRequest() request}
* @return <code>true</code> to continue and call {@link #invokeInternal(Object)}; <code>false</code> otherwise
*/
protected boolean onUnmarshalRequest(MessageContext messageContext, Object requestObject) throws Exception {
return true;
}
private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException {
Marshaller marshaller = getMarshaller();
Assert.notNull(marshaller, "No marshaller registered. Check configuration of endpoint.");
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + responseObject + "] to response payload");
}
MarshallingUtils.marshal(marshaller, responseObject, response);
}
/**
* Callback for post-processing in terms of marshalling. Called on each message request, after standard marshalling
* of the response. Only invoked when {@link #invokeInternal(Object)} returns an object.
* <p/>
* Default implementation is empty.
*
* @param messageContext the message context
* @param requestObject the object unmarshalled from the {@link MessageContext#getRequest() request}
* @param responseObject the object marshalled to the {@link MessageContext#getResponse()} request}
*/
protected void onMarshalResponse(MessageContext messageContext, Object requestObject, Object responseObject) {
}
/**
* Template method that gets called after the marshaller and unmarshaller have been set.
* <p/>
* The default implementation does nothing.
*
* @deprecated as of Spring Web Services 1.5: {@link #afterPropertiesSet()} is no longer final, so this can safely
* be overridden in subclasses
*/
@Deprecated
public void afterMarshallerSet() throws Exception {
}
/**
* Template method that subclasses must implement to process a request.
* <p/>
* The unmarshalled request object is passed as a parameter, and the returned object is marshalled to a response. If
* no response is required, return <code>null</code>.
*
* @param requestObject the unmarshalled message payload as an object
* @return the object to be marshalled as response, or <code>null</code> if a response is not required
*/
protected abstract Object invokeInternal(Object requestObject) throws Exception;
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXResult;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.xml.sax.ContentHandler;
/**
* Abstract base class for endpoints that handle the message payload with a SAX <code>ContentHandler</code>. Allows
* subclasses to create a response by returning a <code>Source</code>.
* <p/>
* Implementations of this class should create a new handler for each call of <code>createContentHandler</code>, because
* of thread safety. The handlers is later passed on to <code>createResponse</code>, so it can be used for holding
* request-specific state.
*
* @author Arjen Poutsma
* @see #createContentHandler()
* @see #getResponse(org.xml.sax.ContentHandler)
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractSaxPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
/**
* Invokes the provided <code>ContentHandler</code> on the given request. After parsing has been done, the provided
* response is returned.
*
* @see #createContentHandler()
* @see #getResponse(org.xml.sax.ContentHandler)
*/
public final Source invoke(Source request) throws Exception {
ContentHandler contentHandler = null;
if (request != null) {
contentHandler = createContentHandler();
SAXResult result = new SAXResult(contentHandler);
transform(request, result);
}
return getResponse(contentHandler);
}
/**
* Returns the SAX <code>ContentHandler</code> used to parse the incoming request payload. A new instance should be
* created for each call, because of thread-safety. The content handler can be used to hold request-specific state.
* <p/>
* If an incoming message does not contain a payload, this method will not be invoked.
*
* @return a SAX content handler to be used for parsing
*/
protected abstract ContentHandler createContentHandler() throws Exception;
/**
* Returns the response to be given, if any. This method is called after the request payload has been parsed using
* the SAX <code>ContentHandler</code>. The passed <code>ContentHandler</code> is created by {@link
* #createContentHandler()}: it can be used to hold request-specific state.
* <p/>
* If an incoming message does not contain a payload, this method will be invoked with <code>null</code> as content
* handler.
*
* @param contentHandler the content handler used to parse the request
*/
protected abstract Source getResponse(ContentHandler contentHandler) throws Exception;
}

View File

@@ -0,0 +1,239 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import javax.xml.stream.util.XMLEventConsumer;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.util.xml.StaxUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
/**
* Abstract base class for endpoints that handle the message payload with event-based StAX. Allows subclasses to read
* the request with a <code>XMLEventReader</code>, and to create a response using a <code>XMLEventWriter</code>.
*
* @author Arjen Poutsma
* @see #invokeInternal(javax.xml.stream.XMLEventReader,javax.xml.stream.util.XMLEventConsumer,
* javax.xml.stream.XMLEventFactory)
* @see XMLEventReader
* @see XMLEventWriter
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
public abstract class AbstractStaxEventPayloadEndpoint extends AbstractStaxPayloadEndpoint implements MessageEndpoint {
private XMLEventFactory eventFactory;
public final void invoke(MessageContext messageContext) throws Exception {
XMLEventReader eventReader = getEventReader(messageContext.getRequest().getPayloadSource());
XMLEventWriter streamWriter = new ResponseCreatingEventWriter(messageContext);
invokeInternal(eventReader, streamWriter, getEventFactory());
streamWriter.flush();
}
/**
* Create a <code>XMLEventFactory</code> that this endpoint will use to create <code>XMLEvent</code>s. Can be
* overridden in subclasses, adding further initialization of the factory. The resulting
* <code>XMLEventFactory</code> is cached, so this method will only be called once.
*
* @return the created <code>XMLEventFactory</code>
*/
protected XMLEventFactory createXmlEventFactory() {
return XMLEventFactory.newInstance();
}
/** Returns an <code>XMLEventFactory</code> to read XML from. */
private XMLEventFactory getEventFactory() {
if (eventFactory == null) {
eventFactory = createXmlEventFactory();
}
return eventFactory;
}
private XMLEventReader getEventReader(Source source) throws XMLStreamException, TransformerException {
if (source == null) {
return null;
}
XMLEventReader eventReader = null;
if (StaxUtils.isStaxSource(source)) {
eventReader = StaxUtils.getXMLEventReader(source);
if (eventReader == null) {
XMLStreamReader streamReader = StaxUtils.getXMLStreamReader(source);
if (streamReader != null) {
try {
eventReader = getInputFactory().createXMLEventReader(streamReader);
}
catch (XMLStreamException ex) {
eventReader = null;
}
}
}
}
if (eventReader == null) {
try {
eventReader = getInputFactory().createXMLEventReader(source);
}
catch (XMLStreamException ex) {
eventReader = null;
}
catch (UnsupportedOperationException ex) {
eventReader = null;
}
}
if (eventReader == null) {
// as a final resort, transform the source to a stream, and read from that
ByteArrayOutputStream os = new ByteArrayOutputStream();
transform(source, new StreamResult(os));
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
eventReader = getInputFactory().createXMLEventReader(is);
}
return eventReader;
}
private XMLEventWriter getEventWriter(Result result) {
XMLEventWriter eventWriter = null;
if (StaxUtils.isStaxResult(result)) {
eventWriter = StaxUtils.getXMLEventWriter(result);
}
if (eventWriter == null) {
try {
eventWriter = getOutputFactory().createXMLEventWriter(result);
}
catch (XMLStreamException ex) {
// ignore
}
}
return eventWriter;
}
/**
* Template method. Subclasses must implement this. Offers the request payload as a <code>XMLEventReader</code>, and
* a <code>XMLEventWriter</code> to write the response payload to.
*
* @param eventReader the reader to read the payload events from
* @param eventWriter the writer to write payload events to
* @param eventFactory an <code>XMLEventFactory</code> that can be used to create events
*/
protected abstract void invokeInternal(XMLEventReader eventReader,
XMLEventConsumer eventWriter,
XMLEventFactory eventFactory) throws Exception;
/**
* Implementation of the <code>XMLEventWriter</code> interface that creates a response
* <code>WebServiceMessage</code> as soon as any method is called, thus lazily creating the response.
*/
private class ResponseCreatingEventWriter implements XMLEventWriter {
private XMLEventWriter eventWriter;
private MessageContext messageContext;
private ByteArrayOutputStream os;
public ResponseCreatingEventWriter(MessageContext messageContext) {
this.messageContext = messageContext;
}
public NamespaceContext getNamespaceContext() {
return eventWriter.getNamespaceContext();
}
public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
createEventWriter();
eventWriter.setNamespaceContext(context);
}
public void add(XMLEventReader reader) throws XMLStreamException {
createEventWriter();
while (reader.hasNext()) {
add(reader.nextEvent());
}
}
public void add(XMLEvent event) throws XMLStreamException {
createEventWriter();
eventWriter.add(event);
if (event.isEndDocument()) {
if (os != null) {
eventWriter.flush();
// if we used an output stream cache, we have to transform it to the response again
try {
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
transform(new StreamSource(is), messageContext.getResponse().getPayloadResult());
}
catch (TransformerException ex) {
throw new XMLStreamException(ex);
}
}
}
}
public void close() throws XMLStreamException {
if (eventWriter != null) {
eventWriter.close();
}
}
public void flush() throws XMLStreamException {
if (eventWriter != null) {
eventWriter.flush();
}
}
public String getPrefix(String uri) throws XMLStreamException {
createEventWriter();
return eventWriter.getPrefix(uri);
}
public void setDefaultNamespace(String uri) throws XMLStreamException {
createEventWriter();
eventWriter.setDefaultNamespace(uri);
}
public void setPrefix(String prefix, String uri) throws XMLStreamException {
createEventWriter();
eventWriter.setPrefix(prefix, uri);
}
private void createEventWriter() throws XMLStreamException {
if (eventWriter == null) {
WebServiceMessage response = messageContext.getResponse();
eventWriter = getEventWriter(response.getPayloadResult());
if (eventWriter == null) {
// as a final resort, use a stream, and transform that at endDocument()
os = new ByteArrayOutputStream();
eventWriter = getOutputFactory().createXMLEventWriter(os);
}
}
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for endpoints use StAX. Provides an <code>XMLInputFactory</code> and an
* <code>XMLOutputFactory</code>.
*
* @author Arjen Poutsma
* @see XMLInputFactory
* @see XMLOutputFactory
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
@SuppressWarnings("Since15")
public abstract class AbstractStaxPayloadEndpoint extends TransformerObjectSupport {
private XMLInputFactory inputFactory;
private XMLOutputFactory outputFactory;
/** Returns an <code>XMLInputFactory</code> to read XML from. */
protected final XMLInputFactory getInputFactory() {
if (inputFactory == null) {
inputFactory = createXmlInputFactory();
}
return inputFactory;
}
/** Returns an <code>XMLOutputFactory</code> to write XML to. */
protected final XMLOutputFactory getOutputFactory() {
if (outputFactory == null) {
outputFactory = createXmlOutputFactory();
}
return outputFactory;
}
/**
* Create a <code>XMLInputFactory</code> that this endpoint will use to create <code>XMLStreamReader</code>s or
* <code>XMLEventReader</code>. Can be overridden in subclasses, adding further initialization of the factory. The
* resulting <code>XMLInputFactory</code> is cached, so this method will only be called once.
*
* @return the created <code>XMLInputFactory</code>
*/
protected XMLInputFactory createXmlInputFactory() {
return XMLInputFactory.newInstance();
}
/**
* Create a <code>XMLOutputFactory</code> that this endpoint will use to create <code>XMLStreamWriters</code>s or
* <code>XMLEventWriters</code>. Can be overridden in subclasses, adding further initialization of the factory. The
* resulting <code>XMLOutputFactory</code> is cached, so this method will only be called once.
*
* @return the created <code>XMLOutputFactory</code>
*/
protected XMLOutputFactory createXmlOutputFactory() {
return XMLOutputFactory.newInstance();
}
}

View File

@@ -0,0 +1,327 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.util.xml.StaxUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
/**
* Abstract base class for endpoints that handle the message payload with streaming StAX. Allows subclasses to read the
* request with a <code>XMLStreamReader</code>, and to create a response using a <code>XMLStreamWriter</code>.
*
* @author Arjen Poutsma
* @see #invokeInternal(javax.xml.stream.XMLStreamReader,javax.xml.stream.XMLStreamWriter)
* @see XMLStreamReader
* @see XMLStreamWriter
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
@SuppressWarnings("Since15")
public abstract class AbstractStaxStreamPayloadEndpoint extends AbstractStaxPayloadEndpoint implements MessageEndpoint {
public final void invoke(MessageContext messageContext) throws Exception {
XMLStreamReader streamReader = getStreamReader(messageContext.getRequest().getPayloadSource());
XMLStreamWriter streamWriter = new ResponseCreatingStreamWriter(messageContext);
invokeInternal(streamReader, streamWriter);
streamWriter.close();
}
private XMLStreamReader getStreamReader(Source source) throws XMLStreamException, TransformerException {
if (source == null) {
return null;
}
XMLStreamReader streamReader = null;
if (StaxUtils.isStaxSource(source)) {
streamReader = StaxUtils.getXMLStreamReader(source);
if (streamReader == null) {
XMLEventReader eventReader = StaxUtils.getXMLEventReader(source);
if (eventReader != null) {
try {
streamReader = StaxUtils.createEventStreamReader(eventReader);
}
catch (XMLStreamException ex) {
streamReader = null;
}
}
}
}
if (streamReader == null) {
try {
streamReader = getInputFactory().createXMLStreamReader(source);
}
catch (XMLStreamException ex) {
streamReader = null;
}
catch (UnsupportedOperationException ex) {
streamReader = null;
}
}
if (streamReader == null) {
// as a final resort, transform the source to a stream, and read from that
ByteArrayOutputStream os = new ByteArrayOutputStream();
transform(source, new StreamResult(os));
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
streamReader = getInputFactory().createXMLStreamReader(is);
}
return streamReader;
}
private XMLStreamWriter getStreamWriter(Result result) {
XMLStreamWriter streamWriter = null;
if (StaxUtils.isStaxResult(result)) {
streamWriter = StaxUtils.getXMLStreamWriter(result);
}
if (streamWriter == null) {
try {
streamWriter = getOutputFactory().createXMLStreamWriter(result);
}
catch (XMLStreamException ex) {
// ignore
}
}
return streamWriter;
}
/**
* Template method. Subclasses must implement this. Offers the request payload as a <code>XMLStreamReader</code>,
* and a <code>XMLStreamWriter</code> to write the response payload to.
*
* @param streamReader the reader to read the payload from
* @param streamWriter the writer to write the payload to
*/
protected abstract void invokeInternal(XMLStreamReader streamReader, XMLStreamWriter streamWriter) throws Exception;
/**
* Implementation of the <code>XMLStreamWriter</code> interface that creates a response
* <code>WebServiceMessage</code> as soon as any method is called, thus lazily creating the response.
*/
private class ResponseCreatingStreamWriter implements XMLStreamWriter {
private MessageContext messageContext;
private XMLStreamWriter streamWriter;
private ByteArrayOutputStream os;
private ResponseCreatingStreamWriter(MessageContext messageContext) {
this.messageContext = messageContext;
}
public NamespaceContext getNamespaceContext() {
return streamWriter.getNamespaceContext();
}
public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
createStreamWriter();
streamWriter.setNamespaceContext(context);
}
public void close() throws XMLStreamException {
if (streamWriter != null) {
streamWriter.close();
if (os != null) {
streamWriter.flush();
// if we used an output stream cache, we have to transform it to the response again
try {
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
transform(new StreamSource(is), messageContext.getResponse().getPayloadResult());
os = null;
}
catch (TransformerException ex) {
throw new XMLStreamException(ex);
}
}
streamWriter = null;
}
}
public void flush() throws XMLStreamException {
if (streamWriter != null) {
streamWriter.flush();
}
}
public String getPrefix(String uri) throws XMLStreamException {
createStreamWriter();
return streamWriter.getPrefix(uri);
}
public Object getProperty(String name) throws IllegalArgumentException {
return streamWriter.getProperty(name);
}
public void setDefaultNamespace(String uri) throws XMLStreamException {
createStreamWriter();
streamWriter.setDefaultNamespace(uri);
}
public void setPrefix(String prefix, String uri) throws XMLStreamException {
createStreamWriter();
streamWriter.setPrefix(prefix, uri);
}
public void writeAttribute(String localName, String value) throws XMLStreamException {
createStreamWriter();
streamWriter.writeAttribute(localName, value);
}
public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException {
createStreamWriter();
streamWriter.writeAttribute(namespaceURI, localName, value);
}
public void writeAttribute(String prefix, String namespaceURI, String localName, String value)
throws XMLStreamException {
createStreamWriter();
streamWriter.writeAttribute(prefix, namespaceURI, localName, value);
}
public void writeCData(String data) throws XMLStreamException {
createStreamWriter();
streamWriter.writeCData(data);
}
public void writeCharacters(String text) throws XMLStreamException {
createStreamWriter();
streamWriter.writeCharacters(text);
}
public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
createStreamWriter();
streamWriter.writeCharacters(text, start, len);
}
public void writeComment(String data) throws XMLStreamException {
createStreamWriter();
streamWriter.writeComment(data);
}
public void writeDTD(String dtd) throws XMLStreamException {
createStreamWriter();
streamWriter.writeDTD(dtd);
}
public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
createStreamWriter();
streamWriter.writeDefaultNamespace(namespaceURI);
}
public void writeEmptyElement(String localName) throws XMLStreamException {
createStreamWriter();
streamWriter.writeEmptyElement(localName);
}
public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
createStreamWriter();
streamWriter.writeEmptyElement(namespaceURI, localName);
}
public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
createStreamWriter();
streamWriter.writeEmptyElement(prefix, localName, namespaceURI);
}
public void writeEndDocument() throws XMLStreamException {
createStreamWriter();
streamWriter.writeEndDocument();
}
public void writeEndElement() throws XMLStreamException {
createStreamWriter();
streamWriter.writeEndElement();
}
public void writeEntityRef(String name) throws XMLStreamException {
createStreamWriter();
streamWriter.writeEntityRef(name);
}
public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
createStreamWriter();
streamWriter.writeNamespace(prefix, namespaceURI);
}
public void writeProcessingInstruction(String target) throws XMLStreamException {
createStreamWriter();
streamWriter.writeProcessingInstruction(target);
}
public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
createStreamWriter();
streamWriter.writeProcessingInstruction(target, data);
}
public void writeStartDocument() throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartDocument();
}
public void writeStartDocument(String version) throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartDocument(version);
}
public void writeStartDocument(String encoding, String version) throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartDocument(encoding, version);
}
public void writeStartElement(String localName) throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartElement(localName);
}
public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartElement(namespaceURI, localName);
}
public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
createStreamWriter();
streamWriter.writeStartElement(prefix, localName, namespaceURI);
}
private void createStreamWriter() throws XMLStreamException {
if (streamWriter == null) {
WebServiceMessage response = messageContext.getResponse();
streamWriter = getStreamWriter(response.getPayloadResult());
if (streamWriter == null) {
// as a final resort, use a stream, and transform that at endDocument()
os = new ByteArrayOutputStream();
streamWriter = getOutputFactory().createXMLStreamWriter(os);
}
}
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import org.springframework.ws.context.MessageContext;
/**
* Extension of the {@link AbstractMarshallingPayloadEndpoint} which validates the request payload with {@link
* Validator}(s). The desired validators can be set using properties, and <strong>must</strong> {@link
* Validator#supports(Class) support} the request object.
*
* @author Arjen Poutsma
* @since 1.0.2
*/
public abstract class AbstractValidatingMarshallingPayloadEndpoint extends AbstractMarshallingPayloadEndpoint {
/** Default request object name used for validating request objects. */
public static final String DEFAULT_REQUEST_NAME = "request";
private String requestName = DEFAULT_REQUEST_NAME;
private Validator[] validators;
/** Return the name of the request object for validation error codes. */
public String getRequestName() {
return requestName;
}
/** Set the name of the request object user for validation errors. */
public void setRequestName(String requestName) {
this.requestName = requestName;
}
/** Return the primary Validator for this controller. */
public Validator getValidator() {
Validator[] validators = getValidators();
return (validators != null && validators.length > 0 ? validators[0] : null);
}
/**
* Set the primary {@link Validator} for this endpoint. The {@link Validator} is must support the unmarshalled
* class. If there are one or more existing validators set already when this method is called, only the specified
* validator will be kept. Use {@link #setValidators(Validator[])} to set multiple validators.
*/
public void setValidator(Validator validator) {
this.validators = new Validator[]{validator};
}
/** Return the Validators for this controller. */
public Validator[] getValidators() {
return validators;
}
/** Set the Validators for this controller. The Validator must support the specified command class. */
public void setValidators(Validator[] validators) {
this.validators = validators;
}
@Override
protected boolean onUnmarshalRequest(MessageContext messageContext, Object requestObject) throws Exception {
Validator[] validators = getValidators();
if (validators != null) {
Errors errors = new BindException(requestObject, getRequestName());
for (Validator validator : validators) {
ValidationUtils.invokeValidator(validator, requestObject, errors);
}
if (errors.hasErrors()) {
return onValidationErrors(messageContext, requestObject, errors);
}
}
return true;
}
/**
* Callback for post-processing validation errors. Called when validator(s) have been specified, and validation
* fails.
*
* @param messageContext the message context
* @param requestObject the object unmarshalled from the {@link MessageContext#getRequest() request}
* @param errors validation errors holder
* @return <code>true</code> to continue and call {@link #invokeInternal(Object)}; <code>false</code> otherwise
*/
protected abstract boolean onValidationErrors(MessageContext messageContext, Object requestObject, Errors errors);
}

View File

@@ -0,0 +1,329 @@
/*
* Copyright 2005-2010 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.server.endpoint;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Locale;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.springframework.core.NestedRuntimeException;
import org.springframework.xml.namespace.QNameUtils;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.xml.transform.TraxUtils;
import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.NodeFactory;
import nu.xom.ParentNode;
import nu.xom.ParsingException;
import nu.xom.Serializer;
import nu.xom.ValidityException;
import nu.xom.converters.DOMConverter;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
/**
* Abstract base class for endpoints that handle the message payload as XOM elements. Offers the message payload as a
* XOM <code>Element</code>, and allows subclasses to create a response by returning an <code>Element</code>.
* <p/>
* An <code>AbstractXomPayloadEndpoint</code> only accept one payload element. Multiple payload elements are not in
* accordance with WS-I.
*
* @author Arjen Poutsma
* @see Element
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of annotated endpoints
*/
@Deprecated
@SuppressWarnings("Since15")
public abstract class AbstractXomPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
public final Source invoke(Source request) throws Exception {
Element requestElement = null;
if (request != null) {
XomSourceCallback sourceCallback = new XomSourceCallback();
try {
TraxUtils.doWithSource(request, sourceCallback);
}
catch (XomParsingException ex) {
throw (ParsingException) ex.getCause();
}
requestElement = sourceCallback.element;
}
Element responseElement = invokeInternal(requestElement);
return responseElement != null ? convertResponse(responseElement) : null;
}
private Source convertResponse(Element responseElement) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Serializer serializer = createSerializer(os);
Document document = responseElement.getDocument();
if (document == null) {
document = new Document(responseElement);
}
serializer.write(document);
byte[] bytes = os.toByteArray();
return new StreamSource(new ByteArrayInputStream(bytes));
}
/**
* Creates a {@link Serializer} to be used for writing the response to.
* <p/>
* Default implementation uses the UTF-8 encoding and does not set any options, but this may be changed in
* subclasses.
*
* @param outputStream the output stream to serialize to
* @return the serializer
*/
protected Serializer createSerializer(OutputStream outputStream) {
return new Serializer(outputStream);
}
/**
* Template method. Subclasses must implement this. Offers the request payload as a XOM <code>Element</code>, and
* allows subclasses to return a response <code>Element</code>.
*
* @param requestElement the contents of the SOAP message as XOM element
* @return the response element. Can be <code>null</code> to specify no response.
*/
protected abstract Element invokeInternal(Element requestElement) throws Exception;
private static class XomSourceCallback implements TraxUtils.SourceCallback {
private Element element;
public void domSource(Node node) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
element = DOMConverter.convert((org.w3c.dom.Element) node);
}
else if (node.getNodeType() == Node.DOCUMENT_NODE) {
Document document = DOMConverter.convert((org.w3c.dom.Document) node);
element = document.getRootElement();
}
else {
throw new IllegalArgumentException("DOMSource contains neither Document nor Element");
}
}
public void saxSource(XMLReader reader, InputSource inputSource) throws IOException, SAXException {
try {
Builder builder = new Builder(reader);
Document document;
if (inputSource.getByteStream() != null) {
document = builder.build(inputSource.getByteStream());
}
else if (inputSource.getCharacterStream() != null) {
document = builder.build(inputSource.getCharacterStream());
}
else {
throw new IllegalArgumentException(
"InputSource in SAXSource contains neither byte stream nor character stream");
}
element = document.getRootElement();
}
catch (ValidityException ex) {
throw new XomParsingException(ex);
}
catch (ParsingException ex) {
throw new XomParsingException(ex);
}
}
public void staxSource(XMLEventReader eventReader) throws XMLStreamException {
throw new IllegalArgumentException("XMLEventReader not supported");
}
public void staxSource(XMLStreamReader streamReader) throws XMLStreamException {
Document document = StaxStreamConverter.convert(streamReader);
element = document.getRootElement();
}
public void streamSource(InputStream inputStream) throws IOException {
try {
Builder builder = new Builder();
Document document = builder.build(inputStream);
element = document.getRootElement();
}
catch (ParsingException ex) {
throw new XomParsingException(ex);
}
}
public void streamSource(Reader reader) throws IOException {
try {
Builder builder = new Builder();
Document document = builder.build(reader);
element = document.getRootElement();
}
catch (ParsingException ex) {
throw new XomParsingException(ex);
}
}
public void source(String systemId) throws Exception {
try {
Builder builder = new Builder();
Document document = builder.build(systemId);
element = document.getRootElement();
}
catch (ParsingException ex) {
throw new XomParsingException(ex);
}
}
}
private static class XomParsingException extends NestedRuntimeException {
private XomParsingException(ParsingException ex) {
super(ex.getMessage(), ex);
}
}
private static class StaxStreamConverter {
private static Document convert(XMLStreamReader streamReader) throws XMLStreamException {
NodeFactory nodeFactory = new NodeFactory();
Document document = null;
Element element = null;
ParentNode parent = null;
boolean documentFinished = false;
while (streamReader.hasNext()) {
int event = streamReader.next();
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
document = nodeFactory.startMakingDocument();
parent = document;
break;
case XMLStreamConstants.END_DOCUMENT:
nodeFactory.finishMakingDocument(document);
documentFinished = true;
break;
case XMLStreamConstants.START_ELEMENT:
if (document == null) {
document = nodeFactory.startMakingDocument();
parent = document;
}
String name = QNameUtils.toQualifiedName(streamReader.getName());
if (element == null) {
element = nodeFactory.makeRootElement(name, streamReader.getNamespaceURI());
document.setRootElement(element);
}
else {
element = nodeFactory.startMakingElement(name, streamReader.getNamespaceURI());
parent.appendChild(element);
}
convertNamespaces(streamReader, element);
convertAttributes(streamReader, nodeFactory);
parent = element;
break;
case XMLStreamConstants.END_ELEMENT:
nodeFactory.finishMakingElement(element);
parent = parent.getParent();
break;
case XMLStreamConstants.ATTRIBUTE:
convertAttributes(streamReader, nodeFactory);
break;
case XMLStreamConstants.CHARACTERS:
nodeFactory.makeText(streamReader.getText());
break;
case XMLStreamConstants.COMMENT:
nodeFactory.makeComment(streamReader.getText());
break;
default:
break;
}
}
if (!documentFinished) {
nodeFactory.finishMakingDocument(document);
}
return document;
}
private static void convertNamespaces(XMLStreamReader streamReader, Element element) {
for (int i = 0; i < streamReader.getNamespaceCount(); i++) {
String uri = streamReader.getNamespaceURI(i);
String prefix = streamReader.getNamespacePrefix(i);
element.addNamespaceDeclaration(prefix, uri);
}
}
private static void convertAttributes(XMLStreamReader streamReader, NodeFactory nodeFactory) {
for (int i = 0; i < streamReader.getAttributeCount(); i++) {
String name = QNameUtils.toQualifiedName(streamReader.getAttributeName(i));
String uri = streamReader.getAttributeNamespace(i);
String value = streamReader.getAttributeValue(i);
Attribute.Type type = convertAttributeType(streamReader.getAttributeType(i));
nodeFactory.makeAttribute(name, uri, value, type);
}
}
private static Attribute.Type convertAttributeType(String type) {
type = type.toUpperCase(Locale.ENGLISH);
if ("CDATA".equals(type)) {
return Attribute.Type.CDATA;
}
else if ("ENTITIES".equals(type)) {
return Attribute.Type.ENTITIES;
}
else if ("ENTITY".equals(type)) {
return Attribute.Type.ENTITY;
}
else if ("ENUMERATION".equals(type)) {
return Attribute.Type.ENUMERATION;
}
else if ("ID".equals(type)) {
return Attribute.Type.ID;
}
else if ("IDREF".equals(type)) {
return Attribute.Type.IDREF;
}
else if ("IDREFS".equals(type)) {
return Attribute.Type.IDREFS;
}
else if ("NMTOKEN".equals(type)) {
return Attribute.Type.NMTOKEN;
}
else if ("NMTOKENS".equals(type)) {
return Attribute.Type.NMTOKENS;
}
else if ("NOTATION".equals(type)) {
return Attribute.Type.NOTATION;
}
else {
return Attribute.Type.UNDECLARED;
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2005 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.server.endpoint;
import org.springframework.ws.context.MessageContext;
/**
* Defines the basic contract for Web Services interested in the entire message payload.
* <p/>
* <p>The main entrypoint is {@link #invoke(MessageContext)}, which gets invoked with the message context. This context
* contains the {@link MessageContext#getRequest() request}, and can be used to create a response.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.PayloadEndpoint
* @since 1.0.0
*/
public interface MessageEndpoint {
/**
* Invokes an operation.
* <p/>
* <p>The given <code>messageContext</code> can be used to create a response.
*
* @param messageContext the message context
* @throws Exception if an exception occurs
*/
void invoke(MessageContext messageContext) throws Exception;
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2005-2012 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.server.endpoint;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* Represents a bean method that will be invoked as part of an incoming Web service message.
* <p/>
* Consists of a {@link Method}, and a bean {@link Object}.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public final class MethodEndpoint {
private final Object bean;
private final Method method;
private final BeanFactory beanFactory;
/**
* Constructs a new method endpoint with the given bean and method.
*
* @param bean the object bean
* @param method the method
*/
public MethodEndpoint(Object bean, Method method) {
Assert.notNull(bean, "bean must not be null");
Assert.notNull(method, "method must not be null");
this.bean = bean;
this.method = method;
this.beanFactory = null;
}
/**
* Constructs a new method endpoint with the given bean, method name and parameters.
*
* @param bean the object bean
* @param methodName the method name
* @param parameterTypes the method parameter types
* @throws NoSuchMethodException when the method cannot be found
*/
public MethodEndpoint(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
Assert.notNull(bean, "bean must not be null");
Assert.notNull(methodName, "method must not be null");
this.bean = bean;
this.method = bean.getClass().getMethod(methodName, parameterTypes);
this.beanFactory = null;
}
/**
* Constructs a new method endpoint with the given bean name and method. The bean name will be lazily initialized when
* {@link #invoke(Object...)} is called.
*
* @param beanName the bean name
* @param beanFactory the bean factory to use for bean initialization
* @param method the method
*/
public MethodEndpoint(String beanName, BeanFactory beanFactory, Method method) {
Assert.hasText(beanName, "'beanName' must not be null");
Assert.notNull(beanFactory, "'beanFactory' must not be null");
Assert.notNull(method, "'method' must not be null");
Assert.isTrue(beanFactory.containsBean(beanName),
"Bean factory [" + beanFactory + "] does not contain bean " + "with name [" + beanName + "]");
this.bean = beanName;
this.beanFactory = beanFactory;
this.method = method;
}
/** Returns the object bean for this method endpoint. */
public Object getBean() {
if (beanFactory != null && bean instanceof String) {
String beanName = (String) bean;
return beanFactory.getBean(beanName);
}
else {
return bean;
}
}
/** Returns the method for this method endpoint. */
public Method getMethod() {
return this.method;
}
/** Returns the method parameters for this method endpoint. */
public MethodParameter[] getMethodParameters() {
int parameterCount = getMethod().getParameterTypes().length;
MethodParameter[] parameters = new MethodParameter[parameterCount];
for (int i = 0; i < parameterCount; i++) {
parameters[i] = new MethodParameter(getMethod(), i);
}
return parameters;
}
/** Returns the method return type, as {@code MethodParameter}. */
public MethodParameter getReturnType() {
return new MethodParameter(method, -1);
}
/**
* Invokes this method endpoint with the given arguments.
*
* @param args the arguments
* @return the invocation result
* @throws Exception when the method invocation results in an exception
*/
public Object invoke(Object... args) throws Exception {
Object endpoint = getBean();
ReflectionUtils.makeAccessible(method);
try {
return method.invoke(endpoint, args);
}
catch (InvocationTargetException ex) {
handleInvocationTargetException(ex);
throw new IllegalStateException(
"Unexpected exception thrown by method - " + ex.getTargetException().getClass().getName() + ": " +
ex.getTargetException().getMessage());
}
}
private void handleInvocationTargetException(InvocationTargetException ex) throws Exception {
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
if (targetException instanceof Error) {
throw (Error) targetException;
}
if (targetException instanceof Exception) {
throw (Exception) targetException;
}
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o != null && o instanceof MethodEndpoint) {
MethodEndpoint other = (MethodEndpoint) o;
return this.bean.equals(other.bean) && this.method.equals(other.method);
}
return false;
}
public int hashCode() {
return 31 * this.bean.hashCode() + this.method.hashCode();
}
public String toString() {
return method.toGenericString();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2005 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.server.endpoint;
import javax.xml.transform.Source;
/**
* Defines the basic contract for Web Services interested in just the message payload.
* <p/>
* The main entrypoint is {@link #invoke(Source)}, which gets invoked with the contents of the requesting message.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public interface PayloadEndpoint {
/**
* Invokes the endpoint with the given request payload, and possibly returns a response.
*
* @param request the payload of the request message, may be <code>null</code>
* @return the payload of the response message, may be <code>null</code> to indicate no response
* @throws Exception if an exception occurs
*/
Source invoke(Source request) throws Exception;
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for {@link EndpointAdapter} implementations that support {@link MethodEndpoint}s. Contains
* template methods for handling these method endpoints.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractMethodEndpointAdapter extends TransformerObjectSupport implements EndpointAdapter {
/**
* Delegates to {@link #supportsInternal(org.springframework.ws.server.endpoint.MethodEndpoint)}.
*
* @param endpoint endpoint object to check
* @return whether or not this adapter can adapt the given endpoint
*/
public final boolean supports(Object endpoint) {
return endpoint instanceof MethodEndpoint && supportsInternal((MethodEndpoint) endpoint);
}
/**
* Delegates to {@link #invokeInternal(org.springframework.ws.context.MessageContext,MethodEndpoint)}.
*
* @param messageContext the current message context
* @param endpoint the endpoint to use. This object must have previously been passed to the
* <code>supportsInternal</code> method of this interface, which must have returned
* <code>true</code>
* @throws Exception in case of errors
*/
public final void invoke(MessageContext messageContext, Object endpoint) throws Exception {
invokeInternal(messageContext, (MethodEndpoint) endpoint);
}
/**
* Given a method endpoint, return whether or not this adapter can support it.
*
* @param methodEndpoint method endpoint to check
* @return whether or not this adapter can adapt the given method
*/
protected abstract boolean supportsInternal(MethodEndpoint methodEndpoint);
/**
* Use the given method endpoint to handle the request.
*
* @param messageContext the current message context
* @param methodEndpoint the method endpoint to use
* @throws Exception in case of errors
*/
protected abstract void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint)
throws Exception;
}

View File

@@ -0,0 +1,302 @@
/*
* Copyright 2005-2012 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.server.endpoint.adapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;
/**
* Default extension of {@link AbstractMethodEndpointAdapter} with support for pluggable {@linkplain
* MethodArgumentResolver argument resolvers} and {@linkplain MethodReturnValueHandler return value handlers}.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
implements BeanClassLoaderAware, InitializingBean {
private static final String DOM4J_CLASS_NAME = "org.dom4j.Element";
private static final String JAXB2_CLASS_NAME = "javax.xml.bind.Binder";
private static final String JDOM_CLASS_NAME = "org.jdom2.Element";
private static final String STAX_CLASS_NAME = "javax.xml.stream.XMLInputFactory";
private static final String XOM_CLASS_NAME = "nu.xom.Element";
private static final String SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME =
"org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver";
private static final String SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME =
"org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver";
private List<MethodArgumentResolver> methodArgumentResolvers;
private List<MethodReturnValueHandler> methodReturnValueHandlers;
private ClassLoader classLoader;
/** Returns the list of {@code MethodArgumentResolver}s to use. */
public List<MethodArgumentResolver> getMethodArgumentResolvers() {
return methodArgumentResolvers;
}
/** Sets the list of {@code MethodArgumentResolver}s to use. */
public void setMethodArgumentResolvers(List<MethodArgumentResolver> methodArgumentResolvers) {
this.methodArgumentResolvers = methodArgumentResolvers;
}
/** Returns the list of {@code MethodReturnValueHandler}s to use. */
public List<MethodReturnValueHandler> getMethodReturnValueHandlers() {
return methodReturnValueHandlers;
}
/** Sets the list of {@code MethodReturnValueHandler}s to use. */
public void setMethodReturnValueHandlers(List<MethodReturnValueHandler> methodReturnValueHandlers) {
this.methodReturnValueHandlers = methodReturnValueHandlers;
}
private ClassLoader getClassLoader() {
return this.classLoader != null ? this.classLoader : DefaultMethodEndpointAdapter.class.getClassLoader();
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public void afterPropertiesSet() throws Exception {
initDefaultStrategies();
}
/** Initialize the default implementations for the adapter's strategies. */
protected void initDefaultStrategies() {
initMethodArgumentResolvers();
initMethodReturnValueHandlers();
}
private void initMethodArgumentResolvers() {
if (CollectionUtils.isEmpty(methodArgumentResolvers)) {
List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
methodArgumentResolvers.add(new DomPayloadMethodProcessor());
methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
methodArgumentResolvers.add(new XPathParamMethodArgumentResolver());
addMethodArgumentResolver(SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
addMethodArgumentResolver(SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
if (isPresent(DOM4J_CLASS_NAME)) {
methodArgumentResolvers.add(new Dom4jPayloadMethodProcessor());
}
if (isPresent(JAXB2_CLASS_NAME)) {
methodArgumentResolvers.add(new XmlRootElementPayloadMethodProcessor());
methodArgumentResolvers.add(new JaxbElementPayloadMethodProcessor());
}
if (isPresent(JDOM_CLASS_NAME)) {
methodArgumentResolvers.add(new JDomPayloadMethodProcessor());
}
if (isPresent(STAX_CLASS_NAME)) {
methodArgumentResolvers.add(new StaxPayloadMethodArgumentResolver());
}
if (isPresent(XOM_CLASS_NAME)) {
methodArgumentResolvers.add(new XomPayloadMethodProcessor());
}
if (logger.isDebugEnabled()) {
logger.debug("No MethodArgumentResolvers set, using defaults: " + methodArgumentResolvers);
}
setMethodArgumentResolvers(methodArgumentResolvers);
}
}
/**
* Certain (SOAP-specific) {@code MethodArgumentResolver}s have to be instantiated by class name, in order to not
* introduce a cyclic dependency.
*/
@SuppressWarnings("unchecked")
private void addMethodArgumentResolver(String className, List<MethodArgumentResolver> methodArgumentResolvers) {
try {
Class<MethodArgumentResolver> methodArgumentResolverClass =
(Class<MethodArgumentResolver>) ClassUtils.forName(className, getClassLoader());
methodArgumentResolvers.add(BeanUtils.instantiate(methodArgumentResolverClass));
}
catch (ClassNotFoundException e) {
logger.warn("Could not find \"" + className + "\" on the classpath");
}
}
private void initMethodReturnValueHandlers() {
if (CollectionUtils.isEmpty(methodReturnValueHandlers)) {
List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
methodReturnValueHandlers.add(new DomPayloadMethodProcessor());
methodReturnValueHandlers.add(new SourcePayloadMethodProcessor());
if (isPresent(DOM4J_CLASS_NAME)) {
methodReturnValueHandlers.add(new Dom4jPayloadMethodProcessor());
}
if (isPresent(JAXB2_CLASS_NAME)) {
methodReturnValueHandlers.add(new XmlRootElementPayloadMethodProcessor());
methodReturnValueHandlers.add(new JaxbElementPayloadMethodProcessor());
}
if (isPresent(JDOM_CLASS_NAME)) {
methodReturnValueHandlers.add(new JDomPayloadMethodProcessor());
}
if (isPresent(XOM_CLASS_NAME)) {
methodReturnValueHandlers.add(new XomPayloadMethodProcessor());
}
if (logger.isDebugEnabled()) {
logger.debug("No MethodReturnValueHandlers set, using defaults: " + methodReturnValueHandlers);
}
setMethodReturnValueHandlers(methodReturnValueHandlers);
}
}
private boolean isPresent(String className) {
return ClassUtils.isPresent(className, getClassLoader());
}
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
return supportsParameters(methodEndpoint.getMethodParameters()) &&
supportsReturnType(methodEndpoint.getReturnType());
}
private boolean supportsParameters(MethodParameter[] methodParameters) {
for (MethodParameter methodParameter : methodParameters) {
boolean supported = false;
for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
methodParameter.getGenericParameterType() + "]");
}
if (methodArgumentResolver.supportsParameter(methodParameter)) {
supported = true;
break;
}
}
if (!supported) {
return false;
}
}
return true;
}
private boolean supportsReturnType(MethodParameter methodReturnType) {
if (Void.TYPE.equals(methodReturnType.getParameterType())) {
return true;
}
for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
if (methodReturnValueHandler.supportsReturnType(methodReturnType)) {
return true;
}
}
return false;
}
@Override
protected final void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
Object[] args = getMethodArguments(messageContext, methodEndpoint);
if (logger.isTraceEnabled()) {
StringBuilder builder = new StringBuilder("Invoking [");
builder.append(methodEndpoint).append("] with arguments ");
builder.append(Arrays.asList(args));
logger.trace(builder.toString());
}
Object returnValue = methodEndpoint.invoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + methodEndpoint + "] returned [" + returnValue + "]");
}
Class<?> returnType = methodEndpoint.getMethod().getReturnType();
if (!Void.TYPE.equals(returnType)) {
handleMethodReturnValue(messageContext, returnValue, methodEndpoint);
}
}
/**
* Returns the argument array for the given method endpoint.
* <p/>
* This implementation iterates over the set {@linkplain #setMethodArgumentResolvers(List) argument resolvers} to
* resolve each argument.
*
* @param messageContext the current message context
* @param methodEndpoint the method endpoint to get arguments for
* @return the arguments
* @throws Exception in case of errors
*/
protected Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint)
throws Exception {
MethodParameter[] parameters = methodEndpoint.getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameters[i])) {
args[i] = methodArgumentResolver.resolveArgument(messageContext, parameters[i]);
break;
}
}
}
return args;
}
/**
* Handle the return value for the given method endpoint.
* <p/>
* This implementation iterates over the set {@linkplain #setMethodReturnValueHandlers(java.util.List)} return value
* handlers} to resolve the return value.
*
* @param messageContext the current message context
* @param returnValue the return value
* @param methodEndpoint the method endpoint to get arguments for
* @throws Exception in case of errors
*/
protected void handleMethodReturnValue(MessageContext messageContext,
Object returnValue,
MethodEndpoint methodEndpoint) throws Exception {
MethodParameter returnType = methodEndpoint.getReturnType();
for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
if (methodReturnValueHandler.supportsReturnType(returnType)) {
methodReturnValueHandler.handleReturnValue(messageContext, returnType, returnValue);
return;
}
}
throw new IllegalStateException(
"Return value [" + returnValue + "] not resolved by any MethodReturnValueHandler");
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter;
import java.lang.reflect.Method;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.server.endpoint.MethodEndpoint;
/**
* Subclass of {@link MarshallingMethodEndpointAdapter} that supports {@link GenericMarshaller} and {@link
* GenericUnmarshaller}. More specifically, this adapter is aware of the {@link Method#getGenericParameterTypes()} and
* {@link Method#getGenericReturnType()}.
* <p/>
* Prefer to use this adapter rather than the plain {@link MarshallingMethodEndpointAdapter} in combination with Java 5
* marshallers, such as the {@link Jaxb2Marshaller}.
*
* @author Arjen Poutsma
* @since 1.0.2
* @deprecated as of Spring Web Services 2.0, in favor of {@link DefaultMethodEndpointAdapter} and {@link
* org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor
* MarshallingPayloadMethodProcessor}.
*/
@Deprecated
public class GenericMarshallingMethodEndpointAdapter extends MarshallingMethodEndpointAdapter {
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link
* Unmarshaller} must be injected using properties.
*
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
public GenericMarshallingMethodEndpointAdapter() {
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring-WS also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller) {
super(marshaller);
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller, Unmarshaller unmarshaller) {
super(marshaller, unmarshaller);
}
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return supportsReturnType(method) && supportsParameters(method);
}
private boolean supportsReturnType(Method method) {
if (Void.TYPE.equals(method.getReturnType())) {
return true;
}
else {
if (getMarshaller() instanceof GenericMarshaller) {
return ((GenericMarshaller) getMarshaller()).supports(method.getGenericReturnType());
}
else {
return getMarshaller().supports(method.getReturnType());
}
}
}
private boolean supportsParameters(Method method) {
if (method.getParameterTypes().length != 1) {
return false;
}
else if (getUnmarshaller() instanceof GenericUnmarshaller) {
GenericUnmarshaller genericUnmarshaller = (GenericUnmarshaller) getUnmarshaller();
return genericUnmarshaller.supports(method.getGenericParameterTypes()[0]);
}
else {
return getUnmarshaller().supports(method.getParameterTypes()[0]);
}
}
}

View File

@@ -0,0 +1,187 @@
/*
* Copyright 2005-2011 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.server.endpoint.adapter;
import java.io.IOException;
import java.lang.reflect.Method;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.support.MarshallingUtils;
/**
* Adapter that supports endpoint methods that use marshalling. Supports methods with the following signature:
* <pre>
* void handleMyMessage(MyUnmarshalledType request);
* </pre>
* or
* <pre>
* MyMarshalledType handleMyMessage(MyUnmarshalledType request);
* </pre>
* I.e. methods that take a single parameter that {@link Unmarshaller#supports(Class) is supported} by the {@link
* Unmarshaller}, and return either <code>void</code> or a type {@link Marshaller#supports(Class) supported} by the
* {@link Marshaller}. The method can have any name, as long as it is mapped by an {@link EndpointMapping}.
* <p/>
* This endpoint needs a <code>Marshaller</code> and <code>Unmarshaller</code>, both of which can be set using
* properties.
*
* @author Arjen Poutsma
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link DefaultMethodEndpointAdapter} and {@link
* org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor
* MarshallingPayloadMethodProcessor}.
*/
@Deprecated
public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdapter implements InitializingBean {
private Marshaller marshaller;
private Unmarshaller unmarshaller;
/**
* Creates a new <code>MarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link Unmarshaller} must
* be injected using properties.
*
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
public MarshallingMethodEndpointAdapter() {
}
/**
* Creates a new <code>MarshallingMethodEndpointAdapter</code> with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
*/
public MarshallingMethodEndpointAdapter(Marshaller marshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
if (!(marshaller instanceof Unmarshaller)) {
throw new IllegalArgumentException("Marshaller [" + marshaller + "] does not implement the Unmarshaller " +
"interface. Please set an Unmarshaller explicitly by using the " +
"MarshallingMethodEndpointAdapter(Marshaller, Unmarshaller) constructor.");
}
else {
this.setMarshaller(marshaller);
this.setUnmarshaller((Unmarshaller) marshaller);
}
}
/**
* Creates a new <code>MarshallingMethodEndpointAdapter</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
public MarshallingMethodEndpointAdapter(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.notNull(unmarshaller, "unmarshaller must not be null");
this.setMarshaller(marshaller);
this.setUnmarshaller(unmarshaller);
}
/** Returns the marshaller used for transforming objects into XML. */
public Marshaller getMarshaller() {
return marshaller;
}
/** Sets the marshaller used for transforming objects into XML. */
public final void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/** Returns the unmarshaller used for transforming XML into objects. */
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
/** Sets the unmarshaller used for transforming XML into objects. */
public final void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(getMarshaller(), "marshaller is required");
Assert.notNull(getUnmarshaller(), "unmarshaller is required");
}
@Override
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
WebServiceMessage request = messageContext.getRequest();
Object requestObject = unmarshalRequest(request);
Object responseObject = methodEndpoint.invoke(new Object[]{requestObject});
if (responseObject != null) {
WebServiceMessage response = messageContext.getResponse();
marshalResponse(responseObject, response);
}
}
private Object unmarshalRequest(WebServiceMessage request) throws IOException {
Object requestObject = MarshallingUtils.unmarshal(getUnmarshaller(), request);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
}
return requestObject;
}
private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException {
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + responseObject + "] to response payload");
}
MarshallingUtils.marshal(getMarshaller(), responseObject, response);
}
/**
* Supports a method with a single, unmarshallable parameter, and that return <code>void</code> or a marshallable
* type.
*
* @see Marshaller#supports(Class)
* @see Unmarshaller#supports(Class)
*/
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return supportsReturnType(method) && supportsParameters(method);
}
private boolean supportsReturnType(Method method) {
return (Void.TYPE.equals(method.getReturnType()) || getMarshaller().supports(method.getReturnType()));
}
private boolean supportsParameters(Method method) {
if (method.getParameterTypes().length != 1) {
return false;
}
else {
return getUnmarshaller().supports(method.getParameterTypes()[0]);
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2005 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.server.endpoint.adapter;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
/**
* Adapter to use a <code>MessageEndpoint</code> as the endpoint for a <code>EndpointInvocationChain</code>.
* <p/>
* This adapter is registered by default by the {@link MessageDispatcher} and {@link SoapMessageDispatcher}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.EndpointInvocationChain
* @since 1.0.0
*/
public class MessageEndpointAdapter implements EndpointAdapter {
public boolean supports(Object endpoint) {
return endpoint instanceof MessageEndpoint;
}
public void invoke(MessageContext messageContext, Object endpoint) throws Exception {
((MessageEndpoint) endpoint).invoke(messageContext);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter;
import java.lang.reflect.Method;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
/**
* Adapter that supports endpoint methods with message contexts. Supports methods with the following signature:
* <pre>
* void handleMyMessage(MessageContext request);
* </pre>
* I.e. methods that take a single {@link MessageContext} parameter, and return <code>void</code>. The method can have
* any name, as long as it is mapped by an {@link org.springframework.ws.server.EndpointMapping}.
* <p/>
* This adapter is registered by default by the {@link MessageDispatcher} and {@link SoapMessageDispatcher}.
*
* @author Arjen Poutsma
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link DefaultMethodEndpointAdapter} and {@link
* org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver
* MessageContextMethodArgumentResolver}.
*/
@Deprecated
public class MessageMethodEndpointAdapter extends AbstractMethodEndpointAdapter {
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return Void.TYPE.isAssignableFrom(method.getReturnType()) && method.getParameterTypes().length == 1 &&
MessageContext.class.isAssignableFrom(method.getParameterTypes()[0]);
}
@Override
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
methodEndpoint.invoke(messageContext);
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2005 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.server.endpoint.adapter;
import javax.xml.transform.Source;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.server.endpoint.PayloadEndpoint;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Adapter to use a <code>PayloadEndpoint</code> as the endpoint for a <code>EndpointInvocationChain</code>.
* <p/>
* This adapter is registered by default by the {@link MessageDispatcher} and {@link SoapMessageDispatcher}.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.PayloadEndpoint
* @see org.springframework.ws.server.EndpointInvocationChain
* @since 1.0.0
*/
public class PayloadEndpointAdapter extends TransformerObjectSupport implements EndpointAdapter {
public boolean supports(Object endpoint) {
return endpoint instanceof PayloadEndpoint;
}
public void invoke(MessageContext messageContext, Object endpoint) throws Exception {
PayloadEndpoint payloadEndpoint = (PayloadEndpoint) endpoint;
Source requestSource = messageContext.getRequest().getPayloadSource();
Source responseSource = payloadEndpoint.invoke(requestSource);
if (responseSource != null) {
WebServiceMessage response = messageContext.getResponse();
transform(responseSource, response.getPayloadResult());
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter;
import java.lang.reflect.Method;
import javax.xml.transform.Source;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
/**
* Adapter that supports endpoint methods that use marshalling. Supports methods with the following signature:
* <pre>
* void handleMyMessage(Source request);
* </pre>
* or
* <pre>
* Source handleMyMessage(Source request);
* </pre>
* I.e. methods that take a single {@link Source} parameter, and return either <code>void</code> or a {@link Source}.
* The method can have any name, as long as it is mapped by an {@link org.springframework.ws.server.EndpointMapping}.
* <p/>
* This adapter is registered by default by the {@link MessageDispatcher} and {@link SoapMessageDispatcher}.
*
* @author Arjen Poutsma
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link DefaultMethodEndpointAdapter} and {@link
* org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor
* SourcePayloadMethodProcessor}.
*/
@Deprecated
public class PayloadMethodEndpointAdapter extends AbstractMethodEndpointAdapter {
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return (Void.TYPE.isAssignableFrom(method.getReturnType()) ||
Source.class.isAssignableFrom(method.getReturnType())) && method.getParameterTypes().length == 1 &&
Source.class.isAssignableFrom(method.getParameterTypes()[0]);
}
@Override
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
Source requestSource = messageContext.getRequest().getPayloadSource();
Object result = methodEndpoint.invoke(requestSource);
if (result != null) {
Source responseSource = (Source) result;
WebServiceMessage response = messageContext.getResponse();
transform(responseSource, response.getPayloadResult());
}
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.springframework.xml.namespace.SimpleNamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Adapter that supports endpoint methods that use XPath expressions. Supports methods with the following signature:
* <pre>
* void handleMyMessage(@XPathParam("/root/child/text")String param);
* </pre>
* or
* <pre>
* Source handleMyMessage(@XPathParam("/root/child/text")String param1, @XPathParam("/root/child/number")double
* param2);
* </pre>
* I.e. methods that return either <code>void</code> or a {@link Source}, and have parameters annotated with {@link
* XPathParam} that specify the XPath expression that should be bound to that parameter. The parameter can be of the
* following types: <ul> <li><code>boolean</code>, or {@link Boolean}</li> <li><code>double</code>, or {@link
* Double}</li> <li>{@link String}</li> <li>{@link Node}</li> <li>{@link NodeList}</li> </ul>
*
* @author Arjen Poutsma
* @since 1.0.0
* @deprecated as of Spring Web Services 2.0, in favor of {@link DefaultMethodEndpointAdapter} and {@link
* org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver
* XPathParamMethodArgumentResolver}.
*/
@Deprecated
public class XPathParamAnnotationMethodEndpointAdapter extends AbstractMethodEndpointAdapter
implements InitializingBean {
private XPathFactory xpathFactory;
private Map<String, String> namespaces;
/** Sets namespaces used in the XPath expression. Maps prefixes to namespaces. */
public void setNamespaces(Map<String, String> namespaces) {
this.namespaces = namespaces;
}
public void afterPropertiesSet() throws Exception {
xpathFactory = XPathFactory.newInstance();
}
/** Supports methods with @XPathParam parameters, and return either <code>Source</code> or nothing. */
@Override
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
if (!(Source.class.isAssignableFrom(method.getReturnType()) || Void.TYPE.equals(method.getReturnType()))) {
return false;
}
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
if (getXPathParamAnnotation(method, i) == null || !isSupportedType(parameterTypes[i])) {
return false;
}
}
return true;
}
private XPathParam getXPathParamAnnotation(Method method, int paramIdx) {
Annotation[][] paramAnnotations = method.getParameterAnnotations();
for (int annIdx = 0; annIdx < paramAnnotations[paramIdx].length; annIdx++) {
if (paramAnnotations[paramIdx][annIdx].annotationType().equals(XPathParam.class)) {
return (XPathParam) paramAnnotations[paramIdx][annIdx];
}
}
return null;
}
private boolean isSupportedType(Class<?> clazz) {
return Boolean.class.isAssignableFrom(clazz) || Boolean.TYPE.isAssignableFrom(clazz) ||
Double.class.isAssignableFrom(clazz) || Double.TYPE.isAssignableFrom(clazz) ||
Node.class.isAssignableFrom(clazz) || NodeList.class.isAssignableFrom(clazz) ||
String.class.isAssignableFrom(clazz);
}
@Override
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
Element payloadElement = getRootElement(messageContext.getRequest().getPayloadSource());
Object[] args = getMethodArguments(payloadElement, methodEndpoint.getMethod());
Object result = methodEndpoint.invoke(args);
if (result != null && result instanceof Source) {
Source responseSource = (Source) result;
WebServiceMessage response = messageContext.getResponse();
transform(responseSource, response.getPayloadResult());
}
}
private Object[] getMethodArguments(Element payloadElement, Method method) throws XPathExpressionException {
Class<?>[] parameterTypes = method.getParameterTypes();
XPath xpath = createXPath();
Object[] args = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
String expression = getXPathParamAnnotation(method, i).value();
QName conversionType;
if (Boolean.class.isAssignableFrom(parameterTypes[i]) || Boolean.TYPE.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.BOOLEAN;
}
else
if (Double.class.isAssignableFrom(parameterTypes[i]) || Double.TYPE.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NUMBER;
}
else if (Node.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NODE;
}
else if (NodeList.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NODESET;
}
else if (String.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.STRING;
}
else {
throw new IllegalArgumentException("Invalid parameter type [" + parameterTypes[i] + "]. " +
"Supported are: Boolean, Double, Node, NodeList, and String.");
}
args[i] = xpath.evaluate(expression, payloadElement, conversionType);
}
return args;
}
private synchronized XPath createXPath() {
XPath xpath = xpathFactory.newXPath();
if (namespaces != null) {
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
namespaceContext.setBindings(namespaces);
xpath.setNamespaceContext(namespaceContext);
}
return xpath;
}
/**
* Returns the root element of the given source.
*
* @param source the source to get the root element from
* @return the root element
*/
private Element getRootElement(Source source) throws TransformerException {
DOMResult domResult = new DOMResult();
transform(source, domResult);
Document document = (Document) domResult.getNode();
return document.getDocumentElement();
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} implementations based on
* {@link RequestPayload} and {@link ResponsePayload} annotations.
*
* @author Arjen Poutsma
* @since 2.0
*/
public abstract class AbstractPayloadMethodProcessor extends TransformerObjectSupport
implements MethodArgumentResolver, MethodReturnValueHandler {
// MethodArgumentResolver
/**
* {@inheritDoc}
* <p/>
* This implementation gets checks if the given parameter is annotated with {@link RequestPayload}, and invokes
* {@link #supportsRequestPayloadParameter(org.springframework.core.MethodParameter)} afterwards.
*/
public final boolean supportsParameter(MethodParameter parameter) {
Assert.isTrue(parameter.getParameterIndex() >= 0, "Parameter index larger smaller than 0");
if (parameter.getParameterAnnotation(RequestPayload.class) == null) {
return false;
}
else {
return supportsRequestPayloadParameter(parameter);
}
}
/**
* Indicates whether the given {@linkplain MethodParameter method parameter}, annotated with {@link RequestPayload},
* is supported by this resolver.
*
* @param parameter the method parameter to check
* @return {@code true} if this resolver supports the supplied parameter; {@code false} otherwise
*/
protected abstract boolean supportsRequestPayloadParameter(MethodParameter parameter);
// MethodReturnValueHandler
/**
* {@inheritDoc}
* <p/>
* This implementation gets checks if the method of the given return type is annotated with {@link ResponsePayload},
* and invokes {@link #supportsResponsePayloadReturnType(org.springframework.core.MethodParameter)} afterwards.
*/
public final boolean supportsReturnType(MethodParameter returnType) {
Assert.isTrue(returnType.getParameterIndex() == -1, "Parameter index is not -1");
if (returnType.getMethodAnnotation(ResponsePayload.class) == null) {
return false;
}
else {
return supportsResponsePayloadReturnType(returnType);
}
}
/**
* Indicates whether the given {@linkplain MethodParameter method return type}, annotated with {@link
* ResponsePayload}, is supported.
*
* @param returnType the method parameter to check
* @return {@code true} if this resolver supports the supplied return type; {@code false} otherwise
*/
protected abstract boolean supportsResponsePayloadReturnType(MethodParameter returnType);
/**
* Converts the given source to a byte array input stream.
*
* @param source the source to convert
* @return the input stream
* @throws javax.xml.transform.TransformerException in case of transformation errors
*/
protected ByteArrayInputStream convertToByteArrayInputStream(Source source) throws TransformerException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transform(source, new StreamResult(bos));
return new ByteArrayInputStream(bos.toByteArray());
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import javax.xml.transform.Source;
import org.springframework.core.MethodParameter;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
/**
* Abstract base class for {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} implementations based on
* {@link Source}s.
*
* @author Arjen Poutsma
* @since 2.0
*/
public abstract class AbstractPayloadSourceMethodProcessor extends AbstractPayloadMethodProcessor {
// MethodArgumentResolver
public final Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception {
Source requestPayload = getRequestPayload(messageContext);
return requestPayload != null ? resolveRequestPayloadArgument(parameter, requestPayload) : null;
}
/** Returns the request payload as {@code Source}. */
private Source getRequestPayload(MessageContext messageContext) {
WebServiceMessage request = messageContext.getRequest();
return request != null ? request.getPayloadSource() : null;
}
/**
* Resolves the given parameter, annotated with {@link RequestPayload}, into a method argument.
*
* @param parameter the parameter to resolve to an argument
* @param requestPayload the request payload
* @return the resolved argument. May be {@code null}.
* @throws Exception in case of errors
*/
protected abstract Object resolveRequestPayloadArgument(MethodParameter parameter, Source requestPayload)
throws Exception;
// MethodReturnValueHandler
public final void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws Exception {
if (returnValue != null) {
Source responsePayload = createResponsePayload(returnType, returnValue);
if (responsePayload != null) {
WebServiceMessage response = messageContext.getResponse();
transform(responsePayload, response.getPayloadResult());
}
}
}
/**
* Creates a response payload for the given return value.
*
* @param returnType the return type to handle
* @param returnValue the return value to handle
* @return the response payload
* @throws Exception in case of errors
*/
protected abstract Source createResponsePayload(MethodParameter returnType, Object returnValue) throws Exception;
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import org.springframework.core.MethodParameter;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.support.MarshallingUtils;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that uses {@link Marshaller}
* and {@link Unmarshaller} to support marshalled objects.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class MarshallingPayloadMethodProcessor extends AbstractPayloadMethodProcessor {
private Marshaller marshaller;
private Unmarshaller unmarshaller;
/**
* Creates a new {@code MarshallingPayloadMethodProcessor}. The {@link Marshaller} and {@link Unmarshaller} must be
* injected using properties.
*
* @see #setMarshaller(Marshaller)
* @see #setUnmarshaller(Unmarshaller)
*/
public MarshallingPayloadMethodProcessor() {
}
/**
* Creates a new {@code MarshallingPayloadMethodProcessor} with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring also implement the {@link Unmarshaller} interface, so
* that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when {@code marshaller} does not implement the {@link Unmarshaller} interface
*/
public MarshallingPayloadMethodProcessor(Marshaller marshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.isInstanceOf(Unmarshaller.class, marshaller);
setMarshaller(marshaller);
setUnmarshaller((Unmarshaller) marshaller);
}
/**
* Creates a new {@code MarshallingPayloadMethodProcessor} with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
public MarshallingPayloadMethodProcessor(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.notNull(unmarshaller, "unmarshaller must not be null");
setMarshaller(marshaller);
setUnmarshaller(unmarshaller);
}
/**
* Returns the marshaller used for transforming objects into XML.
*/
public Marshaller getMarshaller() {
return marshaller;
}
/**
* Sets the marshaller used for transforming objects into XML.
*/
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/**
* Returns the unmarshaller used for transforming XML into objects.
*/
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
/**
* Sets the unmarshaller used for transforming XML into objects.
*/
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
@Override
protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
Unmarshaller unmarshaller = getUnmarshaller();
if (unmarshaller == null) {
return false;
}
else if (unmarshaller instanceof GenericUnmarshaller) {
return ((GenericUnmarshaller) unmarshaller).supports(parameter.getGenericParameterType());
}
else {
return unmarshaller.supports(parameter.getParameterType());
}
}
public Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception {
Unmarshaller unmarshaller = getUnmarshaller();
Assert.state(unmarshaller != null, "unmarshaller must not be null");
WebServiceMessage request = messageContext.getRequest();
Object argument = MarshallingUtils.unmarshal(unmarshaller, request);
if (logger.isDebugEnabled()) {
logger.debug("Unmarshalled payload request to [" + argument + "]");
}
return argument;
}
@Override
protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
Marshaller marshaller = getMarshaller();
if (marshaller == null) {
return false;
}
else if (marshaller instanceof GenericMarshaller) {
GenericMarshaller genericMarshaller = (GenericMarshaller) marshaller;
return genericMarshaller.supports(returnType.getGenericParameterType());
}
else {
return marshaller.supports(returnType.getParameterType());
}
}
public void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws Exception {
Marshaller marshaller = getMarshaller();
Assert.state(marshaller != null, "marshaller must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Marshalling [" + returnValue + "] to response payload");
}
WebServiceMessage response = messageContext.getResponse();
MarshallingUtils.marshal(marshaller, returnValue, response);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import org.springframework.core.MethodParameter;
import org.springframework.ws.context.MessageContext;
/**
* Implementation of {@link MethodArgumentResolver} that supports {@link MessageContext} arguments.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class MessageContextMethodArgumentResolver implements MethodArgumentResolver {
public boolean supportsParameter(MethodParameter parameter) {
return MessageContext.class.equals(parameter.getParameterType());
}
public MessageContext resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception {
return messageContext;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import org.springframework.core.MethodParameter;
import org.springframework.ws.context.MessageContext;
/**
* Strategy interface used to resolve method parameters into arguments. This interface is used to allow the {@link
* org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter DefaultMethodEndpointAdapter} to be
* indefinitely extensible.
*
* @author Arjen Poutsma
* @since 2.0
*/
public interface MethodArgumentResolver {
/**
* Indicates whether the given {@linkplain MethodParameter method parameter} is supported by this resolver.
*
* @param parameter the method parameter to check
* @return {@code true} if this resolver supports the supplied parameter; {@code false} otherwise
*/
boolean supportsParameter(MethodParameter parameter);
/**
* Resolves the given parameter into a method argument.
*
* @param messageContext the current message context
* @param parameter the parameter to resolve to an argument. This parameter must have previously been passed to
* the {@link #supportsParameter(MethodParameter)} method of this interface, which must
* have returned {@code true}.
* @return the resolved argument. May be {@code null}.
* @throws Exception in case of errors
*/
Object resolveArgument(MessageContext messageContext, MethodParameter parameter) throws Exception;
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import org.springframework.core.MethodParameter;
import org.springframework.ws.context.MessageContext;
/**
* Strategy interface used to handle method return values. This interface is used to allow the {@link
* org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter DefaultMethodEndpointAdapter} to be
* indefinitely extensible.
*
* @author Arjen Poutsma
* @since 2.0
*/
public interface MethodReturnValueHandler {
/**
* Indicates whether the given {@linkplain MethodParameter method return type} is supported by this handler.
*
* @param returnType the method return type to check
* @return {@code true} if this handler supports the supplied return type; {@code false} otherwise
*/
boolean supportsReturnType(MethodParameter returnType);
/**
* Handles the given return value.
*
* @param messageContext the current message context
* @param returnType the return type to handle. This type must have previously been passed to the {@link
* #supportsReturnType(MethodParameter)} method of this interface, which must have returned
* {@code true}.
* @param returnValue the return value to handle
* @throws Exception in case of errors
*/
void handleReturnValue(MessageContext messageContext, MethodParameter returnType, Object returnValue)
throws Exception;
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import java.io.ByteArrayInputStream;
import javax.xml.stream.Location;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import org.springframework.core.MethodParameter;
import org.springframework.xml.JaxpVersion;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
/**
* Implementation of {@link MethodArgumentResolver} and {@link MethodReturnValueHandler} that supports {@link Source}
* objects.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class SourcePayloadMethodProcessor extends AbstractPayloadSourceMethodProcessor {
private XMLInputFactory inputFactory = createXmlInputFactory();
// MethodArgumentResolver
@Override
protected boolean supportsRequestPayloadParameter(MethodParameter parameter) {
return supports(parameter);
}
@Override
protected Source resolveRequestPayloadArgument(MethodParameter parameter, Source requestPayload) throws Exception {
Class<?> parameterType = parameter.getParameterType();
if (parameterType.isAssignableFrom(requestPayload.getClass())) {
return requestPayload;
}
if (DOMSource.class.isAssignableFrom(parameterType)) {
DOMResult domResult = new DOMResult();
transform(requestPayload, domResult);
Node node = domResult.getNode();
if (node.getNodeType() == Node.DOCUMENT_NODE) {
return new DOMSource(((Document) node).getDocumentElement());
}
else {
return new DOMSource(domResult.getNode());
}
}
else if (SAXSource.class.isAssignableFrom(parameterType)) {
ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
InputSource inputSource = new InputSource(bis);
return new SAXSource(inputSource);
}
else if (StreamSource.class.isAssignableFrom(parameterType)) {
ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
return new StreamSource(bis);
}
else if (JaxpVersion.isAtLeastJaxp14() && Jaxp14StaxHandler.isStaxSource(parameterType)) {
XMLStreamReader streamReader;
try {
streamReader = inputFactory.createXMLStreamReader(requestPayload);
} catch (UnsupportedOperationException ignored) {
streamReader = null;
}
catch (XMLStreamException ignored) {
streamReader = null;
}
if (streamReader == null) {
ByteArrayInputStream bis = convertToByteArrayInputStream(requestPayload);
streamReader = inputFactory.createXMLStreamReader(bis);
}
return Jaxp14StaxHandler.createStaxSource(streamReader, requestPayload.getSystemId());
}
throw new IllegalArgumentException("Unknown Source type: " + parameterType);
}
// MethodReturnValueHandler
@Override
protected boolean supportsResponsePayloadReturnType(MethodParameter returnType) {
return supports(returnType);
}
@Override
protected Source createResponsePayload(MethodParameter returnType, Object returnValue) {
return (Source) returnValue;
}
private boolean supports(MethodParameter parameter) {
return Source.class.isAssignableFrom(parameter.getParameterType());
}
/**
* Create a {@code XMLInputFactory} that this resolver will use to create {@link javax.xml.stream.XMLStreamReader}
* and {@link javax.xml.stream.XMLEventReader} objects.
* <p/>
* Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
* so this method will only be called once.
*
* @return the created factory
*/
protected XMLInputFactory createXmlInputFactory() {
return XMLInputFactory.newInstance();
}
/** Inner class to avoid a static JAXP 1.4 dependency. */
private static class Jaxp14StaxHandler {
private static boolean isStaxSource(Class<?> clazz) {
return StAXSource.class.isAssignableFrom(clazz);
}
private static Source createStaxSource(XMLStreamReader streamReader, String systemId) {
return new StAXSource(new SystemIdStreamReaderDelegate(streamReader, systemId));
}
}
private static class SystemIdStreamReaderDelegate extends StreamReaderDelegate {
private final String systemId;
private SystemIdStreamReaderDelegate(XMLStreamReader reader, String systemId) {
super(reader);
this.systemId = systemId;
}
@Override
public Location getLocation() {
final Location parentLocation = getParent().getLocation();
return new Location() {
public int getLineNumber() {
return parentLocation != null ? parentLocation.getLineNumber() : -1;
}
public int getColumnNumber() {
return parentLocation != null ? parentLocation.getColumnNumber() : -1;
}
public int getCharacterOffset() {
return parentLocation != null ? parentLocation.getLineNumber() : -1;
}
public String getPublicId() {
return parentLocation != null ? parentLocation.getPublicId() : null;
}
public String getSystemId() {
return systemId;
}
};
}
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import org.springframework.core.MethodParameter;
import org.springframework.util.xml.StaxUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Implementation of {@link MethodArgumentResolver} that supports StAX {@link XMLStreamReader} and {@link
* XMLEventReader} arguments.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class StaxPayloadMethodArgumentResolver extends TransformerObjectSupport implements MethodArgumentResolver {
private final XMLInputFactory inputFactory = createXmlInputFactory();
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.getParameterAnnotation(RequestPayload.class) == null) {
return false;
}
else {
Class<?> parameterType = parameter.getParameterType();
return XMLStreamReader.class.equals(parameterType) || XMLEventReader.class.equals(parameterType);
}
}
public Object resolveArgument(MessageContext messageContext, MethodParameter parameter)
throws TransformerException, XMLStreamException {
Source source = messageContext.getRequest().getPayloadSource();
if (source == null) {
return null;
}
Class<?> parameterType = parameter.getParameterType();
if (XMLStreamReader.class.equals(parameterType)) {
return resolveStreamReader(source);
}
else if (XMLEventReader.class.equals(parameterType)) {
return resolveEventReader(source);
}
throw new UnsupportedOperationException();
}
private XMLStreamReader resolveStreamReader(Source requestSource) throws TransformerException, XMLStreamException {
XMLStreamReader streamReader = null;
if (StaxUtils.isStaxSource(requestSource)) {
streamReader = StaxUtils.getXMLStreamReader(requestSource);
if (streamReader == null) {
XMLEventReader eventReader = StaxUtils.getXMLEventReader(requestSource);
if (eventReader != null) {
try {
streamReader = StaxUtils.createEventStreamReader(eventReader);
}
catch (XMLStreamException ex) {
streamReader = null;
}
}
}
}
if (streamReader == null) {
try {
streamReader = inputFactory.createXMLStreamReader(requestSource);
}
catch (XMLStreamException ex) {
streamReader = null;
}
catch (UnsupportedOperationException ex) {
streamReader = null;
}
}
if (streamReader == null) {
// as a final resort, transform the source to a stream, and read from that
ByteArrayInputStream bis = convertToByteArrayInputStream(requestSource);
streamReader = inputFactory.createXMLStreamReader(bis);
}
return streamReader;
}
private XMLEventReader resolveEventReader(Source requestSource) throws TransformerException, XMLStreamException {
XMLEventReader eventReader = null;
if (StaxUtils.isStaxSource(requestSource)) {
eventReader = StaxUtils.getXMLEventReader(requestSource);
if (eventReader == null) {
XMLStreamReader streamReader = StaxUtils.getXMLStreamReader(requestSource);
if (streamReader != null) {
try {
eventReader = inputFactory.createXMLEventReader(streamReader);
}
catch (XMLStreamException ex) {
eventReader = null;
}
}
}
}
if (eventReader == null) {
try {
eventReader = inputFactory.createXMLEventReader(requestSource);
}
catch (XMLStreamException ex) {
eventReader = null;
}
catch (UnsupportedOperationException ex) {
eventReader = null;
}
}
if (eventReader == null) {
// as a final resort, transform the source to a stream, and read from that
ByteArrayInputStream bis = convertToByteArrayInputStream(requestSource);
eventReader = inputFactory.createXMLEventReader(bis);
}
return eventReader;
}
/**
* Create a {@code XMLInputFactory} that this resolver will use to create {@link XMLStreamReader} and {@link
* XMLEventReader} objects.
* <p/>
* Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
* so this method will only be called once.
*
* @return the created factory
*/
protected XMLInputFactory createXmlInputFactory() {
return XMLInputFactory.newInstance();
}
private ByteArrayInputStream convertToByteArrayInputStream(Source source) throws TransformerException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transform(source, new StreamResult(bos));
return new ByteArrayInputStream(bos.toByteArray());
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2005-2010 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.server.endpoint.adapter.method;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.springframework.ws.server.endpoint.support.NamespaceUtils;
import org.springframework.xml.transform.TransformerHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Implementation of {@link MethodArgumentResolver} that supports the {@link XPathParam @XPathParam} annotation.
* <p/>
* This resolver supports parameters annotated with {@link XPathParam @XPathParam} that specifies the XPath expression
* that should be bound to that parameter. The parameter can either a "natively supported" XPath type ({@link Boolean
* boolean}, {@link Double double}, {@link String}, {@link Node}, or {@link NodeList}), or a type that is {@linkplain
* ConversionService#canConvert(Class, Class) supported} by the {@link ConversionService}.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class XPathParamMethodArgumentResolver implements MethodArgumentResolver {
private final XPathFactory xpathFactory = createXPathFactory();
private TransformerHelper transformerHelper = new TransformerHelper();
private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
/**
* Sets the conversion service to use.
* <p/>
* Defaults to the {@linkplain ConversionServiceFactory#createDefaultConversionService() default conversion
* service}.
*/
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
public void setTransformerHelper(TransformerHelper transformerHelper) {
this.transformerHelper = transformerHelper;
}
public boolean supportsParameter(MethodParameter parameter) {
if (parameter.getParameterAnnotation(XPathParam.class) == null) {
return false;
}
Class<?> parameterType = parameter.getParameterType();
if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType) ||
Double.class.equals(parameterType) || Double.TYPE.equals(parameterType) ||
Node.class.isAssignableFrom(parameterType) || NodeList.class.isAssignableFrom(parameterType) ||
String.class.isAssignableFrom(parameterType)) {
return true;
}
else {
return conversionService.canConvert(String.class, parameterType);
}
}
public Object resolveArgument(MessageContext messageContext, MethodParameter parameter)
throws TransformerException, XPathExpressionException {
Class<?> parameterType = parameter.getParameterType();
QName evaluationReturnType = getReturnType(parameterType);
boolean useConversionService = false;
if (evaluationReturnType == null) {
evaluationReturnType = XPathConstants.STRING;
useConversionService = true;
}
XPath xpath = createXPath();
xpath.setNamespaceContext(NamespaceUtils.getNamespaceContext(parameter.getMethod()));
Element rootElement = getRootElement(messageContext.getRequest().getPayloadSource());
String expression = parameter.getParameterAnnotation(XPathParam.class).value();
Object result = xpath.evaluate(expression, rootElement, evaluationReturnType);
return useConversionService ? conversionService.convert(result, parameterType) : result;
}
private QName getReturnType(Class<?> parameterType) {
if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType)) {
return XPathConstants.BOOLEAN;
}
else if (Double.class.equals(parameterType) || Double.TYPE.equals(parameterType)) {
return XPathConstants.NUMBER;
}
else if (Node.class.equals(parameterType)) {
return XPathConstants.NODE;
}
else if (NodeList.class.equals(parameterType)) {
return XPathConstants.NODESET;
}
else if (String.class.equals(parameterType)) {
return XPathConstants.STRING;
}
else {
return null;
}
}
private XPath createXPath() {
synchronized (xpathFactory) {
return xpathFactory.newXPath();
}
}
private Element getRootElement(Source source) throws TransformerException {
DOMResult domResult = new DOMResult();
transformerHelper.transform(source, domResult);
Document document = (Document) domResult.getNode();
return document.getDocumentElement();
}
/**
* Create a {@code XPathFactory} that this resolver will use to create {@link XPath} objects.
* <p/>
* Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
* so this method will only be called once.
*
* @return the created factory
*/
protected XPathFactory createXPathFactory() {
return XPathFactory.newInstance();
}
}

Some files were not shown because too many files have changed in this diff Show More