Call bean method from XML configutaion - spring-bean

I have a bean which is initialized with some content (a collection with a few built-in elements). I'd like to ship this pre-configured bean with my library.
At the same time I'd like to give the user of the library the possibility to insert his or her own elements into this collection (currently done from code by calling an addDocument() function).
Is there a way to achieve this from the configuration? How is this problem addressed in other libraries?

Related

JSF separate DB logic from #Named bean

Good day
This question is more of a meta question than a specific problem based question.
It is always a good idea to separate any and all DB code from view related code and view files, correct?
Thus is my assumption when using JSF correct in that:
The xhtml file forms part of the view in the MVC.
The #Named backing beans also forms part of the view.
To ensure that one can relatively painlessly migrate away from JSF to another type of tech, one would ensure to not have ANY DB code inside the #Named backing beans.
All DB code should reside in a controller / service class.
The controller / service class will contain all the DB access code and business logic. This thus forms the controller of the MVC.
The #Entity classes are used to map the DB to JPA and this thus forms the model of the MVC.
Now, if my understanding of the above is correct, what would best methods and methodologies be when handling the following scenario:
I have an XHTML file displaying JSF components (Primefaces). The lists and component linked members that link the JSF components to the Java code all resides in the #Named backing bean.
Now for argument sake, let's say that the specific form is used to CRUD a supplier's information, which of the following methods is recommended as best practices (while attemping to maintain as much seperation of concern between the View and the Controller Java code) when for instance edits were made on the XHTML form:
Enforce ZERO DB code (thus never defining or using the Entity Manager) in the #Named backing bean file). The code to persist the changes after all input validation was successfully done, will reside in the Controller. To get these values to the Controller, we will have a function looking perhaps like this (basically send all the components on the xhtml form as parameters to a function in the Controller):public void supplierService (String supName, String SupAddress, String supTel....) The problem with this of course is that one may end up running into methods that takes tens of parameters. Very ugly and difficult to maintain.
Accept that separating some DB code is not possible and every #Named file must have the required JPA DB code to persist and or merge changes to the models (however if this is considered best practice, what is the use of having Controller classes?).
Create a temporary object of the same type as the model and set the attributes of this temporary object to the values obtained from the XHTML mapped components. Then only pass this temporary object to a method in the Controller. This method in the Controller will then persist and or merge the passed object's info. However I feel this may introduce unnecessary object instantiation overhead. Also I am not 100% sure what exactly happens 'behind the scenes' when I have a model named SupplierEntity.java that is mapped via JPA to a PostgreSQL DB and I call this code: SupplierEntity tempSup = new SupplierEntity(); Will JPA via Hibernate on Wildfly actually at this point create a new entity (record in the DB), and as such I cannot use this to create a temporary object to hold the values I am passing to the Controller as a temp instance of the underlying JPA entity, or will Hibernate (using JPA 2.1) ONLY create a new record when I do em.persist(mySupplier); and thus it is safe to use this method to pass objects to the controller's persisting method, instead of passing tens of parameters to the persisting method.
Something completely different than what I mentioned above is considered to be the best practice for separating the MVC components in JSF as much as possible, while still preventing having to pass 50 parameters to the Controller.
Please as said right in the start, this is a meta question regarding best practices. If Stackoverflow is not the right forum for these questions, instead of down voting this into oblivion, please let me know where I should ask instead and I will gladly delete the question from here and create it on the right forum.

Xpages bean vs object data

