I am writing a JSR-168 portlet that can be added to a container multiple times. Each container (Liferay, JBoss, etc.) has its own internal way of differentiating between multiple instantiations of the same portlet.
I, however, would like to uniquely identify my portlet instance inside the doView() method itself.
Is there any standard, JSR-168 mechanism to retrieve some unique identifier that's different for each instance of my portlet? I've seen various solutions where people randomly generate unique IDs and save them in the session, but I'd prefer a standard mechanism if one exists.
Portlet 1.0 (168) provides the RenderResponse.getNamespace() method, which should be unique per portlet instance.
From spec: PLT.12.3.4 Namespace encoding:
The getNamespace method must provide
the portlet with a mechanism that
ensures the uniqueness of the returned
string in the whole portal page. For
example, the getNamespace method would
return a unique string that could be
prefixed to a JavaScript variable name
within the content generated by the
portlet, ensuring its 5 uniqueness in
the whole page. The getNamespace
method must return the same value if
invoked multiple times within a render
request.
If you want to access it in processAction, you'll probably want to store it in the session or as an actionURL parameter.
If upgrading is an option, Portlet 2.0 (286) changes the underlying PortletResponse interface to provide the getNamespace() method and also adds a PortletRequest.getWindowID() method which might be of some use to you.
No, there is no common ID for the instance. I have implemented a portlet container myself, there is no per instance id in the public api - the container has one, of cause. The portlet session (javax.portlet.PortletRequest#getPortletSession()) is unique for one portlet (definition by tag in portlet.xml) and one user (javax.servlet.http.HttpSession), that is not enough for you.
So imho an id generated (can also be a simple (sync) counter in the portletl class) and stored in the portlet session is the only portable way. THe portlet class itself is typically shared beween instances, so the java.lang.System#identityHashCode(Object x) is also useless.
Why do you need it?
I am surprised that this unique ID does not seem to exist as per Ame. The Instance ID can be used for storing all the portlet preferences with in our own database rather than the container provided one. One of the reason we need to store this on our own is the preferences provided by container does not support locale specific preferences.
i.e one portlet instance may have different preferences per locale.
We are trying to use Liferay for our needs.
Related
It's as simple. In Spring MVC, how and where do I store a complex java object so that it is available across the action servlets. For example if an ajax is called on next page, the business object from within some previously called servlet, stored somewhere should be accessible in that ajax action method in java. I did this by creating a singleton bean but it failed when multiple users hit the application. User outputs are affected among each other. I need to achieve this in a non-singleton manner.
You can store objects in your request object:
request.setAttribute("key", valueObject);
To get the object, simply use
request.getAttribute("key");
Or, as Subir Kumar Sao said in the comments, use the session to store your stuff:
request.getSession().setAttribute("key", valueObject);
and
request.getSession().getAttribute("key");
You can use either
request.setAttribute("key", valueObject);
request.getAttribute("key");
or
session.setAttribute("key", valueObject);
session.getAttribute("key");
Difference between them : Request-scoped attribute is visible only while current request is processed. Session-scoped attribute is persistent between several requests from the same user.
You should keep your objects on session level. As long as the session is alive, you can access your session level variables, regardless of the requests.
request.getSession().getAttribute("key");
request.getSession().getAttribute("key", value);
Keep in my mind that once a session level attribute is set, that is always there until, session is killed or invalidated. So you may need to remove the attribute according to your logic.
request.getSession().removeAttribute("key");
In our web application (in JBoss using Struts) we use sessions largely for security as well as to cache some data for a User. Thus, every user logged into the application has a session and different data cached in it.
Based on some parameter change, i want to change the cache of the subset of users who are logged in (i.e. have session)
Can this be achieved? I have not been able to find anything so far from general search.
You can use a HttpAttributeListener
a basic example here
HttpSessionAttributeListener:
The HttpSessionAttributeListener interface enables an object to
monitor changes to the attribute lists of sessions within a given Web
application. The HttpSessionAttributeListener in turn extends
java.util.EventListener. The methods in it are
attributeAdded(HttpSessionBindingEvent se)- This is the notification that an attribute has been added to a session.
attributeRemoved(HttpSessionBindingEvent se)- This is the notification that an attribute has been removed from a session.
attributeReplaced(HttpSessionBindingEvent se)- This is the notification that an attribute has been replaced in a session.
You can do it by storing each session object in a static List<Session> in some holder object. You can put it by a HttpSessionListener#sessionCreated(..). Remember to remove it from the list on sessionDestroyed(..)
Then, whenever you want to do something, simply loop the previously stored list of sessions and do whatever you want with them.
You have basically 2 options:
Push the changes. Get hold of all HttpSession instances in an application wide map which you manage with help of a HttpSessionListener. This way you can just get them from the application scope and walk through them to make the necessary changes directly.
Poll the changes. Store a change instruction in the application scope. On every HTTP request, check with help of a Filter or ServletRequestListener if a change is required, then make the necessary change in the current session and remove/disable the change instruction.
A completely different alternative is to use an application wide shared cache, such as Terracotta or Ehcache, so that you don't need to duplicate the same data over all HTTP sessions. You'd just need to deal with the data on a per-request basis. When database access comes into picture with JPA, then read on about "2nd level cache", that's exactly what it does.
anyone know if we can create a session-like mechanism in java desktop application?
i am going to develop a java desktop application which has a log-in mechanism to ensure only authorized people can access stored information, then i think if java can something like session, or if there is any mechanism to do something like session. that's all.
can somebody explain?
Basically a session consists of a set of binary or serialized objects, mapped to a session id. Either independently or, most likely, via a Map or Table. So yes, you can implement something like that, by using a smart DB schema. Just be careful about who can see (and use) that DB.
I think, though, your approach is not the best one. After all I think the app will be used by a single user at any time on each machine, so I don't think this is the best approach. Rather you should save the current "session" (AKA app state) in some way, instead of thinking of the session as in the Servlet way.
The session is just a hashmap that is singleton per user . So , you can think that every user has their own hashmap which allows them to store objects. In the servlet , the session is provided by the HttpSession interface.
The session-like mechanism depends on your application 's architecture .If it is a thick client implementation , which contains only 2 tiers (database tier and the java client) ,and most of the business codes are embedded inside the java application , then every user has their own JVM to run the java code on their machines .Thus , you simply create a singleton hashmap for your desktop application .When the application starts , just initialize this hashmap and put a key and its boolean value to indicate the login status of the user ( e.g. singltonHashmap.put ("LOGIN" , false)) .Once the user login , you should update the value of the LOGIN key to true to indicate that the user is logged in .
If the java desktop application is thin client implementation , which has an application server to process all the requests from all users, then you can use the stateful session bean defined by the Enterprise JavaBeans specification (EJB) .There is an one-to-one mapping between a client and a stateful session bean instance .The application server will makes sure that subsequent method invocations by the same client are handled by the same stateful bean instance . You just declare a hashmap inside an stateful session beans and put the objects that you want to keep track during the conversation in that hashmap. Here is an example for your reference.
Say a logged in user hits the url:
www.example.com/forum/234
Before the spring mvc action fires, I want to load the User Object, the user's permission, the Forum object.
Now I want to share these objects accross this request. So other classes can look to see, in the current request, for a User, Permission and Forum object.
Potentially it would be cool if a custom freemarker module could also reference these objects if they are available.
is this possible?
First, consider using spring-security, whose filters do everything you need.
If you want to do all by hand, then you have at least two options:
- use servlet filters
- use spring handler interceptor (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor).
In both cases store this data in request attributes.
Another option is to create bean with request scope which will store your data.
As for Freemarker, you must provide own subclass of FreemarkerViewResolver, which will return subclass of FreeMarkerView in requiredViewClass() method. Add your objects in exposeHelpers() method in this FreeMarkerView subclass.
Is it possible to assign a custom ID to a HTTP session through Servlet API?
I know that session handling from any application server, Tomcat for example, it's enough good to generate unique IDs. But I have custom unique session IDs based on information per user and time, so it won't be repeated.
And I looked at every documentation about session handling but nowhere I find what I need.
It's a requirement for a project, so if it's not possible, I need to know the reasons (or it's only not available through API?).
If you are using Tomcat, you may be able to create a custom session manager (see this discussion). You would then have access to the Tomcat Session object and could call setId.
The servlet API does not support creating your own cookie value. In fact, it does not guarantee that sessions are maintained via cookies... it specifically states that they can be maintained via a mechanism such as "URL Rewriting". It DOES guarantee that the session is maintained in some fashion, and that pretty much requires some sort of unique ID which is passed to the browser and returned, but no mechanism is provided in the Servlet API for servlet code to control what value is used. Nor do common servlet containers that I know of (such as Tomcat) provide a means for controlling this value.
However, none of this should be a problem for you if I understand your requirements properly. Just because Tomcat (or whatever servlet container you use) is creating a unique ID based on its own algorithms (that contain things like cryptographically secure random number generators to prevent "guessing" of session IDs), doesn't mean that you cannot create a SEPARATE ID which meets your requirements (based on user and time, unique across all sessions... whatever you need). This ID can be stored in the session (if that's all you need), or can be stored on the browser in a separate cookie (if you need it maintained across sessions). The only effect would be that the browser was storing TWO cookies -- and most websites store many more cookies than that!
Um...if you have the code to generate a unique ID, you can just do this:
/**
* The String key of the user id attribute.
*/
public static final String USER_ID_KEY = "userIdKey";
// Set the user attribute (createUniqueUserId's parameters and return type are up to you)
httpSession.setAttribute(USER_ID_KEY, createUniqueUserId());
// Retrieve the user attribute later
httpSession.getAttribute(USER_ID_KEY);
The HttpSession interface also provides a getId() method, which is documented here (copying the documentation for reference):
public java.lang.String getId()
Returns a string containing the unique
identifier assigned to this session.
The identifier is assigned by the
servlet container and is
implementation dependent.
Returns: a
string specifying the identifier
assigned to this session