Vaadin ThreadLocal for User Management - java

I'm currently developing a web application in Java which will be accessed by multiple users at the same time and as such need to store userdata in order to tailor the application to their individual requirements (such as what company they are apart of etc).
There are 2 classes that i use to manage this. User, MainSystem detailed below:
User
#Entity
public class User implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String username;
private String password;
private String type;
private String company;
private String DOB;
private String email;
private int PayrollId;
public User(String firstName, String lastName, String username, String password, String type, String company, String DOB, String email) {
this.firstName = firstName;
this. lastName = lastName;
this.username = username;
this.password = password;
this.type = type;
this.company = company;
this.DOB = DOB;
this.email = email;
}
MainSystem:
public class MainSystem {
public UserController userController;
private UserRepository userRepository;
private static ThreadLocal<User> loggedInUser = new ThreadLocal<>();
public DbController dbController;
public MainSystem(){
userController = new UserController(userRepository);
loggedInUser.set(new User());
}
public Boolean Login(String username, String password) {
if(userController.checkUser(username,password)){
User aUser = userController.getUser(username);
setLoggedInUser(userController.getUser(username));
VaadinSession.getCurrent().setAttribute("username",loggedInUser.get().getUsername());
System.out.println("Logged in User: "+loggedInUser.get().getUsername());
return true;
}
else {
return false;
}
}
public static void setLoggedInUser(User user){
loggedInUser.set(user);
}
public static User getLoggedInUser() {
return loggedInUser.get();
}
Ideally what i'd like to do is access the ThreadLocal variable from another class, for instance the ViewProfile.View:
public class EditProfileView extends VerticalLayout implements View {
MainSystem main = new MainSystem();
NavigatorUI aUI = new NavigatorUI();
User aUser = main.getLoggedInUser();
TextField username = new TextField("Username");
TextField Id = new TextField("Id");
TextField email = new TextField("Email");
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
TextField type = new TextField("Type");
PasswordField oldPassword = new PasswordField("Current Password");
PasswordField changePassword1 = new PasswordField("New Password");
PasswordField changePassword2 = new PasswordField("Confirm Password");
private UserController userController;
private UserRepository userRepository;
public EditProfileView() {
setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
userController = new UserController(userRepository);
setStyleName("backgroundImage");
setMargin(true);
setSizeFull();
addComponent(aUI.getHeader());
FormLayout content = new FormLayout(generateInfo());
Panel aPanel = new Panel("Edit User",content);
aPanel.setWidthUndefined();
content.setMargin(true);
aPanel.setStyleName(ValoTheme.PANEL_WELL);
addComponent(aPanel);
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = main.getLoggedInUser();
System.out.println( aUser.getUsername());
Id.setValue(aUser.getId().toString());
username.setValue(aUser.getUsername());
firstName.setValue(aUser.getFirstName());
lastName.setValue(aUser.getLastName());
type.setValue(aUser.getType());
email.setValue(aUser.getEmail());
aUI.setUserMenu();
aUI.refreshPayroll();}
catch (Exception e){
System.out.println(e.getMessage());
}
}}
However, i'm finding that it is presenting me with a "null" value? I fear i may have missunderstood how ThreadLocal works. but essentially what i'm trying to achieve is to Store an instance relevant variable of the User.Class in MainSystem for other classes to use?
Any help would be appreciated.
My Solution:
My solution to this was to store the User.class in a VaadinSession Attribute like so:
public Boolean Login(String username, String password) {
if(userController.checkUser(username,password)){
User aUser = userController.getUser(username);
VaadinSession.getCurrent().setAttribute("user",aUser);
VaadinSession.getCurrent().setAttribute("username",loggedInUser.get().getUsername());
System.out.println("Logged in User: "+loggedInUser.get().getUsername());
return true;
}
else {
return false;
}
}
Then in other classes if i want to use that attribute i retrieved it like so:
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = (User)VaadinSession.getCurrent().getAttribute("user");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}

