2008-10 - API and feature requests
The following suggestions are based on a recent in-house project done with [fleXive] 3.0.
The related forum discussion can be found here
.
1. API quirks/suggestions for improvement
a) FxContent#getValue and Checked Exceptions
The fact that FxContent#getValue uses checked exceptions for missing values and invalid XPaths quickly leads to cluttered code. For example, the following code checks if a String value is not empty (and will still throw a FxInvalidParameterException):
private boolean isCompleted() throws FxInvalidParameterException {
try {
return StringUtils.isNotBlank(
content.getValue("/confirmation/code").toString()
);
} catch (FxNotFoundException e) {
return false;
}
}
Additionally, this does not work at all with optional properties when used via JBoss-EL (which allows function calls) on a JSF page.
Suggestions:
- Do not throw an exception for missing values. Return null or an empty FxValue instance instead.
- Throw the FxInvalidParameterException as Runtime exception. Usually the XPath is a String literal, so the program cannot react to it anyway, since it's a programmer error.
- Maybe create a "FxInvalidXPathException", since this is an error likely to occur when working with FxContents.
b) FxContent#setValue and primitive values *fixed*
Since #setValue only takes FxValue arguments, updating a content can get unnecessarily repetitive (especially, but not only for singlelanguage properties). For example, instead of writing
content.setValue("/stringValue", new FxString(false, "value"))
the same effect could be expressed with
content.setValue("/stringValue", "value")
or for a multilanguage property with
content.setValue("/stringValue", FxLanguage.ENGLISH, "value")
This also improves updates for multilanguage properties because otherwise one would have to check first if a value already exists under the given XPath (which would have to be updated, unless all languages are set at once).
c) FxReference constructor for PKs
new FxReference(false, new ReferencedContent(pk))
and
new FxReference(false, pk)
are equivalent, but no constructor for FxPKs is available. This is a special case because ReferencedContent extends FxPK.
d) Create/Save/Load cycle of contents *fixed*
Currently, creating a new content and then using it requires the following steps:
FxContent content = EJBLookup.getContentEngine().initialize(...);
content.setValue("/...", new FxString("..."))
content.setValue("/...", new FxString("..."))
content.setValue("/...", new FxString("..."))
content = EJBLookup.getContentEngine().load(EJBLookup.getContentEngine().save(content))
Some syntactic sugar with support for chaining would simplify the trivial case to
final FxContent content = EJBLookup.getContentEngine().initialize(...)
.setValue("/...", new FxString("..."))
.setValue("/...", new FxString("..."))
.setValue("/...", new FxString("..."))
.save();
Where save() would make the EJB call and set its own PK.
e) Determining missing properties of a content instance
When saving a content instance with invalid or missing values, only the first is reported. Ideally the XPaths of all invalid values would be returned at once, which would allow fancier UI error reporting.
2. Features dearly missed
a) URL Rewriting layer *fixed*
Often the page URI contains more information than just the ID of a content to be displayed. For example, the site locale ("en") followed by a tree path. Also, some pages are mapped directly to templates in the WAR file system, others are grouped and mapped to a single template (e.g. product detail pages). Writing a custom Filter is not that hard, but repetitive and it's easy to make mistakes (e.g. handling of trailing slashes).
Apparently there exists a pretty flexible URL rewriting layer similar to mod_rewrite, UrlRewriteFilter
(also included in Seam). It also seems to solve the "pretty URLs for postbacks" issue in JSF applications.
Bugs: FX-342
b) Tree API: extract page path from URL
There is no support for dealing with the tree path found in an URL (e.g. strip locale, strip file extensions). If UrlRewriteFilter is included, it should also add support for marking the tree path section of an URL for common usecases.
c) Tree API: get content reference for current page
Likewise, there is no single call to get the content PK (or content) assigned to the current page.
d) Content API: Determine if XPath is set
There seems to be no single method to determine whether a given XPath is present in a content instance, because the public methods either expect property or group paths. The following function checks if a XPath is present:
public boolean containsXPath(FxContent content, String xpath) throws FxInvalidParameterException {
try {
content.getValue(xpath);
return true;
} catch (FxNotFoundException e) {
return false;
} catch (FxInvalidParameterException e) {
try {
content.getGroupData(xpath);
return true;
} catch (FxNotFoundException e1) {
return false;
}
}
}
e) Creating lists from iterators *fixed*
Some flexive methods, like FxResultSet#getResultRows, return (with good reason) an Iterator instead of a complete list. However, to use such an enumeration in JSF it has to be converted to a List or Array.
Among other useful methods for Java 5, Google Collections
offers Lists.newArrayList(Iterable) which does exactly that.
Bug: FX-417
f) FxContent: iterating over XPaths with cardinality
There is no iterator for groups or values with a cardinality greater than one. This leads to the following, non-trivial code for iterating over the instances of a group:
for (FxData itemGroup : content.getGroupData("/contentGroup").getElements()) {
final FxString label = (FxReference) content.getValue(itemGroup.getXPathFull() + "/label");
final FxDouble price = (FxDouble) content.getValue(itemGroup.getXPathFull() + "/price");
}
The same applies to properties.
Suggestion:
Create a XPath iterator, possibly create Value/Group iterators, e.g.
for (String group: content.groupIterator("/contentGroup")) {
final FxString label = (FxString) content.getValue(group + "/label");
}
for (FxGroupData group : content.groupIterator("/contentGroup")) {
final FxString label = (FxString) group.getValue("/label");
}
g) FxContent: clear all indices of an XPath
Currently, the following code is required to remove all instances of a group/property with a cardinality greater than one:
try {
while (true) {
invoice.remove("/cartItem");
}
} catch (FxNotFoundException e) {
}
h) JSF-UI: Iterate over tree folder *fixed*
Parts of a webpage are often represented in tree folders. We need at least an iterator tag that provides the PK, path and caption of each direct child of a node (identified by a path).
Bugs: FX-58
i) Skeleton web app
Add a skeleton web application with tree-based navigation.
j) Import/Export of entire application data
While it is relatively easy to write an export script for the content tree, there is no "one-click" solution to export the tree and all associated contents (references, select lists, types).
Also, references are only exported via ID, which means that they are only resolved correctly when they have the same IDs on the target system. A complete export could solve this problem with an internal "reference mapping table" of some kind.