I've been googling for the last 2 days and still can't figure out why it wont expose the SOAP web service. It works when I run it locally using Tomcat and Spring Boot. In the jboss-deployment-structure, jpa, javaee-api and webservices has been excluded. Also, there are no exceptions in sysout or logs. Only the message specified further down (HTTP 405). Even checked through TRACE logs.
JBoss Version: 6.4.4 (or 6.4.0)
Spring Boot: 1.3.0
CXF: 3.0.4
Spring MVC: From Spring Boot parent
I get this message:
HTTP Status 405 - Request method 'POST' not supported.
When debugging, I placed a breakpoint in class: DispatcherServlet, which then in getHandlerAdapter returned HttpRequestHandlerAdapter. Further along, it calls the HttpRequestHandlerAdapter.handle which again calls handleRequest on a WebContentGenerator. This only supports GET or HEAD requests.
Any ideas?
Code:
#Configuration
public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {
ApplicationConfig.class
};
}
#Override
protected String[] getServletMappings() {
return new String[] {
"/*"
};
}
}
#Configuration
public class ApplicationServletInitializer extends SpringBootServletInitializer {
}
#Configuration
#EnableAutoConfiguration
#Import({
RepositoryConfig.class,
WebConfig.class,
WsProviderConfig.class
})
public class ApplicationConfig {
}
#Configuration
#EnableConfigurationProperties
public class WebConfig {
#Bean
public SelftestController selftestController() {
return new SelftestController();
}
}
#Configuration
public class WsProviderConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(WsProviderConfig.class);
#Autowired
private ApplicationContext context;
#Bean
ServletRegistrationBean messageDispatcherServlet() {
ServletRegistrationBean bean = new ServletRegistrationBean(new CXFServlet(), "/soap/*");
bean.setLoadOnStartup(1);
return bean;
}
#Bean(name = Bus.DEFAULT_BUS_ID)
Bus bus() {
SpringBus bus = new SpringBus();
bus.getFeatures().addAll(Arrays.asList(new WSAddressingFeature(), new LoggingFeature()));
return bus;
}
#Bean
PlayerServiceV1 defaultPlayerService() {
return new DefaultPlayerService();
}
#PostConstruct
void publishWebServices() {
LOGGER.info("Publishing WebServices");
DefaultPlayerService defaultPlayerService = context.getBean(DefaultPlayerService.class);
Bus bus = context.getBean(Bus.DEFAULT_BUS_ID, Bus.class);
EndpointImpl endpoint = new EndpointImpl(bus, defaultPlayerService);
endpoint.publish("/test/players");
}
}
Related
I'am trying to create a simple controller with Spring Boot
Congifuration is:
#Configuration
#EnableWebMvc
#ComponentScan (basePackages = { "ru.spb.chat.controller" })
public class WebConfig implements WebMvcConfigurer {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/view/");
bean.setSuffix(".html");
return bean;
}
}
and for servlet:
public class MainWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(final ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root =
new AnnotationConfigWebApplicationContext();
root.scan("ru.spb");
sc.addListener(new ContextLoaderListener(root));
ServletRegistration.Dynamic appServlet =
sc.addServlet("mvc", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
}
}
My controller.
#Controller
public class RootController {
#GetMapping ("/")
public String root() {
return "login";
}
}
But when I try to map on "/" it returns 404-ERROR
This is my project-structure:
Remove your WebConfig and remove your ServletInitializer and MainWebAppInitializer. (You can probably also remove the WebSocketConfig and use the auto-configuration from Spring Boot!).
Let your ChatApplication extend SpringBootServletInitializer and implement the configure method.
#SpringBootApplication
public class ChatApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ChatApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(ChatApplication.class);
}
}
Then in your application.properties add
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.html
Now you are using the proper Spring Boot auto-configuration AND proper way of creating a WAR which is executable.
That being said, you generally don't want a WAR (only if you use JSP, which is discouraged with embedded containers).
I'm using Apache CXF to implement Bottom Up Soap WS on a Spring Boot application. Everything was working fine until deployed on Weblogic (12.2.1.3.0). The issue is that the LoggingInterceptors that I'm trying to use are not being exceuted at all.
First problem was acctually a nullpointer on a #Autowired injection on the WebService implementation class. To fix that I use some workaround that I founded here on StackO. Appears that weblogic start separated context loaders, one for spring and all the beans and one for CXF. So when the webservice impl class is called via wsdl url the injection are not done. After fixing this issue, the WS works fine, but the logging interceptors added via spring boot configuration are not triggered. And one important feature of the application is the ability to store the soap request response on the database. So it's important that the Interceptors chain works.
The Spring Boot config class:
#Configuration
public class LmsReloadCXFWSConfig implements ServletContextInitializer{
private static WebApplicationContext webApplicationContext;
public static WebApplicationContext getCurrentWebApplicationContext() {
return webApplicationContext;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Bean
public ServletRegistrationBean servletRegistration() {
return new ServletRegistrationBean(new CXFServlet(), "/*");
}
#Bean
public LoggingInInterceptor logInInterceptor() {
return new LmsReloadWSInboundInterceptor();
}
#Bean
public LoggingOutInterceptor logOutInterceptor() {
return new LmsReloadWSOutboundInterceptor();
}
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}
#Bean
public LmsReloadWebService lmsReloadWebService() {
LmsReloadWebService lmsReloadWebService = new LmsReloadWebServiceImpl();
return lmsReloadWebService;
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), lmsReloadWebService());
endpoint.getInInterceptors().add(logInInterceptor());
endpoint.getOutInterceptors().add(logOutInterceptor());
endpoint.publish("/Soap");
return endpoint;
}
}
Both are Custom Interceptors that extends LoggingInInterceptor and LoggingOutInterceptor:
public class LmsReloadWSInboundInterceptor extends LoggingInInterceptor{
...
}
public class LmsReloadWSOutboundInterceptor extends LoggingOutInterceptor{
...
}
The Web Service interface and implementation:
#WebService(name = "LmsServiceInterface", targetNamespace=LmsReloadUtil.LMSRELOAD_NAMESPACE_ORI)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public interface LmsReloadWebService {
...
}
#WebService(portName = "LmsServicePort", serviceName = "Soap", targetNamespace = LmsReloadUtil.LMSRELOAD_NAMESPACE_ORI, endpointInterface = "com.dell.lms.reload.ws.LmsReloadWebService")
public class LmsReloadWebServiceImpl implements LmsReloadWebService {
#Autowired
private LmsReloadService lmsReloadService;
#Autowired
private LmsReloadLoggingService lmsReloadLoggingService;
public LmsReloadWebServiceImpl() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
WebApplicationContext currentContext = LmsReloadCXFWSConfig.getCurrentWebApplicationContext();
bpp.setBeanFactory(currentContext.getAutowireCapableBeanFactory());
bpp.processInjection(this);
}
...
}
The CXF version on my pom.xml is 3.2.7
What I need to do is to get those interceptors working so I can save the request and response on the database. Again, the application works fine and coomplete when executed useing the spring boot tomcat started in Eclipse. And since the issue with the Autowired on the WebService Impl Class, I think is something related to the way weblogic depoloy the application. Distinct context loaders.
Being investigating this problem during the last week, found a lot of possible solution, tried all but with no success.
I have been trying out the Java Configuration feature of Spring Web Flow 2.4 by modifying an existing project from xml configuration to JavaConfig. The XML version works, but JavaConfig doesn't. Every time I try to start the flow with URL http://localhost:8080/sia_p219_ch08_spring_web_flow_order_pizza_customer_flow_complete/pizza , it returns 404. There are no exceptions. The console show no "no request mapping found for..." message. The webpage shows The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
The project is hosted on github, the working XML version is here.
I think the problem is the request URL doesn't call the pizza flow (/WEB-INF/flows/pizza/pizza-flow.xml).
Here are some code snippets:
WebAppInitializer:
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
// map DispatcherServlet to /
protected String[] getServletMappings() {
return new String[] { "/" };
}
RootConfig:
#Configuration
#Import({WebFlowConfig.class})
public class RootConfig {}
WebFlowConfig:
#Configuration
#ComponentScan({"pizza"})
public class WebFlowConfig extends AbstractFlowConfiguration {
static{
System.out.println("WebFlowConfig loaded");
}
#Autowired
private WebConfig webMvcConfig;
#Bean
public FlowDefinitionRegistry flowRegistry() {
return
getFlowDefinitionRegistryBuilder(flowBuilderServices())
.setBasePath("/WEB-INF/flows")
.addFlowLocationPattern("/**/*-flow.xml")
.build();
}
#Bean
public FlowExecutor flowExecutor(){
return getFlowExecutorBuilder(flowRegistry()).build();
}
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setViewFactoryCreator(mvcViewFactoryCreator())
.setDevelopmentMode(true)
.build();
}
#Bean
public MvcViewFactoryCreator mvcViewFactoryCreator() {
MvcViewFactoryCreator factoryCreator = new MvcViewFactoryCreator();
factoryCreator.setViewResolvers(Collections.singletonList(this.webMvcConfig.viewResolver()));
factoryCreator.setUseSpringBeanBinding(true);
return factoryCreator;
}
}
WebConfig
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
static{
System.out.println("WebConfig loaded");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/flows/");
resolver.setSuffix(".jsp");
return resolver;
}
// configure static content handling
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
The flow definition files and JSPs are fine and you can see them on github if you want.
Thanks a lot, any help is greatly appreciated.
What I've found so far that the configuration definitely lacks this part of configuration in WebFlowConfig (take a look at the documentation page for integration with Spring MVC for details):
#Bean
#Autowired
public FlowHandlerAdapter flowHandlerAdapter(FlowExecutor flowExecutor) {
FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor);
return flowHandlerAdapter;
}
#Bean
#Autowired
public FlowHandlerMapping flowHandlerMapping(FlowDefinitionRegistry flowDefinitionRegistry) {
FlowHandlerMapping flowHandlerMapping = new FlowHandlerMapping();
flowHandlerMapping.setFlowRegistry(flowDefinitionRegistry);
flowHandlerMapping.setOrder(0);
return flowHandlerMapping;
}
Also remove mvcViewFactoryCreator definition and setViewFactoryCreator call from the flowBuilderServices bean definition as well. It works for me.
We are looking to migrate our project to Spring Boot. However it is unclear how to replicate the functionality of AbstractAnnotationConfigDispatcherServletInitializer in Spring Boot?
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
#Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[]{AppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[]{WebappConfig.class};
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setAsyncSupported(true);
}
#Override
protected String[] getServletMappings()
{
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters()
{
DelegatingFilterProxy shiroFilter = new DelegatingFilterProxy("shiroFilter");
shiroFilter.setTargetFilterLifecycle(true);
CompositeFilter compositeFilter = new CompositeFilter();
compositeFilter.setFilters(ImmutableList.of(new CorsFilter(),shiroFilter));
return new Filter[]{compositeFilter};
}
}
The AppConfig and WebappConfig parent/child relationship can be handled by SpringApplicationBuilder, although you might also consider a flat hierarchy.
Assuming that you are going the whole hog, and running an embedded servlet container you can register Filters and Servlets directly as beans.
You can also use ServletRegistrationBean and FilterRegistrationBean if you need to set things such as setAsyncSupported. The final option is to add a bean that implements org.springframework.boot.context.embedded.ServletContextInitializer then do the registration yourself.
Something like this might get you a bit further:
#Bean
public ServletRegistrationBean dispatcherServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(
new DispatcherServlet(), "/");
registration.setAsyncSupported(true);
return registration;
}
#Bean
public Filter compositeFilter() {
CompositeFilter compositeFilter = new CompositeFilter();
compositeFilter.setFilters(ImmutableList.of(new CorsFilter(), shiroFilter));
return compositeFilter
}
Also, take a look at this section in the reference manual http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-embedded-container
Well there is nothing special like just mark your AppInitializer with Boot annotations:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
}
I haven't tried it, but just combined the documentation:
Normally all the code from an existing WebApplicationInitializer can be moved into a SpringBootServletInitializer. If your existing application has more than one ApplicationContext (e.g. if it uses AbstractDispatcherServletInitializer) then you might be able to squash all your context sources into a single SpringApplication.
And SpringBootServletInitializer JavaDocs:
If your application is more complicated consider using one of the
other WebApplicationInitializers.
i am trying to combine a Spring Web Application (completed Annotation Based configuration, no xml configuration) with metrics 3.0.
I am running the application inside a jetty.
This is my current configuration for the default DispatcherServlet:
public class WebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] { characterEncodingFilter };
}
}
This is the WebConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.rebuy.silo.amqpredelivery")
#EnableJpaRepositories(basePackages = "com.rebuy.silo.amqpredelivery.domain")
#EnableAspectJAutoProxy
#EnableTransactionManagement
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
jacksonConverter.setObjectMapper(objectMapper());
converters.add(jacksonConverter);
super.configureMessageConverters(converters);
}
#Bean
public ObjectMapper objectMapper() {
SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssXXX");
format.setTimeZone(TimeZone.getTimeZone("GMT+1"));
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(format);
return mapper;
}
}
I want to add these two Servlets:
https://github.com/codahale/metrics/blob/master/metrics-servlets/src/main/java/com/codahale/metrics/servlets/HealthCheckServlet.java
https://github.com/codahale/metrics/blob/master/metrics-servlets/src/main/java/com/codahale/metrics/servlets/MetricsServlet.java
What is the best way to do this? I think there should be some spring magic to make this extremly easy to do! But I was not able to find it :(
Thanks in advance
Björn
You can follow this codebase https://github.com/spiritedtechie/metrics-examples.
Or use this library called metrics-spring http://ryantenney.github.io/metrics-spring/
If you are using Spring and Metrics you should also be using #RyanTenney's Metrics-Spring module. It will simplify your Java config and make your Metrics usage much cleaner.
Take a look at the code behind the MetricsServlet and HealthCheckServlet. In my opinion its easier to just write your own Spring Controller to do the same thing than to figure out how to embed and wrap those old servlets.
Its easy!
Create a metrics specific config:
#Configuration
#EnableMetrics
public class MetricsConfig extends MetricsConfigurerAdapter {
#Override
public void configureReporters(MetricRegistry metricRegistry) {
registerReporter(ConsoleReporter
.forRegistry(metricRegistry)
.build()).start(5, TimeUnit.MINUTES);
}
}
And include it from your existing config by adding:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.rebuy.silo.amqpredelivery")
#EnableJpaRepositories(basePackages = "com.rebuy.silo.amqpredelivery.domain")
#EnableAspectJAutoProxy
#EnableTransactionManagement
#Import({MetricsConfig.class})
public class WebConfig extends WebMvcConfigurerAdapter {
...
The above config changes make it trivial to inject a MetricRegistry in any Spring component. All the MetricsServlet does is send the registry in response to the request. That is really easy to accomplish in a simple controller. For example:
#Controller
public class AdminMetricsController
{
#Autowired
MetricRegistry metricRegistry;
#RequestMapping(value = "/admin/metrics/", produces = {APPLICATION_JSON_VALUE})
public #ResponseBody MetricRegistry getMetrics(final HttpServletResponse response)
{
response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
return metricRegistry;
}
}
A HealthCheckRegistry can be injected in a similar way and another method added which would respond to /admin/health/ or whatever url you wanted.
Take a look at the following answer. It explains how to register a Servlet via JavaConfig:
Spring JavaConfig: Add mapping for custom Servlet