The problem is that there's no guarantee that MainSystem.Login() and EditProfileView.enter() will happen on the same thread. Every user action is processed as a separate HTTP request that the servlet container will run on any available thread.
For this kind of functionality, I would instead recommend storing the user information in the HTTP session. If you don't have any custom servlets or such, you could instead have a an field that contains the user object in your own custom UI class. Vaadin takes care of making UI.getCurrent() always return the right value in all code that is run through Vaadin.
If you instead also are integrating with other servlet functionality, you could store the user in the HttpSession instead. Generic servlet code can find the session through the getSession() method in e.g. servlet requests and response. In code run by Vaadin, you can use VaadinSession().getCurrent().getSession() to get a WrappedSession instance that is based on to the same HttpSession data.

There is also another approach. Instead it could be possible to make #SessionScoped user service, and either #Inject or #Autowire that depending whether you are using CDI or Spring. When doing this way, it will be the bean manager that takes care of binding correct entity with your view.

Related

Spring boot API - How to ensure no concurrency issues

I'm still in the process of learning Java / spring and I think I'm getting better. Now at this point I'm able to build a rest api BUT I'm at a lost at how to ensure I've no concurrency issues . I've read many topics regarding making the API stateless or making my POJO's immutable but I'm sure if in my case below I need to. And if I did, I'm actually unsure how my code can function by making everything final in my POJO.
If someone could help me learn here I'd be VERY grateful. Thank you for your time
Below i have a POJO called User:
#Getter
#Setter
#Document(collection = "UserProfiles")
public class User {
#Id
#JsonIgnore
private String _id;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String userId;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String name;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String displayName;
#DBRef
#JsonView({ProfileViews.Full.class})
private UserInterests personalInterests;
#DBRef
#JsonIgnore
private ProfileFollows profileFollowDetails;
}
#Getter
#Setter
#Document(collection = "ProfileFollows")
public class ProfileFollows {
#Id
//Id of The Mongo Document
private String id;
//The Id of the User Profile who owns the document
private String userId;
//A list containing the Ids of the Users who have followed the Profile belonging to userId
private List<String> profileFollowedByUserIds;
//A list containing the Ids of the Profiles the current user has followed
private List<String> profileFollowingByUserList;
}
And here is my Service layer where I create and update the user
#Service
public class UserService {
#Autowired
UserDal userDal;
public User createNewUserAccount(String userId, String userName) {
//check If userId already in DB
if (checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Cannot create User with Id { " + userId + " }, a user with this Id already " +
"exists");
}
//Create a Empty / Base New User Object
User newUser = new User();
UserInterests userInterests = new UserInterests();
userInterests.setUserId(userId);
userInterests.setPersonalInterestsExtras(null);
userInterests.setCreatedDate(Instant.now());
userInterests.setLastUpdatedAt(Instant.now());
userInterestsDAL.save(userInterests);
newUser.setPersonalInterests(userInterests);
ProfileFollows userProfileFollows = new ProfileFollows();
userProfileFollows.setUserId(userId);
userProfileFollows.setProfileFollowedByUserIds(new ArrayList<>());
userProfileFollows.setProfileFollowingByUserList(new ArrayList<>());
newUser.setProfileFollowDetails(profileFollowsDAL.save(userProfileFollows));
newUser.setUserId(userId);
newUser.setDisplayName(generateUserDisplayName(userName));
newUser.setCreatedDate(Instant.now());
newUser.setLastUpdatedAt(Instant.now());
//save the new User Profile to the DB
return userDal.save(newUser);
}
Here is my UserDAL:
public interface UserDal {
/**
* Method to check if a user exists with a given user Id
* #param Id -- Id of user to look up where id is a string
* #return
*/
Boolean existsById(String Id);
/**
* Method to save a user to the DB
* #param user -- User object to save to the DB
* #return
*/
User save(User user);
}
My User Repository / DALImpl:
#Repository
public class UserDALImpl implements UserDal {
private final MongoTemplate mongoTemplate;
#Autowired
public UserDALImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public User save(User user) {
return mongoTemplate.save(user);
}
And lastly my controller:
#RestController
#RequestMapping("/profile")
public class CreateProfileController {
#Autowired
public CreateProfileController() {
}
#Autowired
UserService userService;
#ApiOperation(value = "Allows for the creation of a user Profile")
#PostMapping("/create")
public User createUserProfile(#RequestParam(name = "userId") String userId,
#RequestParam(name = "displayName", required = true, defaultValue = "AnonymousDev") String displayName) {
if (userId.equals("")) throw new BadRequestException("UserId cannot be blank");
if (userService.checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Unable to create user with Id { " + userId + " }, the " +
"userId already exists");
}
return userService.createNewUserAccount(userId, displayName);
}
}

