I was wondering about this article explaining the direct access of EJB from JSF : http://www.mastertheboss.com/cdi/context-dependency-injection-with-jboss-weld
I do understand, that with CDI you can inject and access every bean type, including entity beans from the far end of the layer tier.
However.
[Question 1]: Should I discard the #Model controller and only apply #Named to all the classes? This kind of abandons the approach of having JSF --> ManagedBean--> EJB --> EntityBean to JSF --> EJB --> EntityBean. I just have the feeling this extra ManagedBean is causing me an extra layer without not much benefit.
[Question 2]: In what cases would you still want to maintain that extra Controller layer?
thanks
I don't think that there is a universal answer. It depends on your controller, both are valid arquitectures.
The key is whether your controller requires services offered by the container.
For example if your controller should execute outside a transaction then justifies the extra layer.
However, always tend towards simplicity if you can. If your application is simple enough to have just the three layers then don't over complicate it.
As far as replacing #Model for #Named goes, #Model is just a shortcut for a #RequestScoped #Named bean. Only replace #Model for #Named if you want the bean to have some other scope.
The best way to get the most from the overall platform is to use CDI as your controller layer (receiving requests from the JSF based frontend) and delegating internally to EJBs or other CDI beans for business logic. I would not use JSF ManagedBeans as the concept is deprecated in Java EE 7, in favor of the CDI programming model.
The controller can be used to always convert data types, separating out your front end and back end models.
I think the equation should be:
JSF = View (.xhtml) + Controller (ManagedBean)
EJB = Model
There's no skipping to go directly from View to Model unless you're putting the whole back-end logic inside a ManagedBean, which is obviously not a good practice.
Related
I like to have static helper classes in my apps for common plumbing stuff, like checking roles, or Razor Html helpers and stuff... but how do you do this in the DI world?
Like lets say I want an extension helper to check if a user is an admin
public static async Task<bool> IsAdmin(this ApplicationUser user)
...
if(user.IsAdmin()){...}
So pre-core I could just ignore DI and create a UserManager all inside IsAdmin do whatever I need to do. But now is there no way to get the UserManager in these helpers to just use? The only way I can see is to inject it into the Controller, then pass along into the method (which I find ugly). Then there's the issue of trying to do user.IsAdmin() in the Razor view, would I need to add the UserManager to the ViewData collection to get it into the view markup?
Am I just missing something here?
Thanks,
Steve
First of all if you just asked how to use static class with di, i would say that your question is duplicate of How to use DI inside a static Method in Asp.net Core rc1
But as i see, you have some other question?
But now is there no way to get the UserManager in these helpers to
just use?
Yes there is a way : Service Locator pattern. But it is an anti pattern (see this article) . As far as possible you should avoid to use this pattern. Also see discussion in github.
The only way I can see is to inject it into the Controller, then pass
along into the method (which I find ugly)
I think this way is better than you want. I would prefer this.
Then there's the issue of trying to do user.IsAdmin() in the Razor
view, would I need to add the UserManager to the ViewData collection
to get it into the view markup?
In Aspnet core you can inject a dependency into a view, so you don't need to use ViewData. Simply you can inject UserManager into your view and then pass it as parameter to method. Take a look at official docs
Well you are talking about a cross-cutting concern here and one way how I've seen cross cutting concerns solved in ASP.NET Core MVC is with attributes (like [Authorize] for example). Which I think is an elegant solution.
So, if I understand your question correctly I think you can solve this with an Action Filter. Damien Bod described a few days ago how to use ActionFilters: https://damienbod.com/2016/09/09/asp-net-core-action-arguments-validation-using-an-actionfilter/.
So in short, you inherit from ActionFilterAttribute and make your own curstom filter called MyCustomFilter or whatever. Have this MyCustomFilter request UserManager in its constructor via DI. Then above any action method in a controller you say:
ServiceFilter[typeof(MyCustomFilter)]
And in MyCustomFilter you ofcourse have logic to check if User is IsAdmin and then take action accordingly.
Now, I've always used Microsoft's Unity to handle cross cutting concerns via interception (you can read more about that here: https://dannyvanderkraan.wordpress.com/2015/09/30/real-world-example-of-adding-auditing-with-dependency-injections-interception/. But last time I checked there is no Unity container for asp.net core yet. But this guy has a great article about porting it to core: https://dzimchuk.net/post/bring-your-own-di-container-to-aspnet-5-unity. I would really like my Interception back! Very elegant solution to cross cutting concerns. They are working on it though: https://github.com/unitycontainer/unity/issues/66. Fingers crossed...
I have been tasked with migrating JSF 1.x with RichFaces 3.x on JSP to JSF 2.x on Facelets. The previous developer used RichFaces <rich:dataTable>. As data a bean was sent to the table. This bean was a SerializableDataModel which has a walk() method allowing you to easily traverse the data table using the visitor pattern. This also allowed the table to only load data needed using lazy loading. We have over 216k rows of data and all of them are loaded when the page loads or when you try to change pages to view the next set of rows.
I thus need to migrate this to JSF 2.x. I have never used JSF 2.x before and I am simply asking if anyone has ever experience this, how they solved it and if they can give me some resources to get started.
I can not share more as it is against my works policies.
<h:dataTable value="#{records}" var="record" rows="20"
class="table table-striped"
styleClass="dataTableRecords dataListTable" rowClasses="odd, even"
id="dataTableRecords" rendered="#{records.rowCount > 0}">
</h:dataTable>
#ManagedBean(name="records")
#RequestScoped
public class Records extends BseDataModel{...}
BseDataModel is what contained our walk method, it now extends DataModel
If you think you can help please let me know, I can give some more limited information, if you need it please ask.
I have a sample use case: I have an edit page that use GET parameter "id".
eg. edit?id=1
This edit page is backed by a ViewAccessScoped (CODI) Bean.
In this edit page, I have a datatable with links that link to the same "edit" page, but with another id. (eg. edit?id=2)
<h:link value="#{mecaPart.id}" outcome="edit" target="_blank">
<f:param name="id" value="#{mecaPart.id}" />
</h:link>
The problem, is that the window open correctly, but it is the same bean that is used! And so I am editing the same part...
I have placed a log in #PostConstruct, and it is the same bean reference that is called multiple times. (even with the new ID!)
My question, how can I tell JSF to create a new ViewAccessScoped backing bean when I click the link, and not re-use the actually used one?
Finally, I discovered that #ViewScoped CODI bean did not preserved the backing bean from page refresh. So, I have to use ViewAccessScoped.
According to Gerhard Petracek: http://os890.blogspot.fr/2011/08/scopes-view-scope-vs-view-access-scope.html
the view-scope of jsf2+ is bound to a concrete jsf page. that means: as soon as you navigate to a different page, the state gets lost. that's better than nothing, but not useful for a lot of use-cases. the main use-case which needs it are ajax-requests on a page and the data used by them aren't needed on other pages, but it's pretty easy to break it e.g. with a browser-refresh on a page which stores the data in a view-scoped bean and has no form with input components. (in a previous blog post i described how to use the infrastructure provided by codi to create a session based view-scope to overcome such disadvantages cause by storing view scoped beans as part of the tree-state.)
like with the view-scope view-access-scoped beans are available on a page, but they also exist for the next page. that means: they are forwarded to the next page and get destroyed autom. if they don't get used during the first request of the next page. that's e.g. useful for wizards. if you have a wizard page which doesn't use the bean or you have to support the possibility to interrupt a wizard, you can use the grouped-conversation scope (and even the window-scope) provided by codi. however, due to the powerful api of codi you can also destroy the scope manually at any time (if needed).
So, to solve the problem of opening a new tab with another "ID", I had to set "CODI Client Side WindowHandler", according to the CODI Wiki.
https://cwiki.apache.org/confluence/display/EXTCDI/JSF+WindowHandler
So I added:
<alternatives>
<class>org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.ClientSideWindowHandler</class>
</alternatives>
To the file beans.xml, and I used #ViewAccessScoped. Everything is working smoothly now.
You can use #ViewScoped which also works in CODI
Please note: This question is about CDI scopes as we are using CDI scopes in the app and not JSF scopes.
1) Controller Bean (TestController.java) which is in RequestScoped (enterprise context) is called index_cut.xhtml, when we come for first time on this page.
2) On button “Load”, we load the following method to populate the sapFinancialPeriodList which works fine and displays the data
3) After changing the content on the page and submitting, the sapFinancialPeriodList appears as NULL in the following method –
Any suggestions?
Your bean is request scoped and you're loading the data model on action only instead of on (post)construction. When the HTTP response after the action which loaded the data is finished, then the bean is garbaged. The subsequent request would get a brand new instance of the bean with all properties set to default. However, as the same data model isn't been preserved during (post)construct, it remains empty.
In JSF2 you'd solve this with using #ViewScoped. This way the bean will live as long as you're interacting with the same view by postbacks (which return null or void).
In CDI you'd need to solve this using #ConversationScoped, which in turn requires some additional #Inject Conversation boilerplate, complete with begin() and end() calls at the right moments. For a concrete example, see also What scope to use in JSF 2.0 for Wizard pattern?.
An alternative is to pass the parameters responsible for creating the data model to the subsequent request via <f:param> in the command link/button as follows
<h:commandButton value="save" ...>
<f:param name="period" value="#{bean.period}" />
</h:commandButton>
and then recreate exactly the same data model in (post)constructor of the request scoped bean as follows
String period = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("period");
List<SapFinancialPeriod> sapFinancialPeriodList = someservice.list(period);
(the above is by the way nicer to solve with #ManagedProperty if you were using standard JSF; as far as I know CDI doesn't have an annotation which enables you to set a HTTP request parameter as a bean property)
See also:
How to choose the right bean scope?
Unrelated to the concrete problem, the upcoming JSF 2.2 solves this functional requirement in a nicer way using the new "Faces Flow" feature with the new #FlowScoped annotation and the new xmlns:j="http://java.sun.com/jsf/flow" tags.
Whats the most efficient way of doing pagination in JSF 2.0 app?
I use Primefaces datatable and it is intelligent enough to perform
pagination by itself with no coding at all.
<p:dataTable var="car" value="#{carBean.cars}" paginator="true" rows="10">
<!-- Multiple columns here-->
</p:dataTable>
The thing that I see, is that I need to place my bean to session scoped or greater.
#ManagedBean
#SessionScoped
public class CarBean{
public List<Car> getCars(){
//return data from DB
}
}
I wanted to know is there another efficient way on how to perform this?
I used EJB/JPA at the backend by the way. Would like to know any links or tutorials
to learn more about this.
Thanks.
You need to use LazyDataModel in order to have only the rows in memory which the client actually needs to see. See also the example in PrimeFaces showcase. This does pagination at DB level which is what you ultimately want.
RichFaces supports by the way the same in flavor of ArrangableDataModel, here's the RichFaces showcase example.
In a production app, we've used a lazy datamodel to deal with 700000 records in db. I'd suggest using M3 which has fixes on lazy datatable cases.
I have found that the built in pagination feature of the Primefaces data table is one of the best features and did a good amount of load testing on it, bringing in recordsets with over 30,000 Hibernate entities and found the performance to be lackluster. This of course means that you will have 30,000 entities in session so I have the following in my web.xml to help by storing session on the server side.
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
This will reduce the size of the ViewState allowing request/response size to be greatly reduced however server side memory can suffer enormously by doing this.
Another potential option in some JSF implementations to help mitigate the size of ViewStat or session memory usage is compression. The following link describes a number of SUN RI and MyFaces JSF configuration parameters that can be set, some of which give the option of compression of the session state. http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Frweb_jsfengine.html
As far as learning more about how the Primefaces DataTable pagination feature works, why not go straight to the source? Primefaces is after all an open source project, so just look at the code and see what you can learn: http://code.google.com/p/primefaces/source/browse/#svn%2Fprimefaces
Important note depending on which version of Primefaces you are using. Starting with 3.0.M2 (I think) if you want to use the row select feature you must implement a SelectableDataModel. This breaks a lot of legacy code and there were a number of bitches about that.
Easiest thing to do is to create an inner class like this:
private MyDataModel dataModel = null;
public MyDataModel getDataModel() {
if (dataModel != null) return dataModel;
dataModel = new MyDataModel(some list);
return dataModel;
}
public static class MyDataModel extends ListDataModel<SomeRecord>
implements SelectableDataModel<SomeRecord> {
MyDataModel(List<SomeRecord> source) {
super(source);
}
etc.
Then the value attribute to p:dataTable becomes #{bean.dataModel}.
Good luck.