Vaadin UI - cannot use static fields for every client - java

I'm creating a web app.
I have a MyUI that extends UI.
public class MyUI extends UI {
public static Authentication AUTH;
#Override
protected void init(VaadinRequest vaadinRequest) {
AUTH = new Authentication();
updateContent();
}
//other methods
}
In Authentication() I have the user logged. When I do the logout, that user is set to null.
I noticed that when I access to the server from two device, so when I should have two connection to the server, when someone do the logout, the other one is logged out too.
In Authentication class there is this method:
public void doLogout() {
System.out.println("User: " + this.user.getMail() + " has logged out.");
this.user = null;
}
I get error in user.getMail() because the user is already set to null, when I try to do the logout from the other account.
Is com.vaadin.ui.UI unique? How can I handle different connections in Vaadin?

Java, in general
Basic Java here, nothing to do with Vaadin…
The keyword static means one value per class, otherwise known as a “class variable”, more generally known as a “global variable”. Not object-oriented. Generally speaking, you should minimize your use of static.
Omitting that keyword means “one value per instance of this class”, an instance variable also known as member variables. This is object-oriented.
I suggest you learn more of the basics of Java before embarking on a Vaadin project. And learn the basics of how Java Servlet technology works, perhaps reading the Head First book on Servlet published by O’Reilly (now outdated, but basics are the same). You also need to learn about advanced topics such as threading and concurrency issues as a Servlet environment such as Vaadin is inherently multi-threaded. Eventually, read the book Java Concurrency In Practice by Goetz.
Vaadin specifically
To store values per user of a Vaadin app, use session attributes. This is a key-value store where you insert and retrieve a value by specifying a key, the name of the "attribute". The session is automatically instantiated for you when the user first connects, as part of the Java Servlet technology.
Alternatively, you can store values per user on that UI class as instance variables. Each Vaadin user starts with a UI instance when first connecting. But beware: you can open multiple web browser tabs/windows in a Vaadin 8 app, each having their own UI instance. So to share data between those multiple UI objects, use the session attributes.
Note that while every Vaadin app has at least one UI subclass defined, you can define additional UI subclasses as well, for those additional browser tabs/windows mentioned above to show different content.

Maybe instead of static variable you should use here session attribute (updated to be more generic):
UI.getCurrent().getSession().setAttribute("AUTH", AUTH);
Authentication auth2 = UI.getCurrent().getSession().getAttribute("AUTH");
So use VaadinSession to store session specific data.

Related

How to store a static variable in desktop application designed in Java Swing?

I start my desktop app with a login, validate the user and "redirect" to the index Jframe.
What I want now is to store a user Object obtained from login so that it's available in all jframes that I'll use later.
Is it possible? I know that session variables are not that useful in desktop apps but I can't seem to find the way to create a static variable.
I tried creating my Object user in main, then setting it up after login. But it couldn't find the variable.
you can use a static variable:
public class MyAppContext {
public static volatile Object loginObject;
}
MyAppContext.loginObject = "whatever";
Or use a framework like Spring to manage your contexts.

How to use Analytics service to indicate a page view

I'm trying to set up a page view when a certain form is shown, and this is a GUI builder project. I initialized the AnalyticsService with the Google Analytics ID and my app name in the initVars method, and then when I want to fire a page view I used the AnalyticsService.visit(page name, referer). When I view the Google analytics data, is always shows no page info.
What needs to be done to get page view information sent to Google Analytics? Am I calling the visit method incorrectly?
Here's the initialization:
public StateMachine(String resFile) {
super(resFile);
// do not modify, write code in initVars and initialize class members
// there,
// the constructor might be invoked too late due to race conditions that
// might occur
}
/**
* this method should be used to initialize variables instead of the
* constructor/class scope to avoid race conditions
*/
protected void initVars(Resources res) {
Display.getInstance().lockOrientation(true);
AnalyticsService.init("(my Analytics ID)",
"rpcontrol.fastlaneinnovations.com");
AnalyticsService.setAppsMode(true);
AnalyticsService.setFailSilently(false):
....bunch more stuff}
And then elsewhere I try to trigger a page view:
#Override
protected void beforeDataLogs(Form f) {
logsContainer = findLogsContainer(f);
updateLogList();
AnalyticsService.visit("Logs", "");
}
It seems that the AnalyticsService class has two modes and if you created a mobile apps analytics you need to enable the apps mode using
setAppsMode.
This is probably better than the default behavior of using the old mobile website approach, unfortunately I don't think we can flip the default as this would break existing applications that might rely on this API.

Making a variable accessible in all Play 2.0 project views

It is sometimes desirable to share context variables with all views, such as the current user or navigational state. Looking through the documentation, I haven't been able to find a way to share such global context variables accessible to the template engine in all views.
Is this provided by the framework, or am I better off explicitly passing these variables to all views, perhaps by writing a wrapper method called in all controllers whose views need these global variables?
You can use for that Session and Flash scopes
public static Result index() {
// session is good for storing session data such as for an example logged user's info
session("username", "John Doe");
// flash is available only for next request (in this case for view rendering process)
flash("navId", "mainPage");
return ok(index.render("ellou' World"));
}
index.scala.html
#(message: String)
#main(message) {
#if(flash.get("navId")=="mainPage"){<h1>Great! You're on main page again</h1>}
<div>You're logged as #session.get("username")</div>
}
of course for data which are individual for each page (like sample navId) you can also pass it to the view, where you can declare required type other than String.

HttpServletRequest.getRemoteUser() vs HttpServletRequest.getUserPrincipal().getName()

