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.net.URI;
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.Collections;
023import java.util.LinkedHashSet;
024import java.util.Set;
025
026import javax.xml.transform.TransformerFactory;
027
028import org.springframework.beans.BeanUtils;
029import org.springframework.boot.context.properties.PropertyMapper;
030import org.springframework.oxm.Marshaller;
031import org.springframework.oxm.Unmarshaller;
032import org.springframework.util.Assert;
033import org.springframework.util.CollectionUtils;
034import org.springframework.ws.WebServiceMessageFactory;
035import org.springframework.ws.client.core.FaultMessageResolver;
036import org.springframework.ws.client.core.WebServiceTemplate;
037import org.springframework.ws.client.support.destination.DestinationProvider;
038import org.springframework.ws.client.support.interceptor.ClientInterceptor;
039import org.springframework.ws.transport.WebServiceMessageSender;
040
041/**
042 * Builder that can be used to configure and create a {@link WebServiceTemplate}. Provides
043 * convenience methods to register {@link #messageSenders(WebServiceMessageSender...)
044 * message senders}, {@link #interceptors(ClientInterceptor...) client interceptors} and
045 * {@link #customizers(WebServiceTemplateCustomizer...) customizers}.
046 * <p>
047 * By default the built {@link WebServiceTemplate} uses the most suitable HTTP-based
048 * {@link WebServiceMessageSender}, call {@link #detectHttpMessageSender(boolean)
049 * detectHttpMessageSender(false)} if you prefer to keep the default. In a typical
050 * auto-configured Spring Boot application this builder is available as a bean and can be
051 * injected whenever a {@link WebServiceTemplate} is needed.
052 *
053 * @author Dmytro Nosan
054 * @author Stephane Nicoll
055 * @since 2.1.0
056 */
057public class WebServiceTemplateBuilder {
058
059        private final boolean detectHttpMessageSender;
060
061        private final Set<ClientInterceptor> interceptors;
062
063        private final Set<WebServiceTemplateCustomizer> internalCustomizers;
064
065        private final Set<WebServiceTemplateCustomizer> customizers;
066
067        private final WebServiceMessageSenders messageSenders;
068
069        private final Marshaller marshaller;
070
071        private final Unmarshaller unmarshaller;
072
073        private final DestinationProvider destinationProvider;
074
075        private final Class<? extends TransformerFactory> transformerFactoryClass;
076
077        private final WebServiceMessageFactory messageFactory;
078
079        public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) {
080                this.detectHttpMessageSender = true;
081                this.interceptors = null;
082                this.internalCustomizers = null;
083                this.customizers = Collections
084                                .unmodifiableSet(new LinkedHashSet<>(Arrays.asList(customizers)));
085                this.messageSenders = new WebServiceMessageSenders();
086                this.marshaller = null;
087                this.unmarshaller = null;
088                this.destinationProvider = null;
089                this.transformerFactoryClass = null;
090                this.messageFactory = null;
091        }
092
093        private WebServiceTemplateBuilder(boolean detectHttpMessageSender,
094                        Set<ClientInterceptor> interceptors,
095                        Set<WebServiceTemplateCustomizer> internalCustomizers,
096                        Set<WebServiceTemplateCustomizer> customizers,
097                        WebServiceMessageSenders messageSenders, Marshaller marshaller,
098                        Unmarshaller unmarshaller, DestinationProvider destinationProvider,
099                        Class<? extends TransformerFactory> transformerFactoryClass,
100                        WebServiceMessageFactory messageFactory) {
101                this.detectHttpMessageSender = detectHttpMessageSender;
102                this.interceptors = interceptors;
103                this.internalCustomizers = internalCustomizers;
104                this.customizers = customizers;
105                this.messageSenders = messageSenders;
106                this.marshaller = marshaller;
107                this.unmarshaller = unmarshaller;
108                this.destinationProvider = destinationProvider;
109                this.transformerFactoryClass = transformerFactoryClass;
110                this.messageFactory = messageFactory;
111        }
112
113        /**
114         * Set if a suitable HTTP-based {@link WebServiceMessageSender} should be detected
115         * based on the classpath. Default is {@code true}.
116         * @param detectHttpMessageSender if a HTTP-based {@link WebServiceMessageSender}
117         * should be detected
118         * @return a new builder instance
119         * @see HttpWebServiceMessageSenderBuilder
120         */
121        public WebServiceTemplateBuilder detectHttpMessageSender(
122                        boolean detectHttpMessageSender) {
123                return new WebServiceTemplateBuilder(detectHttpMessageSender, this.interceptors,
124                                this.internalCustomizers, this.customizers, this.messageSenders,
125                                this.marshaller, this.unmarshaller, this.destinationProvider,
126                                this.transformerFactoryClass, this.messageFactory);
127        }
128
129        /**
130         * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be
131         * used with the {@link WebServiceTemplate}. Setting this value will replace any
132         * previously defined message senders, including the HTTP-based message sender, if
133         * any. Consider using {@link #additionalMessageSenders(WebServiceMessageSender...)}
134         * to keep it with user-defined message senders.
135         * @param messageSenders the message senders to set
136         * @return a new builder instance.
137         * @see #additionalMessageSenders(WebServiceMessageSender...)
138         * @see #detectHttpMessageSender(boolean)
139         */
140        public WebServiceTemplateBuilder messageSenders(
141                        WebServiceMessageSender... messageSenders) {
142                Assert.notNull(messageSenders, "MessageSenders must not be null");
143                return messageSenders(Arrays.asList(messageSenders));
144        }
145
146        /**
147         * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be
148         * used with the {@link WebServiceTemplate}. Setting this value will replace any
149         * previously defined message senders, including the HTTP-based message sender, if
150         * any. Consider using {@link #additionalMessageSenders(Collection)} to keep it with
151         * user-defined message senders.
152         * @param messageSenders the message senders to set
153         * @return a new builder instance.
154         * @see #additionalMessageSenders(Collection)
155         * @see #detectHttpMessageSender(boolean)
156         */
157        public WebServiceTemplateBuilder messageSenders(
158                        Collection<? extends WebServiceMessageSender> messageSenders) {
159                Assert.notNull(messageSenders, "MessageSenders must not be null");
160                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
161                                this.interceptors, this.internalCustomizers, this.customizers,
162                                this.messageSenders.set(messageSenders), this.marshaller,
163                                this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,
164                                this.messageFactory);
165        }
166
167        /**
168         * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should
169         * be used with the {@link WebServiceTemplate}.
170         * @param messageSenders the message senders to add
171         * @return a new builder instance.
172         * @see #messageSenders(WebServiceMessageSender...)
173         */
174        public WebServiceTemplateBuilder additionalMessageSenders(
175                        WebServiceMessageSender... messageSenders) {
176                Assert.notNull(messageSenders, "MessageSenders must not be null");
177                return additionalMessageSenders(Arrays.asList(messageSenders));
178        }
179
180        /**
181         * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should
182         * be used with the {@link WebServiceTemplate}.
183         * @param messageSenders the message senders to add
184         * @return a new builder instance.
185         * @see #messageSenders(Collection)
186         */
187        public WebServiceTemplateBuilder additionalMessageSenders(
188                        Collection<? extends WebServiceMessageSender> messageSenders) {
189                Assert.notNull(messageSenders, "MessageSenders must not be null");
190                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
191                                this.interceptors, this.internalCustomizers, this.customizers,
192                                this.messageSenders.add(messageSenders), this.marshaller,
193                                this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,
194                                this.messageFactory);
195        }
196
197        /**
198         * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the
199         * {@link WebServiceTemplate}. Setting this value will replace any previously defined
200         * interceptors.
201         * @param interceptors the interceptors to set
202         * @return a new builder instance
203         * @see #additionalInterceptors(ClientInterceptor...)
204         */
205        public WebServiceTemplateBuilder interceptors(ClientInterceptor... interceptors) {
206                Assert.notNull(interceptors, "Interceptors must not be null");
207                return interceptors(Arrays.asList(interceptors));
208        }
209
210        /**
211         * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the
212         * {@link WebServiceTemplate}. Setting this value will replace any previously defined
213         * interceptors.
214         * @param interceptors the interceptors to set
215         * @return a new builder instance
216         * @see #additionalInterceptors(Collection)
217         */
218        public WebServiceTemplateBuilder interceptors(
219                        Collection<? extends ClientInterceptor> interceptors) {
220                Assert.notNull(interceptors, "Interceptors must not be null");
221                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
222                                append(Collections.<ClientInterceptor>emptySet(), interceptors),
223                                this.internalCustomizers, this.customizers, this.messageSenders,
224                                this.marshaller, this.unmarshaller, this.destinationProvider,
225                                this.transformerFactoryClass, this.messageFactory);
226        }
227
228        /**
229         * Add additional {@link ClientInterceptor ClientInterceptors} that should be used
230         * with the {@link WebServiceTemplate}.
231         * @param interceptors the interceptors to add
232         * @return a new builder instance
233         * @see #interceptors(ClientInterceptor...)
234         */
235        public WebServiceTemplateBuilder additionalInterceptors(
236                        ClientInterceptor... interceptors) {
237                Assert.notNull(interceptors, "Interceptors must not be null");
238                return additionalInterceptors(Arrays.asList(interceptors));
239        }
240
241        /**
242         * Add additional {@link ClientInterceptor ClientInterceptors} that should be used
243         * with the {@link WebServiceTemplate}.
244         * @param interceptors the interceptors to add
245         * @return a new builder instance
246         * @see #interceptors(Collection)
247         */
248        public WebServiceTemplateBuilder additionalInterceptors(
249                        Collection<? extends ClientInterceptor> interceptors) {
250                Assert.notNull(interceptors, "Interceptors must not be null");
251                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
252                                append(this.interceptors, interceptors), this.internalCustomizers,
253                                this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,
254                                this.destinationProvider, this.transformerFactoryClass,
255                                this.messageFactory);
256        }
257
258        /**
259         * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should
260         * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order
261         * that they were added after builder configuration has been applied. Setting this
262         * value will replace any previously configured customizers.
263         * @param customizers the customizers to set
264         * @return a new builder instance
265         * @see #additionalCustomizers(WebServiceTemplateCustomizer...)
266         */
267        public WebServiceTemplateBuilder customizers(
268                        WebServiceTemplateCustomizer... customizers) {
269                Assert.notNull(customizers, "Customizers must not be null");
270                return customizers(Arrays.asList(customizers));
271        }
272
273        /**
274         * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should
275         * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order
276         * that they were added after builder configuration has been applied. Setting this
277         * value will replace any previously configured customizers.
278         * @param customizers the customizers to set
279         * @return a new builder instance
280         * @see #additionalCustomizers(Collection)
281         */
282        public WebServiceTemplateBuilder customizers(
283                        Collection<? extends WebServiceTemplateCustomizer> customizers) {
284                Assert.notNull(customizers, "Customizers must not be null");
285                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
286                                this.interceptors, this.internalCustomizers,
287                                append(Collections.<WebServiceTemplateCustomizer>emptySet(), customizers),
288                                this.messageSenders, this.marshaller, this.unmarshaller,
289                                this.destinationProvider, this.transformerFactoryClass,
290                                this.messageFactory);
291        }
292
293        /**
294         * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers}
295         * that should be applied to the {@link WebServiceTemplate}. Customizers are applied
296         * in the order that they were added after builder configuration has been applied.
297         * @param customizers the customizers to add
298         * @return a new builder instance
299         * @see #customizers(WebServiceTemplateCustomizer...)
300         */
301        public WebServiceTemplateBuilder additionalCustomizers(
302                        WebServiceTemplateCustomizer... customizers) {
303                Assert.notNull(customizers, "Customizers must not be null");
304                return additionalCustomizers(Arrays.asList(customizers));
305        }
306
307        /**
308         * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers}
309         * that should be applied to the {@link WebServiceTemplate}. Customizers are applied
310         * in the order that they were added after builder configuration has been applied.
311         * @param customizers the customizers to add
312         * @return a new builder instance
313         * @see #customizers(Collection)
314         */
315        public WebServiceTemplateBuilder additionalCustomizers(
316                        Collection<? extends WebServiceTemplateCustomizer> customizers) {
317                Assert.notNull(customizers, "Customizers must not be null");
318                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
319                                this.interceptors, this.internalCustomizers,
320                                append(this.customizers, customizers), this.messageSenders,
321                                this.marshaller, this.unmarshaller, this.destinationProvider,
322                                this.transformerFactoryClass, this.messageFactory);
323        }
324
325        /**
326         * Indicates whether the connection should be checked for fault indicators
327         * ({@code true}), or whether we should rely on the message only ({@code false}).
328         * @param checkConnectionForFault whether to check for fault indicators
329         * @return a new builder instance.
330         * @see WebServiceTemplate#setCheckConnectionForFault(boolean)
331         */
332        public WebServiceTemplateBuilder setCheckConnectionForFault(
333                        boolean checkConnectionForFault) {
334                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
335                                this.interceptors,
336                                append(this.internalCustomizers,
337                                                new CheckConnectionFaultCustomizer(checkConnectionForFault)),
338                                this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,
339                                this.destinationProvider, this.transformerFactoryClass,
340                                this.messageFactory);
341        }
342
343        /**
344         * Indicates whether the connection should be checked for error indicators
345         * ({@code true}), or whether these should be ignored ({@code false}).
346         * @param checkConnectionForError whether to check for error indicators
347         * @return a new builder instance.
348         * @see WebServiceTemplate#setCheckConnectionForError(boolean)
349         */
350        public WebServiceTemplateBuilder setCheckConnectionForError(
351                        boolean checkConnectionForError) {
352                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
353                                this.interceptors,
354                                append(this.internalCustomizers,
355                                                new CheckConnectionForErrorCustomizer(checkConnectionForError)),
356                                this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,
357                                this.destinationProvider, this.transformerFactoryClass,
358                                this.messageFactory);
359        }
360
361        /**
362         * Sets the {@link WebServiceMessageFactory} to use for creating messages.
363         * @param messageFactory the message factory to use for creating messages
364         * @return a new builder instance.
365         * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory)
366         **/
367        public WebServiceTemplateBuilder setWebServiceMessageFactory(
368                        WebServiceMessageFactory messageFactory) {
369                Assert.notNull(messageFactory, "MessageFactory must not be null");
370                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
371                                this.interceptors, this.internalCustomizers, this.customizers,
372                                this.messageSenders, this.marshaller, this.unmarshaller,
373                                this.destinationProvider, this.transformerFactoryClass, messageFactory);
374        }
375
376        /**
377         * Set the {@link Unmarshaller} to use to deserialize messages.
378         * @param unmarshaller the message unmarshaller
379         * @return a new builder instance.
380         * @see WebServiceTemplate#setUnmarshaller(Unmarshaller)
381         **/
382        public WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) {
383                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
384                                this.interceptors, this.internalCustomizers, this.customizers,
385                                this.messageSenders, this.marshaller, unmarshaller,
386                                this.destinationProvider, this.transformerFactoryClass,
387                                this.messageFactory);
388        }
389
390        /**
391         * Set the {@link Marshaller} to use to serialize messages.
392         * @param marshaller the message marshaller
393         * @return a new builder instance.
394         * @see WebServiceTemplate#setMarshaller(Marshaller)
395         **/
396        public WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) {
397                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
398                                this.interceptors, this.internalCustomizers, this.customizers,
399                                this.messageSenders, marshaller, this.unmarshaller,
400                                this.destinationProvider, this.transformerFactoryClass,
401                                this.messageFactory);
402        }
403
404        /**
405         * Set the {@link FaultMessageResolver} to use.
406         * @param faultMessageResolver the fault message resolver to use
407         * @return a new builder instance.
408         * @see WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver)
409         */
410        public WebServiceTemplateBuilder setFaultMessageResolver(
411                        FaultMessageResolver faultMessageResolver) {
412                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
413                                this.interceptors,
414                                append(this.internalCustomizers,
415                                                new FaultMessageResolverCustomizer(faultMessageResolver)),
416                                this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,
417                                this.destinationProvider, this.transformerFactoryClass,
418                                this.messageFactory);
419        }
420
421        /**
422         * Set the {@link TransformerFactory} implementation to use.
423         * @param transformerFactoryClass the transformer factory implementation to use
424         * @return a new builder instance.
425         * @see WebServiceTemplate#setTransformerFactoryClass(Class)
426         */
427        public WebServiceTemplateBuilder setTransformerFactoryClass(
428                        Class<? extends TransformerFactory> transformerFactoryClass) {
429                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
430                                this.interceptors, this.internalCustomizers, this.customizers,
431                                this.messageSenders, this.marshaller, this.unmarshaller,
432                                this.destinationProvider, transformerFactoryClass, this.messageFactory);
433        }
434
435        /**
436         * Set the default URI to be used on operations that do not have a URI parameter.
437         * Typically, either this property is set, or
438         * {@link #setDestinationProvider(DestinationProvider)}, but not both.
439         * @param defaultUri the destination provider URI to be used on operations that do not
440         * have a URI parameter.
441         * @return a new builder instance.
442         * @see #setDestinationProvider(DestinationProvider)
443         */
444        public WebServiceTemplateBuilder setDefaultUri(String defaultUri) {
445                Assert.hasText(defaultUri, "DefaultUri must not be empty");
446                return setDestinationProvider(() -> URI.create(defaultUri));
447        }
448
449        /**
450         * Set the {@link DestinationProvider} to use. Typically, either this property is set,
451         * or {@link #setDefaultUri(String)}, but not both.
452         * @param destinationProvider the destination provider to be used on operations that
453         * do not have a URI parameter.
454         * @return a new builder instance.
455         * @see WebServiceTemplate#setDestinationProvider(DestinationProvider)
456         */
457        public WebServiceTemplateBuilder setDestinationProvider(
458                        DestinationProvider destinationProvider) {
459                Assert.notNull(destinationProvider, "DestinationProvider must not be null");
460                return new WebServiceTemplateBuilder(this.detectHttpMessageSender,
461                                this.interceptors, this.internalCustomizers, this.customizers,
462                                this.messageSenders, this.marshaller, this.unmarshaller,
463                                destinationProvider, this.transformerFactoryClass, this.messageFactory);
464        }
465
466        /**
467         * Build a new {@link WebServiceTemplate} instance and configure it using this
468         * builder.
469         * @return a configured {@link WebServiceTemplate} instance.
470         * @see #build(Class)
471         * @see #configure(WebServiceTemplate)
472         */
473        public WebServiceTemplate build() {
474                return build(WebServiceTemplate.class);
475        }
476
477        /**
478         * Build a new {@link WebServiceTemplate} instance of the specified type and configure
479         * it using this builder.
480         * @param <T> the type of web service template
481         * @param webServiceTemplateClass the template type to create
482         * @return a configured {@link WebServiceTemplate} instance.
483         * @see WebServiceTemplateBuilder#build()
484         * @see #configure(WebServiceTemplate)
485         */
486        public <T extends WebServiceTemplate> T build(Class<T> webServiceTemplateClass) {
487                Assert.notNull(webServiceTemplateClass,
488                                "WebServiceTemplateClass must not be null");
489                return configure(BeanUtils.instantiateClass(webServiceTemplateClass));
490        }
491
492        /**
493         * Configure the provided {@link WebServiceTemplate} instance using this builder.
494         * @param <T> the type of web service template
495         * @param webServiceTemplate the {@link WebServiceTemplate} to configure
496         * @return the web service template instance
497         * @see #build()
498         * @see #build(Class)
499         */
500        public <T extends WebServiceTemplate> T configure(T webServiceTemplate) {
501                Assert.notNull(webServiceTemplate, "WebServiceTemplate must not be null");
502                configureMessageSenders(webServiceTemplate);
503                PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
504                applyCustomizers(webServiceTemplate, this.internalCustomizers);
505                map.from(this.marshaller).to(webServiceTemplate::setMarshaller);
506                map.from(this.unmarshaller).to(webServiceTemplate::setUnmarshaller);
507                map.from(this.destinationProvider).to(webServiceTemplate::setDestinationProvider);
508                map.from(this.transformerFactoryClass)
509                                .to(webServiceTemplate::setTransformerFactoryClass);
510                map.from(this.messageFactory).to(webServiceTemplate::setMessageFactory);
511                if (!CollectionUtils.isEmpty(this.interceptors)) {
512                        Set<ClientInterceptor> merged = new LinkedHashSet<>(this.interceptors);
513                        if (webServiceTemplate.getInterceptors() != null) {
514                                merged.addAll(Arrays.asList(webServiceTemplate.getInterceptors()));
515                        }
516                        webServiceTemplate.setInterceptors(merged.toArray(new ClientInterceptor[0]));
517                }
518                applyCustomizers(webServiceTemplate, this.customizers);
519                return webServiceTemplate;
520        }
521
522        private void applyCustomizers(WebServiceTemplate webServiceTemplate,
523                        Set<WebServiceTemplateCustomizer> customizers) {
524                if (!CollectionUtils.isEmpty(customizers)) {
525                        for (WebServiceTemplateCustomizer internalCustomizer : customizers) {
526                                internalCustomizer.customize(webServiceTemplate);
527                        }
528                }
529        }
530
531        private <T extends WebServiceTemplate> void configureMessageSenders(
532                        T webServiceTemplate) {
533                if (this.messageSenders.isOnlyAdditional() && this.detectHttpMessageSender) {
534                        Set<WebServiceMessageSender> merged = append(
535                                        this.messageSenders.getMessageSenders(),
536                                        new HttpWebServiceMessageSenderBuilder().build());
537                        webServiceTemplate
538                                        .setMessageSenders(merged.toArray(new WebServiceMessageSender[0]));
539                }
540                else if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) {
541                        webServiceTemplate.setMessageSenders(this.messageSenders.getMessageSenders()
542                                        .toArray(new WebServiceMessageSender[0]));
543                }
544        }
545
546        private <T> Set<T> append(Set<T> set, T addition) {
547                return append(set, Collections.singleton(addition));
548        }
549
550        private static <T> Set<T> append(Set<T> set, Collection<? extends T> additions) {
551                Set<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());
552                result.addAll((additions != null) ? additions : Collections.emptyList());
553                return Collections.unmodifiableSet(result);
554        }
555
556        /**
557         * Collect user-defined {@link WebServiceMessageSender} and whether only additional
558         * message senders were added or not.
559         */
560        private static class WebServiceMessageSenders {
561
562                private final boolean onlyAdditional;
563
564                private Set<WebServiceMessageSender> messageSenders;
565
566                WebServiceMessageSenders() {
567                        this(true, Collections.emptySet());
568                }
569
570                private WebServiceMessageSenders(boolean onlyAdditional,
571                                Set<WebServiceMessageSender> messageSenders) {
572                        this.onlyAdditional = onlyAdditional;
573                        this.messageSenders = messageSenders;
574                }
575
576                public boolean isOnlyAdditional() {
577                        return this.onlyAdditional;
578                }
579
580                public Set<WebServiceMessageSender> getMessageSenders() {
581                        return this.messageSenders;
582                }
583
584                public WebServiceMessageSenders set(
585                                Collection<? extends WebServiceMessageSender> messageSenders) {
586                        return new WebServiceMessageSenders(false,
587                                        new LinkedHashSet<>(messageSenders));
588                }
589
590                public WebServiceMessageSenders add(
591                                Collection<? extends WebServiceMessageSender> messageSenders) {
592                        return new WebServiceMessageSenders(this.onlyAdditional,
593                                        append(this.messageSenders, messageSenders));
594                }
595
596        }
597
598        /**
599         * {@link WebServiceTemplateCustomizer} to set
600         * {@link WebServiceTemplate#checkConnectionForFault checkConnectionForFault }.
601         */
602        private static final class CheckConnectionFaultCustomizer
603                        implements WebServiceTemplateCustomizer {
604
605                private final boolean checkConnectionFault;
606
607                private CheckConnectionFaultCustomizer(boolean checkConnectionFault) {
608                        this.checkConnectionFault = checkConnectionFault;
609                }
610
611                @Override
612                public void customize(WebServiceTemplate webServiceTemplate) {
613                        webServiceTemplate.setCheckConnectionForFault(this.checkConnectionFault);
614                }
615
616        }
617
618        /**
619         * {@link WebServiceTemplateCustomizer} to set
620         * {@link WebServiceTemplate#checkConnectionForError checkConnectionForError }.
621         */
622        private static final class CheckConnectionForErrorCustomizer
623                        implements WebServiceTemplateCustomizer {
624
625                private final boolean checkConnectionForError;
626
627                private CheckConnectionForErrorCustomizer(boolean checkConnectionForError) {
628                        this.checkConnectionForError = checkConnectionForError;
629                }
630
631                @Override
632                public void customize(WebServiceTemplate webServiceTemplate) {
633                        webServiceTemplate.setCheckConnectionForError(this.checkConnectionForError);
634                }
635
636        }
637
638        /**
639         * {@link WebServiceTemplateCustomizer} to set
640         * {@link WebServiceTemplate#faultMessageResolver faultMessageResolver }.
641         */
642        private static final class FaultMessageResolverCustomizer
643                        implements WebServiceTemplateCustomizer {
644
645                private final FaultMessageResolver faultMessageResolver;
646
647                private FaultMessageResolverCustomizer(
648                                FaultMessageResolver faultMessageResolver) {
649                        this.faultMessageResolver = faultMessageResolver;
650                }
651
652                @Override
653                public void customize(WebServiceTemplate webServiceTemplate) {
654                        webServiceTemplate.setFaultMessageResolver(this.faultMessageResolver);
655                }
656
657        }
658
659}