Does RequestDispatcher work over multiple webapps ?
I'm asking because I had a single webapp working fine that uses RequestDispatcher rather than redirects so state isnt lost when displaying error and feedback messages.
However I now need to split some functionality between two webapps, so initial call is made from a webpage hosted on webapp1, calls webapp2 which eventually returns user to a page hosted on webapp1.
Clearly if webapps and webapp2 were on different websites using RequestDispatcher would not be possible but is it if both webapps are deployed within the same instance of a servlet container (tomcat 7)
Update
Got the request dispatcher part to work as explained in answer but am unable to retrieve data put in my webapp2 which iss why Im using it
i.e
webapp2 called , does some processing and then dispatches to a jsp on webapp1
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
HttpSession userSession = request.getSession(true);
String emailAddress = ......
String nextPage = /finish.jsp
userSession.setAttribute("DATA", emailAddress);
ServletContext otherContext = getServletContext().getContext("/webapp1");
otherContext.getRequestDispatcher(nextPage).forward(request, response);
}
webapp2 jsp file contains
...
<p>Email(<%=((String)session.getAttribute("DATA"))%>)</p>
...
but always displays null
Update 2 **
Im wondering if Im misunderstanding what crossContext="true" actually does . Does it make the same HttpSession availble in different webapps, or does it just make the ServletContext from one webap availble to another and hence allow one webapp to see the HttpSessions of another webapp ?
Im starting to think what Im doing is a bad idea as Ive always been keen to use vanilla servlet setups and never want to tie myself to a particular implementation. I think it might help if I explain why I flet the need to split the webapps in the first place.
I had a one webapp (webapp1), that was a website about a product I develop and code for purchasing that product using Google Checkout (now Google Wallet).
I then added created a new webapp for a new product (webapp2).
I then tried to add Google Checkout for new product into webapp2, but realised I couldnt do this easily because Google Checkout requires me to provide it with a url which it can call by application once it has processed payment so that I can then send
user a license. The url was already set to a servlet in webapp1, but
it wouldn't make sense for webapp1 to process payment s for product 2.
One option was to merge webpp1 and webapp2 into one webapp, but this goes against my general view of keeping things modular, it
would also mean evey time I would want to make chnages for one
product Id have to redeploy everything. It also meant big
modifications to webapp1 which I really didnt want to modify as it
was working and stable.
The alternative was to create webapp3 and then google url can point to this, and use this for processing purchases of product 1
and product 2 which is what Ive done. But the problem is when
purchasing product 1 the starting page is in webapp1 , and once
purchase has taken place I want to go back to a page in webapp1, but
only webapp3 has the details of the user who has just made the
purchase which I wanted to display on on the page in webapp1.
This is due to security reasons by default not possible. You need to configure Tomcat first to enable exposing the ServletContext of the current webapp to other webapps. This is to be done by setting the crossContext attribute of context.xml to true.
<Context ... crossContext="true">
Once done that, then you can use ServletContext#getContext() to obtain the other servlet context by its context path and finally use the RequestDispatcher as obtained by ServletContext#getRequestDispatcher() the usual way.
E.g.
ServletContext otherContext = getServletContext().getContext("/otherContext");
otherContext.getRequestDispatcher("/WEB-INF/some.jsp").forward(request, response);
Yes.
The first thing you need to do is get hold of a ServletContext for the other webapp. You do that with ServletContext::getContext on your own ServletContext, passing the context path of the other webapp.
Then, you simply do ServletContext::getRequestDispatcher as normal on the foreign context.
I haven't actually tried this, but i 100% guarantee that it will work.
I am not sure about different servlet container. But it works for same container by using
getServletContext().getContext() method.
First you need to make changes in below file
(Windows) C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf\context.xml
Set value of crossContext to true.
context.xml
<Context crossContext="true">
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
</Context>
Please note that crossContext="true".
Suppose you have two web applications with name InterServletComm1 and InterServletComm2
having servlets Servlet1 and Servlet1 in each web application respectively. Then the code in each servlets goes as follows:
Servlet1.java
package interServletComm1;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Servlet1
*/
#WebServlet("/Servlet1")
public class Servlet1 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public Servlet1() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
request.setAttribute("name", "WebApp1");
ServletContext context = getServletContext().getContext("/InterServletComm2");
RequestDispatcher rd = context.getRequestDispatcher("/Servlet2");
rd.forward(request, response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
Servlet2.java
package interServletComm2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Servlet2
*/
#WebServlet("/Servlet2")
public class Servlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public Servlet2() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
String name = (String) request.getAttribute("name");
pw.println("This is web application 2.");
pw.println("<br>The value received from web application one is: " + name);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
Above code sends attribute name from InterServletComm1 and it is received in InterServletComm2.
Please let me know if this answer is not clear.
Related
This question already has answers here:
Where is Tomcat Console Output on Windows
(4 answers)
Closed 4 years ago.
I am using Java 7, tomcat 7. While learning about servlet logging I wrote a simple program.
package net.codejava;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class LogCheck
*/
#WebServlet("/LogCheck")
public class LogCheck extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public LogCheck() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
ServletContext context = getServletContext();
String par = request.getParameter("msg");
if (par == null || par.equals("")){
context.log("No Message received",new IllegalStateException("Missing Parameter"));
}else{
context.log("Here is visitor's message:"+par);
}
PrintWriter out = response.getWriter();
out.println("Log Testing.");
}
}
Now I am able to see the log messages in my Eclipse console. But I do not see any files under Tomcat Home/logs folder ?
But I read that it should store the log messages in some log files. I do not see any log file in my case.
Am I missing some configuraions? Please help
They will be logged to the file localhost.${today}.log.
As Maks said, ServletContext#log will logged with the category org.apache.catalina.core.ContainerBase. and when you look at Tomcat's logging configuration in conf/logging.properties, you'll see that these messages go to files with the prefix localhost.
https://tomcat.apache.org/tomcat-7.0-doc/logging.html
The calls to javax.servlet.ServletContext.log(...) to write log messages are handled by internal Tomcat logging. Such messages are logged to the category named
org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]
This logging is performed according to the Tomcat logging configuration. You cannot overwrite it in a web application.
Where the logs live:
When running Tomcat on unixes, the console output is usually redirected to the file named catalina.out. The name is configurable using an environment variable.
When running as a service on Windows, the console output is also caught and redirected, but the file names are different.
I have an existing Web Application (Servlet) that remotely accesses an EJB currently written to the EJB 2.1 Specification (EJBHome, EJBObject, SessionBean, all configuration in ejb-jar.xml). The servlet access the EJB via JNDI lookup, the JNDI name being specified in weblogic-ejb-jar.xml.
I would like to update the EJB to EJB3.0, which will (hopefully) make it easier to add to the API.
My issue is that I need to do it with a minimum of change to the existing servlet code. In other words, I still need to:
Access the EJB with a simple, global JNDI name (it is stored in a database, and the servlet can can change the name it looks up on the fly), and
Be able to use the 2.1 style:
String jndiName = getJndiName(); // e.g. "BeanV2.0"
BeanHome home = (BeanHome) PortableRemoteObject.narrow(
jndiContext.lookup(jndiName), BeanHome.class);
BeanRemote remote = home.create();
remote.doBusiness(); // call business method
I have tried a stripped down version, applying #RemoteHome, but I keep getting errors during deployment.
I am deploying (for development/production) on Weblogic, mostly 10.3.5 (11gR1), and am limited to EJB 3.0. I am using Eclipse (with the Oracle Weblogic Pack) for development.
Thanks.
I would suggest you to first understand the architectural difference between EJB2.1 and EJB3.x (refer here)
You will have some major/minor changes in code based on your bean implementation and client side invocation, because of the removal of Home and Deployment Descriptor in EJB3.x
Refer this example for accessing EJB3.x from a client, in your case Servlet
/**
* Servlet implementation class SampleServlet
*/
public class SampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public SampleServlet() {
super();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Context ctx=getInitialContext();
String jndiName=getJndiName(); // eg. java:global/BeanProject/Bean!demo.BeanRemote
BeanRemote beanRemote = (BeanRemote)ctx.lookup(jndiName);
remote.doBusiness();
} catch(Exception exception) {
System.out.println(exception.getMessage());
}
}
private static Context getInitialContext() throws Exception
{
Properties properties=new Properties();
properties.put("java.naming.factory.initial","org.jboss.naming.remote.client.InitialContextFactory");
properties.put("java.naming.provider.url","remote://localhost:4447");
return new InitialContext(properties);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Hope this helps!
I create a servlet in my CQ5 application:
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
#SlingServlet(
label = "Example Servlet",
paths = {"/bin/project/signin"},
methods = {"GET"},
extensions = {"html"},
metatype = false
)
public class SignInServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 796802690004962223L;
#Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
doPost(request, response);
}
#Override
protected void doPost(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/plain");
response.getOutputStream().print("Sigin Servlet");
}
}
i try to call it via rest-client but it return:
No resource found for url: http://localhost:4502/bin/project/signin
I also open Sling Resource Resolver at Felix side to test if it available. But i received:
NonExistingResource, path=/bin/project/signin
/bin/ already config in Apache Sling Servlet/Script Resolver and Error Handler at Fellix
In the #SlingServlet annotation you've declared that this servlet supports only requests with .html extension, so you should hit following URL:
http://localhost:4502/bin/project/signin.html
If you don't want to use the extension, remove appropriate parameter from the servlet annotation.
Two ways to help debug this type of situation —
The ServletResolver will allow you to check which Servlet a given GET or POST request will resolve against.
If you find the request you made that generated the 404 in the Recent Requests tab, it should tell you exactly what properties it has found by Sling when trying to resolve it.
E.g. in your case, I presume the 404 is giving something like:
LOG Resource Path Info: SlingRequestPathInfo: \
path='/bin/project/signin', \
selectorString='null', \
extension='null', \
suffix='null'
Comparing this against the settings in your annotation, there's an extension='null' here that wouldn't match against your servlet — which is binding only against a 'html' extension, as Tomek rightly says above.
I'm using SimpleCaptcha to secure our contact form. It works well, but only after reloading the page.
The Servlet is nl.captcha.servlet.StickyCaptchaServlet, so it should not change the image after reloads. But when first opening the page the image is just not loaded. However, after reloading everything works fine.
the web.xml
The captcha is served by an application running at /services.
<web-app>
<servlet>
<servlet-name>captcha</servlet-name>
<servlet-class>nl.captcha.servlet.StickyCaptchaServlet<servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>captcha</servlet>
<url-pattern>/captcha.png</url-pattern>
</servlet-mapping>
</web-app>
the html
<img src="/services/captcha.png">
the server
I'm using tomcat-7.0.34 on a Windows 7 64bit machine with Java 1.7.0_07.
the question
Why does the image only show up after a reload? Any ideas?
there are several steps you can follow:
1> modify web.xml add your servlet that extends nl.captcha.servlet.StickyCaptchaServlet class
<servlet>
<description></description>
<display-name>CustomCaptchaServlet</display-name>
<servlet-name>CustomCaptchaServlet</servlet-name>
<servlet-class>org.example.servlets.CustomCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CustomCaptchaServlet</servlet-name>
<url-pattern>/CustomCaptchaServlet</url-pattern>
</servlet-mapping>
2> CustomCaptchaServlet.java
package org.example.servlets;
import static nl.captcha.Captcha.NAME;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import nl.captcha.Captcha;
import nl.captcha.servlet.CaptchaServletUtil;
import nl.captcha.servlet.StickyCaptchaServlet;
public class CustomCaptchaServlet extends StickyCaptchaServlet {
private static final long serialVersionUID = 1L;
/**
* #see StickyCaptchaServlet#StickyCaptchaServlet()
*/
public CustomCaptchaServlet() {
super();
// TODO Auto-generated constructor stub
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String _width = getServletConfig().getInitParameter("width");
String _height = getServletConfig().getInitParameter("height");
HttpSession session = request.getSession();
Captcha captcha;
if (session.getAttribute(NAME) == null) {
captcha = new Captcha.Builder(Integer.parseInt(_width), Integer.parseInt(_height))
.addText()
.gimp()
.addBorder()
.addNoise()
.addBackground()
.build();
session.setAttribute(NAME, captcha);
CaptchaServletUtil.writeImage(response, captcha.getImage());
return;
}
captcha = (Captcha) session.getAttribute(NAME);
CaptchaServletUtil.writeImage(response, captcha.getImage());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Just do this way to by pass what emka86 had said.
<img src="/services/captcha.png" style="display:none"> (Duplicate part to fix the issue)
<img src="/services/captcha.png"> (The actual one)
Hope this helps for any future developer out there.
Check that the web.xml has captcha.png while the HTML is referring to captcha.jpg.
Does that solve the issue?
The problem is that StickyCaptchaServlet is creating new captcha image for session. When you make initial request to a page you have no session id so StickyCaptchaServlet cannot connect you to any image created for a particular session. After first request main servlet create session for you and send you back some kind of sessionId. With next request (also reload) you send to server request with recevied previously sessionId so now your StickyCaptchaServlet is possible to collect captcha image for your session because it knows that you are in any session.
Do you understand this explanation? Will it be helpfull for you?
Added after your question to resolve this problem.
You can add to your web app class which will implements HttpSessionListener. Then, in method sessionCreated you can add request to StickyCaptchaServlet with just created sessionId. According to StickyCaptchaServlet doc You just have to invoke doGet method of it with passed sessionId key. After that - when browser on your page will request for url /services/captcha.png it should get as response image created and prepared just before it by your HttpSessionListener implementation.
Other way is to use cliend side scripting and after page is loaded, with no image at all, just reload it - as this internal reload, for example JavaScript, the browser will know sessionId and will pass it through the request for captcha image. By reload I mean only reload image, not the whole page.
Will any of those suggestions resolve your problem? Give me a feedback about it.
I have few questions.
Can i have a Servlet without these two methods?
Can i call my form directly to Service method... Like
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FormServlet extends HttpServlet {
protected void doService (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
No, it's not mandatory. Since HttpServlet is an abstract class, there are abstract implementations of all doXXX methods, and you don't have to implement them if you don't want to.
Yes, you can have a servlet without either of these methods (they have no implementation). Still having a HttpServlet without having doGet/doPost seems a bit pointless, since servlet can only communicate with the a limited number of request methods such as GET, POST, DELETE, PUT (for more see specification section 5.1.1 ).
HttpServlet don't have doService methods. If you meant void service() then I advise you not to mess with it unless you really know what you're doing.
If all you need is to use doService call it from doGet, doPost (as someone already suggested).
Ok, examples:
public class DoesNothingServlet extends HttpServlet {} //does what the name implies
public class FormServlet extends HttpServlet { //what you want to do
protected doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
protected void doService (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Do something
}
}
Read http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/servlet/http/HttpServlet.html
Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site. A subclass of HttpServlet must override at least one method, usually one of these:
doGet, if the servlet supports HTTP GET requests
doPost, for HTTP POST requests
doPut, for HTTP PUT requests
doDelete, for HTTP DELETE requests
init and destroy, to manage resources that are held for the life of the servlet
getServletInfo, which the servlet uses to provide information about itself
From your doGet and doPost methods, you can call your doService(..,..) method if you wish.
You will note that the service() method originates from the javax.servlet.GenericServlet and not javax.servlet.http.HttpServlet.
If you want to do something with a servlet which doesn't involve the http protocol, I would say go ahead.
In the Head First Servlets and JSP they explain this in detail. 99% You will make use of the HttpServlet.
By extending GenericServlet, the servlet would run regardless of the content submitted. As long as the URL is fired the service() method will execute.
My understanding, if I got you correct, is you want your HTTP GET, POST, (PUT, DELETE) to call your doService method. If that's the case, you can do this.
protected doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
protected doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doService(request,response)
}
If you extends HttpServlet you don't have to override doGet and doPost as it's already implemented by HttpServlet. Servlet request get handled by the service() method which then (based on the HTTP request method) calls its relevant doXXX method.
I wouldn't mess with the service() method though, unless you know what you're doing.