Frustrated, i am posting this question. I am sure I have surfed enough to know that the proper answer is not discussed so far. But if the case is the contrary, please accept my Apologies and share with me the apt forum link.
I am testing the concepts of SSE broadcast using Jersey SSE API.
I am not using Maven or anything. Because the pet project i am working on, was started way before i became familiar with Maven, hence i manually add Jar files to the Web-Inf lib folder
I have the following relevant jars-
2/28/2016 06:58 PM 85,147 javax.json-1.0.4.jar
12/28/2016 06:58 PM 85,353 javax.servlet-api-3.0.1.jar
12/28/2016 06:58 PM 115,534 javax.ws.rs-api-2.0.1.jar
12/28/2016 06:58 PM 100,146 jaxb-api-2.2.7.jar
12/28/2016 06:58 PM 117,090 jersey-client-2.2.jar
12/28/2016 06:58 PM 600,514 jersey-common-2.2.jar
12/28/2016 06:58 PM 52,819 jersey-container-servlet-core-2.2.jar
12/28/2016 06:58 PM 18,107 jersey-container-servlet.jar
12/28/2016 06:58 PM 971,310 jersey-guava-2.24.1.jar
12/28/2016 06:58 PM 30,495 jersey-media-sse.jar
12/28/2016 06:58 PM 801,094 jersey-server-2.2.jar
My 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_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>SDTP-SS-UK-ERP</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/struts/*</url-pattern>
</filter-mapping>
<!-- Jersey Support Configuration for RestFul WebServices -->
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<!-- <servlet-name>jersey-servlet</servlet-name> -->
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.rest.services,com.sse.services</param-value>
</init-param>
<!--
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<!-- <servlet-name>jersey-servlet</servlet-name> -->
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
My Test SSE registration file. I use this to register for the SSE:
#Singleton
#Path("/sse")
public class SseTest extends ResourceConfig
{
public SseTest() {
super(SseTest.class, SseFeature.class);
}
public SseBroadcaster BROADCASTER = new SseBroadcaster();
#GET
#Path("/getSSE")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getMessageQueue()
{
EventOutput eventOutput = new EventOutput();
this.BROADCASTER.add(eventOutput);
System.out.println(eventOutput.toString());
return eventOutput;
}
//After this is registered, i trigger broadcast via another service-
#GET
#Path("/test2/{id}")
#Produces(MediaType.TEXT_PLAIN)
//#Consumes(MediaType.TEXT_PLAIN)
public String addMessage(#PathParam("id") final String msg) throws IOException
{
String misg= msg+"\\n\\n";
OutboundEvent.Builder eventBuilder = new OutboundEvent.Builder();
OutboundEvent event = eventBuilder.mediaType(MediaType.TEXT_PLAIN_TYPE).data(String.class, misg).build();
System.out.println(event.getData());
BROADCASTER.broadcast(event);
return "Message '" + msg + "' has been broadcast.";
}
Now i will share what happens in Chrome, or firefox:
When i am calling the service getSSE, the browser is registering event-stream and even there is a tab eventStream in the network details with a blank table- id, type, data.
When i call the service /test2/10, it shows 200 OK for that and the response is displayed in the browser.
In the getSSE tab, the first getSSE shows as complete and another getSSE comes up as pending.
But the eventsource data is still zero.
After calling test2 twice here is the result:
getSSE 200 eventsource sse.html:-Infinity 149 B 35.41 s
getSSE 200 eventsource Other 149 B 11.0 min
getSSE 200 eventsource Other 144 B Pending
Can someone please point out why i am not getting data? I am not getting any runtime errors in Server End Java.
The server is Tomcat 7.0.69
Java is JDK 1.7
Please help me make this work.. I am losing sleep out of curiosity where i am going wrong
Issue solved
Problem with Library versions
Related
I'm trying to do session replication with hazelcast in grails application as given in Hazelcast docs.
Grails version: 1.2.1
Hazelcast: 2.5.1 (Opensource edition)
I'm getting com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver when login.
All the domain objects that are added to session are serialized. But org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver is from spring framework. How can i serialize classes from springframework?.
Please help on configuring properly with spring and spring security in grails app.
Log when application is started:
Running Grails application..
loading security config ...
Feb 18, 2016 9:04:11 PM com.hazelcast.config.UrlXmlConfig
INFO: Configuring Hazelcast from 'jndi:/localhost/WEB-INF/hazelcast.xml'.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Prefer IPv4 stack is true.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Picked Address[192.168.43.68]:5702, using socket ServerSocket[addr=/0.0.0.0,localport=5702], bind any local is true
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Hazelcast Community Edition 2.5.1 (20130427) starting at Address[192.168.43.68]:5702
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Copyright (C) 2008-2013 Hazelcast.com
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTING
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.MulticastJoiner
INFO: [192.168.43.68]:5702 [dev] Connecting to master node: Address[192.168.43.68]:5701
Feb 18, 2016 9:04:12 PM com.hazelcast.nio.ConnectionManager
INFO: [192.168.43.68]:5702 [dev] 57981 accepted socket connection from /192.168.43.68:5701
Feb 18, 2016 9:04:18 PM com.hazelcast.cluster.ClusterManager
INFO: [192.168.43.68]:5702 [dev]
Members [2] {
Member [192.168.43.68]:5701
Member [192.168.43.68]:5702 this
}
Feb 18, 2016 9:04:19 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTED
Server running. Browse to http://localhost:8090/
Once I logged in I'm getting HazelcastSerializationException.
Stacktrace:
Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
[/].[default][21:04:27,561][http-8090-4] Servlet.service() for servlet default threw exception
com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
at com.hazelcast.nio.AbstractSerializer.toByteArray(AbstractSerializer.java:139)
at com.hazelcast.nio.Serializer.writeObject(Serializer.java:56)
...
Caused by: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
organization.ErrorController[21:04:27,754][http-8090-4] Exception in Controller; Cause=java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, Message=org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, forwardURI=/j_spring_security_check
org.codehaus.groovy.grails.web.errors.GrailsWrappedRuntimeException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at java.lang.Thread.run(Thread.java:662)
Caused by: com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
Process finished with exit code -1
User Domain Class:
class User implements Serializable {
def authenticateService
//domain properties
boolean isAccessingOwnProfile(){
User user = authenticateService.userDomain()
if(user?.id?.toString()?.equalsIgnoreCase(id?.toString())){
return true
}else {
return false
}
}
}
With this i got
com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.grails.plugins.springsecurity.service.AuthenticateService
So i did a quick fix by creating AuthenticateService as below
package com.example
class AuthenticateService extends org.grails.plugins.springsecurity.service.AuthenticateService implements Serializable {
}
after this i'm getting same exception in QualifierAnnotationAutowireCandidateResolver class
Config files:
/src/templates/war/web.xml
<?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">
<filter>
<filter-name>hazelcast-filter</filter-name>
<filter-class>com.hazelcast.web.WebFilter</filter-class>
<init-param>
<param-name>map-name</param-name>
<param-value>my-sessions</param-value>
</init-param>
<init-param>
<param-name>config-location</param-name>
<param-value>/WEB-INF/hazelcast.xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hazelcast-filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>com.hazelcast.web.SessionListener</listener-class>
</listener>
<display-name>/#grails.project.key#</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>#grails.project.key#</param-value>
</context-param>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
</filter>
<filter>
<filter-name>charEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>characterEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
</listener>
<!-- Grails dispatcher servlet -->
<servlet>
<servlet-name>grails</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- The Groovy Server Pages servlet -->
<servlet>
<servlet-name>gsp</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gsp</servlet-name>
<url-pattern>*.gsp</url-pattern>
</servlet-mapping>
<welcome-file-list>
<!--
The order of the welcome pages is important. JBoss deployment will
break if index.gsp is first in the list.
-->
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.gsp</welcome-file>
</welcome-file-list>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tld/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://www.springframework.org/tags</taglib-uri>
<taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
<taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
/WEB-INF/hazelcast.xml
<?xml version="1.0" encoding="UTF-8"?>
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-2.5.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<group>
<name>dev</name>
<password>dev-pass</password>
</group>
<network>
<port auto-increment="true">5701</port>
<join>
<multicast enabled="true">
<multicast-group>224.2.2.3</multicast-group>
<multicast-port>54327</multicast-port>
</multicast>
<tcp-ip enabled="false">
<interface>127.0.0.1</interface>
</tcp-ip>
<aws enabled="false">
<access-key>my-access-key</access-key>
<secret-key>my-secret-key</secret-key>
<!--optional, default is us-east-1 -->
<region>us-west-1</region>
<!-- optional, only instances belonging to this group will be discovered, default will try all running instances -->
<security-group-name>hazelcast-sg</security-group-name>
<tag-key>type</tag-key>
<tag-value>hz-nodes</tag-value>
</aws>
</join>
<interfaces enabled="false">
<interface>10.10.1.*</interface>
</interfaces>
<ssl enabled="false" />
<socket-interceptor enabled="false" />
<symmetric-encryption enabled="false">
<algorithm>PBEWithMD5AndDES</algorithm>
<!-- salt value to use when generating the secret key -->
<salt>thesalt</salt>
<!-- pass phrase to use when generating the secret key -->
<password>thepass</password>
<!-- iteration count to use when generating the secret key -->
<iteration-count>19</iteration-count>
</symmetric-encryption>
<asymmetric-encryption enabled="false">
<!-- encryption algorithm -->
<algorithm>RSA/NONE/PKCS1PADDING</algorithm>
<!-- private key password -->
<keyPassword>thekeypass</keyPassword>
<!-- private key alias -->
<keyAlias>local</keyAlias>
<!-- key store type -->
<storeType>JKS</storeType>
<!-- key store password -->
<storePassword>thestorepass</storePassword>
<!-- path to the key store -->
<storePath>keystore</storePath>
</asymmetric-encryption>
</network>
<partition-group enabled="false"/>
<management-center enabled="false" update-interval="3" >http://localhost:9999</management-center>
<executor-service>
<core-pool-size>16</core-pool-size>
<max-pool-size>64</max-pool-size>
<keep-alive-seconds>60</keep-alive-seconds>
</executor-service>
<queue name="default">
<max-size-per-jvm>0</max-size-per-jvm>
<backing-map-ref>default</backing-map-ref>
</queue>
<map name="default">
<backup-count>1</backup-count>
<time-to-live-seconds>0</time-to-live-seconds>
<max-idle-seconds>0</max-idle-seconds>
<eviction-policy>NONE</eviction-policy>
<max-size policy="cluster_wide_map_size">0</max-size>
<eviction-percentage>25</eviction-percentage>
<merge-policy>hz.ADD_NEW_ENTRY</merge-policy>
</map>
</hazelcast>
The exception is because of injecting service in domain class that implements Serializable interface.
I removed service injection in Domain class and tried logged in.
User domain class after removing dependency injection
class User implements Serializable {
// Removed authenticateService injection
//def authenticateService
//domain properties
/*boolean isAccessingOwnProfile(){
User user = authenticateService.userDomain()
if(user?.id?.toString()?.equalsIgnoreCase(id?.toString())){
return true
}else {
return false
}
}*/
}
and also removed custom AuthenticateService, that implements Serializable.
Now i can login to 1 instance and the session was replicated remaining instances.
I am development success and failure handlers in Spring Security.
Depends device type I must show one html view or send one json response. To this purpose I use Spring Mobile, but when I create Device object with HtttpServletRequest not found. Some idea?
web.xml
<filter>
<filter-name>deviceResolverRequestFilter</filter-name>
<filter-class>org.springframework.mobile.device.DeviceResolverRequestFilter</filter-class>
</filter>
ApplicationContext.xml
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.mobile.device.DeviceWebArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
Class
public class AuthFailureHandler implements AuthenticationFailureHandler{
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException ae) throws IOException, ServletException {
Device device = DeviceUtils.getCurrentDevice(request);
if(device.isNormal()){
response.sendRedirect(response.encodeRedirectURL("./userNoAuth"));
} else {
response.sendRedirect(response.encodeRedirectURL("./rest/userNoAuth"));
}
}
}
Error
java.lang.NullPointerException at com.myapp.security.handler.AuthFailureHandler.onAuthenticationFailure(AuthFailureHandler.java:19)
UPDATE:
I am change .getCurrentDevice(HttpServletRequest) method to getRequiredCurrentDevice(HttpServletRequest).
Now I get this error.
java.lang.IllegalStateException: No currenet device is set in this request and one is required - have you configured a DeviceResolvingHandlerInterceptor?
Verify your web.xml contains a filter-mapping for the deviceResolverRequestFilter. The following is a working example from the Spring Mobile Samples repository. Hope that helps!
https://github.com/SpringSource/spring-mobile-samples/tree/master/lite-device-resolver-xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Use the DeviceResolverRequestFilter OR the DeviceResolverHandlerInterceptor in the servlet-context.xml -->
<filter>
<filter-name>deviceResolverRequestFilter</filter-name>
<filter-class>org.springframework.mobile.device.DeviceResolverRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>deviceResolverRequestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Is it possible to implement annotation based custom HTTP 404 error page using Spring 3.2.1?
I looked for ways in various forums but couldn't find any clear answer.
I also tried configuring using web.xml but it is not working when I access unmapped URL.
Any help please?
Log output
7259 [DEBUG] org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'spring-test' processing GET request for [/spring-test/ss]
7261 [DEBUG] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /ss
7262 [DEBUG] org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/ss]
7262 [WARN ] org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/spring-test/ss] in DispatcherServlet with name 'spring-test'
7262 [DEBUG] org.springframework.web.servlet.DispatcherServlet - Successfully completed request
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
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"
id="rest" version="3.0" metadata-complete="true">
<!-- The definition of the Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>main.java.net.bornil.config</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>main.java.net.bornil.config</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>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file />
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/errors/404</location>
</error-page>
</web-app>
Controller
#Controller
#RequestMapping(value = "/errors")
public class CommonExceptionHandler {
private static Logger log = Logger.getLogger(CommonExceptionHandler.class.getName());
#RequestMapping(method = RequestMethod.GET, value = "/{code}")
public ModelAndView handleException(#PathVariable int code) {
if (log.isDebugEnabled()) {
log.debug("ERROR CODE IS: " + code);
}
return new ModelAndView("errors/404");
}
}
I had the same issue. I've a simple webapp, single page and, after spending a morning on the Spring forum (so nice you cannot search '404' there because it's just 3 chars long) and Google this is the best solution I found.
Assuming you have a index.jsp and a 404.jsp, my #Configuration' has:
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/*").setViewName("404");
}
I've read the docs ( http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework ) several times and I can't confirm if the WebApplicationContext context that gets injected when you use the #WebApplicationContext annotation is actually looking at the web.xml.
In other words, I want to test my web.xml configuration. The filters and servlet path specifically. But when I configure my test it ignores the web.xml. (e.g. I try a get request on a URL like this /myServletPath/foo and it fails with a 404.)
My test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration({
"classpath*:WEB-INF/config/application-context.xml",
"classpath*:WEB-INF/oms-servlet.xml",
"classpath*:persistence-context.xml"
})
public class OrderSummaryControllerIntegrationTests {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void testFindOrderSummariesExpectsSuccess() throws Exception {
mockMvc.perform(get("/oms/orders?user=1234&catalog=bcs"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
}
And my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_2_5.xsd"
version="2.5">
<display-name>OMS REST Services</display-name>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<filter>
<filter-name>webappMetricsFilter</filter-name>
<filter-class>com.yammer.metrics.web.DefaultWebappMetricsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>webappMetricsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/application-context.xml, classpath*:persistence-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>oms</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>oms</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
You are right, Spring-mvc-test does not read the web.xml file, but you can configure the filters this way:
webAppContextSetup(this.wac).addFilter(new DefaultWebappMetricsFilter(), "/*").build()
I'm attempting to make use of JAX-RS' (Jersey) MVC pattern. Attempts to reach http://localhost:8080/myproject/foos/test result in an error that reads:
java.io.IOException: The template name, /view, could not be resolved to a fully qualified template name
http://localhost:8080/myproject/foos results in the same error.
What am I missing?
Resource:
package resources;
import com.sun.jersey.api.view.Viewable;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("foos")
public class FooResource {
#GET
#Produces(MediaType.TEXT_HTML)
public Viewable get() {
return new Viewable("/index", this);
}
#GET
#Path("{id}")
#Produces(MediaType.TEXT_HTML)
public Viewable get(#PathParam("id") String id) {
return new Viewable("/view", id);
}
}
Views:
WEB-INF / jsp / resources / FooResource
index.jsp
view.jsp
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">
<filter>
<filter-name>jersey</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
<param-value>/(resources|images|js|styles|(WEB-INF/jsp))/.*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<description>Set the default, base template path to the WEB-INF folder.</description>
<param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
<param-value>/WEB-INF/jsp</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
Made the following changes:
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">
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>welcome.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>jersey</filter-name>
<filter-class>com.sun.jersey.spi.container.servlet.ServletContainer</filter-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>controllers</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.WebPageContentRegex</param-name>
<param-value>/((WEB-INF/views))/.*</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
<param-value>/WEB-INF/views/</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.Redirect</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Resource:
#Path("foos")
public class FooResource {
#GET
#Produces(MediaType.TEXT_HTML)
public Viewable index() {
return new Viewable("/foos/index", this);
}
#GET
#Path("{id}")
#Produces(MediaType.TEXT_HTML)
public Viewable view(#PathParam("id") String id) {
return new Viewable("/foos/view", id);
}
}
Views:
\welcome.jsp
\WEB-INF\views\foos\
index.jsp
view.jsp
I had this same error running under Jetty 9. The application ran fine using mvn clean jetty:run but had this error when packaged as a war and deployed under Jetty. This is the fix in web.xml that worked for me:
<init-param>
<param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
- <param-value>/WEB-INF/views/</param-value>
+ <param-value>/WEB-INF/views</param-value>
</init-param>
Yep, that's it. So, hopefully this helps someone who stumbles across this. My config is basically the same as craig's, but had the extra slash.
From initial inspection I think you want to put index.jsp and view.jsp directly in WEB-INF/jsp.
The name should be a fully qualified name like /index.jsp or /index.html.