I am developing a servlet which will support Async operation.
This servlet will be called via multiple filters. Some of the filters are as part of FilterProxyChain which is created via DelegatingFilterProxy.
If we have to start an Async Context from a servlet, then the Filter Chain should also support Async operation. Else below exception gets thrown -
28-Jul-2017 09:41:51.196 SEVERE [http-nio-127.0.0.1-7441-exec-2] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [eventBus] in context with path [] threw exception
java.lang.IllegalStateException: A filter or servlet of the current chain does not support asynchronous operations.
at org.apache.catalina.connector.Request.startAsync(Request.java:1630)
at org.apache.catalina.connector.Request.startAsync(Request.java:1623)
at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:1030)
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:379)
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:379)
at org.springframework.security.web.servletapi.HttpServlet3RequestFactory$Servlet3SecurityContextHolderAwareRequestWrapper.startAsync(HttpServlet3RequestFactory.java:167)
at com.amdocs.vshield.vsm.asyncrest.VsmAsyncRestController.doGet(VsmAsyncRestController.java:89)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
Some of the filters which are called via DelegatingFilterProxy are not configured in web.xml explicitly.
So how to make these filters to support Async ?
Here is what they say here: https://spring.io/blog/2012/12/17/spring-security-3-2-m1-highlights-servlet-3-api-support/#servlet3-async
So:
Spring Security version must be at least 3.2
web.xml's webapp element must have version="3.0"
Your DelegatingFilterProxy <filter> element must have <async-supported>true</async-supported>
Its mapping should have the following:
<dispatcher>REQUEST</dispatcher>
<dispatcher>ASYNC</dispatcher>
Finally found the root cause. There were some errors in web.xml due to which it servlets/filters not properly deployed. Dont know why tomcat didnt failed to start in that case.
You have to add for all the filters(Coming in filter chain)/ servlets. And with value as True.
I have a JSP-type servlet that registers a WebSocket Endpoint with the Servlet container.
I want to pass a reference of that servlet, and/or some of its objects, to the WebSocket Endpoint, so that I can use the code from that servlet, e.g. for Authentication or Session management (the servlet has its own non-Java EE Session management).
I was hoping that I could set some attribute somewhere when I call addEndpoint() on ServerContainer, because at that point I have access to the objects that I want to use later, but none of the classes that I've seen at that point have an attribute collection, e.g.
objectThatWillBeAvailableAtWebSocket.addAttribute("some.custom.object", someObject);
By the time my code reaches an ServletRequestListener, ServerEndpointConfig.Configurator, or the registered Endpoint, I do not have any reference to the original servlet that added the Endpoint.
How can I pass an Object to the WebSocket servlet? I'm running my test code in Embedded Jetty, but I'm aiming for Container-agnostic code.
Just like Spring MVC when we used deploy the application in the servlet container it is used to pickup the project name as servlet context and then as per our servlet mapping the container will process the request.
Here my question is i created spring-boot rest application having crud operations and deployed in tomcat server. But when i try to access any url like [http://localhost:8080/findAllRecords] then the server return 404 error request url not found but i add extra / in the url[http://localhost:8080//findAllRecords] it successfully execute the request.
As most people, I have a root and servlet contexts. I need to enable websocket Stomp. I also need to send messages from the Service layer. So how do I configure?
If I put websocket:message-broker into the servlet config, then SimpMessagingTemplate is not autowired in the service layer. If I put it into the root, then it doesn't work at all, it isn't registered as an HTTP handler (even though logs say it does). If I put everything into the dispatcher context, then there is a
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:252
For now I am going to work around it by calling SimpMessaging from Controller, and not Service, but I'd rather a better solution.
The familiar code:
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
My understanding is that /* maps to http://host:port/context/*.
How about /? It sure doesn't map to http://host:port/context root only. In fact, it will accept http://host:port/context/hello, but reject http://host:port/context/hello.jsp.
Can anyone explain how is http://host:port/context/hello mapped?
<url-pattern>/*</url-pattern>
The /* on a servlet overrides all other servlets, including all servlets provided by the servletcontainer such as the default servlet and the JSP servlet. Whatever request you fire, it will end up in that servlet. This is thus a bad URL pattern for servlets. Usually, you'd like to use /* on a Filter only. It is able to let the request continue to any of the servlets listening on a more specific URL pattern by calling FilterChain#doFilter().
<url-pattern>/</url-pattern>
The / doesn't override any other servlet. It only replaces the servletcontainer's built in default servlet for all requests which doesn't match any other registered servlet. This is normally only invoked on static resources (CSS/JS/image/etc) and directory listings. The servletcontainer's built in default servlet is also capable of dealing with HTTP cache requests, media (audio/video) streaming and file download resumes. Usually, you don't want to override the default servlet as you would otherwise have to take care of all its tasks, which is not exactly trivial (JSF utility library OmniFaces has an open source example). This is thus also a bad URL pattern for servlets. As to why JSP pages doesn't hit this servlet, it's because the servletcontainer's built in JSP servlet will be invoked, which is already by default mapped on the more specific URL pattern *.jsp.
<url-pattern></url-pattern>
Then there's also the empty string URL pattern . This will be invoked when the context root is requested. This is different from the <welcome-file> approach that it isn't invoked when any subfolder is requested. This is most likely the URL pattern you're actually looking for in case you want a "home page servlet". I only have to admit that I'd intuitively expect the empty string URL pattern and the slash URL pattern / be defined exactly the other way round, so I can understand that a lot of starters got confused on this. But it is what it is.
Front Controller
In case you actually intend to have a front controller servlet, then you'd best map it on a more specific URL pattern like *.html, *.do, /pages/*, /app/*, etc. You can hide away the front controller URL pattern and cover static resources on a common URL pattern like /resources/*, /static/*, etc with help of a servlet filter. See also How to prevent static resources from being handled by front controller servlet which is mapped on /*. Noted should be that Spring MVC has a built in static resource servlet, so that's why you could map its front controller on / if you configure a common URL pattern for static resources in Spring. See also How to handle static content in Spring MVC?
I'd like to supplement BalusC's answer with the mapping rules and an example.
Mapping rules from Servlet 2.5 specification:
Map exact URL
Map wildcard paths
Map extensions
Map to the default servlet
In our example, there're three servlets. / is the default servlet installed by us. Tomcat installs two servlets to serve jsp and jspx. So to map http://host:port/context/hello
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Doesn't match any extensions, next.
Map to the default servlet, return.
To map http://host:port/context/hello.jsp
No exact URL servlets installed, next.
No wildcard paths servlets installed, next.
Found extension servlet, return.
Perhaps you need to know how urls are mapped too, since I suffered 404 for hours. There are two kinds of handlers handling requests. BeanNameUrlHandlerMapping and SimpleUrlHandlerMapping. When we defined a servlet-mapping, we are using SimpleUrlHandlerMapping. One thing we need to know is these two handlers share a common property called alwaysUseFullPath which defaults to false.
false here means Spring will not use the full path to mapp a url to a controller. What does it mean? It means when you define a servlet-mapping:
<servlet-mapping>
<servlet-name>viewServlet</servlet-name>
<url-pattern>/perfix/*</url-pattern>
</servlet-mapping>
the handler will actually use the * part to find the controller. For example, the following controller will face a 404 error when you request it using /perfix/api/feature/doSomething
#Controller()
#RequestMapping("/perfix/api/feature")
public class MyController {
#RequestMapping(value = "/doSomething", method = RequestMethod.GET)
#ResponseBody
public String doSomething(HttpServletRequest request) {
....
}
}
It is a perfect match, right? But why 404. As mentioned before, default value of alwaysUseFullPath is false, which means in your request, only /api/feature/doSomething is used to find a corresponding Controller, but there is no Controller cares about that path. You need to either change your url to /perfix/perfix/api/feature/doSomething or remove perfix from MyController base #RequestingMapping.
I think Candy's answer is mostly correct. There is one small part I think otherwise.
To map host:port/context/hello.jsp
No exact URL servlets installed, next.
Found wildcard paths servlets, return.
I believe that why "/*" does not match host:port/context/hello because it treats "/hello" as a path instead of a file (since it does not have an extension).
The essential difference between /* and / is that a servlet with mapping /* will be selected before any servlet with an extension mapping (like *.html), while a servlet with mapping / will be selected only after extension mappings are considered (and will be used for any request which doesn't match anything else---it is the "default servlet").
In particular, a /* mapping will always be selected before a / mapping. Having either prevents any requests from reaching the container's own default servlet.
Either will be selected only after servlet mappings which are exact matches (like /foo/bar) and those which are path mappings longer than /* (like /foo/*). Note that the empty string mapping is an exact match for the context root (http://host:port/context/).
See Chapter 12 of the Java Servlet Specification, available in version 3.1 at http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html.