I'm wondering how to use CDI to build multiple independent objects trees representing the same type of data. Here is an example:
I have a Car, in which I want to inject GearShift and Engine.
I also want to inject Engine in GearShift
This Car + GearShift + Engine is my tree.
If I want to have several cars at the same time, what would be the best way to do this using CDI?
I would expect to be able to define a kind of scope or a qualifier for each tree.
But CDI scopes and qualifiers are defined statically, while the number of cars is dynamic.
As an additional requirement, I would like to inject another dependency that would be shared between cars.
For example, all cars would share the same Road for their whole lifetime (couldn't find something else that makes more sense).
Thanks in advance
I am no sure if I understand you properly, but I think you can, at least, use Session Scope, because you could create several Sessions with different Ids. For every Session you will have own Session Map.
In that way you can manage separate set of Cars Objects.
If you use Weld as CDI your implementation, you can use a BoundSessionContext which can be bound to any Map. The context is automatically attached to the map on activation, and detached when invalidate() is called.
I'm trying to implement a proper layer separation in my XPage project. Ideally I'm trying to get to a point where the XML in the XPage contains no SSJS and uses only EL to access Java objects.
So far I've worked out how to load all my data from the domino database into Java Beans (where 1 document = 1 Object, more or less), I'm reading view contents into Java Maps or Lists, and I've managed to display the content of these collections in repeat controls.
What I'm unsure of is how to display the content of a 'form', of a single document, without referencing the domino document. In particular, I'm unsure of how to deal with the 'new document' case. I suppose I create an empty object, then set that object as a data source for the Xpage.
I'm aware that I have to use a ObjectDataSource for this, but I'm unsure where to actually store it. I read an article from Stephan Wissel stating that one shouldn't put them in managed bean, so where can I put it? In one of the scoped variables like viewScope?
Right now I've written an 'ApplicationBean' which is a session-scope Managed Bean where I'm storing all my objects.
What is the best practise? It seems that there are many different ways to meet that goal. Currently I'm exploring Christian Güdemann's XPages Toolkit, which sounds very promising. I know that Samir Pipalia, John Daalsgard and Frank van der Linden have worked up their own frameworks.
So how should I go about it? Any pitfalls?
This is a large topic indeed. As Paul mentioned, Tim's document model classes are a great example of how to do that clearly, and Tim goes into more detail in later episodes in that NotesIn9 series. My own Framework's model objects are fairly similar, though I also added collection managers to handle the dirty business of accessing views. For better or for worse, almost every XPage developer solves this problem in a unique way.
There are a number of ways you can go about implementing this sort of thing, and some of the differences aren't terribly important in normal cases (for example, whether you preload all data from the document when constructing the model object or do lazy fetching to the back-end only as needed), but there are definitely a couple overarching questions to tackle.
Model Access
As you mentioned in the question, one of the big problems is how you actually access model objects from the XPage - how the objects are fetched from the DB or created anew. My Framework's model objects use a conceit of "Manager" objects, which are application-scoped beans that allow getting either named collections (which map to views), model objects by UNID, or a new model object via the keyword "new". Generally, these models (which are Serializable) are then stored in the view scope of the page using them either via <xp:dataContext/>, <xe:objectData/>, or the Framework's own <ff:modelObjectData/>.
I've found it very wise to avoid using managed beans to represent individual objects (like "CurrentWhatever" that you then fill with data on each page), since that muddies up your faces-config in the best case or runs into session problems in the worst (if you put it in session scope, which I rarely use).
How you implement "new" vs. "fetched" model objects depends largely on the tack you take to write your models in the first place, but most boil down to having two constructors: one to take a UNID (at least) to point to existing document and one to create a new one. If you go the "write every properly explicitly in the object with getters and setters" route, the latter would also initialize all of the fields with default values instead of reading them from a document. Internally, you should have fields to store the UNID of the document, which can indicate whether it's new or not - then, your save method can check if this field is empty and create a new document if needed (and then store the new doc's UNID in the field).
Views
It sounds like you're already reading your model collections into Lists, which is good. One down side there, though, is scalability: with small (less than 100) collections, you're likely to not run into any load-speed problems, but afterwards things are going to slow down on initial page load as your code reads in the entire view ahead of time. You can mitigate this somewhat with efficient view reading, but there's a limit. The built-in views are generally speedy because they only load data as needed (they also cheat like hell to do so, but that's another issue).
This is a noble goal to aim for yourself, but doing so to cover all cases is no small feat: you end up running into questions of FT searching, column resorting, efficient data preloading (you don't want to re-open the View object only to read in one entry at a time, but you also don't want to read the whole thing), use in viewPanel and maybe others (which require specialized interfaces), expanding/collapsing categories, and so forth. It's a large sub-topic on its own.
Esoterica
You're also liable to run across other areas that are more difficult than you'd think at first, such as "proper" rich text handing and file attachments. Attachments, in particular, require direct conflict with the XSP framework to get to function properly with custom model objects and the standard upload/download controls.
Case-sensitivity in field names is another potential area of trouble. If you're writing getters and setters for all of your fields, it's a moot point, but if you're going the "thin wrapper" route (which I prefer), it's important to code any intermediary caches/lookups in a way that deal with the fact that "FOO" and "foo" are (basically) the same as item names to Notes, but are distinct in Java. The tack I take is to make extensive use of TreeMaps: if you pass String.CASE_INSENSITIVE_ORDER as the parameter to the constructor, it handles treating Strings as generally case-insensitive when used as keys.
Having your model objects work with all the standard controls like that may or may not be a priority - I find it very valuable, so I did a lot of legwork to make it happen with my framework, but if you're just going to do some basic Strings-and-numbers models, you don't necessarily need to worry.
So... yeah, it's a big topic! Depending on how confident you are with Java and the XPages undergirdings, I would suggest either going the route of fairly-simple "beans with getters and setters" for your objects or by looking into the implementation details of one of the existing frameworks (my own or the ones you mentioned). Sadly, there are a lot of little things that will crop up as your code gets more complicated, many of which are non-obvious to deal with.
Jesse Gallagher's Scaffolding framework also accesses Java objects rather than dominoDocument datasources. I've used (and modified) Tim Tripcony's Java objects in his "Using Java in XPages series" from NotesIn9 (the first is episode 132. The source code for what he does is on BitBucket. This basically converts the dominoDocument to a Map. It doesn't cover MIME (Rich Text) or attachments. If it's useful, I can share the amendments I made (e.g. making field names all the same case, to ensure it still works for existing documents, where fields may have been created with LotusScript).
Andrew - Jesse's one of the experts here so I'd read his response carefully.
What I do is I took one of the key pieces of Jesses bigger framework - the "pageControllers" and I use that HEAVILY. So I end up with a Java Class for each XPages to act as the controller. "All" Jesse's page controller framework does is make it a little easier to consume. So you can reference it on each page as "controller" and don't nee dot make individual managed beans for them.
I still will use SOMES SSJS on the XPage if I really need to for things like button events.. some methods that don't have proper getters and setters.. HashMap.size() for instance. But the vast bulk of the code goes into the Java Class. No real need for viewScope variables any more as well.
in the case of a "New Document".. In the controller I'll create a new Java Object that represents the "Current document". I'll bind all the fields to that. If it's new I create a new Object and assign it to the private variable. If I'm loading form somewhere then I take that variable and load the document I want.
I've started to really try and detail this in more recent NotesIn9's. Especially the little series on Java for Xpages developers. I think I got far enough there to show you what you need to know. I do plan on doing a lot more on this topic as soon as I can.
I don't know If this is the right place to ask this question.
How do I make some non technical person to understand "Facelets as View technology"?
I try it.
If you use JSF as presentation layer you can use the advantages of input validation for forms, have a direct data binding to one or more ManagedBeans also known as PoJos with annotation #ManagedBean or #Model/#Named...
JSF components also support the usage of Ajax, so you can update tableviews asynchronous after adding new entries for example.
summarizing in my opinion it is easier to built a modern feeling site by using JSF, there are many different implementations e.g. primefaces, richfaces, etc. so you have the choice which framework you'll use.
Hope this helps, maybe the community can add more.
Patrick
Let's say If I have an application where I have been keeping all my XPages, most not necessarily related to each other. If I define several beans in the faces-config file for some of these XPages, what is the effect on memory and performance in the other XPages that do not use any of these managed beans? Aren't they instantiated and kept in memory (even if empty) for all the XPages in this application?
If so, then would it be best practice to keep the related XPages that will use a managed bean (and maybe share them) in their own NSF vs. having a single store for all the XPages for a site?
Howard
Managed bean is constructed only if referenced in EL/SSJS. Its scope defines, when it is discarded.
So from performance standpoint it does not matter (sort of) how many beans are defined in faces-config.
What you must take into account, though, is performance of methods. Especially setters/getters, which are called usually more times per request. Also avoid any excessive code in constructor of request scoped beans. Applies to memory demands too - try not to keep vast amount of data (arrays, maps...) in beans.
I would recommend to split XPages into more databases. Reason is different from beans performance - application logic. It is better to keep related functions together (into single NSF) and separated from others (don't mix them all at the same place).
That realy depends on the scope you are using to keep them in memory, what you are using them for etc etc..
NOTE: I have a related question here (http://stackoverflow.com/questions/6915055/are-jsf-views-shared-between-users) but that deals with a few other issues, so I am creating this one to focus on a more specific area.
I am using RichFaces (and in the last few weeks, have gotten a better feel for its implementation, object distribution, memory footprint, and things of that nature) along with JSR-168 Portlets, and am running into scalability issues. Given that a majority of my pages (aka, views) are user-agnostic (they are read-only, and generic to the user community for the most part), I want to force the RichFaces Framework to create a single view (# of logical views and sessions is set to 1 in web.xml) that is shared across the sessions.
In other words, I don't want any more than 1 view per session (easily, done by the config params mentioned above in web.xml) but more importantly, I don't want more than 1 view (of the same underlying view definition) even across sessions.
Now, what would it take to accomplish this?
I figured this one out. I extended the JBoss Portlet Bridge and JSF StateHolder classes (amongst other things) and have a custom implementation that lets me share the JSF views across user sessions (again, these views are read-only and generic to the user community). The ones that are session-specific, I just let those resort to the default behavior. This has helped cut the JSF contribution to the overall session size (in terms of memory) by about half.