Reputation: 8731
In my vaadin application, i need to use @Push
, but since i added it, i can't read and write cookies because VaadinService.getSurrentResponse()
returns null because of Push
. I manager cookies using this class :
import javax.servlet.http.Cookie;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
public class CookieManager {
private VaadinResponse response;
public CookieManager(VaadinResponse response){
this.response = response;
}
public Cookie getCookieByName(final String name) {
// Fetch all cookies from the request
Cookie[] cookies = VaadinService.getCurrentRequest().getCookies();
// Iterate to find cookie by its name
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
public Cookie createCookie(final String name, final String value, final int maxAge) {
// Create a new cookie
final Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
// Set the cookie path.
cookie.setPath(VaadinService.getCurrentRequest().getContextPath());
// Save cookie
addCookie(cookie);
return cookie;
}
private void addCookie(Cookie cookie){
response.addCookie(cookie);
}
public Cookie updateCookieValue(final String name, final String value) {
// Create a new cookie
Cookie cookie = getCookieByName(name);
cookie.setValue(value);
// Save cookie
addCookie(cookie);
return cookie;
}
public void destroyCookieByName(final String name) {
Cookie cookie = getCookieByName(name);
if (cookie != null) {
cookie.setValue(null);
// By setting the cookie maxAge to 0 it will deleted immediately
cookie.setMaxAge(0);
cookie.setPath(VaadinService.getCurrentRequest().getContextPath());
addCookie(cookie);
}
}
}
When i want to create a cookie (like at user's login), i get a nullPointerException because of the VaadinResponse being null.
So i tried to disable Push in constructor and re-enable it at the end of addCookie()
method, but it disabled push for all of my application, even if i re-enable it just after the addCookie
method.
I saw a ticket on vaadin's trac (http://dev.vaadin.com/ticket/11808) saying that will not be fixed, and someone suggested to create a regular AJAX query from server to create cookie, but i really don't know how to do.
How can i manage my cookies? i need to create AND get cookies, so javascript can't help me there, because i can't get javascript's return in vaadin, so i can't get a cookie.
Upvotes: 2
Views: 2008
Reputation: 109
Here is my solution how to store cookie when @Push is using. First we create container to storage all instance of client UI. ( This container itself has a great potential)
public class UISession {
private List<WebAppUI> uis = new ArrayList<WebAppUI>();
public void addUI(WebAppUI webAppUI) {
uis.add(webAppUI);
}
public List<WebAppUI> getUIs() {
return uis;
}
public static UISession getInstance() {
try {
UI.getCurrent().getSession().lock();
return (UISession) UI.getCurrent().getSession().getAttribute("userUiSession");
} finally {
UI.getCurrent().getSession().unlock();
}
}
In UI.init() we add new instance to the session (e.g when user open new tab)
@Override
protected void init(VaadinRequest vaadinRequest) {
/** Set singleton uisesison for each browser*/
if(UISession.getInstance()==null){
UI.getCurrent().getSession().setAttribute("userUiSession",new UISession());
}
UISession.getInstance().addUI(this);
System.out.println("UI count fo current browser "+UISession.getInstance().getUIs().size());
...
}
Here is my helper cookie class:
class MyCookie{
private String value;
private String name;
private Date expired;
private String path="/";
public MyCookie(String name, String value) {
this.name=name;
this.value=value;
}
public void setMaxAge(int minute) {
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, minute);
expired=c.getTime();
}
public String getStringToCreateCookie(){
return "document.cookie=\""+getName()+"="+getValue()+"; expires="+expired.toString()+"; path="+path+"\"";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Date getExpired() {
return expired;
}
public void setExpired(Date expired) {
this.expired = expired;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
And on final when we need add new cookie, we just must find Ui that is active and call js function
public static void addCookie(String name, String value, int age){
MyCookie myCookie = new MyCookie(name, value);
myCookie.setMaxAge(age);
for(WebAppUI ui : UISession.getInstance().getUIs()){
if(ui.isAttached()){
ui.getPage().getJavaScript().execute(myCookie.getStringToCreateCookie());
return;
}
}
}
In my case i have access to storage cookie (when user made request). I just only have problem with add new cookie so this is my working solutions.
Upvotes: 3
Reputation: 1934
The Viritin add-on contains a helper class called BrowserCookie. It works in pretty much the way suggested by cfrick, but just hides all the cookie handling complexity into a helper class. It don't contain built in "max age" handling yet, but that could be easily added as a workaround you can manually "encode" the age into cookie value.
BTW. Don't know what you are doing, but if you happen to be using TouchKit add-on, it has a helper for html5 local storage. It has rather wide browsers support already and is in many ways better way to store e.g. settings than cookies.
Upvotes: 0
Reputation: 37073
As mentioned in the ticket, you can use JavaScript
to call client code and also request a cookie value back by that. E.g.
@Grapes([
@Grab('org.vaadin.spring:spring-boot-vaadin:0.0.3'),
@Grab('com.vaadin:vaadin-server:7.4.0.beta1'),
@Grab('com.vaadin:vaadin-client-compiled:7.4.0.beta1'),
@Grab('com.vaadin:vaadin-themes:7.4.0.beta1'),
])
import com.vaadin.ui.*
@org.vaadin.spring.VaadinUI
@groovy.transform.CompileStatic
class MyUI extends UI {
protected void init(com.vaadin.server.VaadinRequest request) {
final resultLabel = new Label()
// provide a callback for the client to tell the cookies
JavaScript.current.addFunction("tellCookie", { elemental.json.JsonArray arguments ->
resultLabel.value = arguments?.get(0)?.asString()
} as JavaScriptFunction)
setContent(new VerticalLayout().with{
addComponent(new Button("Set Cookie", {
// just simply set the cookies via JS (attn: quoting etc)
JavaScript.current.execute("document.cookie='mycookie=${System.currentTimeMillis()}'")
} as Button.ClickListener))
addComponent(new Button("Get Cookie", {
// tell the client to tell the server the cookies
JavaScript.current.execute("this.tellCookie(document.cookie)")
} as Button.ClickListener))
addComponent(resultLabel)
return it
})
}
}
This is a running example (e.g. spring run vaadin.groovy
) for testing. See the comments for the important parts.
Upvotes: 0