Servlet Called Twice - java

On my web application, which is hosted on Google App Engine, whenever I call a Servlet by typing in the URL on a browser, this results in two calls being made to the Servlet. However, if I make a call to the Servlet by clicking on an anchor, then only one call is made.
What is the cause and how can I correct this behavior?
Web.xml
<servlet>
<servlet-name>ServletOne</servlet-name>
<servlet-class>com.test.nz.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletOne</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
Servlet:
public class MyServlet extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
final Logger log = Logger.getLogger(MyServlet.class.getName());
log.info("Here in MyServlet");
}
}
Update:
The issue appears to be caused by Google Chrome making requests on its own. Whenever I type in a URL, a request is made before I actually press enter, followed by the actual request. Is there any way to disallow these type of requests to my application?

I had the same issue, only in Chrome, turns out the servlet was mapped to / and was accepting requests for favicon.ico as well. For me this is the source of the second request.

Related

Java GWT server programming handling GET/POST requests

I am new to java programming in the web environment and am having trouble understanding the flow.
For an assignment coming up I need to build a web application accessible with an API via get/post requests. For the tutorials that I have followed here is the flow I understand.
User visits top domain->
Per configuration user is directed to a jsp page->
Jsp contains javascrip and html. To access server code (for database, computations and other processes) the jsp page can use RCP to make async requests to a java servlet->
Java servlet does server handling and returns response to jsp page
Is this the required flow or can a user directly acess a servlet, and can that servlet handle get/post, or do I have to handle at the jsp and foward to the servlet?
Servlets can be accessed directly. You just need to extend HttpServlet and implement doGet and/or doPost. For example:
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
Integer param = null;
try {
param = Integer.parseInt(req.getParameter("param"));
}
catch(NumberFormatException e) {
}
}
}
You also need to map your servlet to url in web.xml:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.adam.test.server.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/my_servlet</url-pattern>
</servlet-mapping>
Now you can access your servlet using url like this:
http://domain.com/my_servlet?param=123

What exactly do the service() method of this HttpServlet?

