At line 1 added 310 lines |
!!! Question And Answer (Q&A) / Frequently Asked Questions (FAQ) |
|
%%(font-size:150%)__[Tables and grids|1]__%%\\ |
%%(font-size:150%)__[ORM with RSF|2]__%%\\ |
%%(font-size:150%)__[Debugging rendering problems|3]__%%\\ |
%%(font-size:150%)__[XML mappings in RSF|4]__%%\\ |
%%(font-size:150%)__[Building with Maven|5]__%%\\ |
%%(font-size:150%)__[Handling file uploads|6]__%%\\ |
%%(font-size:150%)__[Handling different request types|7]__%%\\ |
%%(font-size:150%)__[Difference between UIInput and UIOuput, & "fixups"|8]__%%\\ |
%%(font-size:150%)__[Cool URLs|9]__%%\\ |
%%(font-size:150%)__[The Resource Base URL|10]__%%\\ |
%%(font-size:150%)__[View Producers in Request Scope|11]__%%\\ |
%%(font-size:150%)__[Using ViewParameters to pass data in a link|12]__%%\\ |
%%(font-size:150%)__[Evolvers, Multi-file Templates, and Re-usable Compoments|13]__%%\\ |
%%(font-size:150%)__[Creating a standard "page template" or "frame" or "layout"|14]__%%\\ |
%%(font-size:150%)__[Taking full control of the request|15]__%%\\ |
%%(font-size:150%)__[Using GET forms|16]__%%\\ |
%%(font-size:150%)__[Internationalisation and Localization|17]__%%\\ |
%%(font-size:150%)__[Branches with a single component inside|18]__%%\\ |
%%(font-size:150%)__[SilentRedirectException when calling to producer|19]__%%\\ |
|
|
[#|#1] |
!!! Tables and grids |
__Q:__ Why doesn't RSF provide a table or grid component? (Like JSF's UIData) for example.\\ |
|
__A:__ The philosophy behind having an RSF component is somewhat more minimal than in other frameworks - in general, an RSF component only exists to i) back some kind of reality in the target language (in this case HTML) or ii) reflecting some unique kind of data binding function. These kinds of components are discussed in the page on [primitive components|PrimitiveComponents]. Where neither of these are happening, you'd be much better off building up collections of more basic components. For table controls, you would most likely simply assemble the primitive components for each cell (UIOutput, UIInput, etc.) within a UIBranchContainer for each row, using a simple {{for}} loop (or a [UIReplicator] if you are defining your components in XML). To create reusable tree branches in this way you would most typically use an [evolver]. Since [IKAT] in general accepts whatever tags it finds in the HTML template, this doesn't create a problem during rendering. Since you're in complete control of the table generation logic and are not dipping into framework code, this makes for a much more controllable system.\\ |
Where there ''is'' scope for new RSF components are in reflecting awkward table realities (in HTML, or other native-table languages) such as {{rowspan}} and {{colspan}}. These will probably be added on demand over the next couple of releases - note that in JSF support for these tags [isn't even ''possible''|http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=82&t=000536] except through various hacks and [extensions|http://jsftutorials.net/htmLib/] which break its idiom somewhat in losing target-language neutrality.\\ |
Various table situations are quite common though (such as sorting/paging) - while a lot of the legwork here can be done by Hibernate through query beans, it might be worth putting together a standard view component package and naming convention for the paging/column controls to make this more standard. |
|
[#|#2] |
!!! RSF ORM |
__Q: (Steven Githens)__ This looks really cool. Is it possible to just use the easy ORM layer |
without any of the web stuff? It sounds like it would be great for |
writing persistent Sakai Services (where often the longest part is |
getting the hibernate set up). |
|
__A:__ The short answer is yes, it could help - I've put together a page summarising how [RSF can help with ORM|RSFORMByItself] where it is not being used to operate a webapp interface. Bear in mind that RSF does not do any ORM itself, but more provides a set of idioms and strategies for making it more controllable. Also check the [Disintegrations] page. |
|
[#|#3] |
!!! Debugging rendering problems |
__Q:__ For complex views, figuring out what actually happens during rendering can be quite confusing - I see lots of my components missing from the view, how can I find out why? |
|
__A:__ As of 0.6.1, UIViewRoot contains a debug flag which may be set either through XML or in a Java producer. Not only will this dump the entire view tree (prior to fixup) to the Logger as XML, it will also enable branch diagnostics during rendering. For example, in Java add the following lines to the head of your producer: |
|
{{{ |
public void fillComponents(UIContainer tofill, |
ViewParameters origviewparamso, ComponentChecker checker) { |
... |
if (tofill instanceof ViewRoot) { |
((ViewRoot)tofill).debug = true; |
} |
}}} |
In practice I find most rendering errors are caused by interactions with forms. There are two main types of error to check for, both of which are flagged with {{WARN}} level debug messages during rendering. |
1. Firstly, you may fail to register a component which expects input, or a command (UIInput or UICommand) with a UIForm - you will receive a warning from the OrphanFinder that looks like this: |
{{{ |
2006-04-05 22:35:37,240 WARN (OrphanFinder.java:43) - |
<Control with full ID details-pane:::listener-row:::listener-delete |
expects submission but has not been registered with any form> |
}}} |
(The OrphanFinder is a ComponentProcessor that could be disabled in non-debug builds) |
2. Secondly, you may fail to have an (HTML) {{form}} component with a matching rsf:id in the correct scope to peer with a UIForm. In this case, __ALL__ child components of the UIForm will be skipped, whether they are submitting components or not. This can be quite surprising. This problem is signalled by the following type of warning: |
{{{ |
2006-04-05 21:10:09,615 WARN (BasicHTMLRenderSystem.java:123) - |
<Warning: skipping form tag with rsf:id listeners-delete-form and all |
children at lump index 677 line 170 column 64 since no peer component> |
}}} |
|
In general __always look in the logs first__ when you have missing components, these two messages will signal 90% of problems in my experience! |
|
I often find it useful to use split-screen editing in Eclipe, so that I can compare by eye either Java producer code/XML producer dump with the HTML template to make sure that all the IDs correspond properly. |
[#|#4] |
!!! XML mappings in RSF (and ViewParameters) |
__Q:__ Is there any documentation floating around for the producers and flow xml schemas? I'm trying to piece things together from the demo apps but am getting generally lost without a reference. |
|
For instance I'm trying to get a replicator table of links to load their data on the next page. But when I try to follow the Hibernate demo and see things like this in the view producer for the next page: |
{{{ |
<view-parameters type="entitycentred"> |
<entity name="SyllabusWeek"/> |
</view-parameters> |
}}} |
I'm not sure if I need to change things since I'm not using hibernate. I'm also curious about what other types besides entitycentred there are and what not. |
|
Just looking for a general way to decipher the available options in each of these files. |
|
__A:__ |
1. Producers are serialized by "default serialization" as far as possible - that is the field names correspond DIRECTLY to the field names of the respective components. Polymorphism in the is handled by the "type" attribute (low-level function of the [SAXalizer]). The value of the "type" attribute is either a fully qualified Java class name, or (if you want to go to the trouble), a "type nickname" which is registered with the ClassNameManager inside PonderUtilCore. The convention for all components it that the type nickname is the lower-cased version of the classname with the "UI" prefix missing. |
|
The central answer for all RSF XML mapping questions is inside the [mappings directory|https://saffron.caret.cam.ac.uk/svn/projects/RSFUtil/trunk/src/uk/org/ponder/rsf/mappings/] |
In particular [RSFMappingLoader.java|https://saffron.caret.cam.ac.uk/svn/projects/RSFUtil/trunk/src/uk/org/ponder/rsf/mappings/RSFMappingLoader.java] is the central point of coordination. If you want to add your own mappings, just drop any class implementing "MappingLoader" into your Spring context and it will be automatically invoked on startup. |
|
2. The flow definitions (if you are using any) are actually in standard Spring Web Flow format, which you can consult the [main SWF site|http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home] however note there is only a subset of the features implemented, in particular you may not use any EL expressions in the file. Basically anything which you don't see in the NumberGuess sample is not supported |
|
3. The most important question is - are you quite sure you want to be using XML-based producers at all? For non-autogenerated apps I would strongly recommend ViewProducers written in Java (or in your case in Jython - consult the [Java version of the Cookbook app|HibernateCookBook_4] for details, since these will in general be faster and more readable. Also this would free you from having to worry about mapping issues. |
|
4. The only two ViewParameters definitions bundled with RSF indeed are the EntityCentredViewParameters and the SimpleViewParameters - the idea is that every app will certainly want to implement their own - after all who else would decide on URL structure and state but you? RSF makes it easy for you to have completely different URL structure even on a view-by-view basis - the only fixed part is that the first part of the path-info up to the first slash represents the viewID which is the basic index used by RSF. If you want to add new [ViewParameters], just derive from ViewParameters, and implement the abstract methods. If you want you can then register the nickname with the mapping system in a MappingLoader, as in the following sample from RSFMappingLoader: |
{{{ |
public void loadExtendedMappings(SAXalizerMappingContext context) { |
context.classnamemanager.registerClass("entitycentred", EntityCentredViewParameters.class); |
} |
}}} |
Yes, there is no requirement to be using Hibernate at the same time as EntityCentredViewParameters. The RSF "[OTP]" system just expects you to have a set of EL paths that do the mapping correctly, which you could implement in any way you like (for example by implementing java.util.Map or BeanLocator). |
|
For example for an entity "SyllabusWeek" you might define a (request-scope) bean called SyllabusWeek that is a Map for which the key is the ID of the week, so that paths of the form |
{{{ |
#{SyllabusWeek.syllabusid} |
}}} |
map onto the required object. |
|
I think this is very cool and finally frees us both from the tyranny of DAOs but also from ORM coupling as well as a number of other evils. |
|
[#|#5] |
!!! Building with maven (versions) |
__Q:__ Using RSF-all-source-0.6.zip: running maven in J-RSFUtil/, J-ServletUtil/, and PonderUtil/ builds rsfutil-0.6.jar, j-servletutil-1.1.jar, and ponderutilcore-1.1.jar. However, the examples seem to depend on different versions. For instance running maven in I-RSFNumberGuess indicates a dependency on ponderutilcore-1.1.1-dev.jar, j-servletutil-1.1.1-dev.jar, and rsfutil-0.6.1-dev.jar (plus additional jars not in the CARET repository such as spring-1.2.6.jar). How to make the build work? |
|
__A:__ The spring, aopalliance, cglib, and concurrent jars can be obtained by adding http://www.ibiblio.org/maven to maven.repo.remote in project.properties. Any set of JARs with the {{-dev}} suffix indicate they are from a ''non-released'' version of RSF, which means use of them is at your own risk! This could only arise through checking out a non-tagged version of RSF - in general please only use the externals listed on the [Downloads] page to make checkouts of tagged versions RSF source unless you have good reason not to, and/or are prepared to deal with the consequences! |
|
Any SVN references to trunk paths scattered around the wiki should be considered "for reference only" and should be marked as such. |
|
! Comment |
([AntranigBasman|People]) |
This error was caused by checking out the version of the sample app from trunk rather than from the tagged version. In general please make sure when using SVN that you always get a tag, and the same one for every project you use. See also the [GettingStarted] page for advice on Maven repositories - in general LSU is a better bet than main ibiblio. The project.properties files will be updated to include correct repo.remote references from 0.6.1 onwards. |
[#|#6] |
!!! Handling file uploads |
File uploads in RSF are handled using Spring's [MultipartResolver|http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/web/multipart/MultipartResolver.html] infrastructure. While this is somewhat at odds with RSF's philosophy of not passing on Spring dependencies, the Spring implementation is simply a good API and there would be little point in |
duplicating it. In order to enable file uploads, you must override the RSF application-scope bean {{multipartResolver}} with a suitable implementation of your choice - for example |
|
{{{ |
<bean id="multipartResolver" |
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> |
</bean> |
}}} |
with suitable parameterisation, e.g. maxUploadSize etc. |
|
In this case, the Maven dependencies required are as follows: |
|
{{{ |
<dependency> |
<groupId>commons-fileupload</groupId> |
<artifactId>commons-fileupload</artifactId> |
<version>1.1</version> |
<type>jar</type> |
<properties> |
<war.bundle>true</war.bundle> |
</properties> |
</dependency> |
<dependency> |
<groupId>commons-io</groupId> |
<artifactId>commons-io</artifactId> |
<version>1.2</version> |
<type>jar</type> |
<properties> |
<war.bundle>true</war.bundle> |
</properties> |
</dependency> |
}}} |
to be added to {{project.xml}}. |
|
To actually ''receive'' the file upload is blissfully simple, with the help of [RSAC]. The resolved Map of MultipartFile objects (as returned from the [getFile|http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/web/multipart/MultipartHttpServletRequest.html#getFile(java.lang.String)] method of Spring's MultipartHttpServletRequest is dropped into RSAC under the name {{multipartMap}} - simply express a dependency from your handling bean (in request scope) - for example |
{{{ |
<bean id="uploadAction"> |
<property name="multipartMap" ref="multipartMap"/> |
</bean> |
}}} |
|
[#|#7] |
!!! Handling different request types |
|
Determining the content type for the current request is done by the RSF [OLI] ContentTypeResolver: |
|
{{{ |
public interface ContentTypeResolver { |
public String resolveContentType(ViewParameters viewparams); |
} |
}}} |
|
"Out of the box" this defaults to returning "HTML" type, which sets a suitable ContentType header, XML declaration, template file extension and [RenderSystem] suitable for servicing XHTML requests. Simply override this bean (named {{contentTypeResolver}} at application scope) with your own implementation to choose one of the other request types named in [ContentTypeInfoRegistry|https://saffron.caret.cam.ac.uk/svn/projects/RSFUtil/trunk/src/uk/org/ponder/rsf/content/ContentTypeInfoRegistry.java]. |
If you want to define new types, override the bean {{contentTypeInfoMap}} to hold a {{java.util.Map}} of your chosen [ContentTypeInfo] entries. But please report them to me in general, since I'm keen to fold any even slightly reasonable definitions into the core. |
|
The other aspect of handling different content types is choosing a [RenderSystem] defining component renderers suitable for rendering content of your type. Unfortunately RSF currently only defines the BasicHTMLRenderSystem which is set up in {{renderSystemMap}}. Fortunately, IKAT rendering is sufficiently flexible that by sticking to non-HTML-specific components (such as UIOutput, UIVerbatim and UIBranchContainer) in your component tree, you can in fact achieve most of the behaviour desired for rendering any XML-based content type. (In fact, even non-XML types may be rendered by passing the IKAT output through the [XMLFlattener|https://saffron.caret.cam.ac.uk/svn/projects/RSFUtil/trunk/src/uk/org/ponder/rsf/util/XMLFlattener.java] or similar post-processor). |
|
Rendering languages which define components which expect to perform submissions (such as WAP), or in general require more than simple template replication and/or replacement of text nodes will require their own RenderSystem to be defined, however. |
|
[#|#8] |
!!! Difference between UIInput and UIOuput, & "fixups" |
|
__Q:__ |
|
I find that at PageB the UIInput field will populated the value from the JavaBean, will UIOutpout just populated something like "#{testBean.modifier}", which was supposed to populate value from the JavaBean.) |
|
So, the UIInput & UIOutput behave quite different in RSF? |
|
And if I want UIOutput field to populate value from JavaBean, the way is to |
inject to JavaBean as a field in the corresponding Producer file? |
|
__A:__ |
There is no difference between fixups for UIInput and UIOutput on the rendering cycle - they both fetch their value using EL (if you provide an EL and do not provide a value) in exactly the same way. The difference is that a UIInput will provide a value back via the EL on the following action cycle, and a UIOutput will not. This behaviour and distinction is just the same as in JSF. |
|
You can see this similarity in that both UIInput and UIOutput provide a "full constructor" with the following signature: |
|
|
{{{ |
public static UIOutput make(UIContainer parent, String ID, String initvalue, |
String binding) |
}}} |
|
You can see the similarity even more concretely by looking at the inheritance hierarchy - UIInput and UIOutput are actually exactly the same class! I.e. a UIBoundString with a different value for the field "willinput". |
|
So to answer your last question more specifically - for a UIOutput (or UIInput) you can choose to provide a value explicitly (either by injection, or though some other route) in the producer, or you may supply an EL expression and allow RSF to fetch it itself. Which choice you make is largely a matter of convenience, although in general you would expect that supplying the value would be slightly quicker (by a few microseconds :P) |
|
Note that by supplying BOTH an EL AND a value (for a UIInput for example) you have the capability to provide an initial value which *disagrees* with the current (in this render cycle) value of the EL. The value will be used for rendering, and the EL will not be used until the following cycle - this can/will create an inconsistency and so should not be done unless you are very clear what you are doing (can be useful for a dummy value which "must" be changed by the user in order to be applied - unchanged values are *not* applied by RSF to the model during the action cycle). |
|
[#|#9] |
!!! Cool URLs in RSF |
|
__Q:__ How can I make "cool URLs" in RSF? I want to get around the restriction that the viewID is the first path component of pathInfo. |
|
I want to do things like: |
|
*/new/message/userid <- Goes to a screen for composing a private message to userid |
*/view/chem101/messages <- Goes to my private messages for Chem 101 |
*/admin/edit/userid <- Edit userid's settings (admin style) |
*/view/userid/profile <- View userid's profile |
|
__A:__ A good deal of control over "trunk URL" layout can be obtained by overriding the [getParseSpec|http://saffron.caret.cam.ac.uk/projects/RSFUtil/trunk/site/apidocs/uk/org/ponder/rsf/viewstate/ViewParameters.html#getParseSpec()] method of your [ViewParameters] class. For example, to place a field called {{isbn}} into your second path segment rather than an attribute, supply |
|
{{{ |
public String getParseSpec() { |
return super.getParseSpec() + ",@1:isbn"; |
} |
}}} |
|
in your ViewParameters. You can place the viewid itself in another position by a similar syntax, although of course you must explicitly place another (mandatory) field in the @0 position at the same time. |
|
In future versions RSF will feature further idioms for "chains" and other RESTful URL patterns. In the meantime you can take full manual control by by implementing the ViewIDInferrer [OLI], where you can embed arbitrary logic for parsing the view ID out of any part of the URL structure. Override {{viewIDInferrer}} at application scope with your implementation. Note that you will generally need to implement your own [ViewParameters] for any views for which your ViewIDInferrer bites, i.e. those without the viewID in the normal place. In particular, SimpleViewParameters will not work any more, but you can straightforwardly make an adjusted equivalent following Steve Githens' posting [http://ponder.org.uk/rsf/posts/list/50.page#220] |
|
[#|#10] |
!!! Use of *resourceurlbase* Context Parameter |
|
__Q:__ Obviously the {{resourceurlbase}} parameter is being used to form URLs that reference RSF resources, but who exactly uses this? Is it only used to address RSF templates, or can it be used to address other kinds of resources, such as string bundles?\\ |
|
__A:__ The "resource base URL" for a particular template is the URL base to which every relative URL encountered in the template will be rewritten. This is necessary since the actual RSF view occurs at a different URL point in the server's URL space to the template from which it was derived (and may in some cases even be exposed on a completely different server), and so any relative references within the template, for example to images, CSS and JS files need to be "rebased" to the base URL that they are being served from, called the "resource base URL". This is unrelated to the J2EE concept of "resource" which are always resources from the point of view of the *server* and not the client. Note that the {{resourcebaseurl}} servlet context parameter is only used with the Sakai integration package, and as of the 0.7 release it is now optional. |
|
[#|#11] |
!!! ViewProducers in request scope |
|
__Q:__ Should I declare my ViewProducers in {{applicationContext.xml}} or in {{requestContext.xml}}?\\ |
|
__A:__ This issue is discussed in its own page on [RequestScopeViewProducers]. |
|
|
[#|#12] |
!!! Using ViewParameters to pass data in a link |
|
__Q:__ How do I pass parameters in a link? |
|
__A:__ Extend SimpleViewParameters to create your own own class to encapsulate the parameters you want passed. More than one parameter can be included in a single SimpleViewParameters object. The parameters should be declared publically, so that values can be set via introspection (Java Bean/Pea conventions). See the dedicated page on [ViewParameters] for more information. |
|
The extended SimpleViewParameter class can then be used as the ViewParameters argument in a UIInternalLink component, passing the values to be used in its constructor. |
|
To extract values passed as parameters, down-cast the ViewParaemeters object passed into the fillComponents() method of your ViewProducer. If parameters are not present when fillComponents() is called, the default value of the parameters created during construction of the extended SimpleViewParameters object will be used. |
|
[#|#13] |
!!! Evolvers, Multi-file Templates, and Re-usable Compoments |
|
__Q:__ What is an evolver and how can I use it to create a re-usable RSF component? |
|
__A:__ Building your own RSF UI component is discussed in its own page [BuildingRSFComponents]. |
|
[#|#14] |
!!! Setting up a standard "page template" or frame |
|
__Q:__ I want to set up a standard page template or "layout" to surround some or all of the pages on my site, containing a standard header and footer, etc. How can I do this in RSF? |
|
__A:__ Setting up page templates like this is discussed on its own page [OuterPageTemplates]. |
|
[#|#15] |
!!! Taking full control of the request |
|
__Q:__ How can I take full manual control of the request cycle, for example to render custom headers, or non-XML, non-IKAT rendered responses (for example ZIP files or images)? I still want to keep the benefits of RSF's ViewParameters system and the request bean environment. |
|
__A:__ Use a [HandlerHook]. |
|
[#|#16] |
!!! Using GET forms |
|
__Q:__ How do I set up an HTTP GET form submission that is handled by an RSF view, for example to run a search query? |
|
__A:__ Rendering and handling GET form submissions are treated on their own page [GETForms]. |
|
[#|#17] |
!!! Internationalisation and Localization |
|
__Q:__ How do I take advantage of RSF's features for Internationalisation, and ensure that my app is easily portable to other languages and locales? |
|
__A:__ Look at [I18N]. |
|
[#|#18] |
!!! Branches with a single component inside |
|
__Q:__ A situation that crops up a lot is needing to create a branch which contains just one component - this is because there is some bit of the template surrounding the component which I want to leave out when it is not there. Is there a better way of dealing with this? |
|
__A:__ Use {{[payload-component|PayloadComponent]}}, an special value for the {{rsf:id}} recognised by the [IKAT] renderer which lets you deal with this situation without a branch. |
|
[#|#19] |
!!! SilentRedirectException when calling to producer |
__Q:__ When calling to a producer, I get "Got target exception of class uk.org.ponder.rsf.flow.errors.SilentRedirectException" and the default view is shown. What can cause this? |
|
__A:__ This can be caused by calling a producer that is not defined or is defined incorrectly. Check your producer definition in your context file to make sure the class is correct and all dependencies are handled correctly. |