I'm having a SpringBoot and SpringMVC internal application (internal meaning hidden from the internet by a firewall) and a public authentication (OAuth2) service in the DMZ.
I'm accessing the landing page from the from a client in the internal area.
This page has a login button. When I press it, I'm forwarding the client to the auth server (in the DMZ), that I can access only going through a proxy.
I tried setting the VM env variables:
-Dhttp.proxyHost=xx -Dhttp.proxyPort=yy -Dhttp.proxySet=true
and setting them in the System.properties
System.setProperty("http.proxyHost", "http://xx");
System.setProperty("http.proxyPort", "xx");
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1");
but both with no effect.
I also tried to define a SimpleClientHttpRequestFactory bean :
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="requestFactory"
class="org.springframework.http.client.SimpleClientHttpRequestFactory">
<property name="proxy">
<bean id="proxy" class="java.net.Proxy">
<constructor-arg>
<util:constant static-field="java.net.Proxy.Type.HTTP" />
</constructor-arg>
<constructor-arg>
<bean class="java.net.InetSocketAddress">
<constructor-arg value="xx" />
<constructor-arg value="yy" />
</bean>
</constructor-arg>
</bean>
</property>
</bean>
</beans>
without anymore success.
Question
How can I configure Spring to proxify my redirect ?
Thanks!
Got it work as follow (see restTemplateProxy)
private final String server = "xx";
private final int port = yy;
private final SimpleClientHttpRequestFactory clientHttpReq = new SimpleClientHttpRequestFactory();
private final Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(server, port));
private RestTemplate restTemplateProxy = null;
{
clientHttpReq.setProxy(proxy);
restTemplateProxy = new RestTemplate(clientHttpReq);
}
#RequestMapping(value = "getLightToken", method = RequestMethod.GET)
private String getLightToken(Model model) throws JsonProcessingException, IOException {
/* Header */
headers.clear();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
/* Body */
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add(CLIENT_ID.key, CLIENT_ID.val);
body.add(CLIENT_SECRET.key, CLIENT_SECRET.val);
body.add(GRANT_TYPE.key, GRANT_TYPE.val);
body.add(SCOPE.key, SCOPE.val);
/* Set the body and header of the request */
HttpEntity<?> request = new HttpEntity<>(body, headers);
/* Request Authorisation */
ResponseEntity<String> response = restTemplateProxy.exchange(BASE_URL + TOKEN_URI, HttpMethod.POST, request, String.class);
return response.getBody();
}
Related
I'm trying to send an email to a user once their account is registered, I can get my code to work in a separate project (simple form input etc) however when I try to add the same code to my app it gives me the following error
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException error
Could not autowire method: public void com.finalProject.school.controller.AppController.setMailSender(org.springframework.mail.javamail.JavaMailSender); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.mail.javamail.JavaMailSender] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Here is my code for adding the new user to the database (which works fine) with the code to send an email which is what is giving me errors
#RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(#Valid User user, BindingResult result, #RequestParam("firstName") String firstName,
#RequestParam("password") String password, #RequestParam("email") String emailAddress,
ModelMap model, Model model2) {
if (result.hasErrors()) {
return "registration";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registration";
}
String status = null;
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true,"UTF-8");
helper.setFrom("Administrator");
helper.setTo(emailAddress);
helper.setSubject("Registration confirmation");
Map<String, Object> params = new HashMap<String, Object>();
params.put("firstName", firstName);
params.put("password", password);
String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "spring/emailRegistration.vm", "UTF-8", params);
helper.setText(text, true);
mailSender.send(message);
status = "Confirmation email is sent to your address (" + emailAddress + ")";
} catch (MessagingException e) {
status = "There was an error in email sending. Please check your email address: " + emailAddress;
}
model2.addAttribute("message", status);
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
//return "success";
return "registrationsuccess";
}
Any ideas of how to fix this ?
App Config Class
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.finalProject.school" />
If you are using spring boot, you probably have not included following properties in your application.properties file.
spring.mail.host = smtp.gmail.com
spring.mail.username = abc#abc.com
spring.mail.password = xyz
spring.mail.port=587
spring.mail.properties.mail.smtp.starttls.enable = true
spring.mail.protocol=smtp
UPDATE
Ok. Put the following in your configuration file.
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="myemail1#gmail.com" />
<property name="password" value="password!" />
<!-- The name of the property, following JavaBean naming conventions -->
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.debug">true</prop>
</props>
</property>
</bean>
I'm making a SOAP request with custom headers which contains the security part of the request.
But the request now contains two headers and its throwing the following error :
[Request processing failed; nested exception is org.springframework.ws.soap.client.SoapFaultClientException: No WS-Security header found] with root cause
The headers that is formed is :
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><soapenv:Envelope xmlns:ser="dasdasdasd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header><wsse:Security xmlns:wsse="asdasdasdas" soapenv:mustUnderstand="1"> <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-2"><wsse:Username>test</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">adasdasdasdasd</wsse:Password><wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!##!####$#!#!##%*(&*&^%#$##</wsse:Nonce><wsu:Created>2014-09-04 T1015.41.649Z</wsu:Created></wsse:UsernameToken></wsse:Security></soapenv:Header></soapenv:Envelope></SOAP-ENV:Header><SOAP-ENV:Body><ns2:CreateSaleOrderRequest xmlns:ns2="http://uniware.unicommerce.com/services/"><ns2:SaleOrder><ns2:DisplayOrderCode>200</ns2:DisplayOrderCode></ns2:SaleOrder></ns2:CreateSaleOrderRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>
My code for the above request is below :
private static final String uri = "http://requestb.in/1eh2un81";
public String createSaleOrder(Suborder suborder)
{
SaleOrder saleorder = new SaleOrder();
saleorder = setSaleOrderObject(suborder);
CreateSaleOrderRequest request = new CreateSaleOrderRequest();
request.setSaleOrder(saleorder);
String response = this.getWebServiceTemplate().marshalSendAndReceive(uri, request,
new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException
{
SoapMessage soapmessage = (SoapMessage)message;
SoapHeader header = soapmessage.getSoapHeader();
//soapmessage.getEnvelope().addAttribute(, "soapenv");
StringBuilder soapheader = new StringBuilder();
soapheader.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"zsdasdasdasd">");
soapheader.append("<soapenv:Header>");
soapheader.append("<wsse:Security soapenv:mustUnderstand=\"1\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"> ");
soapheader.append("<wsse:UsernameToken wsu:Id=\"UsernameToken-2\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
soapheader.append("<wsse:Username>test</wsse:Username>");
soapheader.append("<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">adasdasdasdasd</wsse:Password>");
soapheader.append("<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">!2312312!##!##!#$##%R</wsse:Nonce>");
soapheader.append("<wsu:Created>2014-09-04 T1015.41.649Z</wsu:Created>");
soapheader.append("</wsse:UsernameToken>");
soapheader.append("</wsse:Security>");
soapheader.append("</soapenv:Header>");
soapheader.append("</soapenv:Envelope>");
StringSource HeaderSource = new StringSource(soapheader.toString());
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(HeaderSource,header.getResult());
}
}).toString();
System.out.println(response);
Please suggest how do i resolve this error.TIA!
Uhm provided you're using spring you would have to go something like this.. inside your xml for the ws you should have:
<bean id="YourWsClientBean" class="eu.europa.acer.aris.dciws.client.DciWsClient">
<constructor-arg ref="webServiceTemplate"></constructor-arg>
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="unMarshaller"></property>
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
</bean>
</property>
<!-- NON PROXY
<property name="messageSender" ref = "httpSender"></property> -->
<property name="defaultUri" value="https://testframework.test-acer-remit.eu/dci-ws/" />
<property name="interceptors">
<list>
<ref bean="securityConfInterceptor" />
</list>
</property>
</bean>
<bean id="securityConfInterceptor" class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="classpath:securityPolicy.xml" />
<property name="callbackHandlers">
<!-- <bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="keyStore" /> <property name="privateKeyPassword"
value="changeit" /> <property name="trustStore" ref="trustStore" /> </bean> -->
<list>
<ref bean="keyStoreHandler"/>
</list>
</property>
</bean>
marshaller and unmarshaller should be clear to you i suppose.
The most important part in your case is
inside the securityPolicy.xml you will be able to define your desirede policy for outgoing//incoming messages, be it signature, usernameandpassword, etc..
The following file for example is for signing the request with a certain certificate.
<?xml version="1.0" encoding="UTF-8"?>
<!-- <xwss:SecurityConfiguration dumpMessages="false" xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<xwss:Sign includeTimestamp="false"> <xwss:X509Token certificateAlias="ceremp
staging ca"/> </xwss:Sign> </xwss:SecurityConfiguration> -->
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
<!-- <xwss:RequireTimestamp maxClockSkew="60" timestampFreshnessLimit="300"/>
<xwss:RequireUsernameToken passwordDigestRequired="false" nonceRequired="false"/>
<xwss:Timestamp /> <xwss:UsernameToken name="mojo" password="mojopass" digestPassword="true"
useNonce="true"/> -->
<xwss:Sign>
<xwss:X509Token certificateAlias="acerprivate" />
<!-- <xwss:X509Token certificateAlias="acer staging cert" /> -->
<xwss:CanonicalizationMethod algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<xwss:SignatureMethod algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<xwss:SignatureTarget type="xpath"
value="./SOAP-ENV:Envelope/SOAP-ENV:Body">
<xwss:DigestMethod algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<xwss:Transform algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
<xwss:AlgorithmParameter name="XPATH"
value="./SOAP-ENV:Envelope/SOAP-ENV:Header/wsse:Security/ds:Signature[1]/ds:KeyInfo/wsse:SecurityTokenReference" />
</xwss:Transform>
<xwss:Transform
algorithm="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform">
<xwss:AlgorithmParameter name="CanonicalizationMethod"
value="http://www.w3.org/2001/10/xml-exc-c14n#" />
</xwss:Transform>
</xwss:SignatureTarget>
</xwss:Sign>
</xwss:SecurityConfiguration>
Hope this give you an hand as a general concept.
At times I advice some colleague new with ws to take the dirty alternative, if they want to keep the altering as simple as possible.
E.g. this is from spring forum -->
public void sendAndReceiveXMLPayload(String xmlFileNamePath) throws IOException {
ClassPathResource
classPathResource =
new ClassPathResource(xmlFileNamePath);
Source
requestSource =
new ResourceSource(classPathResource);
StringResult
result =
new StringResult();
getWebServiceTemplate().
sendSourceAndReceiveToResult(
requestSource,
new WSSESecurityHeaderRequestWebServiceMessageCallback(),
result
);
}
notice WSSESecurityHeaderRequestWebServiceMessageCallback
define a
public class WSSESecurityHeaderRequestWebServiceMessageCallback implements WebServiceMessageCallback {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
try {
// Assumption: We are using the default SAAJWebMessageFactory
SaajSoapMessage
saajSoapMessage =
(SaajSoapMessage)message;
SOAPMessage
soapMessage =
saajSoapMessage.getSaajMessage();
SOAPPart
soapPart =
soapMessage.getSOAPPart();
SOAPEnvelope
soapEnvelope =
soapPart.getEnvelope();
SOAPHeader
soapHeader =
soapEnvelope.getHeader();
Name
headerElementName =
soapEnvelope.createName(
"Security",
"wsse",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
);
// Add "Security" soapHeaderElement to soapHeader
SOAPHeaderElement
soapHeaderElement =
soapHeader.addHeaderElement(headerElementName);
// This may be important for some portals!
soapHeaderElement.setActor(null);
// Add usernameToken to "Security" soapHeaderElement
SOAPElement
usernameTokenSOAPElement =
soapHeaderElement.addChildElement("UsernameToken");
// Add username to usernameToken
SOAPElement
userNameSOAPElement =
usernameTokenSOAPElement.addChildElement("Username");
userNameSOAPElement.addTextNode("myUserName");
// Add password to usernameToken
SOAPElement
passwordSOAPElement =
usernameTokenSOAPElement.addChildElement("Password");
passwordSOAPElement.addTextNode("myPassword");
} catch (SOAPException soapException) {
throw new RuntimeException("WSSESecurityHeaderRequestWebServiceMessageCallback", soapException);
}
}
}
in this class feel free to change what you do with your header as you see fit and you're done...
I'm using spring 4. I'm trying to call restTemplate.postForEntity but keep getting
no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/html]
My rest template configuration:
<bean id="restTemplate" name="restTemplate"
class="org.springframework.web.client.RestTemplate"
autowire-candidate="true">
<constructor-arg ref="httpClientFactory" />
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean
class="org.springframework.http.converter.StringHttpMessageConverter" />
</list>
</property>
</bean>
My function call:
protected <T> T doExecute(String suffixUrl, MultiValueMap<String, String> requestBody, Class<T> responseType) {
String prefixUrl = "https://blabla.com/api/bla/";
ResponseEntity<T> responseEntity = null;
HttpHeaders headers = new HttpHeaders();
headers.add(
"Content-type",
"application/x-www-form-urlencoded");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(
requestBody, headers);
responseEntity = restTemplate.postForEntity(
prefixUrl + suffixUrl,
request,
responseType);
return responseEntity.getBody();
}
I have a feeling its connected to the response "Content-Encoding: gzip", I've been looking for a gzip converter but it only exists in spring android.
Edit:
This works but its just a workaround:
String templateList = this.doExecute(
"list.json",
map,
String .class);
ObjectMapper mapper = new ObjectMapper();
TemplateResponse[] tr = mapper.readValue(
templateList,
TemplateResponse[].class);
I want to response JSON object or array from Spring MVC controller. From these two beingjavaguys and mkyoung tutorial, i tried.
I could success only in when the response is string. But when the response is in object or in list, it doesn't work for me.
//It works
#RequestMapping(value = "/angular", method = RequestMethod.GET)
public #ResponseBody String getAllProfiles( ModelMap model ) {
String jsonData = "[{\"firstname\":\"ajitesh\",\"lastname\":\"kumar\",\"address\":\"211/20-B,mgstreet\",\"city\":\"hyderabad\",\"phone\":\"999-888-6666\"},{\"firstname\":\"nidhi\",\"lastname\":\"rai\",\"address\":\"201,mgstreet\",\"city\":\"hyderabad\",\"phone\":\"999-876-5432\"}]";
return jsonData;
}
Output is:
But the problem is in it,
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody Shop getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
return shop;
}
It shows,
HTTP ERROR 406
Problem accessing /mkyoung.html. Reason:
Not Acceptable
But if i change it toString() ,
It works but not with right output
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody String getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
return shop.toString();
}
But i need JSON object or array of object as response. What is the probelm ? I have added jsckson dependency in my pom.xml
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.10</version>
</dependency>
UPDATE:
Now i am sending request from angular js by adding
headers: {
"Content-Type": "application/json"
}
My dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.sublime.np.controller" />
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/defs/general.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
</beans>
As Sotirios Delimanolis's Answer suggesion.
$http({
url: '/mkyoung.html',
method: 'GET',
data: id,
headers: {
"Content-Type": "application/json"
}
}).success(function(response){
$scope.response = response;
console.log($scope.response);
/* $scope.hideTable = false;
$scope.hideButton = false ; */
}).error(function(error){
$scope.response = error;
console.log("Failed");
});
But it shows same error.
Also add jackson core
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>2.5.1</version>
</dependency>
For List use method return type Object
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody Object getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
Shop shop1 = new Shop();
shop1.setName("G1");
shop1.setStaffName(new String[] { "mkyong1", "mkyong2" });
List<Shop> shops = new ArrayList<Shop>();
shops.add(shop1);
shops.add(shop);
return shops;
}
Given #ResponseBody with a POJO type return type, a default MVC configuration with #EnableWebMvc or <mvc:annotation-driven />, and Jackson on the classpath, Spring will try to serialize the POJO to JSON and write it to the response body.
Since it's writing JSON, it's going to attempt to write application/json as the Content-type header. The HTTP specification requires that the server only responds with content types that are part of the Accept header in the request.
It seems you're sending your request with an inappropriate Accept header that doesn't contain application/json. Fix that.
Note that you are sending your request to
/mkyoung.html
Spring, by default, uses content negotiation based on some extensions. For example, with .html, Spring will think the request should produces text/html content, which is contrary to the application/json you want to send.
Since your handler is already mapped to
#RequestMapping(value = "/mkyoung", method = RequestMethod.GET)
just send the request to the corresponding URL, ending in /mkyoung. (Get rid of the .html extension.)
I am using org.springframework.ws.client.core.WebServiceTemplate for making Web Service calls. How can i configure timeout for the call.
If you are using Spring Webservices 2.1.0 version, You can set timeout using HttpComponentsMessageSender.
CommonsHttpMessageSender are deprecated and not recommended by Spring anymore.
The way I have it implemented, I define my WebServiceTemplate to use HttpComponentsMessageSender.
Values are in Milliseconds
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="defaultUri" value="${endpoint.url}" />
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="unmarshaller" />
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<property name="connectionTimeout" value="1200000" />
<property name="readTimeout" value="1200000" />
</bean>
</property>
</bean>
Just Make sure you have in your pom file, you added the following
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.1</version>
<scope>compile</scope>
</dependency>
Same as Sathish answer, but programmatically (Spring 4+):
#Component
public class MyWebServiceGatewaySupport extends WebServiceGatewaySupport
{
#Value("${my.ws.readtimeout}")
private String readTimeout;
#Value("${my.ws.connectiontimeout}")
private String connectionTimeout;
Object marshalSendAndReceive(String endpoint, Object requestPayload)
{
WebServiceTemplate wsTemplate = this.getWebServiceTemplate();
WebServiceMessageSender[] senders = wsTemplate.getMessageSenders();
for (WebServiceMessageSender sender: senders)
{
try
{
int readTimeoutMsec = Integer.parseInt(readTimeout);
int connTimeoutMsec = Integer.parseInt(connectionTimeout);
HttpComponentsMessageSender httpSender = (HttpComponentsMessageSender) sender;
httpSender.setReadTimeout(readTimeoutMsec);
httpSender.setConnectionTimeout(connTimeoutMsec);
}
catch (ClassCastException|NumberFormatException cex)
{
logger.warn("Cannot set WS timeout: " + cex.getMessage());
}
}
return wsTemplate.marshalSendAndReceive(endpoint, requestPayload);
}
}
Since Spring Webservices 2.2, you can also use Spring's ClientHttpRequestMessageSender:
#Service
public class CustomWebServiceImpl extends WebServiceGatewaySupport implements CustomWebService {
private static final int CONNECTION_TIMEOUT = (10 * 1000);
private static final int READ_TIMEOUT = (10 * 1000);
public CustomWebServiceImpl() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(CONNECTION_TIMEOUT);
requestFactory.setReadTimeout(READ_TIMEOUT);
setMessageSender(new ClientHttpRequestMessageSender(requestFactory));
}
(...)
}
(no dependency to Apache HTTP Components required)
The below code worked for me.
#Bean
public YourClassImpl yourClassImpl(Jaxb2Marshaller marshaller, HttpComponentsMessageSender httpComponentsMessageSender) {
YourClassImpl client = new YourClassImpl();
client.setDefaultUri(PiiProperties.SOAP_ACTION.getValue());
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
client.setMessageSender(httpComponentsMessageSender);
return client;
}
#Bean
public HttpComponentsMessageSender httpComponentsMessageSender() {
HttpComponentsMessageSender sender = new HttpComponentsMessageSender();
sender.setReadTimeout(1000);
sender.setConnectionTimeout(1000);
return sender;
}
If you want that kind of control, you can
either switch to CommonsHttpMessageSender, which uses the Jakarta Commons
HttpClient
or subclass HttpUrlConnectionMessageSender and in the
prepareConnection(HttpURLConnection) method call
UrlConnection.setReadTimeOut(int)
That's how I did:
#Configuration
public class MunisServiceConfig {
#Value("${service.uri}")
private String soapUri;
#Bean
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath(CheckStatePayment.class.getPackage().getName());
return jaxb2Marshaller;
}
#Bean
public WebServiceTemplate munisService() {
WebServiceTemplate template = new WebServiceTemplate();
template.setMarshaller(jaxb2Marshaller());
template.setUnmarshaller(jaxb2Marshaller());
template.setDefaultUri(soapUri);
HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
httpComponentsMessageSender.setReadTimeout(3000);
httpComponentsMessageSender.setConnectionTimeout(5000);
template.setMessageSender(httpComponentsMessageSender);
return template;
}
}
This article will probably sort you out:
http://onebyteatatime.wordpress.com/2009/03/19/how-to-set-socket-timeout-using-spring-webservicetemplate/
The way I have it implemented, I define my WebServiceTemplate to use CommonsHttpMessageSender:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
</bean>
</property>
</bean>
Then, in code, I get the messageSender and set the timeout on it. You could equally do this in your xml.
CommonsHttpMessageSender messageSender = (CommonsHttpMessageSender)webServiceTemplate.getMessageSenders()[0];
messageSender.getHttpClient().getParams().setSoTimeout(timeoutMillis);
This code works with Spring Boot (verified on 2.1.5.RELEASE):
#Configuration
public class ExampleServiceClientConfiguration {
#Value("${example-service.uri}")
private String exampleServiceUri;
#Value("${example-service.timeout:120}")
private int exampleServiceTimeout;
#Bean
public ExampleServiceClient exampleServiceClient() {
ExampleServiceClient client = new ExampleServiceClient();
client.setMessageSender(httpUrlConnectionMessageSender());
client.setDefaultUri(exampleServiceUri);
client.setMarshaller(marshaller());
client.setUnmarshaller(marshaller());
return client;
}
#Bean
HttpUrlConnectionMessageSender httpUrlConnectionMessageSender() {
HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender();
Duration timeout = Duration.ofSeconds(exampleServiceTimeout);
sender.setReadTimeout(timeout);
sender.setConnectionTimeout(timeout);
return sender;
}
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(ObjectFactory.class.getPackageName());
return marshaller;
}
}
For the CommonsHttpMessageSender, we can set the timeout in the following way:
<bean id="httpParams" class="org.apache.commons.httpclient.params.HttpClientParams">
<!-- Timeout in milliseconds: in this case 1 minute -->
<property name="soTimeout" value="60000" />
</bean>
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<property name="params" ref="httpParams" />
</bean>
<!-- Define the message sender used by all web service templates -->
<bean id="webServiceMessageSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
<constructor-arg>
<ref bean="httpClient"/>
</constructor-arg>
</bean>
and ref the webServiceMessageSender as below:
<bean id="genericWebServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="messageSender" ref="webServiceMessageSender"/>
</bean>