001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.webservices.client; 018 019import java.lang.reflect.Method; 020import java.time.Duration; 021import java.util.function.Supplier; 022 023import org.springframework.boot.web.client.ClientHttpRequestFactorySupplier; 024import org.springframework.http.client.ClientHttpRequestFactory; 025import org.springframework.util.Assert; 026import org.springframework.util.ReflectionUtils; 027import org.springframework.ws.transport.WebServiceMessageSender; 028import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; 029 030/** 031 * {@link WebServiceMessageSender} builder that can detect a suitable HTTP library based 032 * on the classpath. 033 * 034 * @author Stephane Nicoll 035 * @since 2.1.0 036 */ 037public class HttpWebServiceMessageSenderBuilder { 038 039 private Duration connectTimeout; 040 041 private Duration readTimeout; 042 043 private Supplier<ClientHttpRequestFactory> requestFactorySupplier; 044 045 /** 046 * Set the connection timeout. 047 * @param connectTimeout the connection timeout 048 * @return a new builder instance 049 */ 050 public HttpWebServiceMessageSenderBuilder setConnectTimeout(Duration connectTimeout) { 051 this.connectTimeout = connectTimeout; 052 return this; 053 } 054 055 /** 056 * Set the read timeout. 057 * @param readTimeout the read timeout 058 * @return a new builder instance 059 */ 060 public HttpWebServiceMessageSenderBuilder setReadTimeout(Duration readTimeout) { 061 this.readTimeout = readTimeout; 062 return this; 063 } 064 065 /** 066 * Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called 067 * to create the HTTP-based {@link WebServiceMessageSender}. 068 * @param requestFactorySupplier the supplier for the request factory 069 * @return a new builder instance 070 */ 071 public HttpWebServiceMessageSenderBuilder requestFactory( 072 Supplier<ClientHttpRequestFactory> requestFactorySupplier) { 073 Assert.notNull(requestFactorySupplier, 074 "RequestFactory Supplier must not be null"); 075 this.requestFactorySupplier = requestFactorySupplier; 076 return this; 077 } 078 079 public WebServiceMessageSender build() { 080 ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null) 081 ? this.requestFactorySupplier.get() 082 : new ClientHttpRequestFactorySupplier().get(); 083 if (this.connectTimeout != null) { 084 new TimeoutRequestFactoryCustomizer(this.connectTimeout, "setConnectTimeout") 085 .customize(requestFactory); 086 } 087 if (this.readTimeout != null) { 088 new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") 089 .customize(requestFactory); 090 } 091 return new ClientHttpRequestMessageSender(requestFactory); 092 } 093 094 /** 095 * {@link ClientHttpRequestFactory} customizer to call a "set timeout" method. 096 */ 097 private static class TimeoutRequestFactoryCustomizer { 098 099 private final Duration timeout; 100 101 private final String methodName; 102 103 TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) { 104 this.timeout = timeout; 105 this.methodName = methodName; 106 } 107 108 public void customize(ClientHttpRequestFactory factory) { 109 ReflectionUtils.invokeMethod(findMethod(factory), factory, 110 Math.toIntExact(this.timeout.toMillis())); 111 } 112 113 private Method findMethod(ClientHttpRequestFactory factory) { 114 Method method = ReflectionUtils.findMethod(factory.getClass(), 115 this.methodName, int.class); 116 if (method != null) { 117 return method; 118 } 119 throw new IllegalStateException("Request factory " + factory.getClass() 120 + " does not have a " + this.methodName + "(int) method"); 121 } 122 123 } 124 125}