Apache CXF and Spring but no WSDL (recursive links) - spring

I have written a small sample web service, using Apache CXF (CXFServlet) and Spring (ContextLoaderListener) I have registered the CXFServlet to listen on the / url. And I am declaring my beans in beans.xml.
When I start the web service with tomcat and go to the service url, then I can see the web service definition (e.g. methods, endpoint, wsdl link). But the problem is that when I click on the wsdl link, then I do not get the WSDL file, but instead I am recursively forwarded back to the same page, but each time the name of the web service address is appended:
localhost:8080/Test/accountEndpoint
localhost:8080/Test/accountEndpointaccountEndpoint
localhost:8080/Test/accountEndpointaccountEndpointaccountEndpoint
The service is a "code-first" service which a #WebService annotated java interface and a implementation class.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Test</display-name>
<servlet>
<servlet-name>cxf</servlet-name>
<display-name>cxf</display-name>
<description>Apache CXF Endpoint</description>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
beans.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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<bean id="account" class=".....AccountImpl" />
<jaxws:endpoint id="accountEndpoint" implementor="#account"
address="accountEndpoint" />
</beans>
As I understand it, CXF should automatically generate the WSDL file and provide it to me, when I click on the link, so I do not understand why that is not happening.

Specify the address this way, with a leading slash:
<jaxws:endpoint id="accountEndpoint" implementor="#account"
address="/accountEndpoint" />
Sorry, making a change, the above is not correct:
You are right, I am able to replicate the behavior with mapping CXFServlet to the "default" servlet path mapping of /, the fix that I could get to work for myself is to map it to /* instead:
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

Related

Could not resolve view with name X in servlet with name Y

I am using Spring and AngularJS for a rest web application. Base on this tutorial and based on this tutorial I've created the following folder structure:
-src
|----main
|----webapp
|----static
|----api
|----assets
|----resources
|----sections
|----services
|----index.html
|----WEB-INF
|----web.xml
|----spring
|----dispatcher-servlet.xml
|----applicationContext.xml
I want to serve static HTML files so I declared the resources as following:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="org.tools.mvc.controllers"></context:component-scan>
<mvc:resources location="/static/" mapping="/**"/>
<mvc:resources location="/static/api/" mapping="/api/**"/>
<mvc:resources location="/static/assets/" mapping="/assets/**"/>
<mvc:resources location="/static/resources/" mapping="/resources/**"/>
<mvc:resources location="/static/services/" mapping="/services/**"/>
<mvc:resources location="/static/sections/home/" mapping="/sections/home/**"/>
<bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"></bean>
<bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"></bean>
My problem is that when I deploy the application( I am using Glassfish server) the following error occurs( in Eclipse console and also in the browser page):
2016-05-27T04:46:06.640-0700|Warning: StandardWrapperValve[dispatcher]: Servlet.service() for servlet dispatcher threw exception
javax.servlet.ServletException: Could not resolve view with name 'index.html' in servlet with name 'dispatcher'
The functionality of the service is not affected( using Postman to test the rest api results in success). Until now, in order to further develop the application I manually added index.html to the end of the URL(like localhost:8080/status/index.html). The source of the "/" as declared in Web Deployment Assembly is:
Source: /src/main/webapp
Deploy Path: /
Update: The web.xml file is looking like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>status</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
How can I resolve this error?
Thank you
P.S The solutions found on SO didn't applied to my scenario.
I discovered that I've declared a view resolver ( BeanNameViewResolver) inside applicationContext.xml. After deleting the view resolver, I didn't receive the error.
The error occurred because Spring was trying to interpret my view( witch was a html static file) to a bean.

Spring 4 websocket + Tomcat 7.54 async-supported not working

I am creating a sample chat application using the Spring websockets and stomp.js , I am using the tomcat 7.54 but while runing the application I am gettting a async-supported error when browser is making xhr request.
Server info: Apache Tomcat/7.0.54
Servlet version: 3.0
JSP version: 2.2
Java version: 1.7.0_25
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<async-supported>true</async-supported>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:websocket="http://www.springframework.org/schema/websocket"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="index.htm">indexController</prop>
</props>
</property>
</bean>
<context:component-scan base-package="hello" />
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/hello">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic"/>
</websocket:message-broker>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />
</beans>
ERROR
java.lang.IllegalArgumentException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml. Also you must use a Servlet 3.0+ container
at org.springframework.util.Assert.isTrue(Assert.java:65)
I guess you don't show entire web.xml.
<async-supported>true</async-supported> should be configured for <filter>, too.
UPDATE
Well, your issue is very simple:
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
You really should map for all requests, not only the root.
The <async-supported>true</async-supported> should be included in both the
servlet and filter tags. Use the following snippet as reference:
<web-app ...>
...
<servlet>
<servlet-name>instantaction</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF/spring/web/my-servlet-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
...
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Add the below in nginx.conf file if you are using the reverse proxy.
# For WebSocket upgrade header
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Try upgrade you jdk and tomcat version. I encountered this problem also, I upgrade jdk from 1.7 to 1.8, upgrade tomcat form 7.0.54 to 7.0.75, and resolved this problem.
Make sure no other injected component disables async support.
DETAILS
I learned that Spring comes with asynchronous support by default.
And (remotely related) sync logging configuration may disable async handling for entire service.
Specifically, my logback integration was missing IMPORTANT line:
public EmbeddedServletContainerCustomizer containerCustomizer(
final String logbackAccessClasspathConfig
) {
return container -> {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addContextCustomizers(context -> {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename(logbackAccessClasspathConfig);
// IMPORTANT:
logbackValve.setAsyncSupported(true);
context.getPipeline().addValve(logbackValve);
}
);
}
};
}
Thanks to other answer:
LogbackValve is configured for synchronous processing by default
disable the bean that was injecting LogbackAccess
set the asyncSupported="true" attribute where you configure the valve
I was having the same issue with SpringBoot app and for me, it started working
1) after adding asyncSupported to the filter like #WebFilter(urlPatterns="/api-acess/*",asyncSupported = true )
2) added sameOrigin() support to WebSecurityConfigurerAdapter extended class like http.headers().frameOptions().sameOrigin();
I hope it will help someone else.

How to set publishedUrl of a CXF service used by its WS-Discovery plugins?

I am trying to publish the URL of a CXF service using the CXF WS-Discovery plugins.
The tutorial https://cxf.apache.org/docs/writing-a-service-with-spring.html helps me to build an helloworld service.
The CXF documentation of WS-Discovery https://cxf.apache.org/docs/ws-discovery.html, explain that adding cxf-services-ws-discovery-service.jar allow to publish it.
Great, but the published url is relative to the servlet and then not reachable from client that send the WS-Discovery Probe.
I found an interesting approach http://osdir.com/ml/users-cxf-apache/2012-05/msg00524.html that suggests to use the following web.xml and cxf-servlet.xml files :
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app.xsd">
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservices/*</url-pattern>
</servlet-mapping>
</web-app>
cxf-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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<bean id="localhost" class="java.net.InetAddress" factory-method="getLocalHost" />
<bean id="publishedWebServiceUrl" class="java.lang.String">
<constructor-arg value="#{'http://' + localhost.hostAddress + ':8080' + servletContext.contextPath + '/webservices/hello_world'}"/>
</bean>
<jaxws:endpoint id="hello_world" implementor="HelloWorldImpl" address="/hello_world">
<jaxws:properties>
<entry key="publishedEndpointUrl" ><ref bean="publishedWebServiceUrl" /></entry>
</jaxws:properties>
</jaxws:endpoint>
</beans>
This works fine if the servlet container use the port 8080.
I tried to use servletContext.getRealPath('/webservices') but this give the filesystem path and not the http address.
Is there a way to get the servlet container port (compliant with tomcat, jetty, ...) ? or an other way to publish an exportable URL ?
I'm afraid you need configure the address from outside, I don't think CXF can tell the port that the servlet container is using.

Picking up Tomcat's Context.xml parameters via SpEL

Deploying war to Apache Tomcat 8 the following way.
Placing myApp.xml under $CATALINA_HOME/conf/[enginename]/[hostname]/
with the following contents:
<Context>
<Parameter name="myApp_configs" value="file:/the/path/to/configs/folder"
type="java.lang.String" override="false"/>
</Context>
B.t.w. I do not place any kind of Context.xml into war.
Then copying myApp.war to $CATALINA_HOME/webapps
This is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>service</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
And this way I try loading properties-file in beans.xml (referenced in web.xml above).
<?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:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<!-- Imported resources for cxf -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<!--context:property-placeholder
location="#{contextParameters['myApp_configs']}/myApp.properties"/-->
<bean id="configurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="#{contextParameters['myApp_configs']}/myApp.properties"/>
</bean>
...other lines follow here...
</beans>
However I am getting following error upon beans loading:
Field or property 'contextParameters' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
Could you help me understand the error and propose a fix so that I can access Context-defined parameters?
P.S. I have not put here, but I also have some <Environment>-nodes in Context, and they are successfully accessible via JNDI in other places.
So as we were not able to solve the root cause - why contextParameters bean is not available, the following workaround (using ol' syntax) took place:
<bean id="myConfigsLocation"
class="org.springframework.web.context.support.ServletContextParameterFactoryBean">
<property name="initParamName" value="myApp_configs" />
</bean>
<context:property-placeholder
location="#{myConfigsLocation}/myApp.properties" />
And it worked successfully.

What are the configurations or xml files to run a basic Spring MVC application?

I need to know the basic XML configuration files to put in my Web-inf folder, like web.XML, and where to write view resolver bean.
How do I register the controller?
When I run my application I get the error "could not open servlet context resource". What is servlet context resource and where do I mention it?
My web.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
jsp/index.jsp
</welcome-file>
</welcome-file-list>
</web-app>
My springmvc is:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean name="/hello_world.html" class="springmvc.web.HelloWorldController"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
I have these two xml files only.
I know I need a spring configuration file too. I don't know what details I need to put in that.
If you use STS (Spring Tool Suite) then you can create a Spring Template Project.
(New Project/SpringSource Tool Suite/Spring Template Project/-Spring MVC Project)
This contains all the files you need to start.

Resources