These two seem to be doing the same things. Can anyone explain the main difference between the two? When would you use one vs the other?
HttpServletRequest.getRemoteUser()
HttpServletRequest.getUserPrincipal().getName()
A Principal represents someone who could potentially authenticate with your application. The Principal's name depends on the authentication method used:
a username such as "fred" (in the case of HTTP Basic authentication)
a Distinguished Name such as "CN=bob,O=myorg" (in the case of X.509 client certificates - in which case a X500Principal may be returned)
getRemoteUser() returns "the login of the user" which, in the case of HTTP Basic authentication, will also be the username; it doesn't map cleanly in the X.509 client certificate case though, since the user doesn't enter a "login" as such - in the example above, we could use the Distinguished Name or simply the CN, "bob".
The Javadocs state that "whether the user name is sent with each subsequent request depends on the browser and type of authentication", suggesting that getRemoteUser() was originally meant to provide data only for requests in which a username was entered. This, however, would result in it returning null for the majority of requests when cookie-based auth is in use - not too helpful!
In reality, getRemoteUser() often just calls getUserPrincipal().getName(); verified in Tomcat 6 and Jetty 6/7.
The getUserPrincipal() method returns an object of some class derived from the Principal interface, which is an abstraction of the entity that is the "user" responsible for the request. From it you get an actual object that, depending on the implementing class, you can use to get all sorts of information about that user/identity. One of those properties is the string-representation of the name of the user/identity, which you obtain by calling getName().
getRemoteUser() is really just a shortcut to getting that string-representation. You don't have access to any other methods implemented by the implementing class, not do you have access to the object itself, just the string-representation of the name.
For most use-cases that I am familiar with, that string-representation is what you want; I believe this is why getRemoteUser() exists - it's a common case so there's an easy/quick way to get access to it without actually getting a reference to an implementing class object.
A bit related issue:
People converting older IBM Portlet API code to JSR168 one had to change PortletRequest to HttpServletRequest in some method parameters, but then from WPS6.1 and up they can't cast that to PortletRequest (it doesn't implement the respective interface anymore as it seems) and if they call "getRemoteUser" directly on the HttpServletRequest they get back null (some say a workarround is to enable application security option in WAS [WebSphere Application Server], others say more security-related markup is needed in web.xml)
A workarround seems to be to use PUMA, but of course that is IBM WebSphere specific. Probably at other Portlet Containers there are other vendor-specific workarrounds if one finds that getRemoteUser always returns null (judging from other replies then getUserPrincipal().getName() also returns null if getRemoteUser is implemented as just a shortcut to that one).
BTW, the PUMA code I mention above is here, since it's a bit hard to find what works in WPS6.1+:
import com.ibm.portal.portlet.service.PortletServiceHome;
import com.ibm.portal.um.*;
import com.ibm.portal.um.exceptions.PumaException;
import com.ibm.portal.puma.User;
//...
public String getCurrentUser(){
try {
Context ctx = new InitialContext();
Name myjndiname = new CompositeName(PumaHome.JNDI_NAME);
PumaHome myHome = (PumaHome) ctx.lookup(myjndiname);
if (myHome!=null) {
PumaProfile pumaProfile = myHome.getProfile();
com.ibm.portal.um.User user = (com.ibm.portal.um.User)pumaProfile.getCurrentUser();
List attributes = new ArrayList();
attributes.add("uid");
Map userAttributes = pumaProfile.getAttributes(user,attributes);
return (String) userAttributes.get("uid");
}
}

How to preserve object identity across different JVMs

To be specific let me illustrate the question with Spring http-remoting example.
Suppose we have such implementation of a simple interface:
public SearchServiceImpl implements SearchService {
public SearchJdo processSearch(SearchJdo search) {
search.name = "a funky name";
return search;
}
}
SearchJdo is itself a simple POJO.
Now when we call the method from a client through http-remoting (Spring's mechanism of calling remote objects much like EJB that uses serialization) we'll get:
public class HTTPClient {
public static void main(final String[] arguments) {
final ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-http-client-config.xml");
final SearchService searchService =
(SearchService) context.getBean("searchService");
SearchJdo search = new SearchJdo();
search.name = "myName";
// this method actually returns the same object it gets as an argument
SearchJdo search2 = searchService.processSearch(search);
System.out.println(search == search2); // prints "false"
}
}
The problem is that the search objects are different because of serializaton although from logical prospective they are the same.
The question is whether there are some technique that allows to support or emulate object identity across VMs.
You said it - object identity is different from logical equality.
object identity is compared with ==
logical equality is compared with .equals(..)
So override the equals() method and all will be fine. Remember to override hashCode() based on the same field(s) as well. Use your IDE to generate these 2 methods for you.
(Teracotta VM clustering allows sharing objects between VMs, but that doesn't fit your case.)
IMHO attempting to preserve object identity equality across VMs is a losing proposition.
To the best of my knowledge the language specification does not require a VM to support that, so you would be limited in where you can pull off if you truly want to be portable.
May I ask why you don't just use some unique ID that you supply yourself? Java GUIDs, while expensive, are serializable.
I did this once, but I'm not quite sure if this is a right approach:
Every user had a username, session id, roles, and a login date attached to a user object. Every time I logged into a VM the system would load a User object into memory; I would also return the user object to the application.
If I needed to execute an action within the application server, then I would send the user object as an argument. If the VM had the User loaded with the same session ID then it would use the object stored in the VM to know the assigned roles. Otherwise, the application would then be capable of changing the roles in the user and it wouldn't be secure.
If the application had to change the application server, then it sends the user object to the new server and the new server wouldn't be able to find the user within its records.
HERE IS THE SECRET: The session ID is created hashing the username, the login date and a secret password shared among all of the servers.
Once the new server finds that the session ID is coherent, then it would load the roles from the database as a reliable source of information.
Sorry if I couldn't write this before, but hope it helps for someone.

Categories

Resources