Set a custom ELContext in JSF - jsf-2

this question is related to a previous answer to a similar problem, which would fit my requirements.
Programmatically register taglib reference
I understand the solution, but I'm not able to figure out how to register my custom ELContext (or FunctionMapper) to the current FacesContext (or ELContext) without a specific implementation (MyFaces, mojarra etc.). The goal is to use some functions in the *.xhtml source. I DON'T want to use a taglib because some dynamic stuff should be handled by my own function mapper.
So how do I register a FunctionMapper or decorate the current ELContext with my own implementation?
Cheers,
Markus

Register it in faces-config.xml as
<application>
<el-resolver>com.example.YourELResolver<el-resolver>
</application>

Related

Working with helpers in the dotnetcore DI world

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...

#Named versus #Model - CDI vs/and ManagedBean

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.

Open a new tab don't create new ViewAccessScoped bean

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

How to change the standard href="#" attribute of h:commandLink?

I am maintaining a JSF2 Ajax application and we are heavily using h:commandLinks and f:ajax tags for all actions - always only rerendering what is needed.
This does of course break the expected behaviour for the user when performing a right click on the links and choosing "Open Link in New Tab" etc.
I understand that f:ajax forces the href atribute of the resulting a element to be # and does all the magic post request trickery in the onclick function - I now want to provide fallback support for the "Open Link..." action by putting some meaningful link in the href attribute of the resulting <a> tag.
This would not break the "normal" onclick behaviour as the generated javascript always finishes with return false; but would allow me to send my users to some page using a normal GET request in case they want to open the link in a new window.
Is there a build in way to do this? Or could somebody point me in the right direction on where in the JSF lifecycle I would have to jump in to do this maybe using a phase listener?
Simplest would be to extend com.sun.faces.renderkit.html_basic.CommandLinkRenderer and override the renderAsActive() method accordingly. Mojarra is open source, just copy the method and edit the line where it says writer.write("href", "#", "href"). Replace the "#" string accordingly to your insight.
public class MyCommandLinkRenderer extends CommandLinkRenderer {
#Override
protected void renderAsActive(FacesContext context, UIComponent command) throws IOException {
// ...
}
}
To get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Command</component-family>
<renderer-type>javax.faces.Link</renderer-type>
<renderer-class>com.example.MyCommandLinkRenderer</renderer-class>
</renderer>
</render-kit>
Note that this tight couples your renderer to Mojarra. To be JSF implementation independent, you'd need to create a whole new renderer instead of extending a Mojarra specific renderer class.
Unrelated to the concrete problem, consider reading When should I use h:outputLink instead of h:commandLink?

Controller Test problems

I want to test a mvc controller. I'm using Moq to mock the services, but I don't know how to mock this.Request.Files["Attachement1"] and this.Server.MapPath("~/Temp") ("this" is the controller)
I tried to create a new Mock<HttpRequestBase>(); but this.Request doesn't have a setter.
Help me please with an advise. Thanks
I had a similar problem as your - I used the set of fake classes from Stephen Walther's blog.
Asp.Net MVC Tips - Faking the Controller Context
I had to modify some of the classes slightly but it should do what you want and it's definitely a lot easier to setup than having to mock the entire context every time.
For the folder name resolutions such as: this.Server.MapPath("~/Temp") I use public properties, and getter returns this so I can easily test it.
For the Request.Files, I prefer using FormCollection dictionary
If you have a look at the TestHelper in the MVCContrib project, it can easily be extended to Mock other bits of the Http elements. (It has some Request elements already to use as a template.)
Kindness,
Dan

Resources