From a7b3a913c2685d36f52559416a81c5bd6b2787ea Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Sat, 9 Apr 2016 21:20:29 +0200 Subject: [PATCH] Add auto-configuration for Spring Web Services Closes gh-1045 --- spring-boot-autoconfigure/pom.xml | 5 + .../autoconfigure/ws/WsAutoConfiguration.java | 78 +++++++++++ .../boot/autoconfigure/ws/WsProperties.java | 87 ++++++++++++ .../boot/autoconfigure/ws/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 3 +- .../ws/WsAutoConfigurationTests.java | 124 ++++++++++++++++++ .../main/java/sample/ws/WebServiceConfig.java | 13 -- 7 files changed, 316 insertions(+), 14 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsAutoConfiguration.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsProperties.java create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/package-info.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ws/WsAutoConfigurationTests.java diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml index cb05053708..c9864fd57f 100755 --- a/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-autoconfigure/pom.xml @@ -512,6 +512,11 @@ spring-social-linkedin true + + org.springframework.ws + spring-ws-core + true + org.thymeleaf thymeleaf diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsAutoConfiguration.java new file mode 100644 index 0000000000..9393922856 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsAutoConfiguration.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2016 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.boot.autoconfigure.ws; + +import java.util.Map; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; +import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.ws.config.annotation.DelegatingWsConfiguration; +import org.springframework.ws.config.annotation.WsConfigurationSupport; +import org.springframework.ws.transport.http.MessageDispatcherServlet; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Web Services. + * + * @author Vedran Pavic + * @since 1.4.0 + */ +@Configuration +@ConditionalOnWebApplication +@ConditionalOnClass(MessageDispatcherServlet.class) +@ConditionalOnMissingBean(WsConfigurationSupport.class) +@EnableConfigurationProperties(WsProperties.class) +@AutoConfigureAfter(EmbeddedServletContainerAutoConfiguration.class) +public class WsAutoConfiguration { + + private WsProperties properties; + + public WsAutoConfiguration(WsProperties properties) { + this.properties = properties; + } + + @Bean + public ServletRegistrationBean messageDispatcherServlet( + ApplicationContext applicationContext) { + MessageDispatcherServlet servlet = new MessageDispatcherServlet(); + servlet.setApplicationContext(applicationContext); + String path = this.properties.getPath(); + String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*"); + ServletRegistrationBean registration = new ServletRegistrationBean( + servlet, urlMapping); + registration.setLoadOnStartup(this.properties.getServlet().getLoadOnStartup()); + for (Map.Entry entry : this.properties.getInit().entrySet()) { + registration.addInitParameter(entry.getKey(), entry.getValue()); + } + return registration; + } + + @Configuration + @Import(DelegatingWsConfiguration.class) + protected static class WsConfiguration { + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsProperties.java new file mode 100644 index 0000000000..d66e960396 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/WsProperties.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2016 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.boot.autoconfigure.ws; + +import java.util.HashMap; +import java.util.Map; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties} for Spring Web Services. + * + * @author Vedran Pavic + * @since 1.4.0 + */ +@ConfigurationProperties("spring.ws") +public class WsProperties { + + /** + * Path that serves as the base URI for the services. + */ + @NotNull + @Pattern(regexp = "/[^?#]*", message = "Path must start with /") + private String path = "/services"; + + /** + * Init parameters to pass to Spring Web Services via the servlet. + */ + private Map init = new HashMap(); + + private final Servlet servlet = new Servlet(); + + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + public Map getInit() { + return this.init; + } + + public void setInit(Map init) { + this.init = init; + } + + public Servlet getServlet() { + return this.servlet; + } + + public static class Servlet { + + /** + * Load on startup priority of the Spring Web Services servlet. + */ + private int loadOnStartup = -1; + + public int getLoadOnStartup() { + return this.loadOnStartup; + } + + public void setLoadOnStartup(int loadOnStartup) { + this.loadOnStartup = loadOnStartup; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/package-info.java new file mode 100644 index 0000000000..c2b9505e88 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ws/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2016 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. + */ + +/** + * Auto-configuration for Spring Web Services. + */ +package org.springframework.boot.autoconfigure.ws; diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 5afd06d3ff..6171b8ebac 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -96,7 +96,8 @@ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\ -org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration +org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,\ +org.springframework.boot.autoconfigure.ws.WsAutoConfiguration # Template availability providers org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ws/WsAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ws/WsAutoConfigurationTests.java new file mode 100644 index 0000000000..83e8b0195a --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ws/WsAutoConfigurationTests.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012-2016 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.boot.autoconfigure.ws; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.context.embedded.ServletRegistrationBean; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WsAutoConfiguration}. + * + * @author Vedran Pavic + */ +public class WsAutoConfigurationTests { + + private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setupContext() { + this.context.setServletContext(new MockServletContext()); + } + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void defaultConfiguration() { + registerAndRefresh(WsAutoConfiguration.class); + + assertThat(this.context.getBeansOfType(ServletRegistrationBean.class)).hasSize(1); + } + + @Test + public void customPathMustBeginWithASlash() { + this.thrown.expect(BeanCreationException.class); + this.thrown.expectMessage("Path must start with /"); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ws.path=invalid"); + registerAndRefresh(WsAutoConfiguration.class); + } + + @Test + public void customPathWithTrailingSlash() { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ws.path=/valid/"); + registerAndRefresh(WsAutoConfiguration.class); + + assertThat(this.context.getBean(ServletRegistrationBean.class).getUrlMappings()) + .contains("/valid/*"); + } + + @Test + public void customPath() { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ws.path=/valid"); + registerAndRefresh(WsAutoConfiguration.class); + + assertThat(this.context.getBeansOfType(ServletRegistrationBean.class)).hasSize(1); + assertThat(this.context.getBean(ServletRegistrationBean.class).getUrlMappings()) + .contains("/valid/*"); + } + + @Test + public void customLoadOnStartup() { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ws.servlet.load-on-startup=1"); + registerAndRefresh(WsAutoConfiguration.class); + + ServletRegistrationBean registrationBean = this.context + .getBean(ServletRegistrationBean.class); + assertThat(ReflectionTestUtils.getField(registrationBean, "loadOnStartup")) + .isEqualTo(1); + } + + @Test + public void customInitParameters() { + EnvironmentTestUtils.addEnvironment(this.context, + "spring.ws.init.key1=value1", "spring.ws.init.key2=value2"); + registerAndRefresh(WsAutoConfiguration.class); + + ServletRegistrationBean registrationBean = this.context + .getBean(ServletRegistrationBean.class); + assertThat(registrationBean.getInitParameters()).containsEntry("key1", "value1"); + assertThat(registrationBean.getInitParameters()).containsEntry("key2", "value2"); + } + + private void registerAndRefresh(Class... annotatedClasses) { + this.context.register(annotatedClasses); + this.context.refresh(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-ws/src/main/java/sample/ws/WebServiceConfig.java b/spring-boot-samples/spring-boot-sample-ws/src/main/java/sample/ws/WebServiceConfig.java index 3850c6efd2..77c9b70062 100644 --- a/spring-boot-samples/spring-boot-sample-ws/src/main/java/sample/ws/WebServiceConfig.java +++ b/spring-boot-samples/spring-boot-sample-ws/src/main/java/sample/ws/WebServiceConfig.java @@ -16,30 +16,17 @@ package sample.ws; -import org.springframework.boot.context.embedded.ServletRegistrationBean; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; -import org.springframework.ws.config.annotation.EnableWs; import org.springframework.ws.config.annotation.WsConfigurerAdapter; -import org.springframework.ws.transport.http.MessageDispatcherServlet; import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; import org.springframework.xml.xsd.SimpleXsdSchema; import org.springframework.xml.xsd.XsdSchema; -@EnableWs @Configuration public class WebServiceConfig extends WsConfigurerAdapter { - @Bean - public ServletRegistrationBean dispatcherServlet( - ApplicationContext applicationContext) { - MessageDispatcherServlet servlet = new MessageDispatcherServlet(); - servlet.setApplicationContext(applicationContext); - return new ServletRegistrationBean(servlet, "/services/*"); - } - @Bean(name = "holiday") public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) { DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();