SpringBoot JPA throws exception while making post request

Im making a small application where i can save user details using spring-boot. i created the entities and their corresponding repositories. When ever i make a post request to add a user the id of the user object which is null at the point of saving to the data base.This id is auto generated(Auto Increment) in MySQL. From the POST request i get 3 fields which are username,email,password. The User class contains fields id,username,email,password. I've added the annotations
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
for the id field. an the constructors are
public User() { }
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
This is the error im getting.
The debugging process
my userService class
#Service
public class UserService implements UserServiceInterface {
#Autowired(required = true)
private UserRepository userrepository;
#Override
public User CreateNewUser(User user) {
return userrepository.save(user);
}
}
my userController class
#RestController
public class UserController {
UserService us = new UserService();
#RequestMapping(value ="/user",method = RequestMethod.POST)
public void RegisterUser(
#RequestParam(value="username") String username,
#RequestParam(value="email") String email,
#RequestParam(value="password") String password){
us.CreateNewUser(new User(username,email,password));
}
}
Any reason why i cant POST to save data to database? how to overcome this?
After digging through the code i found out the error. by creating a new instance of UserService us = new UserService(); this is not managed by Spring (Spring doesn't know about it and cannot inject UserRepository - this causes NullPointerException). there of instead of creting new instace it should extends the UserService class in this example.

Java Class Relationship and ORM

I have this simple login-registration functionality using the following classes.
User class:
public class User implements Serializable {
private int userId;
private String username;
private String password;
public User() {
userId = 0;
username = "";
password = "";
}
// public set-get methods here
}
Verification class:
public class Verification implements Serializable {
private int userId;
private String code;
private long expirationDate; // millis
public Verification() {
userId = 0;
code = "";
expirationDate = 0;
}
public void setUserId(int Id) {
userId = Id;
}
public void setUserId(User user) {
userId = user.getUserId();
}
// the rest of set-get methods here
}
I would like to confirm if the relationship above is considered Dependency? or Association?
Also, I'm using this classes in ORM. Does omitting one setUserId() overloaded method mess up the relationship between(if there's any)? Thank you.
I would say a dependency exists between Verification and User, as you can pass a User reference to a method of Verification (it uses that reference and depends on it), but Verification instance does not OWN a reference to a User instance, instead it consumes one.
The example you gave , describes dependency .
For reference you can visit the link given below -:
https://nirajrules.wordpress.com/2011/07/15/association-vs-dependency-vs-aggregation-vs-composition/

Models not being saved in Play Framework

Assume a model named User:
#Entity
public class User extends Model {
#Id
#Constraints.Min(10)
public Long id;
#Constraints.Required
public String username;
#Constraints.Required
public String password;
public static Finder<Long, User> find = new Finder<Long, User>(
Long.class, User.class
);
}
When I attempt to update an instance of User in my controller:
User user = User.find.where().eq("username", username).findUnique();
if(user != null) {
user.username = "some_new_username";
user.save();
}
no changes seem to be committed. I read somewhere that when you alter a model instance by its property, it does not get dirty and therefore no changes take place. Hence you should use a setter instead. In the documentation of Play Framework it is said that those setters (and getters) are generated automatically, but using user.setUsername(username) gives me a compilation error:
cannot find symbol [symbol: method setUsername(java.lang.String)] [location: class models.User]
Am I missing something?
Have you tried adding custom setters?
#Entity
public class User extends Model {
#Id
#Constraints.Min(10)
public Long id;
#Constraints.Required
public String username;
public void setUsername(String _username) {
username = _username;
}
#Constraints.Required
public String password;
public void setPassword(String _password) {
password = _password;
}
public static Finder<Long, User> find = new Finder<Long, User>(
Long.class, User.class
);
}
As far as I can tell, automatic getter/setter translation is broken in Play2. Your assignment:
user.username = "some_new_username";
should have triggered the function call:
user.setUsername("some_new_username");
This translation seems to be broken in Play 2. Here's my own question on the subject.

Relationships question in hibernate

