I have a JBoss Seam app that leverages Seam's IdentityManager and JpaIdentityStore components for handling user account creation and authentication. My components.xml file is setup correctly, and I'm able to use IdentityManager for creating accounts with no problem.
I have created a page to allow me to perform rudimentary account maintenance, such as enabling/disabling accounts. However, whenever I call the isUserEnabled(String username) method on IdentityManager, it always returns false. The corresponding method in JpaIdentityStore also returns false. Both occur even though I can see that the accounts have been enabled in the database. My user account class is annotated as follows:
#Name("user")
#Entity(name = "UserAccount")
#Table(name = "tbl_user_acct", uniqueConstraints = { #UniqueConstraint(columnNames = "username") })
public class UserAccountBean extends BaseDomainEntity implements
VersionedDomainEntity {
private static final long serialVersionUID = -3573332411594504888L;
#UserEnabled
private boolean enabled;
...
}
I don't have any issues with any of the other aspects of the IdentityManager class (changing passwords, creating/deleting accounts, etc.) The only error I run into is when I try to determine if a user is enabled or not. I don't receive any exceptions or error messages, I just get the wrong result returned.
Has anyone else encountered this? Any idea how best to start troubleshooting this issue?
EDIT: Some additional info...
I notice that when I call disableUser(String username), I do actually see the database reflect that in the ENABLED column. Additionally, when I call enableUser(String username), I immediately see that the account is enabled. However, if I navigate to another page and then come back and call isUserEnabled(), it still shows false.
Turned out to be an issue related to lazy fetching. I have a UserProfile object with a userAccount property on it. The relation is Lazy-fetched. Once I changed it to Eager fetching, I received the appropriate response from isUserEnabled().
Related
I have users registration controller in my Spring Boot project with spring-boot-starter-data-jpa and spring-boot-starter-web dependencies, which implements the following logic, where usersRepository is an instance of standard CrudRepository:
#PostMapping
public String processRegistrationForm(#Valid #ModelAttribute("registrationForm") UserForm form,
Errors errors, Model model) {
if (!errors.hasErrors()) {
UserEntity user = usersRepository.findByUsername(form.getUsername());
if (user != null) {
errors.rejectValue("username", "registration.username.not.unique");
} else {
usersRepository.save(form.toUserEntity(passwordEncoder));
model.addAttribute("isRegistrationComplete", true);
}
}
return "registration";
}
The method first checks whether the user with the given username exists, and if not - saves it into the database. The problem here is that this check-then-act behavior may result in DataIntegrityViolationException (with the underlying unique username constraint violation) if someone intervenes in between findByUsername() and save() calls and manages to save the user with the same username into the database. How can I avoid this? And would making the whole method #Transactional solve this problem?
It seems you want to create an entity but not overwrite it, and in an atomic operation you cannot test for existence first.
You could, however put a unique key on your resource and then simply go for the create option. If that entity (with that specific key) already exists you should receive an exception telling you about duplicate data. Now you can still decide whether you want to error out or simply update the existing entry.
Edit: Reading the other comments: your unique key is probably the user name, and you want to error out saying that the chosen user name is already in use.
Edit2: So you mention that my suggestion is what you had implemented but you were not happy. I think you did not suffer from performance but did not like the code (parsing - see my comment) or the user behaviour.
A user just fills in a form to register and while being delayed by a captcha or some bad password pattern all of a sudden that user name is taken by someone else. Not a nice situation.
You will only resolve it by acting as soon as a user tries to register with a name. Upon the first such check (and when you return the status that the user is still available) create the entity with an attribute that this is just a placeholder. While the user still fills in the registration form other users already can see the name is taken.
For all cases where a registration is not finished and thus names are blocked for nothing, have a garbage collector job that removes all placeholders after some time. So if a placeholder has not completed to a full user account within one hour, just remove that entry from the DB and another user is free to reuse the name.
I'm in the middle of migrating a project from:
Spring 4.2.1 -> 5.0.0
Spring Data Gosling -> Kay
Hibernate 4.3.8 -> 5.8.0
And I'm running getting "org.hibernate.LazyInitializationException: could not initialize proxy - no Session" when accessing an object coming from my database in a controller method.
Here's a stripped down version of my code:
// CustomUser.java
#Entity
#Access(AccessType.FIELD)
#Table(name = "users")
public class CustomUser implements Serializable {
...
#Id
#GeneratedValue//details omitted
#GenericGenerator//details omitted
#Column(name = "id", insertable = true, updatable = true, unique = true, nullable = false)
private Long id;
#Column(name = "name")
private String name;
public String getName() { return name; }
}
// UserController.java
#RequestMapping(value = "/user/{userId}/", method = RequestMethod.GET)
public String showUser(#PathVariable("userId") CustomUser user) {
System.out.println("user name is [" + user.getName() + "]");
return "someTemplate";
}
// UserService.java
#Service
public class UserServiceImpl implements UserService {
#Autowired UserRepository userRepository;
#Override
public User findUserById(Long userId) {
return userRepository.getOne(userId);
}
}
// UserRepository.java
public interface UserRepository extends JpaRepository<CustomUser, Long> { }
// UserConverter.java
#Component
public class UserConverter implements Converter<String, CustomUser> {
#Autowired UserService userService;
#Override
public CustomUser convert(String userId) {
CustomUser user = userService.findUserById(SomeUtilClass.parseLong(userId));
return user;
}
}
There's also a #Configuration WebMvcConfigurerAdapter class that autowires a UserConverter instance and adds it to a FormatterRegistry.
Prior to starting this upgrade, I could hit:
http://server:port/user/123/
and Spring would take the "123" string, the UserConverter::convert method would fire and hit the Postgres database to look up a user with that id, and I'd get back a CustomUser object in my controller's "showUser" method.
But, now I am getting the org.hibernate.LazyInitializationException. This is occurring when I attempt to print out the user's name in the "showUser" method - or even just "println(user)" without accessing a field.
Most of the info I've been able to turn up from searching suggests that this exception comes from having an object having a lazily loaded collection of sub objects (like if my CustomUser had a collection of Permission objects or something that mapped to a different database table). But in this case I'm not even doing that, this is just a field on the object.
My best guess at the moment is this is due to some kind of hibernate session being terminated after the Converter does its work, so then back in the controller I don't have a valid session. (although again, I don't know why the CustomUser object is coming back unusable, I'm not attempting to fetch a subcollection).
I have added the Hibernate annotation "#Proxy(lazy = false)" to my CustomUser.java and if I do that the problem goes away. But, I'm not sure this is a good solution - for performance reasons, I really don't think I want to go down the road of eagerly fetching EVERYTHING.
I've also tried annotating various things (the service method, the controller method, etc.) with #Transactional; I haven't gotten that to work but I am still reasonably new to Spring and I may be trying that in the wrong place or misunderstanding what that should do.
Is there a better way to handle this than just "#Proxy(lazy = false)" on all of my Entity classes?
The immediate problem comes from the use of userRepository.getOne(userId). It is implemented in the SimpleJpaRepository using EntityManager.getReference. This method returns just a Proxy, which only contains its id. And only when a property gets accessed those get lazy loaded. This includes simple properties like name in your case.
The immediate fix is to use findOne which should load all the eager properties of your entity which should include simple properties, so the exception goes away.
Note that this will slightly change the behavior of your converter. The current version will not fail when the id is not existent in the database because it never checks. The new one will obtain an empty Optional and you'll have to convert it to null or throw an exception.
But there is (or might be) a bigger problem hiding: The entity is still detached because in absence of an explicit transaction demarcation the transactions only span single repository calls. So if you later want to access lazy loaded properties, you might get the same problem again. I see various options to consider:
Leave it as it is, being aware that you must not access lazy loaded properties.
Make sure a transaction is started before the converters get invoked.
Mark your controllers with #Transactional and loading the user (again) in the controller.
I am currently working on a medium sized, desktop-based administration and configuration tool implemented in Java using JavaFx, google-guice, and hibernate for its jpa implementation.
Until now i got away with a single EntityManager injected as a #Singleton. Meaning that i had this EntityManager "open" from start to shutdown. All loaded entites were permanently known in the context and I barely had any problems with this approach. Although i know/believe it is not the best solution (but easy and a I had no time to redesign the application).
Now the application gets extended and I have to use multiple persistence units simultaneously.
I could try to get my current singleton-approach working with using something like:
#Inject
#PersistenceContext(name="JPA-Unit1")
#Singleton
private EntityManager em;
It never felt perfect, but that feels "ugly". And since I had severe problems getting multiple persistence contexts working with guice, I had to do a lot of reasearch on this topic.
And i came across several blogs SO-questions either mentioning that an instance of the EntityManager should only live as long it is needed or some extended persistence contexts.
Since I useJavaFx in place I use the *Property classes to bind the data directly into the UI.
Simplified user entity (property-based access):
#Entity
#Table(name = "USERS")
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
[...]
private final SimpleStringProperty loginProperty = new SimpleStringProperty();
public User() {
}
public String getLogin() {
return this.loginProperty.get();
}
public void setLogin(String login) {
this.loginProperty.set(login);
}
public SimpleStringProperty loginProperty() {
return this.loginProperty;
}
[...]
}
If i start editing the user data in the UI it gets directly updated in the entity:
this.login.textProperty().bindBidirectional(user.loginProperty());
There is no need for extensive "business logic". It gets all handled via (input) validation. If all input is valid i simply save the data via
userService.update(user);
Parts of the UserService (exactly: its abstract super-class):
public abstract class AbstractService<PK extends Serializable, Type> implements GenericService<PK, Type> {
protected Class<Type> clazz;
#PersistenceContext(name = "JPA-Unit1")
#Inject
protected Provider<EntityManager> emProvider;
public AbstractService(Class<Type> clazz) {
this.clazz = clazz;
}
#Transactional
#Override
public Type create(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
#Transactional
#Override
public Type update(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
}
As you can see: the service class is pretty straightforward. I could even delete all this "service"-classes and directly use the entitymanager directly in my UI controller.
In this service you can see the "problem" the user i edit got loaded earlier by its named query and put into a list. The loading is also done in a #Transactional method.
But everytime i call this.emProvider.get() I get a new instance with an empty context. And if I want to save the previously edited user I have the problem that persist actually performs an insert (I assume because it is not known in the context [detached]) which leads to an PK-constraint violation or if I delete (null) its ID-property there is a new user row inserted.
My actual questions are:
1. Is this approach "OK"? If yes what do I do with this "always" new persistence context? Call contains and merge every single time?
Should I get rid of my service class and implement the persistence operations directly in my UI-controller?
Can I do an this.emProvider.get() once the User-UI-controller got loaded and use it the entire life time of the application?
Something totally different?
My understanding is that your app uses Guice Persist.
The answer to this question depends on your use cases; however, you absolutely need to realize one thing:
For as long as an EntityManager is open, its underlying persistence context tracks every single change to each persistent entity.
This means that if you keep an entity manager open for the duration of the application, whenever you call e.g. User.setLogin(), the change you just made is already regarded as persistent. Now, moving to your update method, calling persist on an entity that is already managed has no effect; however, since you're calling it from a #Transactional method, Guice wraps the call in a transaction, and consequently, all the changes are are being flushed to the database once the method ends.
This means that if you modify multiple entities at once within your app, and then call AbstractService.update on one of them, you will actually be saving all the changes your app has done to other entities in the meantime, even if AbstractService.update has not been called on them explicitly.
Using the entity manager-per-transaction approach is indeed much safer. Between transactions, there will be no open persistence context, and as a result all the entities will become detached, which will prevent any updates on them from accidentally being flushed to the database.
However, for the same reason, your update method will need to call em.merge on the entity you want to update in the database. merge is basically telling the entity manager 'please put this entity back into the persistence context, and make it have the exact state that the provided entity has'. Calling persist makes it look as though it was a new entity, and PK-constraint violations will indeed follow.
I have a simple small application which involves an admin having the ability to update and delete information or individual user's from a database. Basically, so far the administrator can view all the current registered user's in a table format on a page. I need to know how I can delete or update the user information based on the user in each row, so assuming based on their actual userID. So far I have been able to extract all the user's from the database and put them into a table, and using JSTL fill in the necessary table values(username, email, etc..).
I do not know, the proper process for doing this, and do not know how to code up the controller to handle this specific task. So far my controller is like this:
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false) Integer id) {
usersService.delete(id);
return "users";
}
where the request mapping comes from a button in the table, and "return users;" just returns back to the same jsp page which displays all the users. This is a little buggy, and I would like to know what would be the proper and best way to implementing this functionality.
Check the users Authority with the Principal.
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false, Principal princiapl) Integer id) {
// Check if user has admin authority using principal.getAuthorities();
}
You could also use the #Secured("ROLE_ADMIN") annotation and lock down the method to the admin role.
Quick version:
We're looking for a way to force a transaction to rollback when specific situations occur during the execution of a method on a backing bean but we'd like the rollback to happen without having to show the user a generic 500 error page. Instead, we'd like the user to see the form she just submitted and a FacesMessage that indicates what the problem was.
Long version:
We've got a few backing beans that use components to perform a few related operations in the database (using JPA/Hibernate). During the process, an error can occur after some of the database operations have happened. This could be for a few different reasons but for this question, let's assume there's been a validation error that is detected after some DB writes have happened that weren't detectible before the writes occurred. When this happens, we'd like to make sure all of the db changes up to this point will be rolled back. Seam can deal with this because if you throw a RuntimeException out of the current FacesRequest, Seam will rollback the current transaction.
The problem with this is that the user is shown a generic error page. In our case, we'd actually like the user to be shown the page she was on with a descriptive message about what went wrong, and have the opportunity to correct the bad input that caused the problem. The solution we've come up with is to throw an Exception from the component that discovers the validation problem with the annotation:
#ApplicationException( rollback = true )
Then our backing bean can catch this exception, assume the component that threw it has published the appropriate FacesMessage, and simply return null to take the user back to the input page with the error displayed. The ApplicationException annotation tells Seam to rollback the transaction and we're not showing the user a generic error page.
This worked well for the first place we used it that happened to only be doing inserts. The second place we tried to use it, we have to delete something during the process. In this second case, everything works if there's no validation error. If a validation error does happen, the rollback Exception is thrown and the transaction is marked for rollback. Even if no database modifications have happened to be rolled back, when the user fixes the bad data and re-submits the page, we're getting:
java.lang.IllegalArgumentException: Removing a detached instance
The detached instance is lazily loaded from another object (there's a many to one relationship). That parent object is loaded when the backing bean is instantiated. Because the transaction was rolled back after the validation error, the object is now detached.
Our next step was to change this page from conversation scope to page scope. When we did this, Seam can't even render the page after the validation error because our page has to hit the DB to render and the transaction has been marked for rollback.
So my question is: how are other people dealing with handling errors cleanly and properly managing transactions at the same time? Better yet, I'd love to be able to use everything we have now if someone can spot something I'm doing wrong that would be relatively easy to fix.
I've read the Seam Framework article on Unified error page and exception handling but this is geared more towards more generic errors your application might encounter.
Update: here's some psudo-code and details of the page flow.
In this case, assume we're editing some user's information (we're not actually dealing with a user in this case but I'm not going to post the actual code).
The edit functionality's edit.page.xml file contains a simple re-write pattern for a RESTful URL and two navigation rules:
If result was successful edit, redirect the user to the corresponding view page to see the updated info.
If the user hit the cancel button, redirect the user to the corresponding view page.
The edit.xhtml is pretty basic with fields for all of the parts of a user that can be edited.
The backing bean has the following annotations:
#Name( "editUser" )
#Scope( ScopeType.PAGE )
There are some injected components like the User:
#In
#Out( scope = ScopeType.CONVERSATION ) // outjected so the view page knows what to display
protected User user;
We have a save method on the backing bean that delegates the work for the user save:
public String save()
{
try
{
userManager.modifyUser( user, newFName, newLName, newType, newOrgName );
}
catch ( GuaranteedRollbackException grbe )
{
log.debug( "Got GuaranteedRollbackException while modifying a user." );
return null;
}
return USER_EDITED;
}
Our GuaranteedRollbackException looks like:
#ApplicationException( rollback = true )
public class GuaranteedRollbackException extends RuntimeException
{
public GuaranteedRollbackException(String message) {
super(message);
}
}
UserManager.modifyUser looks something like this:
public void modifyUser( User user, String newFName, String newLName, String type, String newOrgName )
{
// change the user - org relationship
modifyUser.modifyOrg( user, newOrgName );
modifyUser.modifyUser( user, newFName, newLName, type );
}
ModifyUser.modifyOrg does something like
public void modifyOrg( User user, String newOrgName )
{
if (!userValidator.validateUserOrg( user, newOrgName ))
{
// maybe the org doesn't exist something. we don't care, the validator
// will add the appropriate error message for us
throw new GauaranteedRollbackException( "couldn't validate org" );
}
// do stuff here to change the user stuff
...
}
ModifyUser.modifyUser is similar to modifyOrg.
Now (you're going to have to take this leap with me because it doesn't necessarily sound like it's a problem with this User scenario but it is for the stuff we're doing) assume changing the org causes the modifyUser to fail to validate but that it's impossible to validate this failure ahead of time. We've already written the org update to the db in our current txn but since the user modify fails to validate, the GuaranteedRollbackException will mark the transaction to be rolled back. With this implementation, we're not able to use the DB in the current scope when we're rendering the edit page again to display the error message added by the validator. While rendering, we hit the db to get something to display on the page and that isn't possible because the Session is invalid:
Caused by org.hibernate.LazyInitializationException with message: "could not initialize proxy - no Session"
I must agree with #duffymo about validating before the transaction is initiated. It is quite difficult to handle database exceptions and presenting those to the user.
The reason you get the detached exception is most likely because you think you have written something to the database, and then you call remove on or refresh on the object, and then you try to write something again.
What you need to do instead is create a long-running conversation with flushMode set to MANUAL.
Then you start persisting stuff, and then you can perform your validation, and if that is ok you persist again. After you are done and everything is good to go, you call entityManager.flush(). Which will save everything to the database.
And if something failed, you dont flush. You just return null or "error" with some message. Let me show you with some pseudo code.
Lets say you have a Person and Organization entity.
Now you need to store Person before you can put person to Organization.
private Person person;
private Organization org;
#Begin(join=true,FlushMode=MANUAL) //yes syntax is wrong, but you get the point
public String savePerson() {
//Inside some save method, and person contains some data that user has filled through a form
//Now you want to save person if they have name filled in (yes I know this example should be done from the view, but this is only an example
try {
if("".equals(person.getName()) {
StatusMessages.instance().add("User needs name");
return "error"; //or null
}
entityManager.save(person);
return "success";
} catch(Exception ex) {
//handle error
return "failure";
}
}
Note that we now save person, but we have not flushed the transaction. However, it will check constraints that you have set on your entitybean. (#NotNull, #NotEmpty and so on). So it will only simulate a save.
Now you save organization for person.
#End(FlushMode=MANUAL) //yes syntax is wrong, but you get the point
public String saveOrganization() {
//Inside some save method, and organization contains some data that user has filled through a form, or chosen from combobox
org.setPerson(person); //Yes this is only demonstration and should have been collection (OneToMany)
//Do some constraint or validation check
entityManager.save(org);
//Simulate saving org
//if everything went ok
entityManager.flush() //Now person and organization is finally stored in the database
return "success";
}
Here you can even put stuff in try catch and only return success if no exception occurred, so that you don't get thrown to error page.
Update
You can try this:
#PersistenceContext(type=EXTENDED)
EntityManager em;
This will make a stateful bean has an EJB3 extended persistence context. The messages retrieved in the query remain in the managed state as long as the bean exists, so any subsequent method calls to the stateful bean can update them without needing to make any explicit call to the EntityManager. This might avoid your LazyInitializationException.
You can now use
em.refresh(user);
I think validation should be done before the transaction is ever initiated.
I have faced this situation lately in a variety of guises.
The best I found is to treat the object you have as a value object (which it basically is after the rollback). To remove it from the database, find its 'attached' twin using a find by its id (which will not go to the database as it is almost certainly cached) and then remove the object that was returned.
Similar for updates : get a fresh copy and update it.
It is a bit of a hassle, but it avoids long transactions and all the evil locking issues related to that.