What's the difference? When should I prefer one over another?
And some minor questions related to this:
if I have object data, when is saveObject called?
it looks like garbage collector recycles all my domino handles. I tried to downcast then clone it, but it didn't help (how does it know its still a domino object?). Is there a workaround?
if I create "var tmpVar = new package.TestClass()" from xPages, it gets recycled on update. But if I create java object from bean it stays there. Correct?
Managed beans are exactly that, managed by the XPages runtime. They are created as and when there is a first call to them. Although they have an empty constructor, managed-properties elements in the faces-config allow you to define values (and I believe you can add SSJS code to the faces-config to compute the values).
Object data sources allow you to handle what's created when, and it means they can be scoped to a smaller level than viewScope - to a Panel or Custom Control. The saveObject method is called by a Save All Datasources event. In reality, if you're coding object data sources, you'll code a button and call the relevant method rather than use a simple action.
Java variables can get recycled, but Domino objects are only recycled via two methods. The first is calling recycle() methods, the second is at the end of each request, when the session gets recycled. Because recycle() calls recycle all child elements, everything gets recycled at the end of a request. Which is why you can't store Domino objects in scoped variable or any other persisted object (i.e. a bean). Note that objects like DateTimes, RichTextStyles etc are children of the session, not of any more granular Domino object like a NotesItem or NotesRichTextItem.
var tmpVar = new package.TestClass() will only get persisted beyond the current request if you store tmpVar somewhere. If you're using that code in a crerateObject method, return tmpVar will pass that instance of TestClass into the Data Object.
I go back and forth on pure Managed Beans vs. Data Object. I was using a lot of Data Objects for a while but then ran into some issue with the JSF lifecycle I think that I just couldn't make work. Not sure if a repeat or custom control was involved. So I pretty much have gone back and given up on them for now.
Other then that problem I had I'm not sure there's a ton of difference. I think dataObject can tend to be a little more confusion. Since you can set it on an XPage - but you can change the scope of it to session or application I believe. But if you do then that seems messier and hard to find then making the bean in the faces-config.
I'm not sure about the saveObject part of your question.
You never want to put a pure domino object inside a bean, or scoped variable because they are not serializable and will be tossed by the garbage collector at some point that will likely be most inconvenient to you.
if you just do "var tmpVar = new package.TestClass()" then yeah that will get killed pretty quick because of limited life of that variable. if you want to create an object that way and keep it around longer put it in a true scope: viewScope.put("myObject", tmpVar);
I have a video where I tried to give examples of I think 4 ways to use java Objects. In the blog posting are some really good comments by Tim Tripcony which might give you further information.
http://www.notesin9.com/2013/08/01/notesin9-122-working-with-java-objects-in-xpages/

Storing properties of a custom component in session scope or bean

I've written a new back-end Java component (extending UIComponentBase) as an alternative for the ExtLib Application Layout control. The control needs to show a collection of data that is looked up from another Notes application. The data is user dependant and doesn't change from page to page so, to avoid repeatedly doing a lookup to the other application, I want to store it in the session scope. (Note that because this is a layout control, there will only ever be one per page.)
I know I could use a session-scoped maanged bean (and have done in previous iterations) but the data only needs to be used in this control and shouldn't be used elsewhere on the page which it could be with a bean. So my question is, what's the best practice approach I should take here? Should I just directly store the data in the sessionMap or am I missing a trick with the component stateHolder? Or am I stuck with using a bean?
Thanks
(Edited for clarification)
It looks like you're talking about your own back-end Java components rather than Custom Controls within a single NSF.
I'm not sure at what level, when you write your own native XPages components, the properties are cached by the stateHolder when calling saveState(). I would presume no higher than View, for the reasons Frantisek says, that otherwise it would be unclear which instance to update if you had multiple on one XPage but one on another. It couldn't update both at the same time on the same page, so I would guess that each is a separate instance. As a result, the same component on multiple pages would be a separate discreet instance.
But there's nothing stopping you, in specific setters of the component, writing to sessionScope as well as the private property, and then doing the reverse on the getter. I'm not sure if you'd want to try the internal property before trying sessionScope or vice versa. It would depend how you wanted to handle the situation of the same sessionScope being updated from multiple pages (if the collection could change).

Persisting ViewScoped beans across multiple views

