How to load common/re-useable data globally at Application Level in JSF? - jsf

I am using JSF-2.2, Primefaces-3.5 and JDK-1.7.
I have a Registration Page where i have a Parent-Child Menu Relations on Countries and Cities, that needs to be loaded dynamically,based on the selected parent value.
Currently i am displaying the list of Countries and States! Which works like a charm! :)
How to display list of countries and cities in JSF
My Problem is if we have n-users accessing the page we are creating n-Objects which is load on the server. I want to reduce the load and memory wastage
Is there a way to Load Data and store in Context of Application and access them in JSF.
Useful Reference:
How to Populate Child Menus in JSF

You can just make the bean from Balusc's answer #ApplicationScoped, and only use this bean for reading the codelists. You can then inject the bean in your other beans, or just call it directly from the xhtml.
Cities you can also load in init() and keep in a Map<String, List<String>>, where key is country and value is cities. Or you can lazy initialize the cities:
Map<String, List<String>> map = new HashMap<>();
public synchronized List<String> getCities(String country) {
if (!map.containsKey(country)) {
List<String> cities = someService.getCities(country);
map.put(country, cities);
return cities;
}
return map.get(country);
}
However, if it at all is possible that the entries can change over time (other system updating/deleting in DB for example) #SessionScoped might be better, since you won't have to remember to reload the application/restart the server as with #ApplicationScoped.

Related

Is there anything wrong with using a CDI ViewScoped bean for caching information used in multiple pages?

All of my pages are backed their own ViewScoped bean, but I'm finding that there are a lot of similar methods used on these pages. For example, a user may want to view dates in their preferred time zone so each time a page is loaded, the DB is queried for what their preferred time zone is.
So my initial thought was to create a ViewScoped bean to manage this. The timeZone value would be only be "good" for the lifetime of the page and they would be lazy-loaded to avoid unnecessary database hits:
#Named
#ViewScoped
public class Preference implements Serializable {
#Inject
private SessionManager sessionManager;
#EJB(name = "PreferencesReadFacade")
private PreferencesReadFacadeRemote prefReadFacade;
private HashMap<String, Object> cache = new HashMap<>();
/**
* #return the user's TimeZone preference
*/
public String getTimeZone() {
if(cache.get("TimeZone") == null) {
cache.put("TimeZone", prefReadFacade.getUserPreference(sessionManager.getUserId(), "TimeZone").toString());
}
return cache.get("TimeZone").toString();
}
}
Usage:
<h:outputText value="#{preference.timeZone}"/>
Is there anything wrong with this type of methodology? Is there a better way of doing something like this?
EDIT: Would like to add that I'm using ICEfaces and Omnifaces so if there are resources in these libraries at my disposal, I'm certainly open to using those.
Your approach is bsolutely correct - you may reuse the same bean in multiple pages regardless of its scope. If those pages are in the same scope, a bean would be reused, otherwise a new bean would be created with an empty cache. If the scope is ViewScoped, the bean would be recreated for every page, hence DB would be accessed first when the data is needed on after a page loads.
You may also make your common bean a base bean of other viewscoped beans, which are constructed for a particular page (they must remain viewscoped).
Or, you may inject your Preference bean into any other Named bean, which is used in your pages. In this way, you may inject it to a bean with any scope, but CDI will always give you the same bean for a view (within viewscope), but different when you redirect to a new page.
But your solution is equally correct, if not even better.
You can create one #SessionScoped bean and hold there user preferences like time zone. Then #Inject it to your #ViewScoped beans and get time zone from #SessionScoped. As long as http session lives, the DB query will be done only once in the user session if you do it in #PostConstruct and assign to variables.

using more than one managed bean in same jsf page

