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.
Related
Does Mapkit on IOS support dequeuing of overlays? (like it does annotations). If so what is the code for achieving this?
Background: With annotations I believe you can add many, leaving MapKit to instantiate views when required for them via the dequeuing approach. What about the same thing for overlays however if I have many across the country? Do I need to write the code for checking which overlays I have are visible or not and then instantiate them / remove them myself in realtime?
Map Kit does not support reuse of overlays in the same way it supports doing this for annotation views. One of the reasons for this must certainly be that the two objects are not analogous. Overlays are model objects that represent an area on the map, whereas annotation views are view objects used from time to time to display the location of an annotation on the map. The technique of reusing view objects (as opposed to creating individual ones for every use) is an optimization that is used in a couple of other places in UIKit, notably for Table View Cells and various bits of Collection Views.
The view reuse pattern is to establish some data index (table index paths, map coordinates) and then have a delegate provide an appropriate view object to use when a particular index/location comes into view. When the data object passes out of sight, the view object is recycled in a queue.
An annotation is analogous to an overlay, and MapKit does not provide reuse for them either and for good reason: they are the data that is being displayed!
The analogous object to the annotation view is an overlay renderer, which (of course!) provides rendering for an overlay. I assume that the reason these are not reused is because they are not view system objects and presumably much more lightweight, so there is little benefit from reuse. We find evidence for this in the fact that until iOS 7.0 the MapView delegate did provide a view object for overlays and this was replaced by the renderer concept.
I hope that helps.
What problem is this causing for you?
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've been reading about the conversation scope in Java EE 6 (and therefore CDI 1.0), and how it can isolate data from different tabs in a browser, and preserve data across many requests of a particular workflow of pages. I've no issues there.
In my reading, I've read that many of its ideas came from Seam. Often I see caveats such as 'but CDI's conversationscope does not do "nested" conversations'. I'm not sure what exactly a "nested" conversation is?
I've read this good link also http://www.andygibson.net/blog/article/understanding-nested-conversations/
but I think I'm missing something fundamental.. I'm just not fully getting what a "nested" conversation is in this context. Can anyone help dumb it down for me?
From the Seam 2 documentation:
A nested conversation has its own conversation context, but can read values from the outer conversation's context. The outer conversation's context is read-only within a nested conversation, but because objects are obtained by reference, changes to the objects themselves will be reflected in the outer context.
So with nested conversations you have the chance to split a given parent conversation into several child conversations, each with both their context and access to the parent's context.
Although CDI was heavily influenced by Seam, it is so to say only a common denominator of several influences, so it does not contain everything which Seam had. The idea was, that by creating CDI extensions, such as Seam 3 was about and what now should be done by Apache Deltaspike, more features commonly used could be provided above the CDI standard.
Unfortunately, I am very disappointed with what Deltaspike provides and allthough JavaEE 6 and thus CDI is so long in existence, there is still a gap between what I was used to with my Seam 2 projects. I mean honestly, just have a look at the Deltaspike Homepage which starts with the words "Some logos ideas" which in turn ends my confidence in it...
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..
What is the difference between views as a stand-alone design documents and views grouped in one design document? When do you put two views in one design document? Is there any guide for this?
There's no real guide for this, as it's entirely up to you. Here are the implications as far as I can tell:
Each design document can have as many (or as few) views as you wish. Keep in mind that a view is not created or updated until it is first queried. Also, when a single view is queried, all the other views in that same design document will also be created/updated. This won't be a problem unless you have millions of documents, but it is something to bear in mind.
Also, I believe the full string value of the view is compared between revisions, so it won't rebuild a view if the name and function text are identical. (NOTE this is speculation based on what I've read about views, it's just never explicitly stated)
Generally, I've migrated towards having a "common" design document that contains a lot of the core CommonJS modules (like form validation functions) and other general settings. In addition, each "entity" in my project will have a separate design document with their own views, update handlers, validation functions, show/list functions, etc. This pattern keeps each entity and it's functions grouped together, almost like a class of sorts. I've found it is much easier to maintain and naming is a little easier when each entity is self-contained.