Get virtual path of the invoked servlet inside the servlet code - java

If I've something like this:
<servlet>
<display-name>Step</display-name>
<servlet-name>Step</servlet-name>
<servlet-class>com.foo.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Step</servlet-name>
<url-pattern>/aservlet/*</url-pattern>
</servlet-mapping>
and the servlet is invoked by a request of the form /aservlet/ABC
then is there a way to get the value "ABC" in the code? i.e inside the doGet() or doPost() methods of the class AServlet?

THe easiest thing to do is,
String path = request.getPathInfo();
Which returns "/ABC".

public void doGet(HttpServletRequest request, HttpServletResponse response){
String uriRequest = request.getRequestURI();
//parse to obtain only the last part
String uriRequest = uriRequest.substring(uriRequest.lastIndexOf("/")+1);
}
Same thing for doPost().

Related

Conditional Http Proxy Servlet

Working on a http proxy servlet which is used to forward the request to another remote server.
NOTE: Cannot change the URL Pattern
Snippet of web.xml
<servlet>
<servlet-name>SomeServlet</servlet-name>
<servlet-class>SomeServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SomeServlet</servlet-name>
<url-pattern>/pattern1/*</url-pattern>
</servlet-mapping>
SomeServlet.Java
Validates the requests to check for specific content in request body and if matches forward to remote server. (Working as expected)
but if the condition fails, request processing should continue as is.
what I have now,
public class proxyServlet extends HttpServlet {
/* it has all the init other configs*/
#Overrirde
protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws ServletException, IOException {
/* If true, returns which endpoint for remote server else returns null */
String endPoint = checkForConditions(servletRequest);
if(endPoint == null) {
return; // this is not letting the app to continue with flow.
} else {
HttpRequest newR = new BasicHttpRequest(method, endPoint);
doExecute(servletRequest, newR)
}
}
}
I cannot create a new request and forward since server will again catch the pattern and do it in a infinite loop.
What is the best way to accomplish this? Any suggestions are greatly appreciated.
UPDATE-Solved: As per the comment from #balusc, Used servlet-filter and on condition use a HTTPClient to send POST request to remote server else chain.doFilter(...)

how to have several endpoints in one servlet and declare them in web.xml [duplicate]

This question already has answers here:
Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?
(7 answers)
Closed 1 year ago.
I'm learning servlets and I want to create two different endpoints in a single servlet.
I mean, I want to have /hello and /test each one of them should execute or refer to different class as shown below.
In other words, I want to be able to acceess to:
http://localhost:8080/HelloServlet/hello
and
http://localhost:8080/HelloServlet/Test
So that the corresponding or the respective class must be invoked and display the respective contents
HelloWorld example:
#WebServlet(name = "HelloServlet", urlPatterns = {"/sayHello", "/hello", "/helloWorld"})
public class HelloWorld extends HttpServlet{
private String responseContentType = null;
public HelloWorld() {
super();
}
public void init() throws ServletException {
responseContentType = "text/html;charset=UTF-8";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set the response message's MIME type
response.setContentType(responseContentType);
// Allocate a output writer to write the response message into the network socket
PrintWriter out = response.getWriter();
// Write the response message, in an HTML page
try {
out.println("<!DOCTYPE html>");
out.println("<html><head>");
out.println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
out.println("<title>Hello, World</title></head>");
out.println("<body>");
out.println("<h1>Hello, world!</h1>"); // says Hello
// Echo client's request information
out.println("<p>Request URI: " + request.getRequestURI() + "</p>");
out.println("<p>Protocol: " + request.getProtocol() + "</p>");
out.println("<p>PathInfo: " + request.getPathInfo() + "</p>");
out.println("<p>Remote Address: " + request.getRemoteAddr() + "</p>");
// Generate a random number upon each request
out.println("<p>A Random Number: <strong>" + Math.random() + "</strong></p>");
out.println("</body>");
out.println("</html>");
} finally {
out.close(); // Always close the output writer
}
}
}
Test example:
#WebServlet(name = "HelloServlet", urlPatterns = {"/test"})
public class Test extends HttpServlet{
private String responseContentType = null;
public Test() {
super();
}
public void init() throws ServletException {
responseContentType = "text/html;charset=UTF-8";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set the response message's MIME type
response.setContentType(responseContentType);
// Allocate a output writer to write the response message into the network socket
PrintWriter out = response.getWriter();
// Write the response message, in an HTML page
try {
out.println("<!DOCTYPE html>");
out.println("<html><head>");
out.println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
out.println("<title>Hello, World</title></head>");
out.println("<body>");
out.println("<h1>TEST</h1>"); // says Hello
// Echo client's request information
// Generate a random number upon each request
out.println("<p>A Random Number: <strong>" + Math.random() + "</strong></p>");
out.println("</body>");
out.println("</html>");
} finally {
out.close(); // Always close the output writer
}
}
}
web.xml:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>HelloServlet</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.examples.HelloWorld</servlet-class>
<servlet-class>com.examples.Test</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/sayHello</url-pattern>
<url-pattern>/hello</url-pattern>
<url-pattern>/helloWorld</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</webapp>
If you really want to create two DIFFERENT endpoints inside the same class, for whatever strange reason, here's 2 solutions I can think of:
Try implementing an inner class with the #WebServlet annotation. I don't know if that gets picked up and installed, but worth a try
Have two classes, but let the second class (with the second address) call into the first class. This is what I often do (static) when I have a task that is needed by multiple pages.
I myself once wrote a library that resolved Annotations to addresses, and I thought "ahh I'm better than that stupid JEE stuff... I will allow single methods to be anotated too". Which was not difficult to implement at all.
BUT: I regret doing that, because the software that used that got really clumsy and strange, with one file being the possible root of multiple endpoints...
So when I re-designed that library, I removed that function and now only allow endpoint annotations on class level. Projects sticking to this are just SO MUCH cleaner and easier to maintain.
Well... so those two options are out there for JEE.
But the most important questio is: WHY would you want what you are asking for?
This seems like an XY question: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem.