If I have page, lets say includes two different customers informations, how can I use two different managed beans (which is same java class) in the same page?
As a summary, in the same page I want to hold information of one customer in one bean, another in another bean.
I want to hold information of one customer in one bean, another in
another bean.
Another bean for same purpose is duplication, and If you are thinking it logical. Every page have its page's state (life). when you try #{bean.customer} it will return same value. Because its object is same.
I would suggest to improve your code use another class for the view, layer your application. like
//Base class
public class Customer {
private String id;
/*
*Other fields
*/
//getter Setters
}
#ManagedBean
#RequestScoped
public class PageBackingBean implements Serializable{
List<Customer> customer = new ArrayList<>(); //can Hold more than one customer
public PageBackingBean(){
Customer cus1 = DataBase.loadByCustomerId(id);
customer.add(cus1);
Customer cus2 = DataBase.loadByCustomerId(id);
customer.add(cus2);
}
}

jsf 2 best one managed bean multiple views

I`m kind of noob to JSF and I'm trying to figure out which would be the most elegant solution for the following scenario:
Let's say that I have a user managed bean called UserMB:
#ManagedBean
public class UserMB {
private User user;
private List<User> users;
// getters and setters here
public void addUser(User user){
// do add user logic here
}
public List<User> listAllUsers(){
// do list All users logic here
}
#PostConstruct
private void init(){
// populate List<user> users - for the listAllUsers scenario
}
}
Let`s assume that i do not have a form to submit directly to listAllUsers() method, but instead i want to see all users when I open the page list-all-users.xhtml.
When I hit the managed bean from addUser.xhtml a query will be performed to DB to load all users because the bean will not know if i want to use listAllUsers() method or addUser() method.
Should i split this functionality in 2 managed beans ?
Because if so I would have to create several managed beans to deal with "User" business (ie. in Struts2 i would have only one Action that would take care of all user interactions).
P.S. I know that there is the solution to populate List in getter method but I read one article of BalusC that advise us not to do this...
Should i split this functionality in 2 managed beans ?
Yes. Use one bean per view/form. Keep the backing bean class as slick as possible. Don't give it too much responsibilities.

Scalability and Thread Safety of Application Scoped ManagedBean Methods

During testing a weakness was exposed in how our app builds f:selectItems lists, specifically, entering really long names on some of our entities screws page alignment by making really wide selects.
Many of these selectItem lists are duplicated in multiple views and backing beans, so I'd like to consolidate their creation.
We already have an application scoped bean that provides List<SelectItem> for enums, and my initial thought was to place them there.
I have some questions, though. We're using jsf 1.2 (if that matters)
1) My understanding is that application scoped beans are singleton simply because a single instance is instantiated and placed in session context. They are not like EJB3 singletons in that only one thread can access any method, so multiple requests won't block trying to access different methods. Is that correct?
2) I suspect each method would have to be synchronized to prevent multiple threads calling the same method from clobbering each other. Is that the case even if the only class member accessed in the method is a threadsafe stateless #EJB?
Following is an implementation of one of them that would be used in 20 views. The implementations for 10 other entities would be similar. Also, the appropriate converters are registered.
public synchronized List<SelectItem> getAccountSelect(){
List<Account> list = new ArrayList<Account>(pemEJB.list(Account.class));
Collections.sort(list, new AccountByActiveByName());
List<SelectItem> result=new ArrayList<SelectItem>(list.size());
for(Account row : list){
result.add(new SelectItem(row,
StringUtil.prefixTruncate(row.getName(), MAX_ACCT_LENGTH, row.isActive())));
}
return result;
}
Any advice appreciated
If it's really mandatory to do the data loading in a getter instead of in the constructor/postconstruct, then there's definitely no point of making it an application scoped bean. Just make it a request scoped one where you do the data loading job in the constructor/postconstruct.
In the jsf applications I work on we load almost all of our reference data (values for selectOneMenues primarily) in Application scope beans and we set up the values in the Constructor of those beans. The data is then available to other managed beans and views via getters but is globalized and centralized for the application. Since the values are only read via getters there is no need for synchronization.
We then expose the beans as mbeans through jmx with a reload method so that they can be updated as needed. The reload method(s) are synchronized so as to block during the short reloads.
In your example above it seems like you could just return a Collection of selectItems so as long as the values are setup in advance you can use this method and still serve multiple threads just fine:
public List<SelectItem> getAccountSelectItems() {
return this.accountSelectItems;
}
Just add this private member to your bean:
private List<SelectItem> accountSelectItems;
and set it up in the constructor:
public AccountBean() {
List<Account> list = new ArrayList<Account>(pemEJB.list(Account.class));
Collections.sort(list, new AccountByActiveByName());
this.accountSelectItems = new ArrayList<SelectItem>(list.size());
for(Account row : list) {
this.accountSelectItems.add(new SelectItem(row, StringUtil.prefixTruncate(row.getName(), MAX_ACCT_LENGTH, row.isActive())));
}
}
If on the other hand this is data that is constantly changing and needs to be updated you might be better off just loading it per session or per request, though you can reload it periodically in application scope using Quartz or some other timer to keep the data reads from your data source down if real time is not an essential requirement for this data in your app. If you are reloading the data then you will want to synchronize those operations if you're using application scope.

