Best way to store/retrieve frequently used data from the HttpSession - java

I have a standard GAE app with Java servlets. I want to implement user role functionality throughout the system. For this purpose I want to retrieve user role from the database and store it in the session, in such a way all servlets will have access to this data. I read some articles about it and the basic way to do it is to use Filters to populate HttpSession with necessary data. However, in this case I should retrieve data from the HttpSession in every servlet in the same way, which results in code duplicates. Evident solution for this problem is just to derive from HttpServlet class and create own Servlet with necessary methods for working with HttpSession (e.g. protected Role getUserRole()). This makes the usage of the Filters pointless.
Is there any reason to use Filters in this case?

You should have a top level filter, which maps to /*. This filter will do the fetching of role from database , if not present in session. Now you extend HttpServletRequest and create a wrapper overriding isUserInRole() method, so that role is fetched as you like. Create an object of this request object and use in chain.doFilter in Filter.
So all Servlets can just call request.isUserInRole() to check roles

You can have a main servlet that directly inherit from HttpServlet, this servlet knows how to get the user roles from the HttpSession via protected Role getUserRole(). All other servlets within your application should then subclass that main servlet to have the common functionality available to them.
Servlet filters get invoked prior to the invocation of any other servlet, the main purpose of filters is to decorate the requests/responses before handing them over to the servlets for further processing. You have the choice of accessing your database from within the filters and populate the HttpSession accordingly, then each servlet will know how to retrieve that information from the HttpSession later on.
The other option that I recommend here is to populate the HttpSession with the user roles from within the first servlet that process the request (you could have another common method of the main servlet to do that, e.g. protected void populateUserRole(HttpSession httpSession)).
Cheers;

Related

Managing session and request attributes in Servlet

I have a very simple JSP page where it has one search box and based off the input, in the search box, it will return a response with a submit button to get the following response.
I noticed that whenever I use request.getattribute("foo") in my servlet to retrieve some request it returns null due to the request ending so I looked at the answers on here and started using session.getattribute("foo") instead. However, now I am stuck having session variables responses being set and it is causing my view to have old session data that isn't suppose to be there so now I have to use session.removeAttribute("foo"), whenever, I don't want that particular response data to be shown.
Is there a better way to go about managing this instead of having to use session.getattribute("foo"), session.removeAttribute("foo") and session.setattribute("foo")?
You should work with request.getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
Set an attribute:
request.getSession().setAttribute("foo")
And get attribute using:
request.getSession().getAttribute("foo")
It will be used in the context of the request and not effect other requests, so you don't need to remove attribute.
Read more in Servlets tutorial
Servlets provide an outstanding technical solution: the HttpSession API. This is a high-level interface that allows the server to "remember" a set of information relevant to a particular user's on-going transaction, so that it can retrieve this information to handle any future requests from the same user.
You can go for request.getparameter("foo") or request.setparameter("foo", obj)
This can be used for every request, and it will not add to your session variables and basically will not make your "session object heavy".
Java doc:
Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.

Apache Shiro : Filter vs Realm, which one to use?

Use case : HTTP context, I need to restrict access to urls given a certain session attribute state
Extending the is* methods of AccessControlFilter in a custom filter works, but it looks sorta ugly : I have no Realm.
AFAIK Realms are used for things like LDAP, JDBC, INI backends. Whenever my "realm" is in fact web-bound, i.e the HttpSession itself is the realm.
Is my custom filter the proper way to secure, given that I have the information I need in the HttpSession
If not, how would you bind a Realm to web based context ? Like HttpSession or even HttpServletRequest
You should use a Realm to bind you User [Subject], even if you are just passing in some object from your filter (i.e. a info pulled from the session or http header)
The Realm is the object that will Authenticate and Authorize. Generally speaking there are two types of filters: Filters that build tokens that get passed to a realm (e.g. Form auth, Basic auth, etc) and filters that require some sort of authorization (which assert one or more roles and/or permission)

How to maintain user object throughout the application using session in java

I am writing one application, on that i am setting user object into a session and i cannot able to get that session into another controller. And i want to maintain that session throughout the application(Until the user logout). So how can i get the session object into another controller and throughout the application. And what are the steps that i need to follow to maintain the session throughout the application.
Setting into session:
public ResponseEntity<Object> getCustMenus(HttpSession session){
UserInformation userInformationSession = luser.getRolesData();
session.setAttribute("userInfo", userInformationSession);
}
Getting the session:
UserInformation userInformation=(UserInformation) session.getAttribute("userInfo");
System.out.println("-----"+userInformation.getUserName()+"----------username");
I came across your question, because I'm also facing the same problem.
I think we can rely on Tomcat's request handling mechanism - each request is running in a single thread.
So I can have
Static map where key is the request Thread object and value is the Httpsession or even HTTpRequest object. Map
Filter with url set to /* which means each request passes through this filter. The filter will add the current thread and request object to the static map.
map.put(Thread.currentThread(), httpRequest);
As the map is a static field of some class it will be accessible to all threads and if you need to share an object between different controllers though lifecycle of a request you can put it in this map, e.g. put in httpsession as an attribute and get it anywhere you want.
In filter remove the thread from map when request is done.
map.remove(Thread.currentThread());
In case we use WeakHashMap I suppose we can skip step 3.
I haven't tried this approach yet, but I think it should work. I will share results when I try it.
I found complete answers in another discussion. Get the HttpServletRequest (request) object from Java code
The most useful part of the discussion for me was posted by skaffman. Please find it below.
Spring provides the RequestContextFilter for just this purpose. It uses ThreadLocal, and allows the code to fetch the current request via RequestContextHolder. Note that this filter does not require you to use any other part of Spring:

Access GWT POST parameters via servlet?

I'm creating a GWT application that will be accessed by a POST request, which contains parameters I care about (user id, etc.).
All the reading I've done so far has led me to believe that I should create a servlet (I'm using tomcat) that will handle the POST parameters and then forward to my GWT application. I've gotten this working, but I'm still having trouble passing this data to my application. I've seen 3 suggested approaches:
Save data to context: I have this working right now, but I'm not happy with it. When the servlet is accessed, I parse the parameters and update the context of my GWT web application and then forward to the application where I make an RPC call to read the context. This does what I want it to, but this creates a race condition when multiple users try to access the application at the same and the context is rapidly changing.
Store data in session: I've tried saving the data to the request session in my servlet, and then accessing the session in my RPC, but I always get a new/different session, so I assume I'm mucking this up somewhere.
Save session on servlet
HttpSession session = request.getSession();
session.setAttribute("test", "testValue");
response.sendRedirect(response.encodeRedirectURL("/GWT_Application"));
Access session in RPC
HttpSession session = this.getThreadLocalRequest().getSession();
session.getAttribute("test");
This returns a different session, which results in the "test" attribute being null.
Pass data in URL: My application will be opened in an iframe, meaning Window.location.getParameter() will not be usable.
Any help would be greatly appreciated! I'm still learning GWT and web development in general so don't be afraid to call me out on any obvious or silly mistakes.
Thanks!
SOLUTION
I figured out what the issue was with my session approach: the servlet in which I was previously trying to save the session data was in a separate tomcat web app from my GWT application. Moving them to the same web app solved my problems and it now works. I'm not sure, but I'm guessing that this was a problem because redirecting to another web app switches the context. I'll outline my whole approach in the hopes this saves someone else some time later:
Put your servlet code in the server folder of your GWT project:
package GWTApplication.server;
public class myServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
session.setAttribute("myAttribute", request.getParameter("myParam");
// handle rest of POST parameters
response.sendRedirect(response.encodeRedirectURL("/GWTApplication");
}
}
Map servlet in your GWT application's web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>GWTApplication.myServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
This servlet should now be accessible at .../GWTApplication/myServlet
Next make a standar RPC. Within whatever method you will be calling in the ServiceImpl class on the server:
HttpSession session = this.getThreadLocalRequest().getSession();
return session.getAttribute("myAttribute");
Finally, make your RPC call in the onModuleLoad() method of you GWT application. As a recap:
Send the original POST request to the servlet
Save POST parameters to session variables
Redirect to GWT application
Make RPC call in onModuleLoad()
Read session variables in ServiceImpl class
You can talk with servlets through RPC call in GWT
You need to make a RPC call in the starting point of GWT application.
Set that data to serverside session and get the session data in servceImpl call of GWT which extends to RemoteServiceServlet.
Example :
YourServiceImpl extends RemoteServiceServlet {
#ovveride
doGet(){
//you can access session here
}
#ovveride
doPost(){
//you can access session here
}
#ovveride
doPut(){
//you can access session here
}
----your other methods
}
A brief Example I wrote here:How to make an GWT server call(GWT RPC?)
Since RemoteServiceServlet extends HttpServlet, you can just override doPost() method to access your POST requests. Don't forget to call super.doPost() EDIT: This doesn't work because the method is finalized in AbstractRemoteServiceServlet so it cannot be overridden.
Also, GWT Servlets POST data using the proprietary GWT RPC format. Read more about that format and how to interpret it here: GWT RPC data format
EDIT
There are several methods you can override in your ServiceImpl class that extends RemoteServiceServlet:
public String processCall(String payload) will give you a String representation of the incoming request.
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) will give you a RPCRequest object that has an array of parameters, along with the method that was called.
public void service(ServletRequest request, ServletResponse response) will give you all the Attributes of the HTTP request.

How can I share a variable or object between two or more Servlets?

I would like to know if there is some way to share a variable or an object between two or more Servlets, I mean some "standard" way. I suppose that this is not a good practice but is a easier way to build a prototype.
I don't know if it depends on the technologies used, but I'll use Tomcat 5.5
I want to share a Vector of objects of a simple class (just public attributes, strings, ints, etc). My intention is to have a static data like in a DB, obviously it will be lost when the Tomcat is stopped. (it's just for Testing)
I think what you're looking for here is request, session or application data.
In a servlet you can add an object as an attribute to the request object, session object or servlet context object:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String shared = "shared";
request.setAttribute("sharedId", shared); // add to request
request.getSession().setAttribute("sharedId", shared); // add to session
this.getServletConfig().getServletContext().setAttribute("sharedId", shared); // add to application context
request.getRequestDispatcher("/URLofOtherServlet").forward(request, response);
}
If you put it in the request object it will be available to the servlet that is forwarded to until the request is finished:
request.getAttribute("sharedId");
If you put it in the session it will be available to all the servlets going forward but the value will be tied to the user:
request.getSession().getAttribute("sharedId");
Until the session expires based on inactivity from the user.
Is reset by you:
request.getSession().invalidate();
Or one servlet removes it from scope:
request.getSession().removeAttribute("sharedId");
If you put it in the servlet context it will be available while the application is running:
this.getServletConfig().getServletContext().getAttribute("sharedId");
Until you remove it:
this.getServletConfig().getServletContext().removeAttribute("sharedId");
Put it in one of the 3 different scopes.
request - lasts life of request
session - lasts life of user's session
application - lasts until applciation is shut down
You can access all of these scopes via the HttpServletRequest variable that is passed in to the methods that extend from the HttpServlet class
Depends on the scope of the intended use of the data.
If the data is only used on a per-user basis, like user login info, page hit count, etc. use the session object
(httpServletRequest.getSession().get/setAttribute(String [,Object]))
If it is the same data across multiple users (total web page hits, worker threads, etc) use the ServletContext attributes. servlet.getServletCongfig().getServletContext().get/setAttribute(String [,Object])). This will only work within the same war file/web applicaiton. Note that this data is not persisted across restarts either.
Another option, share data betwheen contexts...
share-data-between-servlets-on-tomcat
<Context path="/myApp1" docBase="myApp1" crossContext="true"/>
<Context path="/myApp2" docBase="myApp2" crossContext="true"/>
On myApp1:
ServletContext sc = getServletContext();
sc.setAttribute("attribute", "value");
On myApp2:
ServletContext sc = getServletContext("/myApp1");
String anwser = (String)sc.getAttribute("attribute");
Couldn't you just put the object in the HttpSession and then refer to it by its attribute name in each of the servlets?
e.g:
getSession().setAttribute("thing", object);
...then in another servlet:
Object obj = getSession.getAttribute("thing");
Here's how I do this with Jetty.
https://stackoverflow.com/a/46968645/1287091
Uses the server context, where a singleton is written to during startup of an embedded Jetty server and shared among all webapps for the life of the server. Can also be used to share objects/data between webapps assuming there is only one writer to the context - otherwise you need to be mindful of concurrency.

Categories

Resources