How to place parameters like /login/{param}/ for a post request in servlets

I have a login servlet and after successful login, I want the user to
/login/{username}/
How can I place username in the URL for POST request?
I have looked up certain answers like this and this but couldn't understand how to actually accomplish my goal.
I would like to stick to using servlets and refrain from using technologies like JAX-RS and so on.
This is my login logic implementation:
private void login_doIT(HttpServletRequest request, HttpServletResponse response) throws SQLException, InvalidKeySpecException, NoSuchAlgorithmException, ServletException, IOException {
String userInput = request.getParameter("user_name");
String pass = request.getParameter("pass");
pst = c.prepareStatement(query);
pst.setString(1,userInput);
rs = pst.executeQuery();
while (rs.next()){
imiya = rs.getString("user_name");
kyuch = rs.getString("key");
kodom = rs.getBytes("nitrate");
}
EncryptClass instance = new EncryptClass(2048,100000);
if(instance.chkPass(pass,kyuch,kodom) && imiya.equals(userInput)){
HttpSession session = request.getSession();
session.setAttribute("userLogged",userInput);
request.setAttribute("title",userInput);
String pathInfo = request.getPathInfo();
if(pathInfo!=null || !pathInfo.isEmpty()){
String[] pathArr = pathInfo.split("/");
String val = pathArr[1];//{username}
//now what??.....
}
request.getRequestDispatcher("/LoginLanding.jsp").forward(request,response);
} else {
request.setAttribute("message", message);
request.getRequestDispatcher("/index.jsp").include(request,response);
}
}
And this is the web.xml for it:
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>AuthPack.ServletLogin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/Login/*</url-pattern>
</servlet-mapping>
After I submit the form, the URL becomes something like
/login
But I want it like this:
/login/{username}
more preferably:
/{username}
you have to use a url rewriter or a filter.
Here is an example using a filter method:
in your login servlet instead of going to loginLanding.jsp
you redirect to the filter like so:
//REDIRECT TO filter
response.sendRedirect("/user/"+userInput);
To create a filter, it's very similar to creating a servlet, and you get the option to create a mapping like this (web.xml):
<filter>
<display-name>UserFilter</display-name>
<filter-name>UserFilter</filter-name>
<filter-class>filters.UserFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UserFilter</filter-name>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
Your filter should look something like this:
public class UserFilter implements Filter {
public UserFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String requri = ((HttpServletRequest) request).getRequestURI().substring(((HttpServletRequest) request).getContextPath().length() + 1);
HttpSession session = (((HttpServletRequest) request).getSession());
String RequestedUsername = null;
if(requri.contains("user/")){
//get the username after "user/"
RequestedUsername=requri.substring(5);
if(!RequestedUsername.isEmpty()){
//if not empty set session
session.setAttribute("loggedInUser",RequestedUsername);
}
}
//forward to servlet which will set user details etc... (just get the user session variable from there) in that servlet you forward to landinglogin.jsp
request.getRequestDispatcher("/profile").forward(request, response);
}
In this code, you expect the parameters to be in the available in HttpServletRequest.getParameter() accessed from the doPost() method in your servlet:
String userInput = request.getParameter("user_name");
String pass = request.getParameter("pass");
But you don't show whether you are a) submitting the request as a POST or b) accessing these from the doPost() call in your servlet.
You can access parameter information on the path by using HttpServletRequest.getPathInfo() (see this link)
String extraPathInfo = request.getPathInfo();
// If extraPathInfo is not null, parse it to extract the user name
String pass = request.getParameter("pass");
If your servlet is available at /login and you append the user name to that (like /login/someUser/) then getPathInfo() will return that, though you may want to check whether this includes the slashes.
As an aside, doing this for a login feature creates a security vulnerability. Rather than putting user names on the path, it's better to simply send both the username and password as POST parameters.

How to trigger servlet execution on application start?

[working with JEE, MVC, servlets, JSP]
In web.xml i have specified home.jsp page as application entry point:
<welcome-file-list>
<welcome-file>/home.jsp</welcome-file>
</welcome-file-list>
In my application I have next servlet:
#WebServlet("/show")
public class ShowPostsController extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private PostDAOLocal postDao;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
List<Post> posts = null;
String sort = request.getParameter("sort");
// current page number
int page = Integer.parseInt(request.getParameter("page"));
// the number of entries to show on a "page"
int postsPerPage = Integer.parseInt(request.getParameter("postsPerPage"));
if(sort.equals("byVisitors"))
posts = postDao.getMostVisitedPosts();
else if(sort.equals("byComments"))
posts = postDao.getMostCommentedPosts();
else
posts = postDao.getNewestPosts(page, postsPerPage);
request.setAttribute("posts", posts);
RequestDispatcher dispatcher = request.getRequestDispatcher("home.jsp");
dispatcher.forward(request, response);
}
Now, how can I make make this servlet to be invoked before home.jsp page is loaded, on application start? (because I would like to display some data on home.jsp that are being extracted from database, and set as request attributes inside servlet's doGet method)
Now, how can I make make this servlet to be invoked before home.jsp page is loaded, on application start?
If by "on application start" you mean "when the application is accessed for the first time by a user using the default path" and all you want is the servlet to be called by default instead of the jsp, then try replacing /home.jsp by /show in your welcome-file-list, e.g.:
<welcome-file-list>
<welcome-file>/show</welcome-file>
</welcome-file-list>
If it doesn't work, try without the leading slash before show.
Edit: Regarding the other question in the comments. To use default values, you can check if getParameter() returns null and if it does, assign a default value to the local variable, e.g.:
String sort = request.getParameter("sort");
if (sort == null) {
sort = "someDefaultValue";
}
Do load a servlet on application start you need to edit the web.xml
<servlet>
<servlet-name>******</servlet-name>
<display-name>******</display-name>
<servlet-class>******</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Sending an xml response back when a url is sent

my task is to check if my program is running fine on server or not.The scenario is like this :A URL is sent to the program that is continuously running and it is supposed to reply with a status OK if it is running fine.I am not able to understand the process how to do it.Can anyone explain.
OK, I am assuming that you wanted to write some sort of health check page for your application. So here it goes.
package test.naishe.so;
public class HealthCheck extends HttpServlet {
private static final long serialVersionUID = 940861886429788526L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int response = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
boolean checkServices = true;
//optional: assumming you wanted to do health check on various services (eg. DB service) and have a utility class for that
checkServices = CheckServices.checkAll();
if(checkServices)
response = HttpServletResponse.SC_OK;
String out =
"<healthCheck>" +
"<services>" +
(checkServices?"OK":"ERROR")
"</services>" +
"</healthCheck>"
;
resp.setStatus(response);
resp.getWriter().println(out);
}
}
in your web.xml add the following:
<servlet>
<servlet-name>healthCheck</servlet-name>
<servlet-class>test.naishe.so.HealthCheck</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>healthCheck</servlet-name>
<url-pattern>/check_health</url-pattern>
</servlet-mapping>
you can access this page from <base_url>/check_health on your local machine, http://localhost[:port][/app_name]/check_health

Categories

Resources