how to avoid model code duplication with JSF and JPA

I'm new to JSF and am wondering if I got things right. Let's say I have a simple CMS that makes it possible to write pages.
First, I define a JPA entity called Page:
#Entity
public class Page {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column
private Long id;
#Column private String title;
#Column private String content;
// getters & setters ...
}
Then I would like in a view to create Page-s. For that, it looks like I need a page bean of some sort. For now I handled things like this:
#Model
public class PageBean {
private Page page = new Page();
public String getTitle() {
return page.getTitle();
}
public void setTitle(String title) {
page.setTitle(title);
}
// rest of properties & getters & setters ...
public void save() {
// persist using EntityManager
}
}
My question is the following one: given that my JPA entity model and the model I want to use in the views are most of the time exactly the same, is there a way of avoiding to have to create a batch of getters & setters in the PageBean?
I read somewhere that you should not use a same bean as JPA entity and JSF model bean (because JSF does repeated calls to getters that may affect JPA), yet I do wonder if there is not a simpler way that would help avoiding this kind of code duplication. Especially when you've got an application with a large model and in many instances do not require anything special in the view beans, it looks like this can get quite cumbersome.
[...] given that my JPA entity model and the model I want to use in the views are most of the time exactly the same, is there a way of avoiding to have to create a batch of getters & setters in the PageBean?
I don't see the point of using a wrapper around an Entity and adding such a layer is indeed duplication. Just use the entity from your JSF page. Yes, this introduce some sort of coupling between the view and the domain but, in general, modifying the database usually means adding or removing fields on the view. In other words, I don't buy the "decoupling" argument and I've written enough extra layers, mapping code, boilerplate code, etc to favor the simple approach when possible.
I read somewhere that you should not use a same bean as JPA entity and JSF model bean (because JSF does repeated calls to getters that may affect JPA)
I'd be interested if you could provide a reference but a wrapper class (delegating calls to the entity) is not going to change anything if there is a problem somewhere.
Just in case, some additional resources:
EclipseLink/Examples/JPA/JSF Tutorial
It's not code duplication. The are no algorithms duplicated. The business logic is still in one place.
What your bean is doing is just connecting the View to the Domain model. This is good, it's part of the MVC pattern.
If you were using your JPA entity as your backing bean, you would be breaking the MVC pattern. For example, if one day instead of displaying a plain String you would need to add a Date to this String because the view requires so (i.e. interface requirements), are you going to write this view logic inside the JPA class? That does not make sense, mixing domain model and view model.
On the other hand, why the view has to know about how the domain is implemented? What if the domain values format change? (For example you save a timestamp String instead a date class in de Database for performance reasons). All you would need to do is just rewrite the method in the backing bean, it would take the timestamp and adapt it to a Date so everything would work as it was before. Just one change outside the JPA class. If you had it in the JPA class you would end up maintaining both logics in just one class (interface logic and domain logic).
What if you want to develop a new view (for example for mobile version)? Are you gonna add even more code to the JPA class? It would be better to keep the JPA as it was and create another Bean (that extends a common bean for both views) for the mobile version.
If after all this, you still want to not to write the getters and setters, you can do
#{myBean.page.title}
all you need is a getPage() inside the backing bean.

Resources