0

I am building a web application with NetBeans 8.0.2 using JSF (2.2) and EclipseLink (JPA 2.1).

Let's assume that the current functionality is quiet basic inlcuding: login, logout, register, user roles, pages available only to admins (by using filters) etc.

I have read maaany SO Q&A (mostly from @BalusC, thanks!) and would like to verify that my design is correct/follows best practices.

Currently I have:

A user Entity (UserEntity.java)

Maybe this name is redundant, but I wanted an obvious name to begin with), corresponding to the user in database:

@Entity
@Table(name = "Users")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "UserEntity.findAll", query = "SELECT u FROM UserEntity u")...})

public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "userID")
    private Integer userID;
    ...
}

A user bean (User.java)

It uses the UserService and keeps a relevant UserEntity. Its methods are used in the EL of the .xhtml files

@ManagedBean(name = "user")  // name not needed here, but I kind of like it
@SessionScoped
public class User implements Serializable {
    private UserEntity userEntity;      // with getter or make this public to be accessed directly from EL?

    public String login() {
        userEntity = UserService.find(username);
        ...
    }
    ...
}

And a UserService.java

which basically has the database access methods:

public class UserService {
    public static String insertUser(UserEntity user) {
            String retMessage;
            EntityManager em = JPAResource.factory.createEntityManager();
            EntityTransaction tx = em.getTransaction();

            tx.begin();
            try {
                em.persist(user);
                tx.commit();
                retMessage = "ok";
                return retMessage;
            }
            catch (PersistenceException e) {
                if (tx.isActive()) tx.rollback();
                retMessage = e.getMessage();
                return retMessage;
            }
            finally {
                em.close();
            }
    }
    ...
}

At some point I noticed that the UserService could have only static methods, so I can access them without creating instances.

Is that bad and why?


I guess the correct way would be to have the UserService as: import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; ...

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public static String insertUser(UserEntity user)
    {
        em.persist(user);
    }
    ...
}

and the user bean as:

@ManagedBean(name = "user")
@SessionScoped
public class User implements Serializable {
    @EJB
    private UserEntity userEntity;

    public String login() {
        userEntity = UserService.find(username);
        ...
    }
    ...
}

Is that correct?

I am not sure what exactly the @Stateless, @EJB, PersistenceContext do/mean. (Are they from javax.ejb.Stateless, javax.ejb.EJB, javax.persistence.PersistenceContext respectively?)

Does using @Stateless and @EJB allow me to utilize my UserService without creating instances of it and without having static methods?

What about checking the transactions? Does @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) have me covered? i.e. no need for further checks? If an exception is thrown, will the method return with the relevant message?

With @PersistenceContext, what/who is creating the EntityManager instance?

Is this design good practice, respecting the separation of concerns etc?

Thanks!


See also:

Community
  • 1
  • 1
LyK
  • 479
  • 7
  • 18
  • You are using JSF 2.2. Who always recommends a session scoped bean in situations where a narrower scoped bean is sufficient? – Tiny Sep 10 '15 at 04:17
  • Not sure why you mention that. If the `User` class has the login method, the currently-logged-in userinfo etc, then it should be session scoped. No? – LyK Sep 10 '15 at 05:00
  • Never. A managed bean used to login can never be a session scoped bean - it is just not required. Any session scoped information is to be placed in a separate session scoped bean. – Tiny Sep 10 '15 at 05:05
  • So you are saying that it is wrong to also keep the login method in the bean I use for the user's session? Why is that? – LyK Sep 10 '15 at 05:07
  • I did not mention anything about methods in that bean. Having any method is legit. Just that it unnecessarily carries a verbose session scoped bean in a place where a narrower scoped bean suffices adequately. – Tiny Sep 10 '15 at 05:10
  • JSF 1.x examples somewhere may be using session scoped beans for this kind of things at the time, when view scope did not exist. – Tiny Sep 10 '15 at 05:22
  • What I am saying is that it needs the session scope, because it carries the user session. – LyK Sep 10 '15 at 05:50
  • A login form is no longer different than any other normal form with basically two input fields and a submit button. You basically need to maintain its state during post backs exactly as that needed during performing basic CRUD operations which a view scoped bean is sufficient for (If you need not maintain any state during post backs, then the bean is to be placed simply in a request scope). You can always create a separate session scoped bean (one or more) to store session scoped information as stated earlier and inject that bean wherever necessary. – Tiny Sep 10 '15 at 06:00
  • So, having separate beans for information I could otherwise have merged, is a good practice. Ok, will look into that, thanks! – LyK Sep 10 '15 at 06:05
  • 1
    It depends upon business requirements, readability, maintainability etc (for example, one can design separate forms with separate managed beans for Read, Insert and Edit/Update or use a single managed bean with a single form/page - it depends upon the nature of the application). – Tiny Sep 10 '15 at 06:12
  • 1
    I think http://stackoverflow.com/questions/30639785/jsf-controller-service-and-dao and the links therein (and the links therein (and the links therein (etc))) answers everything you need to know. – BalusC Sep 10 '15 at 08:03
  • I have read some of those, but I can see some "unread" ones. Will check them all out. Thanks @BalusC (for everything around here :) ) – LyK Sep 10 '15 at 08:15

1 Answers1

1

@Stateless is the way to go instead of static methods. If you use NetBeans you can auto-generate these @Stateless classes, they are called facades there (in NetBeans -> right mouse click on pacakge -> new -> session beans for entity classes and choose entities).

You don't create EJB instances on your own, you just use @EJB annotations and container will provide you "instance".

For transactions you have separate annotations you can read about javax.ejb.TransactionAttribute. You just annotate EJB classes/methods with them and given javax.ejb.TransactionAttributeType and that's everything, container will start/end/nest(hold back) transactions for you.

For the part about @SessionScoped it can be your controller. Let's say you have 5 xhtml pages. Then you create 5 backing beans (@RequestScoped/@ViewScoped etc.) and use @Inject in every of them with the controller class. So your backing beans narrow their logic to only 1 page and then forwards further actions to controller class. Controller class can have methods (API) with only 1 line which forwards actions to EJB. In EJB you can have service (@Stateful) which communicates with this controller, this service communicates with other classes (like backing beans previously but now just call them managers) and managers have business logic. This logic can persist data to database through previously generated facades (@Stateless).

You don't need filters with EJB to control roles, you can use annotation javax.annotation.security.RolesAllowed and specify which method can be invoked by which role.

That's my point of view, it may not be complex explanation but there is plenty of staff which you can google using the keywords.

EDIT:

Don't use JSF annotations like @ManagedBean and @ManagedProperty. Better use newer technology like CDI @Named and @Inject.

Geinmachi
  • 1,251
  • 1
  • 8
  • 20
  • So, `@Stateless` along with `@EJB` have me covered and I won't need to manually create an instance of my UserService. Regarding the transactions, I've editted the original question to include these. About the roles, it is quite a different subject; will look into it and maybe create a new question. Will wait for a few more inputs. Thanks for sharing your opinion on the matter! – LyK Sep 09 '15 at 22:35
  • Inject EJBs/managed beans without using `new`in which you can only have a new unmanaged instance. – Tiny Sep 10 '15 at 04:22