All I want is to instantiate object of list only once upon multiple calls to this servlet. Please help without the use of static keyword as it is not allowed here.
List<Cart> list=new ArrayList<Cart>();
list.add(new Cart(name, cost));
HttpSession s=req.getSession();
s.setAttribute("list",list);
out.println("item successfully added to cart");
out.println("\n<a href=\'viewserv\'>view cart</a>");
out.println("\n<a href=\'item\'>view item</a>");
As you are storing that into session, You need to just check it weather it is there in session already or not .
HttpSession s=req.getSession();
if(s.getAttribute("list") !=null){
sessionList =new ArrayList<Cart>();/create new
}else {
sessionList = (List)s.getAttribute("list");
sessionList.add(....
}
I am guessing you want the same object to persist across all HTTP requests served by this servlet.
Simply make this object as the instance variable of your servlet and instantiate it in servlet's init method.
I want is to instantiate object of list only once upon multiple calls
of servlet
You should initialize the List on init method of Servlet.
List<Cart> list=null;
#Override
public void init() throws ServletException {//This method will call only once
list=Collections.syncronizedList(new ArrayList<Cart>());
}
Please note that, the above declaration must care about synchronization.
Related
I am using Guice's RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a background thread, using the same instances created during request.
However, when I call Provider.get(), guice returns an error:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot
access scoped object. Either we are not currently inside an HTTP Servlet
request, or you may have forgotten to apply
com.google.inject.servlet.GuiceFilter as a servlet
filter for this request.
afaik, this is due to the fact that Guice uses thread local variables in order to keep track of the current request instances, so it is not possible to call Provider.get() from a thread different from the thread that is handling the request.
How can I get the same instances inside new threads using Provider? It is possible to achieve this writing a custom scope?
I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward #RequestScoped objects, only basic things like the HttpServletResponse. That's because #RequestScoped objects are not expected to be thread safe. You have some options:
If your entire #RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.
You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.
Some of my #RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, #ThreadSafeRequestScoped, and only forwarded those ones.
Code sample:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
#Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
// This is like Scopes.isSingleton() but we don't have to follow linked bindings
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
#Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
#Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
#Override
public Boolean visitNoScoping() {
return false;
}
#Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
// This instantiates objects eagerly
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}
I have faced the exact same problem but solved it in a different way. I use jOOQ in my projects and I have implemented transactions using a request scope object and an HTTP filter.
But then I created a background task which is spawned by the server in the middle of the night. And the injection is not working because there is no request scope.
Well. The solutions is simple: create a request scope manually. Of course there is no HTTP request going on but that's not the point (mostly). It is the concept of the request scope. So I just need a request scope that exists alongside my background task.
Guice has an easy way to create a request scope: ServletScope.scopeRequest.
public class MyBackgroundTask extends Thread {
#Override
public void run() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
doTask();
}
}
private void doTask() {
}
}
Oh, and you probably will need some injections. Be sure to use providers there, you want to delay it's creation until inside the created scope.
Better use ServletScopes.transferRequest(Callable) in Guice 4
I am writing integration test cases for the project that uses Struts2, Spring, Hibernate using JUnit.
My test class extends StrutsSpringTestCase. The application needs login/session to invoke any action. Following is the code:
#Test
public void testGetActionProxy() throws Exception {
ActionProxy proxy;
String result;
ActionContext.getContext().setSession(createUserSession()); // Not sure if this is needed here. But in order to get the session working, I need this.
proxy = initAction("cInfo");
assertNotNull(proxy);
CustInfo action = (CustInfo) proxy.getAction();
result = proxy.execute();
assertEquals(Action.SUCCESS, result);
}
The initAction() method:
private ActionProxy initAction(String actionUri) {
ActionProxy proxy = getActionProxy(actionUri);
ActionContext.setContext(proxy.getInvocation().getInvocationContext()); // I tried this line of code to get the ServletActionContext.getMapping().getName() to work. But no use.
ActionContext actionContext = proxy.getInvocation().getInvocationContext();
actionContext.setSession(createUserSession()); // This is for setting a session
return proxy;
}
Before it hits this method, it loads all the config files. struts.xml jpaContext.xml, beans.xml, etc.
My Action class CustInfo implements ServletRequestAware and it has a method getActionName which as the line:
return ServletActionContext.getActionMapping().getName();
This gets invoked when I call result = proxy.execute();. So the request is failing.
Question 1: Why does it return null? I thought ServletActionContext is automatically initiated, so it should return a value. But its not. If its not initialized, where is the proper place to initialize and how?
I tried the following after getActionProxy call. But it still did not work.
ServletActionContext.setContext(proxy.getInvocation().getInvocationContext());
Question 2: To set the session, before getActionProxy(), I am having to call,
ActionContext.getContext().setSession(createUserSession());
And again, after getActionProxy
ActionContext actionContext = proxy.getInvocation().getInvocationContext();
actionContext.setSession(createUserSession());
to set the session. I assume, there is something wrong here.
Question 3: Looks like, there are several contexts in play here:applicationContext, ActionContext ServletContext and ServletActionContext.
When my test class extends StrutsSpringTestCase class, I guess applicationContext is initialized. But I am not sure about other contexts. Where to initialize them?
Edit:
Further investigation in the source code reveals one issue..
When I call ServletActionContext.getActionMapping(), internally its calling ActionContext's get() method.
public Object get(String key) {
return context.get(key);
}
context is a map of object, in which its looking for value for a key struts.actionMapping, which does not exist. So, returns null. But not sure why it is there. It's not empty. It has other key/values.
The answer to your questions:
ServletActionContext.getActionMapping() returns the mapping from the action context, if it's not set then you get null.
You shouldn't set a session manually, a session is created when action is executed.
Don't mess up different classes ActionContext, ServletContext, and ServletActionContext. You shouldn't do anything with initializing these objects, because it's done by the superclass StrutsSpringTestCase.
public void testGetActionMapping() {
ActionMapping mapping = getActionMapping("/cInfo.action");
assertNotNull(mapping);
assertEquals("/", mapping.getNamespace());
assertEquals("cInfo", mapping.getName());
}
public void testGetActionProxy() throws Exception {
ActionProxy proxy = getActionProxy("/cInfo.action");
assertNotNull(proxy);
CustInfo action = (CustInfo) proxy.getAction();
assertNotNull(action);
String result = proxy.execute();
assertEquals(Action.SUCCESS, result);
}
i am developing a sturts2 webapplication, i am having a login page with username and password fields. As soon as user submitted form with values , i am validaing the login, if the user provides valid username and passoword, it is redirected to home page. While redirecting the home page, i have to call a thread in which i sets some data in session for future use. How to do this ?
What i did is
import com.opensymphony.xwork2.ActionContext;
if( loginSuccess(userInfo) ) {
initializeDatas(); // calling thread after userInfo bean validated
// redirecting to home page
return HOME_PAGE;
}
I have added a new class which implements runnable.
class intilalizer implements Runnable {
#Override
public void run() {
try {
System.out.println("Started to set values ");
List<String> iphoneSdks = new ArrayList<String>();
List<String> iphoneOSSdks = IosSdkUtil.getMacSdks(MacSdkType.iphoneos);
List<String> simSdks = IosSdkUtil.getMacSdks(MacSdkType.iphonesimulator);
List<String> macSdks = IosSdkUtil.getMacSdks(MacSdkType.macosx);
iphoneSdks.addAll(iphoneOSSdks);
iphoneSdks.addAll(simSdks);
iphoneSdks.addAll(macSdks);
ActionContext context = ActionContext.getContext();
System.out.println("context ===> " + context); // here i am getting null value
String httpRequest = ServletActionContext.HTTP_REQUEST;
System.out.println("httpRequest =====> " + httpRequest);
Object object = context.get(httpRequest);
System.out.println(object);
HttpServletRequest req = (HttpServletRequest) object;
req.setAttribute(REQ_IPHONE_SDKS, iphoneSdks);
req.setAttribute(REQ_IPHONE_SIMULATOR_SDKS, simSdks);
System.out.println("Value initialized####");
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am getting
java.lang.NullPointerException
at com.photon.phresco.framework.actions.intilalizer.run(Login.java:286)
at java.lang.Thread.run(Thread.java:680)
I am getting this error on line .
ActionContext context = ActionContext.getContext();
System.out.println("context ===> " + context); // here i am getting null value
From Struts 2 JavaDoc
The ActionContext is thread local which means that values stored in the ActionContext are unique per thread
You just create a new Thread so your ThreadLocal variables are not available there. You should do something like this:
import com.opensymphony.xwork2.ActionContext;
if( loginSuccess(userInfo) ) {
ActionContext context = ActionContext.getContext();
initializeDatas(context); // calling thread after userInfo bean validated
// redirecting to home page
return HOME_PAGE;
}
The best way will be pass context to Thread constructor. But I am not sure that COntext is ThreadSafe.
I'm just wondering WHY do you need to start a new Thread to put some data in session
(thing that you say you wanna do, but that you actually don't do in the posted code, where you instead put stuff in request).
You can simply implement SessionAware Interface from your Action(s).
Actions that want access to the user's HTTP session attributes should
implement this interface.
This will give them access to a Map where they can put objects that
can be made available to subsequent requests.
Typical uses may be cached user data such as name, or a shopping cart.
It is not mandatory, but it is a best practice for accessing session from within the Actions, instead of asking to ActionContext:
You can obtain the session attributes by asking the ActionContext or
implementing SessionAware. Implementing SessionAware is preferred.
If needed, here is a little example of usage: http://www.splinter.com.au/how-to-use-sessions-with-struts-2/
if( loginSuccess(userInfo) ) {
// redirecting to home page
return HOME_PAGE;
initializeDatas(); // calling thread after userInfo bean validated
}
That won't work. The method will end after the return call. Try calling the method that creates the new thread first.
if( loginSuccess(userInfo) ) {
// redirecting to home page
initializeDatas(); // calling thread after userInfo bean validated
return HOME_PAGE;
}
(I'm not sure exactly how to phrase the title here, and because of that I'm not really sure how to go about searching for the answer either.)
I have a Java servlet engine that handles requests. Say we have a doGet() request:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//set up user data
//do whatever the user requested
SomeClass c = new SomeClass();
c.doSomething();
}
Now in doSomething(), I want to be able to access which user made the request. Right now I'm doing it by creating a Java object within the method and passing it to wherever I need it:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//set up user data
MyUserObj userObj = new MyUserObj();
userObj.setId('123');
//do whatever the user requested
SomeClass c = new SomeClass(userObj);
c.doSomething();
}
By doing this, I have access to the instance of MyUserObj, and it can be further passed along in the application as needed.
I know in ASP.NET MVC3 I can acheive this by storing items/attributes for the current thread like this: HttpContext.Current.Items.Add("myId", "123"). HttpContext is then available in other functions without explicitly having to pass around an object.
Is there a way in Java to set some variables per request (or even set the MyUserObject to be accessed later) without passing the object through as a parameter?
There isn't in the servlet API, but you can make your own pretty easily. (Some frameworks like spring-mvc, struts provide such functionality)
Just use a public static ThreadLocal to store and retrieve the object. You can even store the HttpServletRequest itself in the threadlocal and use its setAttribute()/getAttribute() methods, or you can store a threadlocal Map, to be agnostic of the servlet API. An important note is that you should clean the threadlocal after the request (with a Filter, for example).
Also note that passing the object as parameter is considered a better practice, because you usually pass it from the web layer to a service layer, which should not be dependent on web-related object, like a HttpContext.
If you decide that it is fine to store them in a thread-local, rather than passing them around:
public class RequestContext {
private static ThreadLocal<Map<Object, Object>> attributes = new ThreadLocal<>();
public static void initialize() {
attributes.set(new HashMap<Map<Object, Object>>());
}
public static void cleanup() {
attributes.set(null);
}
public static <T> T getAttribute(Object key) {
return (T) attributes.get().get(key);
}
public static void setAttribute(Object key, Object value) {
attributes.get().put(key, value);
}
}
And a necessary filter:
#WebFilter(urlPatterns="/")
public class RequestContextFilter implements Filter {
public void doFilter(..) {
RequestContext.initialize();
try {
chain.doFilter(request, response);
} finally {
RequestContext.cleanup();
}
}
}
You can attach an object to the current request with setAttribute. This API is primarily used for internal routing, but it's safe to use for your own purposes too, as long as you use a proper namespace for your attribute names.
i have some problems trying code login+cookies .. when the user is login i create the session
getThreadLocalRequest().getSession(true)
and when i want to check if session its still alive always return null
HttpSession session = getThreadLocalRequest().getSession(false);
if (session != null) {
}
When i check the HttpRequest (when i check session alive) this have
Cookie: JSESSIONID=a1042a8e-9ebc-45b8-a3d8-12161885be96
and the cookie is ok.
I use Eclipse+Development mode
Server side code :
public String login(String rut, String pass) throws AuthenticationException {
//if UserPassMatch ...
session = this.getThreadLocalRequest().getSession(true);
//set user bean
session.setAttribute("beanSession", us);
HttpServletResponse response = getThreadLocalResponse();
Cookie usernameCookie = new Cookie("JSESSIONID", us.getSessionID());
usernameCookie.setPath("/");
usernameCookie.setMaxAge(60 * 60 ); //1 hora
response.addCookie(usernameCookie);
}
#Override
public String checkIfSessionStillActive(String token) {
HttpServletRequest request = getThreadLocalRequest();
//Here ALWAYS return null
HttpSession session = request.getSession(false);
if (session != null) {
//check sessionId and search User Bean
}
return token;
}
From client side nothing special just call checkIfSessionStillActive for check if session exists and go throw the token or go to login if it's not. When the user is logged in still return session NULL. I use MVP pattern and i call from AppController and i use the same rpcService. At once the user login i check session and its exists, but if i call checkIfSessionStillActive this not found any session.
Really i read a lot of code and what i found its almost the same thing, ¿can any help me?
Are you using a subclass extending RemoteServiceServlet and calling on a object created somewhere else (for example in spring context) and have extended RemoteServiceServlet? If yes following will solve your problem
For each request a new instance of RemoteServiceServlet is created. Problem is that the thread local variables defined in super class of RemoteServiceServlet are not static, hence for each object you have different variable. When ever you process call in above scenario, your request response thread local variables are initialized for the object which receives but it does not sets thing for object on which you are invoking a method.
I used a workaround by creating a Class with static threadlocal varrible and set values before invoking on second object. Now swcond object can also access them.
Have you tried using setMaxInactiveInterval() rather than messing with the cookie directly?