this is my first time that I work on a Java project that use HttpServlet.
So I know that an HttpServlet is a program that run on a Web Application server and act as a middle layer between a request coming from a Web browser or other HTTP client and databases or applications on the HTTP server. So the servlet extend the competence of my application server.
I have some doubt to understand how exactly work this servlet founded into my project, into web.xml file I found this configuration:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>My Project</display-name>
<listener>
<listener-class>it.sistinf.ediweb.quartz.QuartzListener</listener-class>
</listener>
<servlet>
<servlet-name>edimon</servlet-name>
<servlet-class>it.sistinf.ediweb.monitor.servlets.Monitoraggio</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>edimon</servlet-name>
<url-pattern>/edimon.do/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/logon.jsp</welcome-file>
</welcome-file-list>
<taglib>
<taglib-uri>displaytag</taglib-uri>
<taglib-location>/WEB-INF/displaytag-11.tld</taglib-location>
</taglib>
</web-app>
So reading some documentation it seem to understand that I have to tell the servlet container (or application server) what servlets to deploy, and what URL's to map the servlets to.
In the previous case I am configuring a servlet named edimon implemented by the Monitoraggio class.
Then it is mapped the servlet to a URL or URL pattern. In this case the edimon servlet is mapping with the /edimon.do/* URL pattern. So when it is called something that match with the previous pattern the edimon servlet is performed.
Then into my Monitoraggio class that implement the HttpServlet I found the service() method:
public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
LoggerMDC.setup(req, res);
Logger logger = (Logger) Logger.getStdLogger(Monitoraggio.class); // do not declare 'logger' as static field in order to work with MDC
String service = req.getParameter("serv");
char serviceId = Utility.getServizio(req.getParameter("serv"));
if (checkSession(req, serviceId) == false) {
gotoPage(ConfigurationFactory.getPropertiesPages().getProperty("pagina_errore_session"), req, res);
return;
}
LoggerWatch loggerWatch = new LoggerWatch(Monitoraggio.class, Long.valueOf(System.getProperty(Constants.Keys.CONFIG_STATS_WARNING_THRESHOLD, String.valueOf(LoggerWatch.DEFAULT_WARNING_THRESHOLD))).longValue());
if (logger.isTraceEnabled())
logger.trace("lanciaServizio() | logger threshold: " + loggerWatch.getWarningThreshold());
loggerWatch.start();
loggerWatch.info(new StringBuffer("service() | servizio: [").append(service).append("] | service start").toString());
String paginaDaLanciare = lanciaServizio(serviceId, req, res);
String executionTime = loggerWatch.getInfoTime();
//Modifica per export
if (req.getSession().getAttribute("export") == null) {
gotoPage(paginaDaLanciare, req, res);
}
loggerWatch.info(new StringBuffer("service() | servizio: [").append(service).append("] | [").append(executionTime).append("] after forward to ").append(paginaDaLanciare).toString(), true);
loggerWatch.stop();
req.getSession().removeAttribute("export");
req.getSession().removeAttribute("stringaXML");
req.getSession().removeAttribute("downbyte");
return;
}
Reading on the documentation it receives standard HTTP requests from the public service method and dispatches them to the doXXX methods defined in this class
So what exatly do this method? I can't understand how the servlet load the JSP
The documentation you read describes what the service() method of HttpServlet does by default. Since your servlet overrides the service() method and provides a different implementation, it doesn't do that anymore. Instead, it does... what the code in the method does.
A servlet doesn't "load a JSP". I don't see how JSPs have any relation to the servlet code you posted. Maybe gotoPage() does tell the container to forward the request to a JSP. You should look at the documentation and/or code of that method to know what it does.

How do I specify a query string in Tomcat's <servlet-mapping> <url-pattern>?

I am running Tomcat 5.5.4 and have a servlet running with no problems. However, I'd like to set up a mapping to only launch the servlet when a URL containing a particular query string is submitted.
Right now in web.xml I have:
<servlet-mapping>
<servlet-name>MyServer</servlet-name>
<url-pattern>/go/*</url-pattern>
</servlet-mapping>
If a browser submits http://localhost/MyServer/go?P=123 the servlet is launched and all is well. However, I'd like to only launch that servlet if the URL is exactly as just shown. Unfortunately, right now if the URL is http://localhost/MyServer/go?P=AnyDarnThing the servlet still launches. I have tried setting up the following:
<url-pattern>/go?P=123</url-pattern>
but this results in The requested resource (/MyServer/go) is not available.
I've tried numerous variations (quoting the string, ...) on the above URL pattern but I always get the above error. I notice that if I (for debugging purposes) drop the "?" as in
<url-pattern>/goP=123</url-pattern>
I no longer get the error message and the server launches (but, of course, it doesn't respond to the "query string" because it's not properly formed.) This suggest to me that the "?" is causing a problem in the mapping. I've tried replacing it with its URL special character equivalent as follows:
<url-pattern>/go%3FP=123</url-pattern>
but this gives the same result just described above when I tried dropping the "?" altogether.
I realize I can let the servlet get launched when any query string is submitted and then "ignore" the request for all but the one I care about but there is a reason I'd prefer to not have the servlet launched to begin with. So, my question is, how can I configure the servlet so that it is only launched when a specific query string is included?
Thank you.
You can't do that. The url-pattern is pretty limited.
If you want to have distinct actions taken based on a GET parameter, you can do that manually. In the doGet() method of the servlet have a simple if-clause and invoke different methods depending on the query string / get param.
You can't do that using URL patterns.
You can achive this using filters. Implement a filter which will forward to the Servlet only if the query params exists.
Here is the how the filter will look like:
public class ServletAcessFilter implements Filter
{
public void init(FilterConfig filterConfig) throws ServletException
{
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException
{
//validate the request, check if the request can be forwarded to servlet.
if(request.getParameter("P").equalsIgnoreCase("123")){
filterChain.doFilter(request, response);
} else {
//write what you want to do if the request has no access
//below code will write 404 not found, you can do based on your requirement
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(404);
}
}
public void destroy()
{
}
}
Define the filter in the web.xml like this:
<filter>
<filter-name>ServletAccessFilter</filter-name>
<filter-class>com.ServletAcessFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ServletAccessFilter</filter-name>
<url-pattern>/go/*</url-pattern>
</filter-mapping>
To add to Bozho response, you may also try to move to Clean URLs
This will greatly increase your options in terms of URL pattern matching, and, in particular, may significantly ease configuration of a fronting reverse proxy if you ever need one.

custom 503 error page thrown from servlet java

This is pretty simple and straightforward. I want to throw a 503 error from the servlet side.
response.sendError(503);
When this is thrown, I need it to hit a custom error page. Basically a 503 error page itself, but with a few modifications.
Say I have 503.html, and I added
<error-page>
<error-code>503</error-code>
<location>/503.html</location>
</error-page>
in web.xml.
I created a war file, with a servlet which throws the 503 error, and web.xml with this content. I kept the 503.html in the parent folder location. (Should I keep it elsewhere ?)
I deployed the app in WLS, but this custom 503.html is not getting hit. I am getting the generic 503 error.
Am I missing something?
My code is below:
webapp1.war
->web-inf
->web-inf->classes->prject4->Class1.class
->web-inf->jsp->error->custom.html
web.xml
<?xml version="1.0"?>
<!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>
<servlet>
<servlet-name>Class1</servlet-name>
<servlet-class>project2.Class1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Class1</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<error-page>
<error-code>503</error-code>
<location>/WEB-INF/jsp/error/custom.html</location>
</error-page>
</web-app>
class1.java
public class Class1 extends HttpServlet
{
private ServletConfig config;
public void init(ServletConfig config)throws ServletException
{
this.config=config;
}
public void service (HttpServletRequest request, HttpServletResponse response)
throws IOException
{
response.setContentType("text/html");
ServletOutputStream l_out = response.getOutputStream();
response.sendError(503);
}
}
Ok, this was a minor error which I didn't figure out in the beginning.
In my web.xml the servlet-mapping was given as /*, which was causing an infinite loop condition as it throws the same code for which it has been mapped. So I had to adjust the servlet mapping so that Class1 doesn't map to any error pages - like say /images/*.
And then everything started working fine. :)
You can also try handling it with custom Error Handler.
public void service (HttpServletRequest request, HttpServletResponse response)
throws IOException
{
try
{
//some error generating code
throw new Exception("503_Exception");
}
catch(Exception e)
{
response.sendRedirect(HandleError.handle(e, request));
}
}
A separate class to handle errors. This can handle different types of errors.
You can add functionality to log stacktrace, send out emails if something is wrong etc.
public class HandleError{
public static String handle(Throwable t, javax.servlet.http.HttpServletRequest request)
{
String sErrorMsg = t.getMessage();
if (sErrorMsg.equals("503_Exception")) {
request.setAttribute("msg", Constants.EINVALSESSION);
return "/503.html";
}
return "/default_error.html";
}
}
If you are using Maven as your project build tool then it will look in the src/main/webapp directory, so for example our config looks like this:
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/error/error404.html</location>
</error-page>
and our error404.html sits in the folder:
${PROJECT_NAME}/src/main/webapp/WEB-INF/jsp/error/
If your not using Maven the path in the location will have a base directory of wherever you put your index.jsp
I guess there's a minimum limit on the number bytes your custom error page has. The lower limit is usually 512 Bytes. See Important note for your Custom error pages. I've seen this behavior in Google-Chrome too when using Tomcat.

Tomcat - Redirect to Error Page when ServletContextListener fails

When Tomcat starts it calls my ServletContextListener to obtain a database connection, which I will later use in other servlets with getServletContext(). It is called in my web.xml as:
listener
listener-class org.ppdc.database.DBCPoolingListener /listener-class
/listener>
(I removed the < > because they wouldn't display properly in this message.>
If I cannot connect to the database when Tomcat starts up I get a 404 error, because Tomcat cannot start the application.
How can I redirect the user to a custom error page at this point? I tried the following in my web.xml (I have the < > brackets in the original):
(error-page)
(error-code404/error-code)
(location/file_not_found.html/location)
(/error-page)
Any ideas on how to redirect a user to one of my error pages when Tomcat tries to start the application?
Thanks
Vic
If your application fails to load, then that's it. Tomcat is not running it and does not serve your error-pages.
So, if you want to handle a half-dead state, you need to start in a half-dead state. Fortunately, the code in your servlets can be spared checks whether the app is half-dead if you install a Filter, that does it before control is transfered to any servlet.
Declare a filter in web.xml:
<filter>
<filter-name>IsHalfDeadFilter</filter-name>
<filter-class>my.package.IsHalfDeadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>IsHalfDeadFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
Then implement doFilter method to redirect to your error page.
#Override
public void doFilter (
final ServletRequest request,
final ServletResponse response,
final FilterChain chain
) throws
IOException,
ServletException
{
if ( isHalfDead )
{
// redirect to error page
return;
}
chain.doFilter( request, response );
}
Read more about Filters here

Categories

Resources