Ok I know scope questions come up all the time but I'm interested in a slightly different approach to the solution. The #ViewScope is a fantastic bridge between the #RequestScope and the #SessionScope.
However there is still a common use case (at least for me) where I really don't want to use #SessionScope but I need the data over a couple of views. A really simple case is when I have multiple datatables chained together each one depending on previous selections.
It's perfectly possible to use <f:paramView> and pass a single or even a couple of pieces of data as params in the address and then retrieve everything from the database again. I am more interested in finding a way of creating a 'snapshot' of the beans state / variables, creating the new #ViewScope and then 'restoring' the 'snapshot state' to the new bean.
Does such a thing exist? Ideas? Opinions?
I don't know if this is the 'accepted solution' but I've implemented an idea that works for me. (Feedback appreciated!)
So I have created a #SessionScoped class with a couple of static maps:
private static Map<String, Object> objectVariableMap;
// Getters, setters and methods etc. are omitted for simplicity
The idea being that I have specified a map that accepts a String as the key and an Object as the value. I've specifically not set the type of object to allow me to store any type of object in there. The caveat is that you need to be sure of the type of object when retrieving it so you can cast it back into its original type.
Now comes the time to set the data from the first #ViewScoped. I generate a random UUID (or what ever you want) as the Map key and then set the value to the object I'm working with (ie. this, or indeed any other objects you might want to pass to the next view). Save the key, value into the map and set the URL param to the key.
I'm never keen on passing data like user id's etc. in URL params (even when its encrypted). This idea has the added benefit of offering disposable URL values that have a specifiable life span.
On the receiving end (ie. The new #ViewScoped bean, or any other scope for that matter) you read in the URL param (the map key) using <f:paramView> and then use a preRenderView event to retrieve and set the Object where working with.
At this point you can choose to remove the key pair from the Map and invalidate the ability to retrieve that object or you can keep keep the key pair for a longer duration by simply updating the object if there are any changes.
UPDATE: Conceptually this has been really successful (for me at least). I've created a handfull of useful methods and classes surrounding the concept to make it more universal. If anybody wants more specific instructions or I might even create a small library if anybody wants.
You can use the CDI "Conversation Scope" for this. This is narrower than the session scope but wider than the view scope.
If the pages between which you pass parameters are a unit, you can also make them a flow in JSF 2.2 and use the flow scope.
Projects like CODI offer various other scopes that can be used between pages.

Custom Control Custom Methods?

I have been making good use of custom properties withing custom controls. Is there such thing as custom methods? Say I want something to happen in a CC. A good example is the show method of the dialog box extension. If I have a cc with a extension dialog inside, I want my custom control to have a Show method which insulates the end user programmer from the extension pages Shoe method.
Is there anyway to do this?
At runtime, all Custom Control elements become instances of the UIIncludeComposite class; as such, there are many built in methods that you can call against any given control instance, but there is no way to specify custom methods, as opposed to custom properties.
There are, however, at least two ways you could achieve the result you're after:
Convert your Custom Control to a component (this NotesIn9 episode describes the simplest approach to this process). Once you've migrated the class that Designer generated to one that won't get overridden every time you build your NSF, you can add custom methods without fear that the next build will just wipe them out again. Since Custom Controls are essentially just IBM's implementation of the JSF 2.0 notion of "composite components", you could also create a component from scratch that has the same behavior as your existing Custom Control but also supports custom behavior. Note that either approach does not necessarily require that you create an OSGi library... you can define these components directly in an NSF; you only need to push them to a library if you want to reuse them across multiple NSFs without having to copy the various files to each.
In the custom properties for your control, include one property that accepts an API object. In other words, you could create any object (say, a Java class or SSJS object) that supports the custom methods you wish to define, and pass that object to the control. You could then call those methods by getting a handle on the object via the CC's property map.
For example:
<myCC id="myCustomControl" API="#{someObject}" />
Assuming whatever #{someObject} resolves to includes a show() method, you can call that method by getting a handle on the instance that has been passed to the control:
var cc = getComponent("myCustomControl");
var ccProperties = cc.getPropertyMap();
var ccAPI = ccProperties.get("API");
ccAPI.show(cc);
In the above example, I'm passing the actual Custom Control to the show() method, because the object itself isn't aware of the Custom Control it was passed to. So if that method needs to get a handle on its children to toggle their rendered property, for example, then it needs some other way of determining its context.
Tim's solution with passing in the object is a great solution to that.
Just something that popped into my head, would be easy to make a property similar to the rendered property on a control. Pass in a value and inside the custom control do something based on its value ie. if true display dialog, else hide, in the XPage during run time modify this value and partial refresh the control, the logic will be re run by this and the control will display etc.
Another solution could be to include a JavaScript library in your custom control providing functions (your custom control methods) where you'd have to pass in the id of the custom control instance.

Resources