As part of exception handling, I want to print data from HTTP session like below:
try{
//business logic
} catch(Exception ex){
String user = session.get("userId"); //get user from HTTP Session.
log.info("Exception when processign the user "+user);
}
My question is do I get the correct UserId for which exception occurred since there will be mulitple threads updating the session?
The HttpSession is not shared among clients. So that part is safe already. The remnant depends on your own code as to obtaining and handling the HttpSession instance. If you're for example assinging the HttpSession as an instance variable of an application wide class, like the servlet itself, then it is indeed not thread safe as it might be overridden by another request at the moment you're accessing it.
public class SomeServlet extends HttpServlet {
private HttpSession session;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
session = request.getSession();
// ...
Object object = session.getAttribute("foo"); // Not threadsafe!
}
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
Session will be unique for each user (if code is according to standard).
Here is sun tutorial on how session works
Related
I wanted to do two tasks simultaneously in web project in the Servlet once the user clicks on submit button
1. Run a code to trigger some backend activity
2. Display a webpage to the user.
I tried with the code sample here
As I have few session attributes being set I need to set this in one of the thread. I tried putting point one in one thread and point two in second but variables are not getting resolved to the thread from doPost() method.
Servlet:
public class JOBRUN extends HttpServlet{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AESASNewOpenPeriod=request.getParameter("AESASNewOpenPeriod");
ScriptRunOption = Integer.parseInt(request.getParameter("AESASJOBRUNOPTION"));
HttpSession session=request.getSession();
String Stream="aaaa";
session.setAttribute("AEStream", Stream);
//Do Job 1 (Update table)
//Do Job 2 (Display webpage to user)
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
You can create an anonymous thread (if you don't want a dedicated Thread class for ) Job 1.
new Thread(new Runnable() {
Session localSession = session;// assign the session object to thread variable.
public void run() {
// you can access localSession here. and do the JOB 1
}
}).start();// this will run asynchrously(non blocking).
Also if you want to pass only some attributes to do the Job 1(i,e if u don't want to change the session), you can pass relevant attributes only.For example
String threadStream = session.setAttribute("AEStream");//local memeber variable inside anonymous thread
Then from the next line after thread, you can do Job 2.
Note: If you mean something else- running an asychrounous worker thread with request , you start wit Servlet 3.x AsyncContext
Hi I have created a private method inside the servlet.
The method will be called from the post method. My questions is, will it be threadsafe since it will be called via ajax by many many user?
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
callPrivateMethod();
}
private static void callPrivateMethod(){
}
As long as callPrivateMethod() is thread safe, i.e. it does not use a class member variable, then you will be fine.
No, your private method won't be thread safe as doPost is not thread safe in servlet.
It is static method with immutable objects as parameters in your case (no parameters) is Thread safe
Servlets should be stateless. Hawever, if you need to use class members or any other thread-unsafe element, you always could use "synchronized" sentences.
The servlet is instanced only once at loading. If you want to make call to callPrivateMethod() thread safe, you can put it inside a synchronized block.
private Object mutex = new Object();
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
synchronized (mutex){
callPrivateMethod();
}
}
private static void callPrivateMethod(){
}
I am calling another servlet from main servlet,It would have been easy by implementing jsp ,but my aim for this experiment is to use only servlet,pls help
You can't override a method more than once in a class, so you can't override the doPost several times.
If you mean overload it, there's not a good reason for doing that. In the end, only one of those methods will be called by the Servlet Container.
If you want to handle more than 1 kind of requests using a single Servlet, you can send a parameter indicating the action you will perform. For example:
#WebServlet("/person")
public class PersonCRUDServlet extends HttpServlet {
private static final String ADD = "add";
private static final String DELETE = "delete";
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
//using if assuming you work with Java SE 6
if (ADD.equals(action)) {
add(request, response);
} else
if (DELETE.equals(action)) {
delete(request, response);
} else {
//submitted action can't be interpreted
//or no action was submitted
errorForward(request, response);
}
}
private void add(HttpServletRequest request, HttpServletResponse response) {
//handle logic for add operation...
}
private void delete(HttpServletRequest request, HttpServletResponse response) {
//handle logic for delete operation...
}
private void errorForward(HttpServletRequest request, HttpServletResponse response) {
//handle logic for delete operation...
}
}
Note that this is a lot of work to handle manually (this is a reason why Java Web MVC frameworks exists). You can also refer to
Java EE web development, where do I start and what skills do I need?
What to learn for making Java web applications in Java EE 6?
Hey I want to implement a Java Servlet that starts a thread only once for every single user. Even on refresh it should not start again. My last approach brought me some trouble so no code^^. Any Suggestions for the layout of the servlet?
public class LoaderServlet extends HttpServlet {
// The thread to load the needed information
private LoaderThread loader;
// The last.fm account
private String lfmaccount;
public LoaderServlet() {
super();
lfmaccount = "";
}
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (loader != null) {
response.setContentType("text/plain");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
out.write(loader.getStatus());
out.flush();
out.close();
} else {
loader = new LoaderThread(lfmaccount);
loader.start();
request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
request, response);
}
}
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (lfmaccount.isEmpty()) {
lfmaccount = request.getSession().getAttribute("lfmUser")
.toString();
}
request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
request, response);
}
}
The jsp uses ajax to regularly post to the servlet and get the status. The thread just runs like 3 minutes, crawling some last.fm data.
What you need here is Session listener. The method sessionCreated() will be called only once for every browser session. So, even if the user refreshes the page, there will be no issues.
You can then go ahead and start the thread for every sessionCreated() method call.
Implement javax.servlet.SingleThreadModel => the service method will not be executed concurrently.
See the servlets specification.
Hypothetically it could be implemented by creating a Map<String,Thread> and then your servlet gets called it tries to look up the map with the sessionId.
Just a sketch:
public class LoaderServlet extends HttpServlet {
private Map<String,Thread> threadMap = new HashMap<>();
protected void doPost(..) {
String sessionId = request.getSesion().getId();
Thread u = null;
if(threadMap.containsKey()) {
u = threadMap.get(sessionId);
} else {
u = new Thread(...);
threadMap.put(sessionId, u);
}
// use thread 'u' as you wish
}
}
Notes:
this uses session id's, not users to associate threads
have a look at ThreadPools, they are great
as a commenter pointed out: synchronization issues are not considered in this sketch
Your first task is to figure out how to identify users uniquely, for instance how would you discern different users behind a proxy/SOHO gateway?
Once you have that down it's basically just having a singleton object serving a user<->thread map to your servlet.
And then we get into the scalability issue as #beny23 mentions in a comment above... I absolutely concur with the point made - your approach is not sound scalability-wise!
Cheers,
As I understand, you want to avoid parallel processing of requests from the same user. I'd suggest you other approach: associate lock with each user and store it in session. And before start processing of users request - try to get that lock. So current thread will wait while other requests from this user are handling. (Use session listener to store lock, when session is created)
I have a java method calling on a web service and making changes to the database based on the response. My task is to eliminate concurrency errors when several users use this application simultaneously.
I was trying to use various types of database locking all day but nothing worked. I finally tried to use synchronized in the process request method and it all worked.
My whole application is single-threaded. Why does synchronized solve this?
Edit: Added Code.
public class ProcessMakePaymentServlet extends HttpServlet {
private DbBean db = new DbBean();
protected synchronized void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// defining variables...
try {
// initialize parameters for invoking remote method
db.connect();
startTransaction(); //autocommit=0; START TRANSACTION;
// process debit
//this method gets the method using a select...for update.
//it then updates it with the new value
successfulDebit = debitAccount(userId, amt);
if (successfulDebit) {
// contact payment gateway by invoking remote pay web service method here.
// create new instances of remote Service objects
org.tempuri.Service service = new org.tempuri.Service();
org.tempuri.ServiceSoap port = service.getServiceSoap();
// invoke the remote method by calling port.pay().
// port.pay() may time out if the remote service is down and throw an exception
successfullyInformedPaymentGateway = port.pay(bankId, bankPwd, payeeId, referenceId, amt);
if (successfullyInformedPaymentGateway) {
// insert payment record
recordPaymentMade(userId, amt, referenceId);
//call to the database to record the transaction. Simple update statement.
out.println("<br/>-----<br/>");
//getTotalPaymentMade does a select to sum all the payment amounts
out.println("Total payment made so far to gateway: " + getTotalPaymentMade());
commitTransaction();// calls COMMIT
db.close(); //connection closed.
} else {
rollbackTransaction();//calls ROLLBACK
db.close();
successfulDebit = false;
out.println("<br/>-----<br/>");
out.println("Incorrect bank details.");
}
} else {
rollbackTransaction();//calls ROLLBACK
db.close();
out.println("<br/>-----<br/>");
out.println("Invalid payment amount.");
}
} catch (Exception ex) {
try {
rollbackTransaction();//calls ROLLBACK
db.close();
} catch (Exception ex1) {
}
}
}
My whole application is single-threaded. Why does synchronized solve
this?
No it is not single threaded. The web service is called by multiple threads receiving the client requests.
The web service method implementation must take care of all synchronization issues same as in a servlet implementation receiving multiple requests, care must be taken to ensure thread safety.
In your case, by adding synchronized you made sure that concurrent processing of web service client request did not result in corruption due to thread issues and you are esentially serializing the client requests (and there of access to the DB).
You have not posted any code to see what you are doing wrong, but since synchronized at the web method level solves your problem, you either did not do the synchronized at the DB level as you say properly or threading issues corrupted common variables at the web service layer accessing the DB.
By synchronizing at the web method, the code is thread safe, but the performance will deteriorate since you will serve 1 client at a time.
Depends on what your requirements are
Just move private DbBean db = new DbBean(); into the servlet method, this should solve the problem concurrency problem:
protected void processRequest(HttpServletRequest request, ...) {
// defining variables...
DbBean db = new DbBean();
...
}
Nevertheless, you should properly clean all database resources in a finally block. A fairly simplified example, but I hope you get what I mean:
protected void processRequest(HttpServletRequest request, ...) {
// defining variables...
DbBean db = null;
boolean commit = false;
try {
db = new DbBean();
} catch (SomeException e) {
commit = false;
} finally{
db.release(commit); /* close database connection => java.sql.Connection#close() */
}
...
}