Servlet url pattern - java.lang.NullPointerException in servlet Context - servlets

my servlet performs three tasks:
When it receives a message "resourceupdate" stores the requested resource (an HTML page) to an object sharedClient.
When it receives an asynchronous get (querystring indicated by "t = UPDATE") adds the object sharedClient this request pending.
When it receives a delivery_resource (indicated by pathinfo myServlet/sharedsessionID - eg. myServlet/8439jfndofsd93jcanjc) performs the dispatch of the resource.
this is my Web.xml:
<servlet>
<description></description>
<display-name>MyServlet</display-name>
<servlet-name>MyServlet</servlet-name>
<servlet-class>it.package.MyServlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet/*</url-pattern>
</servlet-mapping>
I keep all the active SharedClients in this way:
ConcurrentHashMap<String, SharedClient> hmClients = (ConcurrentHashMap<String, SharedClient>) this.getServletConfig().getServletContext().getAttribute("sharedClients");
And I get the SharedClient with a specific SharedSessionID in this way:
SharedClient targetClient = hmClients.get(ssid);
now the problem:
until I do a resourceupdate servlet works fine, but when i do a delivery_resource (to a path of type myServlet/sharedsessionID) the servlet is unable to obtain the sharedClient reference, and I get a Null Pointer Exception.
if (resourceUri!=null) {
String ssid = resourceUri.substring(1);
ConcurrentHashMap<String, SharedClient> hmClients = (ConcurrentHashMap<String, SharedClient>) this.getServletConfig().getServletContext().getAttribute("sharedClients");
if (hmClients.containsKey(ssid)) {
SharedClient targetClient = hmClients.get(ssid);
if (targetClient.getParticipantSession().containsKey(session)) {
IoUtils.copy(targetClient.streamSnapshot(), response.getOutputStream());
}
} else System.out.println("hmClient do not contains ssid"); //always in this branch
From this time also the long polling with asynchronous get are not completed successfully.
If i do not do a delivery_resource to a path of type myServlet/sharedsessionID after the update the asynchronous get continue to function properly.
Thanks to all.

ok, i resolved.
i need to write
#WebServlet(urlPatterns = {"/myServlet/*"}, asyncSupported=true)
before myServlet declaration.

Related

URL pattern servlet mapping

I created hello world example using Spring MVC, but there is one thing I didn't understand in servlet URL mapping, I did the following in web.xml:
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
now if I want to call the following controller:
#Controller
#RequestMapping("/hello")
public class HelloWorld {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model){
model.addAttribute("message","hello world");
return "index";
}
}
it will work using the following link:
http://localhost:8080/test/hello
but when I change the servlet url-pattern to "/*" and try:
http://localhost:8080/hello
it doesn't work, shouldn't it match my servlet ? as * matches everything
When you register a servlet with "/*" then it will override all the servlet mappings if there are any. Hence it should be avoided. This overrides default servlet mapping as well hence all default url handling also overridden and hence any specific url matching fails. In your case it is /hello.
With your case, initially you registered with /test/* this registered all your URL's with /test and hence they got identified.
It doesn't work for /* because, you have not registered/created a controller for that pattern.
It worked for http://localhost:8080/hello because, you have controller #RequestMapping("/hello")
Just change the RequestMapping to #RequestMapping("/") for url-pattern /*

Spring LazyInitializationException when using "redirect" in controller

I started creating an application with Spring-Roo 1.3.1 and Spring-Security 3.1.7
I'm using Spring OpenEntityManagerInViewFilter to be able to do lazy loading of my domain objects.
<filter>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This is working fine so far. However, I encountered the following issue when doing a redirect from a controller:
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#Valid Service service, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, service);
return "services/update";
}
uiModel.asMap().clear();
serviceRepository.save(service);
return "redirect:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest);
}
This redirect return "redirect:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest); is failing with an LazyInitializationException. It fails during execution of the filter chain after the commit is done and redirect took place. The URL redirected to is working when access directly.
When using return "forward:/services/" + encodeUrlPathSegment(service.getId().toString(), httpServletRequest); the page loaded just fine.
I really do not know why the hibernate session is not available when using "redirect". Another strange thing is, when activating DEBUG logging for org.springframework.security.web is is also working fine.
e.g. log4j.logger.org.springframework.security.web=DEBUG
I already searched the internet for some hints but generally lazy loading is working fine in my app, it's just in that circumstance and currently I do not fully understand why.
Any comments/hints are welcome.
Thanks
Stefan
Try to change controller like this:
#RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(#Valid Service service, BindingResult bindingResult,
Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, service);
return "services/update";
}
uiModel.asMap().clear();
Service attached = serviceRepository.save(service);
return "redirect:/services/" +
encodeUrlPathSegment(attached.getId().toString(),
httpServletRequest);
}
The instance service is create by Spring binder to map request values to the object but it is not attached to entityManager (no db session). When you call save you get an attached (instance managed by entityManager) instance so, if you try to get any lazy property from this instance it knows how do it.
You can found more information about JPA objects live cycle here.
Good luck!

Character-encoding Spring MVC

I am having trouble with Turkish characters...In my JSP pages, there is no problem... but, when an alert come from Java side, Turkish character(ŞşİığĞüÜç...) seems like that (ı,?,ü,ç,Å,...)
In JSP pages, I use this code and ı can solve Turkish character problem
<%# page contentType="text/html;charset=UTF-8" language="java"%>
in Spring MVC config, I tried a lot of way but I didn't succeed... For example In my mvc config class, I set my MessageSource like that;
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
messageSource.setCacheSeconds(0);
return messageSource;
}
In this program, I try to reset password and I typed unregister email address..Finally I am getting exception and this following is exception code blog.
#Autowired
private MessageSource messages;
...
#ExceptionHandler({ UserNotFoundException.class })
public ResponseEntity<Object> handleUserNotFound(final RuntimeException exception, final WebRequest request) {
logger.error("404 Status Code", exception);
final GenericResponse bodyOfResponse = new GenericResponse(messages.getMessage("message.userNotFound", null, request.getLocale()), "UserNotFound");
return handleExceptionInternal(exception, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request);
}
In my messages_tr_TR.properties file,
...
message.userNotFound=Kullanıcı Bulunamadı
...
but In JSP pages this alert shows like that;
Kullanıcı Bulunamadı
How can I solve this problem..
Comment follow-up, you can set the encoding in your response header as well. An example if you're returning json would be
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json; charset=utf-8");
return handleExceptionInternal(exception, responseHeaders, HttpStatus.NOT_FOUND, request);
In web.xml:
<jsp-config>
<!-- global JSP configuration -->
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Put the actual text in the handler method (temporarily). Does it now look right? Is your messages file correctly saved as UTF-8? Also, I can't tell if you're using JSON or not...

Spring-mvc servlet mapping, is it possible to have "/" for servlet 1 and "/server/" for servlet 2?

Currently I have the following web.xml config:
<servlet>
<servlet-name>Website</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Website</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Server</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Server</servlet-name>
<url-pattern>/server/</url-pattern>
</servlet-mapping>
As for two example controllers:
#Controller
public class ApiRequests {
protected final Logger logger = Logger.getLogger(ApiRequests.class);
#RequestMapping(value = "api.json", produces = {"application/json"}, method = RequestMethod.GET)
#ResponseBody
public String handleActionJson(final HttpServletRequest request){
return "{test: 'blaat'}";
}
}
And
#Controller
#RequestMapping("/")
public class IndexController {
#RequestMapping("*.html")
public void showIndex(){
}
}
Now my problem is that when I try to call the /server/api.json url, the server won't give the json response, instead it gives me the following error:
PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/api.json] in DispatcherServlet with name 'Website'
Which basically means its trying to search for /server/api.json in the Website servlet instead of the Server serlvet, as for my question: would it be possible to get this setup to work? (So /server/ to map to the Server servlet and all the other url combinations to the Website servlet)
Edit 1
I updated the code to reflect the changes as suggested by Costi Ciudatu but it still doesn't work. I removed the #RequestMapping("/server") and now only have the #RequestMapping at the handleActionJson method. Both resulting in these errors:
10:57:26,046 WARN PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/server/api.json] in DispatcherServlet with name 'Website'
10:57:40,509 WARN PageNotFound:1108 - No mapping found for HTTP request with URI [/WorldDefense/server/api.json] in DispatcherServlet with name 'Website'
Mappings according to the tomcat log:
Server-servlet
11:03:49,655 INFO RequestMappingHandlerMapping:178 - Mapped "{[/api.json],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String com.world2.worlddefense.server.controllers.ApiRequests.handleActionJson(javax.servlet.http.HttpServletRequest)
11:03:50,125 INFO RequestMappingHandlerMapping:178 - Mapped "{[/api.json],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public java.lang.String com.world2.worlddefense.server.controllers.ApiRequests.handleActionJson(javax.servlet.http.HttpServletRequest)
Website-servlet
11:03:50,380 INFO RequestMappingHandlerMapping:178 - Mapped "{[//*.html],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public void com.world2.worlddefense.website.controllers.IndexController.showIndex()
11:03:50,381 INFO RequestMappingHandlerMapping:178 - Mapped "{[/login],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.world2.worlddefense.website.controllers.TempTestController.showTest()
You can define multiple DispatcherServlets in the same web.xml and map them as you wish. However, the servlet mapping should not be reflected in the #RequestMapping of your controllers. Your controllers always map to paths relative to the servlet mapping; in your case, I think you could get that JSON response if you tried /WorldDefence/server/server/api.json...
If you want different controllers to be associated with the two dispatchers, you only need to make sure that the proper controllers are loaded in the corresponding application context: Website-servlet.xml and Server-servlet.xml in case you stick with this convention.
Long story short, your mapping for ApiRequests should be '/', not '/server' and that controller should only be included in the "Server" dispatcher context.
As a side note, since 3.2.x, the .json extension is handled by the ContentNegotiationManager, so your controller should return some domain object which will be transparently marshaled by the Spring HttpMessageConverter mechanism and will thus be able to produce media types other than JSON with no effort.

RequestDispatcher ending in infinite loop

I have two WAR applications and the mode of communication between them is via servlets.
My application (WAR A) opens a child window with the URL of a servlet in another WAR (lets say WAR B).
The servlet (in WAR B) processes the data and should send the processed data back to original application's servlet (i.e WAR A's servlet).
But this process ends in an infinite loop and also the URL parameters sent from WAR-A are null.
Here is the code snippet :
The below script opens a child window with the URL of servlet in WAR-B also passing some URL parameters.
function invokePlugin(invokeURL, custValJSON, meaCompPartJSON) {
window.open(invokeURL + '?custValJSON=' + custValJSON,'');
}
Below is servlet code in WAR-B which extracts the URL parameters and process the data and again send the request back to WAR-A's servlet...
private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String custValJSON = request.getParameter("custValJSON");
System.out.println("custValJSON : " + custValJSON);
CustomValues custVal = gson.fromJson(custValJSON, CustomValues.class);
if(custVal != null) {
System.out.println("Cust val details : " + custVal.getName());
custVal.setValue("Satya");
}
String destination = "/testPlannerPluginResult";
RequestDispatcher reqDispatch = request.getRequestDispatcher(destination);
request.setAttribute("custValJSON", gson.toJson(custVal));
if(reqDispatch != null) {
reqDispatch.forward(request, response);
}
}
Does anybody have idea on this?
Regards,
Satya
That then just means that the servlet is basically calling itself everytime. I don't immediately see the cause in the information given so far, but apparently the URL which you passed into the getRequestDispatcher() matches the URL of the servlet itself.
I however see a major mistake here:
RequestDispatcher reqDispatch = request.getRequestDispatcher(destination);
request.setAttribute("custValJSON", gson.toJson(custVal));
That can impossibly invoke the servlet which runs in another servlet context (read: another WAR). You need ServletContext#getContext() first to get the other servlet context and then use ServletContext#getRequestDispatcher() to dispatch the request to there.
ServletContext otherServletContext = getServletContext().getContext("/otherContextPath");
RequestDispatcher dispatcher = otherServletContext.getRequestDispatcher(destination);
This only requires that the both WARs are configured to expose the context for sharing. On Tomcat for example, this is to be done by adding crossContext="true" to the <Context>.

Resources