I'm learning Hibernate and Play framework (also add Java into account...). I'm having problems saving this kind of entity
#Entity
#Table(name="users")
public class User extends Model {
#Required
public String username;
#Column(name="user_displayname",nullable=true)
public String displayname;
#Password
public String user_password;
#Email
#Column(name="user_email",nullable=false,unique=true)
public String user_email;
public String user_salt;
public Date user_joindate;
#ManyToOne
#JoinTable(name="users_meta")
public UserMeta userdata;
#Required
public boolean user_isActive;
#OneToOne(targetEntity=UserPhotos.class,cascade=CascadeType.ALL)
#JoinColumn(name="id",referencedColumnName="userID")
public UserPhotos userPhoto;
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="links_rol2user")
public List<Rol> rol;
public User (String username, models.Pass password, String user_email) {
this.username = username;
this.user_password = password.getHashedPassword();
this.user_salt = password.getUserHash();
this.user_email = user_email;
this.user_joindate = new Date();
this.user_isActive = false;
}
This is my code when I'm registering a user
// check if the validation has errors
if(validation.hasErrors()) {
params.flash(); // add http parameters to the flash scope
validation.keep(); // keep the errors for the next request
register();
} else {
Cache.delete(uuid);
Pass pass = new Pass(password,new Date().toString());
User newUser = new User(firstName, pass, email);
UserMeta utest = new UserMeta(newUser.id);
utest.setUserTownID(pueblos);
newUser.setUserMeta(utest);
newUser.save();
Logger.info("NewUser ID : %s", newUser.getId());
// UserMeta userInfo = new UserMeta(newUser.getId());
// userInfo.setUserTownID(pueblos);
// userInfo.save();
// TODO salvar foto a null
// Confirmation left
Cache.set("thankyou", "alright!", "3mn");
thankyou();
}
I'm trying to save the userMeta, it does creates a new record when I set the userMeta object into newUser (not visible right now), but it doesn't insert the new ID created in newUser.
What kind of relation do I need? before I tweaked the code as it is now, it was a OneToOne relationship, worked quite well, but now when I was completing the register functions it kinda hit me that I needed to save userMeta object too..
If you need more info let me know, I don't know if I explained it well or not, just trying to get the hang of how Hibernate do relations, etc.
Adding UserMeta:
*/
#Entity
#Table(name="users_meta")
public class UserMeta extends Model {
#Lob
#Column(name="userBio")
public String userBio;
#Column(name="userPhotoID",nullable=true)
public Long userPhotoID = null;
#Column(name="userRoleID", nullable=false)
public Long userRoleID = 2L;
#Lob
public String userDescription;
#Column(name="userViews", nullable=false)
public Long userViews = 0L;
#Column(name="userFavoriteCount", nullable=false)
public Long userFavoriteCount = 0L;
#Column(name="userTotalComments", nullable=false)
public Long userTotalComments = 0L;
#Column(name="userTotalUploadedVideos", nullable=false)
public Long userTotalUploadedVideos = 0L;
public Long userTownID;
public Long userID;
public UserMeta() {}
public UserMeta(Long userid) {
this.userBio = "El usuario no ha escrito nada todavia!";
this.userDescription = "El usuario todavia no se ha describido!";
this.userID = userid;
}
public Long getUserTownID() {
return userTownID;
}
public void setUserTownID(Long userTownID) {
this.userTownID = userTownID;
}
}
// pass model
public class Pass {
protected String hashed;
protected String userHash;
public Pass(String passwordToHash, String salt) {
StringBuffer passSalt = new StringBuffer(passwordToHash);
this.userHash = DigestUtils.md5Hex(salt);
passSalt.append(this.userHash);
passSalt.append(Play.configuration.getProperty("application.passwordSalt"));
this.hashed = DigestUtils.sha512Hex(passSalt.toString());
}
public String getHashedPassword() {
return this.hashed;
}
public String getUserHash() {
return this.userHash;
}
}
There seems to be a lot going on there! But from what I can tell, you problem is with the id that you are passing into the UserMeta.
As you are extending Model, the id is being generated by the Model class. However, this is not set until after the entity is saved to the database (as the id is auto-generated by the database).
Therefore, because you are passing the id into the UserMeta before the User object is saved, the value of id will be null.
If you can save the User object before you create your UserMeta object, your code should work.

Categories

Resources