 |
|
|
|
|
|
|
|
|
Coupon Codes - never pay more again.. find discount coupon codes before making any online purchase just for free at couponrefund.com
|
|
|
|
|
|
| Welcome to ProgrammerTutorials.com!! |
java.net Articles |
PanelMatic 101 Date: 01/11/2012
Learn about PanelMatic, a small library that allows Swing developers to quickly create common UI panels.
Quickly create common UI panels with the PanelMatic library
Learn about PanelMatic, a small library that allows Swing developers to quickly create common UI panels.
Every Swing developer knows this feeling: you've got the design of a UI panel. It's the 'right' design. It 'works'. It's what the user would expect. Hell, it's even what you would expect had you been the user. But it is going to be an awful lotta coding to lay it out in Swing - even before you take into consideration issue like panel re-sizing and localization.
Some developers nest numerous panels to get it working. Some try to "fake it" using the null layout. Others try to fit everything into a single panel and use the GridBagLayout - this involves quite a bit of trial-and-error, as can be seen in this documentary. Some even turn to graphical UI builders... But hey, every Swing developer knows that. Time for something new: PanelMatic.

Figure 1. Panel layout: Sketch, PanelMatic code, GUI panel
PanelMatic allows Swing developers to create common UI panels with ease. Panels are built top-to-bottom (or, more precisely, on the page axis). There is an intuitive connection between the way the code looks and the way the created panel will look. Components can be added to the panel with a label and/or an icon (lines 3-7), or alone (line 9). By default components stretch to occupy all the space they get, but this can be changed using modifiers (lines 9, 10). L_END (stands for "line end") and GROW (stands for "grow") are statically imported constants, and are in fact full-blown object that implement the BehaviorModifier interface - so you can create your own modifiers if you need 'em. Client code can add headers (lines 2, 8) and flexible spaces (not shown). The default implementation uses a pluggable component factory to create all the extra components involved (e.g. JLabels), so you can customize them when the defaults won't do.
As you've probably guessed, panels are built by builders that are obtained by invoking a static method on the PanelMatic class. PanelMatic is designed around an API/SPI approach - all the client code gets to hold is an interface, so the implementation can be changed without affecting the client code at all. Builders are pooled, so you don't have to think twice before asking for one. You can create your own implementation - just implement the service provider interfaces, and point the PanelMatic class to it. This can be done either by code or via a system property.
So this is PanelMatic. Use it to create common UI panels quickly, and use your freed up time to go to more meetings and catch up on some quality PowerPoint presentations. We could stop here, but we'd be missing half the fun.
Beyond Layout
PanelMatic's approach to building UI panels allows for some surprising improvements over normal layout-based code. Here are some of my favorites.
Customizers, or Listening to All Components
Components are passed to the builder, and eventually get added to the produced panel. But before they are, they pass through a chain of PanelMaticComponentCustomizers, or "customizers" for short. Each builder has two customizer chains - one that applies to all the panels it builds, and one for the current panel being built. The latter is disposed after the get() method is called. Customizers have a customize method, which gets and returns a JComponent. This allows the client code to apply uniform customizations to all components in the created panel, or in the application in general. These customizations can be used for, e.g.:
- Changing the background of the focused component
- Automatically wrap
Scrollables in a JScrollPane
- Listen to all components in a panel
Let's look into the last example. A very common requirement is to have a "save" button enabled if and only if the user changed some data on the screen. This involves listening to all components the user can change, which is a lot of boilerplate code. Instead, we can create a customizer that would add a change listener to every component added to the panel, and then add a single listener to that customizer. PanelMatic comes with such a customizer out of the box:
<!-- 12345678901234567890123456789012345678901234567890123456789012345--> <b>ChangeDetectorCustomizer cdc = new ChangeDetectorCustomizer();</b> panel = PanelMatic.begin( <b>cdc</b> ) .addHeader( H1, "Song Details") .add("Name", txfName) .add("Album",txfAlbum) .add("Artist",txfArtist) ... .add( btnSave, L_END) .get(); <b> cdc.addListener( new ChangeDetectorCustomizer.Listener() { @Override public void changeMade(ChangeDetectorCustomizer cdc, Object o) { btnSave.setEnabled(true); }});</b>
The ChangeDetectorCustomizer adds the appropriate listeners to all common swing components, so any change made to any component makes the save button enabled. It also recurses down the containment hierarchy, so changes made to JCheckboxes nested in some sub-sub-sub-panel are detected as well.
Localizations
PanelMatic's PanelBuilders can pass the labeling strings "as-is", like we've seen so far, or use them as keys of a ResourceBundle. Resource bundles are set using static methods of the PanelMatic class itself, and affect all builders generated afterwards. The same goes for ComponentOrientation. So it takes only two lines of code to move from an English left-to-right UI to a right-to-left UI in Urdu/Hebrew/Arabic or any of the other RTL languages (see resources). That, and someone to translate the texts.

Figure 2. Localizations can be easy
Building GUI Using Expressions - Anonymous Panels
With PanelMatic, it is often the case that panels are laid out using a single expression. This is contrary to the normal UI construction process, where one first creates the panel, then applies a layout, and then adds sub-components - each in a statement of its own. The problem with statements is that they cannot be combined - they just sit there, one after the other, as if in a shopping list.
Expressions, on the other hand, can be nested and composed with other expressions. They are "first class citizens" in java, and can appear anywhere. So, one can create a sub panel while adding it to a bigger component, rather than before:
<!-- 12345678901234567890123456789012345678901234567890123456789012345--> JTabbedPane tabs = new JTabbedPane(); tabs.add( "Tab 1", <b>PanelMatic.begin() .addHeader(HeaderLevel.H1, "Tab 1") .add("User Name", txfUserName ) .add("Password", txfPassword ) ... .get()</b>);
This is somewhat similar to Anonymous Classes (those are the classes with no names that are created, say, when you implement an ActionListener). As anonymous panels can go anywhere, the below code works:
System.out.println("A panel with two JLabels would " + "have a preferred height of " + <b>PanelMatic.begin() .add( new JLabel("Label 1")) .add( new JLabel("Label 2")) .get()</b>.getPreferredSize().height + " pixels.");
On my mac, it says:
A panel with two JLabels would have a preferred height of 40 pixels.
Advanced Customizations
PanelMatic takes the "convention over configuration" approach (thanks, guys). Everything can be customized, but you normally don't need to bother with it. When you do, there are several levels of customizations available: one could subclass a PanelBuilderFactory (easy) or implement the entire stack (builders and factories) or get to some level in between. The exact details are beyond the scope of this article, but are in the docs. Bottom line - as long as you can build your panel along the PAGE_AXIS, you can customize PanelMatic to build them. The client code should not be affected when you switch from the default implementation to yours.
Wrapping up
PanelMatic is a small library that allows Swing developers to quickly create common UI panels. It helps with localizations and customizations and makes the code creating the UI readable and intuitive. It's easy to pick up and hard to put down, though I might be slightly biased. Why not give it a go and see for yourself?
Resources (or References)
|
SWELL - An English-Like DSL for Swing Testing Date: 11/18/2011
This article describes the design of SWELL, an English-Like domain-specific language for testing Swing applications
An English-Like Domain-Specific Language for Swing Testing
This article describes the design of SWELL, an English-Like domain-specific language for testing Swing applications.
This article describes an English-Like domain-specific language for testing Swing applications. If you are a potential SWELL user, proceed to the SWELL User Guide. But if you would like to understand the design of the tool to possibly create your own DSL-based tools, read on.
The Wikipedia's entry for domain-specific language (or DSL) explains that "a domain-specific language (DSL) is a programming language or specification language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique ... Creating a domain-specific language (with software to support it) can be worthwhile if the language allows a particular type of problem or solution to be expressed more clearly than an existing languages would allow and the type of problem in question reappears sufficiently often."
The authors interpreted this as a license to create SWELL—An English-Like DSL for Swing Testing. SWELL has the following features:
- English-like in the words used and the sentence construction
- uses familiar Swing terms and English words in sentences typically used by human testers
- allows Swing Components to be identified and referenced using natural language
- can express the idea of any Swing action using a mouse, keyboard, etc. using natural language
- allows structuring of test cases (like JUnit) to facilitate test classification and management
Specific details can be found in SWELL Language Manual and SWELL Grammar below.
SWELL Internals - Anatomy of an Interpreter details the construction of the interpreter that executes SWELL scripts. This part is also a generic blueprint for DSL processors using VisualLangLab as the parser-generator.
A periodically updated version of this article that stays compliant with the current versions of the software used will be available at SWELL Article Update.
SWELL "Hello world"
All of our examples will target VisualLangLab (a convenient Swing application we will be using for parser development anyway). So, if you are not at all familiar with VisualLangLab, take a quick look at the Grammar without Tears article. The following code is a SWELL script for testing two of VisualLangLab's built-in sample grammars: ArithExpr and SimpleJSON.
Suite SampleGrammars begins with - Launch vll.gui.VllGui.main() - Wait for frame "VisualLangLab/S" - clearLogButton is the button with ToolTipText = "Clear log" - parseInputButton is the button with ToolTipText = "Parse input" - parserInputArea is the 3rd textcomponent - logTextPane is the 4th textcomponent Before each test - clear text in ${logTextPane} - clear text in ${parserInputArea} After each test - delay 500 ms Test ArithExpr "Check ArithExpr" is - select "Help" -> "Sample grammars" -> "ArithExpr" from the menubar - Wait for frame "VisualLangLab sample.*" - delay 1 second - click the "OK" button of the "VisualLangLab sample.*" dialog - key "3 * 5" into ${parserInputArea} - click ${parseInputButton} - fail the test with message "Bad parse result" unless ${logTextPane} contains "Array(Array(Pair(0, 3), List(Pair(0, Pair(0, 5)))), List())" within 1 s Test SimpleJSON "Check SimpleJSON" is - select "Help" -> "Sample grammars" -> "SimpleJSON" from the menubar - Wait for frame "VisualLangLab sample.*" - delay 1 second - click the "OK" button of the "VisualLangLab sample.*" dialog - key "{\"name\":\"Centurion\"}" into ${parserInputArea} - click ${parseInputButton} - fail the test with message "Bad parse result" unless ${logTextPane} contains "Pair(0, Array({, List(Array(\"name\", :, Pair(2, \"Centurion\"))), }))" within 2 seconds Suite SampleGrammars ends with - pause "We're done! Please click the \"OK\" button to exit."
The colored (blue, cyan, and red) lines are the structuring constructs. Every SWELL script contains a single test suite delimited by a test header and trailer (the blue lines). The header and trailer include the suite's name (SampleGrammars), which exists for documentation purposes only. The header and trailer can both be optionally followed by one or more SWELL statements that are executed at the start and end of the suite respectively.
A suite contains one or more tests, each starting with a test header (the red lines). Each test header (the red lines) includes the test's name (ArithExpr, SimpleJSON, etc.) and a string containing a more verbose description of the test. Each test-header is followed by one or more SWELL statements that are executed as part of the test. Like JUnit (and other test frameworks) SWELL also has ways of reporting the outcome of a test (e.g. the fail the test ... in these examples).
Optional before and after sections (headed by the cyan lines) list actions to be performed before and after each test respectively.
Figure 1 below shows this script in action. It loads the two sample grammars one by one, provides grammar-specific test input for each (in the Parser Test Input area), runs the parser and verifies that the expected output appears (in the Parser Log area) within one second. A failure is reported if the verification fails.

Figure 1. SWELL in action!
Running the Examples below has instructions on how to run this script. Most readers should have no problem deciphering this SWELL script, but if you need help use the SWELL Language Manual below.
SWELL User Guide
This brief User Guide introduces the available resources, and explains how they can be used to run the examples in this article or to run your own SWELL scripts. All of the resources required to support the descriptions in this article can be found in the swell-article-resources.zip file listed in the Resources section at the bottom of this article.
Prerequisites
Apart from the contents of the swell-article-resources.zip file, you will need to get the latest download from the Abbot Java GUI Test Framework, and to have a 6.0+ JRE installed. Both, SWELL itself and VisualLangLab, are written in Scala, but you do not need a Scala installation to use SWELL or VisualLangLab as described here.
Running the Examples
To run the examples shown, proceed as follows (this runs the Hello world script above):
- download the swell-article-resources.zip file, and unzip the contents into a directory (called swell-article-resources)
- obtain the latest download from the Abbot Java GUI Test Framework, and copy all its jar files into the jars subdirectory of the swell-article-resources directory
- on Windows: open a CMD window, cd into the swell-article-resources directory, and run the command "
launch.bat test-SampleGrammars.txt"
- on Linux/Mac OS/*NIX: at a shell prompt, cd into the swell-article-resources directory, and run the command "
chmod +x launch". Then run the command "launch test-SampleGrammars.txt"
- after completion of the OS-specific actions described in the previous two points, there is a delay of 10-30 seconds before any activity is visible. Do not touch the mouse till the end of the tests
- at the end of the test, a dialog is displayed (as in Figure 1 above), click the "OK" button to exit the test environment
- a detailed test log can be found in the file named test-SampleGrammars.log
Running your own SWELL Tests
The swell-article-resources.zip file contains everything you need to use SWELL for your own test. To create a new SWELL test script proceed as follows:
- download and unzip swell-article-resources.zip into the swell-article-resources directory, and add jar files from the Abbot Java GUI Test Framework as usual (see above)
- modify the launch.bat or launch script (depending on your host OS) to add directories and jar/zip files required for the system-under-test to the classpath. Save the modified launcher script with a different name (e.g. launch-test.bat or launch-test)
- using a text editor program, create one or more SWELL script files (equivalent to the test-SampleGrammars.txt file). Use the SWELL Language Manual for help with SWELL statements
- run the test by using the new launcher script using the OS-specific directions provided in the previous section. For example, if a new SWELL script file is named edit-rates.txt, you can start it by entering the command "
launch-test edit-rates.txt"
Users should be aware that the parser's error-reporting capability is currently rudimentary, and the error messages are sometimes not very helpful. However we expect to improve this aspect progressively, and improved resources and SWELL documentation will be made available at the The SWELL Project.
The SWELL Project
The resources in the swell-article-resources.zip file as well as additional documentation are being published as an open-source project hosted at http://swell.java.net/. The project is expected to be available online by the time (or soon after) this article is published.
SWELL Grammar
We won't be reinventing the wheel here, so just extract the SWELL grammar file swell.vll from the swell-article-resources.zip file listed in the Resources section. You will need the grammar-file to follow the descriptions and examples below.
Introducing VisualLangLab
Our DSL interpreter will need a parser to analyze SWELL scripts, and since the SWELL grammar is quite elaborate we must use a proper parser-generator. However, we would like to avoid the theory and formalisms (as much as possible) and use the simplest tools and approach. So, while there are many good parser generators, our choice for the job is the simple, user-friendly, and easy to learn VisualLangLab. To save space, we won't say much about the tool here, but refer interested readers to the Grammar without Tears article.
Open Grammar in VisualLangLab
The SWELL grammar was developed using VisualLangLab, and you can use the same tool to inspect and review the grammar. You can also test-run the grammar by feeding it snippets of SWELL. Within VisualLangLab, grammars are like gentle herbivores in an open zoo, and they don't bite your hand if you offer them the wrong kind of leaf or straw. You can also modify the grammar, and see how that changes its behavior, and the AST produced.
If you haven't downloaded VisualLangLab yet, get the VLLS-All.jar file now. Start VisualLangLab by double-clicking this file (Linux, Mac OS, and UNIX users will need to chmod +x VisualLangLab.jar). Select File -> Open from the VisualLangLab main menu, choose script.vll in the file-chooser dialog, and click the "Open" button. You should see the grammar-tree for the top-level parser-rule, Suite, displayed as in Figure 2 below.

Figure 2. Initial grammar view
The GUI's menus, toolbars, and displays, and the grammar-tree's icons and annotations are explained in the Grammar without Tears article, but if you need additional help take a look at The GUI. And if you need help with the icons or any other part of the grammar-tree, take a look at Editing the Grammar Tree. A somewhat more complex (but unfortunately essential) concept is the VisualLangLab AST. The rest of the article requires a good understanding of these concepts, so you should revisit the resources listed above if required.
Grammar Structure
A VisualLangLab grammar contains many separate grammar-trees (or parser-rules). You can display any grammar-rule by selecting its name in the toolbar's drop-down list (in the box near the red "A" in Figure 2 above). All these apparently independent grammar-trees actually constitute one large tree rooted at the top-level rule (Suite in this case). You can navigate up any branch of the tree by right-clicking any Reference node and selecting Go to from the grammar-tree's context-menu as shown in Figure 3 below.

Figure 3. Navigating up the singleTest branch
This process (right-clicking a Reference node and selecting Go to) can be repeated till you reach a grammar-tree that has no Reference nodes. The grammar-trees in Figure 4 below trace the path from Suite (the root) through singleTest, runStatements, stmtEnterText, and swingQuery to treePath.

Figure 4. Navigating grammar-tree references
Later in the article, when we discuss SWELL Internals, the grammar-trees in Figure 4 will be used to illustrate how application code (in the SWELL interpreter) is interfaced to the parser. To follow that discussion an understanding of each grammar-tree's AST will be required. The AST is displayed in the text area to the right of the grammar tree (see red box marked with a "B" in Figure 2 above). The information shown is the AST of the currently selected node, so to see the AST of the entire grammar-tree select (click on) the grammar-tree's root node. Also, the radio button marked with a "§" (for Depth, near the red "C" in Figure 2 above) should be selected. More details can be found in AST Structure.
Test-Running a Grammar-Tree
Actually running a parser-rule with different inputs gives you greater insight into the grammar, and we recommend trying to run some of the grammar-trees in Figure 4 above. Figure 5 below shows the simple steps required to test-run the selected grammar tree. Type the input text into the Parser Test Input area (the red box marked "A"), click the Parse input button (near the red "B"), then validate the parser's output (after the words result follows: in the red box marked "C"). If you see any error messages in red in place of the parser's result, the input did not match the grammar.

Figure 5. Testing the treePath grammar-tree
Figure 6 below shows the stmtEnterText parser-rule (middle of Figure 4 above) being tested. Observe that to parse the input provided, stmtEnterText needs to invoke swingQuery as well, but does not require treePath.

Figure 6. Testing the stmtEnterText grammar-tree
Testing Parsers has more detailed information about approaches to testing within the VisualLangLab GUI.
SWELL Internals - Anatomy of an Interpreter
The code described below is obviously SWELL-specific, but the overall organization is a generic blueprint (see Figure 7 below) for any DSL interpreter that uses VisualLangLab.

Figure 7. Interpreter blueprint
Disclaimer: Figure 7 just describes the dependencies between the various components. It does not imply that SWELL embeds any of the other components in any way.
As Figure 7 shows, the internal structure is very simple, just bundle your own code together with any required libraries and the VisualLangLab API. In the case of SWELL, it depends on the ABBOT (http://abbot.sourceforge.net/) framework for Swing GUI testing, so those jars are required. All interpreters using the VisualLangLab API must perform the following steps:
- Locate the grammar (XML) file
- Regenerate the parser
- Parse the given input, and obtain AST
- Interpret the AST
The following sections show and explain the essential code that handles these functions. The first three steps (up to obtaining the AST) are handled in one block of code, and are explained under Locate Grammar ... Obtain the AST below. Interpretation of the AST is explained under Application-Code AST Interaction.
Locate Grammar ... Obtain AST
A parser developed with VisualLangLab is saved as XML in a grammar-file with a .vll type. A program that uses such a parser (like the SWELL interpreter) uses the VisualLangLab API to turn this XML into an instance of the Scala Parsers type. But it must first obtain the contents of the grammar file. In the case of the SWELL interpreter, the grammar file is included as a resource in the jar file, and is retrieved using the system classloader's getResourceAsStream(String) method. This approach is convenient for programs that use large grammar-files. Smaller grammar-files can be embedded as a string within the interpreter program itself. To examine the code that performs these functions, look around the def main(...) {...} function.
Application-Code AST Interaction
The SWELL interpreter is written in Scala, and exploits Scala's pattern matching capability to analyze and unravel the AST. The description below uses snippets of code from SWELL that show how the AST is unraveled in steps strongly reminiscent of the oft-quoted onion skin metaphor. The following function marks the beginning of the onion's odyssey. The expression res.get returns the AST (the entire onion), which is passed to the Suite_handler().
Those interested in reviewing the full code should visit the src directory of the swell-article-resources.zip file.
def main(args: Array[String]) { ... lines removed for clarity ... val res = parser(input) if (res.successful) { ... lines removed for clarity ... Suite_handler(res.get) ... lines removed for clarity ... }
The function Suite_handler() shown below processes the AST from the top-level parser-rule Suite, (the entire onion). The structure of Suite's AST is shown on the left below, and notice how the code uses pattern matching to separate the onion's layers. The part of the onion containing the tests is passed to the function handleTests().
| AST |
Handler Code |
Array( | @stmtSuitBegins, | List(@groupDefinition), | Option(@stmtBeforeEachTest), | Option(@stmtAfterEachTest), | List( | | Choice( | | | Pair(0, @singleTest), | | | Pair(1, @runCommand) | | ) | ), | @stmtSuitEnds )
|
private def Suite_handler(pTree: Any) { pTree match { case Array(suiteBegins, groups, beforeEachTest, afterEachTest, tests, suiteEnds) => ... lines removed for clarity ... handleTests(tests) ... lines removed for clarity ... }
|
The structure of the part of the AST passed to handleTests() is shown below left, and a part of handleTests()'s code is shown on the right. Notice the use of a cast and pattern-matching to locate the list of statements in each test. Each statement is passed off (one at a time) to handleRunStatements().
| AST |
Handler Code |
Array( | @testHeader, | List(@runStatements) )
|
private def handleTests(tests: Any) { tests.asInstanceOf[List[_]].foreach(_ match { case Pair(0, Array(Array(testHeader: String, descrExprRes), statements: List[_])) => ... lines removed for clarity ... handleRunStatements(statements) }
|
An abbreviated version of handleRunStatements()'s AST and code are shown below. Notice how pattern-matching is used to recognize each statement, and then a part of the sub-onion received is passed off to the appropriate handler function.
| AST |
Handler Code |
Choice( | Pair(0, @stmtClearText), ... lines removed ... | Pair(6, @stmtEnterText), ... lines removed ... | Pair(18, @stmtMoveMouse), ... lines removed ... )
|
private def handleRunStatements(stmts: List[_]) { ... lines removed for clarity ... sz._1 match { case Pair(0, c2) => currentStatementName = "Clear Text"; gd(); as(traceAll); stmtClearText(c2) ... lines removed for clarity ... case Pair(6, txt) => currentStatementName = "Enter Text"; gd(); as(traceAll); stmtEnterText(txt) ... lines removed for clarity ... case Pair(18, pos) => currentStatementName = "Move Mouse"; gd(); as(traceAll); stmtMoveMouse(pos) } ... lines removed for clarity ... }
|
The code below illustrates how the enter text statement is executed. The code seems to rely on java.awt.Components having an actionEnterText(String) method! To understand this, check out SWELL Document Object Model below.
An important part of the SWELL grammar is the SwingQuery, a construct that enables any GUI component to be referred using natural-English phrases.
| AST |
Handler Code |
Array( | Choice( | | Pair(0, [STRING]), | | Pair(1, [VAR]) | ), | @swingQuery )
|
private def stmtEnterText(txt: Any) = { txt match { case Array(value: Pair[Int, _], compChoice) => Utils.swingQuery(compChoice) match { case c: Component => value match { case Pair(0, strStr: String) => c.actionEnterText(Utils.unEscape(Utils.unQuote(strStr))) ... lines removed for clarity ... } case x => throw new NotAwtComponent(Utils.scalaTypeOf(x)) } } }
|
Because Swing components are central to the purpose of SWELL, its parser-rules are peppered with references to swingQuery (see Swing-Query Syntax below). The article will not go into the details of the SwingQuery grammar, but readers are encouraged to analyze and test the grammar within the VisualLangLab IDE.
| AST |
Handler Code |
List( | Choice( | | Pair(0, @treePath), | | Pair(1, | | | Array( | | | | [INT], | | | | [INT] | | | ) | | ), | | Pair(2, @uniqueComponentSelector), | | Pair(3, @methodCall), | | Pair(4, [INLINE_CODE]), | | Pair(5, @componentSelector), | | Pair(6, [VAR]) | ) )
|
def swingQuery(mc: Any) = mc match { case tPath: List[Pair[Int, _]] => var expr: Any = null tPath.reverse.foreach(x => x match { case Pair(0, tp: List[_]) => expr match { case jt: JTree => expr = treePath(jt, tp).last ... lines removed for clarity ... } ... lines removed for clarity ... case Pair(1, Array(r, c)) => ... lines removed for clarity ... case Pair(2, ucs) => ... lines removed for clarity ... }) expr }
|
The AST and code below illustrate the last step in the rule chain in Figure 4 above.
| AST |
Handler Code |
List( | Choice( | | Pair(0, [STRING]), | | Pair(1, [INT]), | | Pair(2, [INLINE_CODE]) | ) )
|
def treePath(jt: JTree, path: List[_]) = { path.foreach(p => p match { case Pair(0, strStr: String) => ... lines removed for clarity ... case Pair(1, strInt: String) => ... lines removed for clarity ... case Pair(2, code: String) => ... lines removed for clarity ... }) ... lines removed for clarity ... }
|
SWELL has DOM and SQL (Swing Query Language) Too!
The term DOM is used here in a sense similar to the web-browser usage. The SWELL DOM is a conceptual tree that contains all of the GUI's visual java.awt.Components. The DOM is implemented by the RichComponent class in the SWELL sources (see the src directory inside swell-article-resources.zip). RichComponent and its companion object leverage pimp my library (also see this paper from SigBovik 2010) to magically endow the lowly java.awt.Component with interesting methods and properties.
As explained above, a SwingQuery is a parser-rule (see Figure 8 below) that enables SWELL scripts to refer any GUI component using natural-English (Swing Query Language or SQL) phrases. SWELL's SQL is, in every sense, the heart of SWELL. The English-like character of SWELL scripts comes entirely from SQL. The power of the DOM would be completely wasted if the SWELL user wasn't able to identify a GUI element using an English-like phrase.

Figure 8. The Swing-Query syntax
The SQL grammar is based on the premise that the DOM is rooted at the top-level window. Any GUI Component can be uniquely identified by any one of the following:
- a set of attribute values that uniquely identify the component in the local context
- a path from the root to the Component of interest, where each intermediate step is a uniquely identified component
We give a few real examples here to clarify the concepts described above. The graphics in these examples are slightly modified versions of screens captured during tests on the CIIMS messaging-framework for airports from Unisys.
The following SWELL statements illustrate the use of SQL to work with the login dialog panel shown in Figure 9 below. In each SWELL statement, the underlined part is the SQL.
- key "USER01" into the first textfield of the "Login" dialog - key "pass123" into the passwordfield of the "Login" dialog - key "FATS01" into the 2nd textfield of the "Login" dialog # the following 3 lines are equivalents, and any one may be used - click the 1st button of the "Login" dialog - click the first button of the "Login" dialog - click the "Login" button of the "Login" dialog - click the button with text = "Login" of the "Login" dialog
In all of the above SWELL statements, [... of the "Login" dialog] would have worked as well since there is only one visible dialog, and the type (dialog) itself identifies the component uniquely.

Figure 9. Locator syntax for GUI Components
SQL can also be used with more complex GUI structures. The following two examples show how the syntax is used to access nodes of a JTree and cells of a JTable respectively.

Figure 10. Locator syntax for JTree elements
Figure 10 above shows a JFrame main window containing a JInternalFrame that in turn contains a JTree. Parts of the figure are annotated with alphabetic markers to facilitate referencing from the following explanation.
- the JInternalFrame itself (A) is located with:
the "Flow" internalframe
- the JTree (B) is located with:
the tree of the "Flow" internalframe
- the "Events" node (C) of the JTree is located with:
node / "Events" of the tree of the "Flow" internalframe
- the "TESTEVENT" node (D) of the JTree is located with:
node / "Events" / "TESTEVENT" of the tree of the "Flow" internalframe
- the "TESTEVENT" node may also be located with:
node / 2 / "TESTEVENT" of the tree of the "Flow" internalframe, or
node / "Events" / 0 of the tree of the "Flow" internalframe, or
node / 2 / 0 of the tree of the "Flow" internalframe
The JFrame main window in Figure 11 below contains a JInternalFrame that in turn contains a JTable. The alphabetic markers facilitate referencing from the following explanation.

Figure 11. Locator syntax for JTable elements
- the JInternalFrame itself (A) is located with:
the "Statistics" internalframe
- the Start button (B) is located with:
the "Start" button of the "Statistics" internalframe
- the JTable (C) is located with:
the table of the "Statistics" internalframe
- the outlined cell (D) of the JTable is located with:
cell 17 1 of the table of the "Statistics" internalframe
SWELL Language Manual
This is a short guide to the SWELL language. More details can be found at the SWELL project site.
SWELL Statements
The following table lists all SWELL statements.
| Statement |
Description |
Grammar-Tree Name |
| After-Each-Test |
Introduces a list of statements that are executed after the completion of each and every test (irrespective of the test outcome) |
stmtAfterEachTest |
| Before-Each-Test |
Introduces a list of statements that are executed before each |
stmtBeforeEachTest |
| Clear-Text |
Clears the text in the specified Component |
stmtClearText |
| Click |
Performs a simple mouse-click over the middle of the specified Component. Left Click and Right Click are also available. |
stmtClick |
| Collapse |
Collapses the specified tree node |
stmtCollapse |
| Delay |
Causes the test execution to be delayed by the specified duration |
stmtDelay |
| Display |
Displays the specified string in the test log (same as print) |
stmtDisplay |
| End |
Ends either the current test or the entire test suite and prints the specified message to the test log |
stmtEnd |
| Enter-Text |
Enters the supplied string into the specified Component |
stmtEnterText |
| Exec |
Exectues the specified SWELL file as a sub-process |
stmtExec |
| Expand |
Recursively expands the specified tree node |
stmtExpand |
| Fail-If |
Specifies a condition (and associated message) for a negative test outcome |
stmtFailIf |
| Focus |
Moves focus to the specified Component |
stmtFocus |
| If |
A conditional control flow statement |
stmtIf |
| Key-Text |
Keys the supplied text into the specified Component |
stmtKeyText |
| Launch-GUI |
Launches the specified GUI program |
stmtLaunchGui |
| List-Components |
Lists (on the test log) one or more Components selected |
stmtListComponents |
| Locate-Components |
Helps to locate one or more Components by coloring them |
stmtLocate |
| Maximize |
Maximizes the specified internal frame |
stmtMaximize |
| Minimize |
Minimizes the specified internal frame |
stmtMinimize |
| Move-Mouse |
Moves the mouse over the middle of the specified component |
stmtMoveMouse |
| Pause |
Pops up a blocking dialog with the specified message |
stmtPause |
| Perform |
Executes a previously declared group or some embedded-code |
stmtPerform |
| Print |
Prints the supplied string (with variable substitutions) to the test log |
stmtPrint |
| Reference (or Assignment) |
Assigns a value to a variable |
stmtReference |
| Select |
Executes a GUI operation involving one or more selections from menus or lists |
stmtSelect |
| Set |
Obsolete, do not use |
stmtSet |
| Suite-Begins |
The suite header line |
stmtSuitBegins |
| Suite-Ends |
The suite trailer line |
stmtSuitEnds |
| Trace |
Starts or ends tracing |
stmtTrace |
| Unless |
The unless statement is an inverse if statement |
stmtUnless |
| Wait |
Causes execution to be delayed till the specified event occurs |
stmtWait |
| WarnIf |
Causes a warning to be issued to the test log if the specified condition occurs |
stmtWarnIf |
| While |
The usual procedural control flow statement |
stmtWhile |
Embedded Code
Several SWELL statements allow the use of embedded Scala code. Embedded Scala code must be enclosed within doubled curly-braces, like this: {{your code here}}. Check the token INLINE_CODE for details.
Durations
Time durations in SWELL may be expressed either as seconds or milli-seconds. The unit specification (which follows the magnitude) may be any of the following: s, second, seconds, milli second, milli seconds, ms. Review the parser-rule timeDuration for details.
Variables
Several SWELL statements require (or optionally permit) the use of variables. Variable names are user-chosen following the usual conventions of contemporary programming languages. Variable references are given using the form ${variable name}. Check the token called VAR
Conclusion
The article introduces the SWELL domain-specific language for testing Swing GUIs. The SWELL interpreter uses the completely visual parser-generator VisualLangLab, so the design of SWELL described in the article is also a generic framework for DSLs that use VisualLangLab as their parser-generator.
The SWELL interpreter (being developed at the SWELL Project) is already usable and reliable enough to be valuable in real-world development projects. The authors plan to continue improving upon this early code base to improve the tool further.
Acknowledgements
We would like to thank the following folks at TwoPiRadian Infotech (2PiRad): Prodipta Golder, Debopam Ghoshal, and Ramanendu Chatterjee for the numerous discussions and great ideas that helped to shape the DSL, and Jishnu Ray for editorial comments and guidance on the article contents. The DSL was analyzed, reviewed and refined in lively discussions with many others, and the world's population of DSLs would be one less without 2PiRad's amazing people and environment.
TwoPiRadian Infotech is a boutique software solutions developer, specializing in developing dynamic web applications, rich internet applications, collaboration and content management systems. They have in-depth experience in the new generation software technology platforms covering key business domains (airports, airlines, travel & hospitality, and financial services)
References
swell-article-resources.zip
References
Sanjay Dasgupta has been using Java for telecom applications since 1996 (after many years of using many different languages in many industries).
Chirantan Kundu is Analytics Principal at TwoPiRadian Infotech (http://www.2pirad.com/). He has been designing and developing software, and managing software projects for over 15 years
|
VisualLangLab - Grammar without Tears Date: 09/14/2011
Introduction to parser development using the completely visual tool, VisualLangLab
Introduction to parser development using the completely visual tool, VisualLangLab
Introduction to parser development using the completely visual tool, VisualLangLab.
In the world of computing a grammar is a somewhat different thing
from the object implied in
grammar without tears.
But in terms of the misery caused to those
who have to deal with them, the two grammars appear to be closely related.
This article describes a no tears approach to parser development
using the free, open-source parser-generator VisualLangLab.
It has an
IDE that represents grammar rules
(or productions)
as intuitive trees, like those in Figure 1 below,
without code or scripts of any kind.

Figure 1. VisualLangLab's grammar-trees
The grammar-trees are also executable, and can be run directly
at the click of a button.
This encourages the use of tight
iterative-incremental
development cycles, and improves the pace of development manyfold.
These features also make it an effective prototyping environment and a training tool.
VisualLangLab is itself written in
Scala, a
JVM language that supports object orientation as well as
functional programming,
but you don't have to know much Scala to use VisualLangLab.
Parsing techniques and parser-generator tools are a great addition
to any developer's arsenal,
and VisualLangLab provides a convenient, gentle introduction to those topics.
A later article will describe the use of VisualLangLab to produce
a domain specific language or
DSL
for testing Java-Swing programs.
A periodically
revised version of this article that stays compatible with the current version of
VisualLangLab can be seen here.
Can I see the Generated Code?
As a now-famous panda discovered, powerful recipes sometimes have
no secret ingredient.
And there is no generated code.
VisualLangLab uses Scala's parser
combinator
functions to turn grammar-trees (or XML from a
saved grammar-file) directly into a
parser
at run-time without producing or compiling source-code.
But users of the GUI and the API
do not have to know anything about combinators to use these capabilities.
Download and Run VisualLangLab
The VisualLangLab web site has a
zip file
that includes everything you need. The only prerequisite is a 1.6+ JDK or JRE.
To run the tool, proceed as follows.
No Scala Installation
A Scala installation is not a mandatory prerequisite.
If you do not have Scala (or just want to avoid version issues),
download the executable JAR file
VLLS-All.jar
(which bundles the required Scala libraries).
VisualLangLab is started by double-clicking VLLS-All.jar
in a file browser, or by issuing the following command at a system prompt:
java -jar VLL-All.jar
Linux or UNIX users will, of course, have to enable execution (chmod +x ...)
to have it start by double-clicking.
Have a Scala Installation
To run VisualLangLab with your installed version of Scala
use one of the launchers included in the zip file
(vlls.bat for Windows, vlls for Linux).
Linux or UNIX users will need to enable execution (chmod +x ...)
of the launcher script.
The GUI
When started, VisualLangLab displays the GUI shown in Figure 2 below.
The article explains the menus and buttons as needed, but a full
description can also be found online at
The GUI and in the download zip.
All toolbar buttons have tool-tip texts that explain their use.

Figure 2. The VisualLangLab GUI
The graphical and text panels are used as described below.
The following sections are a tutorial introduction that lead you through the
steps of creating a simple parser.
Managing Tokens
There are two kinds of token, literal and regex, that
the following discussion and examples will help you differentiate.
We create 2 literals and 1 regex that are
used in a rule later.
Literal Token Creation
To create a literal token select Tokens -> New literal from the main
menu as in Figure 3 below. Enter the literal's name (PLUS),
a comma, and the pattern (+) into the popped up dialog box and click
the OK button.
A token's name is used to refer to it from
rules, while the pattern describes its contents.
All instances of a particular literal token (during the parser's run)
have the same fixed content.
Now create another literal token
named MINUS with a - pattern (as in the second dialog box
in Figure 3).

Figure 3. Creating a literal token
Regex Token Creation
Figure 4 below shows how you can create a regex token.
Select Tokens -> New regex from the main menu,
and enter the token's name (NUMBER), a comma, and the
pattern (\\d+) into the dialog box and click OK.
You probably recognize the pattern as a Java
regular-expression
that matches numbers.

Figure 4. Creating a regex token
Observe that the pattern part in the dialogs above (for literal as well as regex tokens)
should be written exactly as if they were inside a String in a Java program
(without the surrounding quote marks).
There is not a great deal more to tokens, but if you would like to read the
fine print, check out the last part of
Editing the Grammar Tree.
Miscellaneous Token Operations
The main menu and toolbar also support several other operations. You can find which
rules use any particular token (Tokens -> Find token),
edit tokens (Tokens -> Edit token), and delete unused tokens (Tokens -> Delete token).
Token Libraries
Tokens tend to be reused within application domains, so VisualLangLab allows you to
create and use token libraries. These operations are invoked from the main menu
by selecting Tokens -> Import tokens and Tokens -> Export tokens,
or by using corresponding toolbar buttons.
Whitespace and Comments
You can specify the character patterns that separate adjacent tokens by invoking
Globals -> Whitespace from the main menu, and entering a regular expression
into the popped up dialog box. The default whitespace specification is "\\s+".
You can also provide a regular expression for recognizing comments in the input text.
Select Globals -> Comment from the main menu, and enter a regular expression
into the dialog box. There is no default value for this parameter.
Managing Rules
VisualLangLab represents rules as grammar-trees with distinctive icons
(as in Figure 1 above) and
a context-sensitive popup-menu.
This graphical depiction makes grammars comprehensible to a wider range of users.
The icons and textual annotations used in the grammar-trees are described below.
Node Icons
The table below lists the icons from which grammar-trees are constructed.
| Non-terminals |
 |
Root - used for the root
node of every grammar tree |
 |
Choice - used as the parent of a group
of alternative items (any one of which occurs in the input) |
 |
Sequence - used as the parent of a
sequence of items which occur in the order specified |
 |
RepSep - parent of a sequence
of similar items that also uses a specified separator |
 |
Reference - invokes another
named parser |
 |
Semantic predicate -
succeeds or fails depending on the run-time value of an expression |
| Terminals |
 |
Literal - matches a
specified literal token |
 |
Regexp - matches a
specified regex token |
| Icon overlays |
 |
Commit - displayed on top
of a node that has the commit annotation |
 |
Error: indicates an error
in the associated node or rule |
Node Annotations
Each grammar-tree node has characteristics (such as multiplicity) that are
represented as the node's annotations, and
are displayed as text beside each node's icon. You can change a node's
annotations by right-clicking the node and choosing the required settings
from the context-menu as in Figure 5 below.

Figure 5. Setting node annotations
The first annotation is a 1-character flag that indicates the node's multiplicity
-- the number of times the corresponding entity may occur in the parser's input.
You can see examples of its use everywhere in the built-in
Sample Grammars.
Multiplicity has one of the following values:
- 1 - exactly one occurrence
- ? - 0 or 1 occurrence
- * - 0 or more occurrences
- + - 1 or more occurrences
- 0 - the associated entity must not occur in the input (but see note below)
- = - the associated entity must occur in the input (but see note below)
Note: Observe that the last two values ("0" and "=") are actually commonly required
syntactic predicates
and have no influence on the structure of the
AST. The names not and guard are inspired
by functions of the same name and function in Scala's
Parsers.
The second annotation is the name of the entity. The value displayed depends on the
type of the node as described below.
- Root - the name of the parser rule itself
- Literal - the name of the literal token
- Regexp - the name of the regular-expression token
- Reference - the name of referred-to parser-rule
- Choice - the description (see below) if defined
- Sequence - the description (see below) if defined
- RepSep - the description (see below) if defined
- Semantic predicate - the description (see below) if defined
All icons have at least the two annotations described above. All other annotations,
described below, are optional. If any of the optional annotations are present, they are
enclosed within square brackets.
- commit - backtracking to optional parser clauses (at an upper level) will be
prevented if this node is successfully parsed
- description - an optional user-assigned string (see below) that can be assigned
to certain types of node
- drop - the node will not be entered into the AST. You can see examples of
its use in the built-in ArithExpr Sample Grammars
- message - the node's associated error-message
- packrat - the parser-rule is a
packrat parser
(applicable only to a root-node)
- trace - the parser's use of the node will be logged at run-time
All node attributes can be reviewed and changed via the context-menu as shown in
Figure 5 above.
Creating Rules
The grammar-tree popup menu is the tool used for creating and editing grammar trees,
and is described fully in
Editing the Grammar Tree.
In the following example we get our feet just a little wet by composing a simple rule
with the tokens we created above.
First, add a Sequence node to the grammar-tree by right-clicking the root node
( ) and selecting
Add -> Sequence from the popup menu as shown on the left side of Figure 6 below.
A sequence icon
( ) is added to the root,
as on the right of the figure.

Figure 6. Adding a sequence node
Then perform the following steps:
- right-click the newly added sequence node
( ) and select Add -> Token.
This will bring up a dialog containing a list of token names.
Select NUMBER and click the dialog's OK button.
A regex icon ( ) is added
to the sequence node
- right-click the sequence node again and select Add -> Choice from the popup menu.
This should add a Choice node icon
( )
to the sequence node
- right-click the newly created choice node (
)
and select Add -> Token.
Select PLUS in the dialog box and click OK.
A literal icon ( )
is added to the choice node.
Repeat this action once more, and add the MUNUS token to the choice node
- repeat the first step above to add another NUMBER to the sequence node
You're done! If your parser does not look like the one in Figure 7 below,
use Edit from the grammar-tree's context menu to make the required changes.

Figure 7. Your first visual parser
The text displayed in the panel to the right of the grammar-tree is the
AST of the selected node,
and so depends on which icon you clicked last.
Miscellaneous Rule Operations
The main menu and toolbar also support several other operations. You can find which
other rules refer any particular rule (Rules -> Find rule),
rename rules (Rules -> Rename rule), and delete unused rules (Rules -> Delete rule).
Saving the Grammar
A grammar can be saved to a file by invoking File -> Save from the main menu.
Grammars are stored in XML files with a .vll suffix.
The contained XML captures the structure of the rules, the token definitions, and
other details, but no generated code of any kind.
The XML is quite intuitive and you can use XSLT or a similar technology to
transform it into another format
(a grammar for another tool, or code of some sort, for example) if required.
A saved grammar can be read back into the GUI by invoking File -> Open from
the main menu. This is useful for review, further editing, or testing.
The API can also load a saved grammar,
and regenerate the parser for use from a client program.
Testing your Parser
Testing is really simple. Key in the test input under
Parser Test Input (as at "A" in Figure 8 below),
click the Parse input button (under the red rectangle),
and validate the output that appears under Parser Log
(at "C" in the figure).
You don't have to write any code, use any other tools, or do anything else.

Figure 8. Testing your parser
The figure shows the result of testing the parser with "3 + 5"
as the input.
The Parser Log are should contain the following text:
Generating parsers ... (10 ms) Parsing ... (3 chars in 0 ms), result follows: <u>Array(3, Pair(0, +), 5)</u>
The first two lines contain performance information that is safely ignored.
The last line (underlined) is the parser's result. The result is an
AST
with a predefined structure shown under Parse Tree (AST) Structure.
Since the test input entered was "3 + 5", we know that the result is correct.
However, real-life parsers are too complex for manual testing, so VisualLangLab supports
several approaches to automated testing that are described online in
Testing Parsers.
That brings us to the end of this quick example. If you feel that the result of
parsing "3 + 5" should be 8 instead of Array(3,Pair(0,+),5) check out
the section ArithExpr with action-code in
Sample Grammars.
The Parse-Tree (or AST)
The terms parse-tree and
Abstract Syntax Tree
(or just AST) are used interchangeably to mean the
structure of information gathered during the parsing process.
VisualLangLab displays the AST of the selected grammar-tree node in the text area
under Parse Tree (AST) Structure as seen in Figure 7 above.
ASTs are constructed from mutually nested instances of certain standard Scala types,
so a rudimentary understanding of their main features is useful.
Examples and more details can be found online at
AST and Action Code or
in the downloaded zip.
Action Code
Action-code (or just actions) are Scala or Javascript
functions associated with grammar-tree nodes, and entered into the text
area under Action Code ("C" in Figure 2 above).
It is never necessary to have action code embedded in the
grammar — you can always remove all code into an application program that invokes
the parser via the API, and then processes the
AST returned by it.
You can see examples of action-code in the ArithExpr with action-code
sample grammar, and more details can be found online at
AST and Action Code
or in the downloaded zip.
Using the API
The VisualLangLab API enables applications written in Scala (and Java with
some awkwardness) to use parsers created with the GUI. The API is very small,
and contains the types and functions required to perform the following
operations.
- load a parser from a saved grammar-file
- parse a string using the parser
- test the result, and retrieve the AST or error information
More details and examples can be found online at
Using the API.
Sample Grammars
To enable users to quickly gain hands-on experience with VisualLangLab grammars,
the tool contains some built-in sample grammars. These samples can be reviewed,
tested, modified, and saved just like any other grammar created from scratch.
To open a sample grammar select Help -> Sample grammars from the main
menu, and choose one of the samples shown as in Figure 9 below.

Figure 9. Sample grammars available
More information about these samples can be found online at
Sample Grammars or
in the downloaded zip file.
Differences from Scala's Combinators
The class diagram
in Figure 10 below shows VisualLangLab's relationship with Scala's parser combinators.

Figure 10. Relationship With Scala parser combinators
However, the tool's classes override and augment a few key functionalities of the
underlying Scala classes, so the behavior and AST of VisualLangLab's parsers
is significantly different in certain ways.
- The Literal and Regex node types use an internal
lexical analyzer,
and do not match input text in the same way
as RegexParsers's
literal() and regex() methods
- The Sequence and Choice node types use
Parsers's
~ and | combinators internally, but have different return types
More details can be found online
at Relationship with Scala Parser Combinators,
or in the downloaded zip.
Conclusion
The article introduces readers to parser development using the completely visual
tool VisualLangLab.
Its features make it an effective prototyping environment and a training tool,
and will hopefully be a useful addition to any developer's skills.
Resources (or References)
Sanjay Dasgupta has been using Java for telecom applications since 1996 (after many years of using many different languages in many industries).
|
Streamline JSF Development with These 3 Facelets Must-Knows Date: 07/22/2011
Learn how Facelets can help you speed up JSF development.
Learn how Facelets can help you speed up JSF development.
Learn how Facelets can help you speed up JSF development.
Facelets offers a powerful way to organize and streamline JSF development. When a cat is thrust into the air, it magically lands upright and safely on its feet. Sadly, this is not always the case with software especially when tinctured with aggressive timelines and insufficient requirements. Facelets is to JSF what the magic is to the cat and can help avoid a CAT-astrophe.
This article is organized as follows: first, decorators are introduced and the underused yet powerful ui:decorate feature is leveraged; next, a powerful custom validator is built, with relatively little code setup; the third section shows how to re-use related form fields and encapsulate complex cross field behavior using ui:include; the concluding section takes all of these concepts and weaves them together.
Leveraging ui:decorate
Just as there are many ways to skin a cat, Facelets ui:decorate affords a way to skin, well, just about anything you can find in a JSF page. Let's take, for instance, a form section container used to visually group form fields and see how to give it a bit of mojo.
Before we do that, let's introduce a simple example. Figure 1 shows a screen shot of the text "Hello Facelets!" wrapped in a decorator. The decorator wraps the text with a green background and a rounded green border.

Figure 1. Hello Facelets!
Listing 1 shows the code used to decorate the text.
Listing 1. /WebContent/example/example1.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 05 <html xmlns="http://www.w3.org/1999/xhtml" 06 xmlns:ui="http://java.sun.com/jsf/facelets" 07 xmlns:f="http://java.sun.com/jsf/core" 08 xmlns:h="http://java.sun.com/jsf/html"> 09 10 <body> 11 <h:form> 12 <ui:decorate template="/WEB-INF/widget/formDecorator.xhtml"> 13 Hello Facelets! 14 </ui:decorate> 15 16 ... 17 </h:form> 18 </body> 19 </html>
The mojo is that it only took 2 lines to achieve this effect; lines 12 and 14. The content you want to decorate is sandwiched between
the <ui:decorate...> and </ui:decorate> tags. The template attribute on line 12 refers to the file that is used to perform the decorating. Line 6 declares the Facelets namespace. In our example, we decorated the text "Hello Facelets!" but we could have just as easily have decorated form fields as seen in Figure 2. To do this, we would simply replace the text "Hello Facelets!" with a group of form fields.

Figure 2. Decorate a grouping of form fields.
Listing 2 shows formDecorator.xhtml, the template responsible for creating this effect. We'll refer to it as the decorator. Lines 9-33 represent the stylesheet. The stylesheet is entirely responsible for creating the green background and the rounded green border without any images. Even though there are no images, we could have just as easily have opted to decorate the form fields with a sophisticated image border. In fact, we could conceivable change the border at any time to an image with relatively no impact to the core code since the logic that performs the decorating is localized within the decorator. In other words, change the decorator and all that is decorated gets a new skin. The ui:insert on line 47 is where the action begins. Conceptually, you can think of the ui:insert as being replaced with the content inside the start and end ui:decorate tags of Listing 1.
Listing 2. /WEB-INF/widget/formDecorator.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 <html xmlns="http://www.w3.org/1999/xhtml" 05 xmlns:ui="http://java.sun.com/jsf/facelets" 06 xmlns:f="http://java.sun.com/jsf/core" 07 xmlns:h="http://java.sun.com/jsf/html"> 08 09 <style> 10 .wrapper { width: auto; } 11 * { border-color: #9CE6AE; } 12 .wrapper * { background-color: #DCFAB9; } 13 .wrapper .horizontalEdge, .wrapper .curvedEdge1, .wrapper .curvedEdge2, .wrapper .verticalEdge{ 14 font-size: 1px; 15 display: block; 16 height: 1px; 17 overflow: hidden; 18 } 19 .wrapper .curvedEdge1, .wrapper .curvedEdge2, .wrapper .verticalEdge{ 20 border-width: 0px 1px 0px 1px; 21 border-style: solid; } 22 .wrapper .horizontalEdge { 23 border-style: solid; 24 border-width: 1px 0px 0px 0px; 25 margin: 0px 5px; } 26 .wrapper .curvedEdge1 { margin: 0px 3px; } 27 .wrapper .curvedEdge2 { margin: 0px 2px; } 28 .wrapper .verticalEdge { margin: 0px 1px; height:2px; } 29 .wrapper .content { 30 border-width: 0px 1px 0px 1px; 31 border-style: solid; 32 padding: 0px 5px; } 33 </style> 34 35 36 <table width="80%"> 37 <tr> 38 <td> 39 <div class="wrapper"> 40 <span> 41 <span class="horizontalEdge"></span> 42 <span class="curvedEdge1" ></span> 43 <span class="curvedEdge2" ></span> 44 <span class="verticalEdge" ></span> 45 </span> 46 <div class="content"> 47 <ui:insert /> 48 </div> 49 <span> 50 <span class="verticalEdge" ></span> 51 <span class="curvedEdge2" ></span> 52 <span class="curvedEdge1" ></span> 53 <span class="horizontalEdge" ></span> 54 </span> 55 </div> 56 </td> 57 </tr> 58 </table> 59 </html>
Not only is the ui:decorate great for adding skins to the form body, form sections, and so on, but it's also perfectly suited for widget creation. In this next example, we'll see how to use a RichFaces rich:modalPanel using decorate and, to make it more interesting, we'll experiment with passing in parameters. Even though the code example utilizes RichFaces, keep in mind that the intention is to introduce the concepts and plant the idea that decorators can be used for widget creation. Figure 3 shows a link which, when clicked, will open the modal panel.

Figure 3. Modal panel link.
The modal panel that opens will display instructions on where to find the secure id as seen in Figure 4.

Figure 4. Modal panel after the link has been clicked.
Listing 3 shows the code that will be decorated.
Listing 3. /WebContent/example/example2.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 <html xmlns="http://www.w3.org/1999/xhtml" 05 xmlns:ui="http://java.sun.com/jsf/facelets" 06 xmlns:f="http://java.sun.com/jsf/core" 07 xmlns:h="http://java.sun.com/jsf/html"> 08 09 <body> 10 11 12 13 <h:form> 14 15 <table> 16 <tr> 17 <td align="left"> 18 <ui:decorate template="/WEB-INF/widget/modalPanel.xhtml"> 19 <ui:param name="linkText" value="How do I find my credit card's secure id?"/> 20 <ui:param name="title" value="Credit Card Security Code"/> 21 <ui:param name="id" value="creditCard"/> 22 The security code is the four digit number shown 23 above the credit card number on the right-hand. 24 </ui:decorate> 25 </td> 26 </tr> 27 </table> 28 29 30 ... 31 </h:form> 32 33 </body> 34 </html>
Line 18 is the name of the template that will perform the decorating. Lines 19, 20, and 21 are the parameters that are passed to the decorator.
We pass it 3 parameters. The linkText parameter on line 19 is used to display the link we saw in Figure 3.
The title parameter on line 20 will be displayed in the modal panel's title bar.
The id parameter on line 21 is the unique id. Let's talk about this last parameter a bit more.
Since every JSF component must have a unique id and our modal panel can appear multiple times on a page, the id attribute takes care of this constraint by allowing the id to be passed in from the calling code. Now the onus is on the calling code to make sure the id is unique which is how it should be.
Listing 4 shows the modal dialog template that performs the decorating.
Listing 4. /WEB-INF/widget/modalPanel.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 05 <f:subview xmlns="http://www.w3.org/1999/xhtml" 06 xmlns:ui="http://java.sun.com/jsf/facelets" 07 xmlns:h="http://java.sun.com/jsf/html" 08 xmlns:f="http://java.sun.com/jsf/core" 09 xmlns:rich="http://richfaces.org/rich"> 10 11 12 <rich:modalPanel width="300" height="100" 13 autosized="true" id="panel#{id}" > 14 <f:facet name="header"> 15 <h:panelGroup> 16 <h:outputText value="#{title}"></h:outputText> 17 </h:panelGroup> 18 </f:facet> 19 <f:facet name="controls"> 20 <h:panelGroup> 21 <a onclick="Richfaces.hideModalPanel('panel#{id}');" 22 style="font-family:arial;cursor:hand;">X Close</a> 23 </h:panelGroup> 24 </f:facet> 25 26 27 <div style="overflow-y:auto;"> 28 <table> 29 <tr> 30 <td align="left"> 31 <ui:insert /> 32 </td> 33 </tr> 34 </table> 35 36 </div> 37 </rich:modalPanel> 38 39 <a onclick="Richfaces.showModalPanel('panel#{id}', {top:'20px', left:'20px', height:'100'});" > 40 41 <h:outputText value="#{linkText}" 42 style="font-family:arial;font-size:11pt;cursor:hand;"></h:outputText> 43 </a> 44 </f:subview>
Line 12 starts the rich:modalPanel and on line 13, its #{id} is going to be replaced with the id parameter being passed in.
In Listing 3 we passed in creditCard as the parameter value for the id, therefore, the modal panel id will become panelcreditCard ("panel" is prepended to "creditCard").
On line 16 the title parameter passed in, "Credit Card Security Code", displays in the titlebar of the modal panel.
Lines 21-22 indicate that when the "X Close" link is clicked, a call to the internal richfaces method hideModalPanel will be made.
On line 31, the ui:insert inserts the text that explains how to locate the credit card's secure id. Finally, lines 41-42 display the linkText.
The mechanics of opening and closing the modal dialog along with its look and feel are encapsulated within the modalPanel.xhtml. This is how we want it to be.
Simplifying Form Field Validation
JSF (version 1.2 and earlier) has a handful of built in validators that are somewhat limited in what they offer. This leaves most of the heavy lifting of custom validation to us. Not an insurmountable task but can be a little pesky and somewhat unwieldy. Fortunately, there's a simple solution that leverages Facelets and allows us to create a custom validator much in the parlance of JSF's validation but with a few mighty perks. For one, the code to setup the custom validator is a lot less complicated and involved. Secondly, the custom validator accepts any number of arguments to be passed to it. In turn, Facelets will take care of auto-magically wiring the individual attributes found in the JSF tag directly into the custom validator class's fields. It does this by matching the attribute name in the tag to the corresponding class's field name. To understand this better, let's look at some code snippets that use a regex custom validator. You may be wondering, what's the point of illustrating a regex validator when JSF 2.0 already supports one. The idea is, once you understand the concept, you can extend the idea and tailor it to your individual project needs. With that said, let's move onto our example. The form contains a credit card field. When a user enters a credit card number, we want the value to be validated once the submit button is clicked. If the value entered doesn't pass validation we want the form to display an error message. Our tag has 2 attributes, regex and errorMessage. Let's look at the following code snippet:
<example:regexValidator regex="([A-Za-z0-9 ]{0,20})" errorMessage="The credit card number is invalid." />
regex is the regular expression that the form field value must conform to. errorMessage will be the error message that displays when the credit card number entered doesn't pass the regex validation. So in our example, the custom validator will be passed 2 arguments.
Here's the java class code snippet for the custom validator:
private String regex; private String errorMessage;
You can see that the tag attributes and the field names are identical. regex will be passed ([A-Za-z0-9 ]{0,20}) and errorMessage will be passed "The credit card number is invalid".
To see how this is put together, let's look at Listing 5 which shows how the custom validator is used. Line 9 declares the regex validator's namespace. On lines 25-26 the custom validator is used to validate the credit card number using the 2 attributes.
Listing 5. /WebContent /example/example3.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 05 <html xmlns="http://www.w3.org/1999/xhtml" 06 xmlns:ui="http://java.sun.com/jsf/facelets" 07 xmlns:f="http://java.sun.com/jsf/core" 08 xmlns:h="http://java.sun.com/jsf/html" 09 xmlns:example="http://example.regex"> 10 11 <body> 12 13 <h:form> 14 <table> 15 <tr> 15 <td align="right" style="font-family:arial;font-size:11pt;"> 17 Credit Card Number: 18 </td> 19 20 <td align="left"> 21 <h:inputText 22 value="#{myBean.creditCardNumber}" 23 maxlength="20" size="20" 24 id="idCreditCardNumber"> 25 <example:regexValidator regex="([A-Za-z0-9 ]{0,20})" 26 errorMessage="The credit card number is invalid." /> 27 </h:inputText> 28 </td> 29 30 </tr> 31 </table> 32 ... 33 34 </h:form> 35 36 </body> 37 </html>
Next, we'll walk through the setup needed to make this work.
Step 1. Create a file called regexValidatorTag.xml and place it in the WEB-INF directory.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "http://java.sun.com/dtd/facelet-taglib_1_0.dtd"> <facelet-taglib xmlns="http://java.sun.com/JSF/Facelet"> <namespace>http://example.regex</namespace> <tag> <tag-name>regexValidator</tag-name> <validator> <validator-id>exampleRegexValidator</validator-id> </validator> </tag> </facelet-taglib>
Step 2. Add an entry to the faces-config that looks like this:
<validator> <validator-id>exampleRegexValidator</validator-id> <validator-class>com.company.example.validator.RegexValidatorExample</validator-class> </validator>
Step 3. Add the namespace, xmlns:example=http://example.regex, to your jsf file as seen here:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:example="http://example.regex">
Step 4. Add a tag to the web.xml as follows:
<context-param> <param-name>facelets.LIBRARIES</param-name> <param-value>/WEB-INF/regexValidatorTag.xml</param-value> </context-param>
Step 5. Create the custom validator class.
01 package com.company.example.validator; 02 03 import java.util.regex.Pattern; 04 import java.util.regex.Matcher; 05 import org.apache.commons.lang.StringUtils; 06 import javax.faces.validator.Validator; 07 import javax.faces.validator.ValidatorException; 08 import javax.faces.application.FacesMessage; 09 import javax.faces.component.StateHolder; 10 import javax.faces.component.UIComponent; 11 import javax.faces.context.FacesContext; 12 13 public class RegexValidatorExample implements Validator, StateHolder { 14 15 //required by StateHolder interface 16 private boolean isTransient; 17 18 //required by StateHolder interface 19 private boolean transientValue; 20 private String regex; 21 private String errorMessage; 22 23 public RegexValidatorExample() { 24 super(); 25 } 26 27 public void validate(FacesContext context, UIComponent component, Object value) 28 throws ValidatorException { 29 30 31 //boundary checking 32 if ( null == regex || null == value) { 33 return; 34 } 35 String fieldValue= StringUtils.trimToEmpty((String)value); 36 Pattern p = Pattern.compile(getRegex()); 37 38 if(StringUtils.isNotEmpty(fieldValue)){ 39 Matcher matcher = p.matcher(fieldValue); 40 if(!matcher.matches()){ 41 FacesMessage msg = new FacesMessage(); 42 msg.setDetail(errorMessage); 43 msg.setSummary(errorMessage); 44 msg.setSeverity(FacesMessage.SEVERITY_ERROR); 45 throw new ValidatorException(msg); 46 } 47 } 48 } 49 public void restoreState(FacesContext context, Object state) { 50 Object values[] = (Object[]) state; 51 regex = (String) values[0]; 52 errorMessage = (String) values[1]; 53 } 54 55 public Object saveState(FacesContext arg0) { 56 Object values[] = new Object[2]; 57 values[0] = regex; 58 values[1] = errorMessage; 59 return (values); 60 } 61 public boolean isTransient() { 62 return this.transientValue; 63 } 64 public void setTransient(boolean transientValue) { 65 this.transientValue = transientValue; 66 } 67 public String getErrorMessage() { 68 return errorMessage; 69 } 70 public void setErrorMessage(String errorMessage) { 71 this.errorMessage = errorMessage; 72 } 73 public String getRegex() { 74 return regex; 75 } 76 public void setRegex(String regex) { 77 this.regex = regex; 78 } 79 }
Line 16 declares the isTransient field and is required when using the StateHolder interface. The StateHolder, as its name implies, assists with saving the state between requests. Its corresponding getter/setters are on lines 61-66. Line 19 shows the transientValue field which is also required by the StateHolder interface. Line 20, regex, and line 21, errorMessage, have their corresponding getters/setters on lines 67-78. They are hydrated via Facelets which takes care of wiring the values of the tag attributes directly into the getters. Line 27 is where the validation begins. Its argument, Object value, corresponds to the value entered by the user in the form field. Line 36 uses the regex compile to create a Pattern. Lines 39 and 40 check to see that the field value passed in matches the regex pattern. If the field value does not match the regex expression, lines 41-44 set up the FacesMessage using the value in errorMessage. Lines 49-53, restoreState, and subsequently, lines 55-60, saveState, are necessary as they save and restore the attributes (i.e. regex, and errorMessage) being passed in across multiple requests. Line 56 sets up an array size of 2 because we have exactly 2 attributes in the tag. If we decided to use more attributes in the tag, the array size would also have to be augmented so that its size matches the number of tag attributes. The same holds true for lines 50-52.
Getting Form Fields Under Control With ui:include
Have you ever had a situation where, aside from the text label and the underlying bean, the same form field appears sprinkled in multiple locations on a form? Moreover, each occurrence of the same form field is laden down with complex validation and client side behavior. This is where Facelets template reuse comes in handy.
To illustrate, Figure 5 shows 2 sets of phone field groupings that will each re-use the same template. Other than their text label and underlying bean, they're identical from a functional perspective. For example, the Home Phone has a text label followed by an area code, a 3 digit phone prefix, and finally a 4 digit phone suffix. Under the covers it will support auto-tabbing and each its phone fields will have their own validator and display their own error message. The same can be said of the Cell Phone.

Figure 5. Two groupings of phone fields.
Before we go any further, let's take a quick look at the bean that will be used by our JSF page called MyBean. MyBean declares 2 Phone classes, homePhone and cellphone as seen below:
class MyBean{ Phone homePhone; Phone cellPhone; ...
In turn, the Phone class looks like this:
class Phone{ String areaCode; String prefix; String suffix; ...
In Listing 6, lines 15-16 will be responsible for displaying the label text.
Lines 17-44 set up the 3 input fields.
The code uses our custom validator from the previous section, only this time the custom validator is being used to validate the individual phone fields.
Specifically, lines 22-23 for the area code, lines 31-32 for the prefix, and lines 42-43 for the suffix.
Lines 21, 30, and 41 refer to a JavaScript function called handleAutoTab which has been omitted since it's beyond the scope of this article. On lines 19, 27, and 37 the value attribute references something called a phoneRef. This is a reference to the MyBean's Phone object. Line 19 references the Phone object's areaCode. Line 27 references the Phone object's prefix, and so on. In the next listing we see the exact details of how this is set up.
Listing 6. /WEB-INF/template/phone.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 05 <html xmlns="http://www.w3.org/1999/xhtml" 06 xmlns:ui="http://java.sun.com/jsf/facelets" 07 xmlns:f="http://java.sun.com/jsf/core" 08 xmlns:h="http://java.sun.com/jsf/html" 09 xmlns:c="http://java.sun.com/jstl/core" 10 xmlns:rich="http://richfaces.org/rich" 11 xmlns:example="http://example.regex"> 12 13 <table> 14 <tr> 15 <td width="130" align="right"><h:outputText 16 value="#{label}" style="font-family:arial;font-size:11pt"/>:</td> 17 <td width="62">(<h:inputText 18 id="#{id}areaCode" 19 value="#{phoneRef.areaCode}" 20 immediate="true" maxlength="3" size="3" 21 onkeyup="handleAutoTab('#{id}areaCode')"> 22 <example:regexValidator regex="([0-9]{3,3})" 23 errorMessage="Please enter a valid 3 digit area code." /> 24 </h:inputText> )</td> 25 <td width="40"><h:inputText 26 id="#{id}prefix" 27 value="#{phoneRef.prefix}" 28 maxlength="3" 29 size="3" 30 onkeyup="handleAutoTab('#{myId}prefix')"> 31 <example:regexValidator regex="([0-9]{3,3})" 32 errorMessage="Please enter a valid 3 digit phone prefix." /> 33 </h:inputText></td> 34 <td align="center">-</td> 35 <td width="50"><h:inputText 36 id="#{id}suffix" 37 value="#{phoneRef.suffix}" 38 immediate="true" 39 maxlength="4" 40 size="4" 41 onkeyup="handleAutoTab('#{id}suffix')"> 42 <example:regexValidator regex="([0-9]{4,4})" 43 errorMessage="Please enter a valid 4 digit phone suffix." /> 44 </h:inputText></td> 45 </tr> 46 </table> 47 </html>
Listing 7 shows the code setup to utilize the phone.xhtml template. Lines 12-17 use the ui:include tag. Conceptually, the ui:include tag says that the lines between its start and end tag are going to be replaced with phone.xhtml. Lines 13-16 show the 3 parameters being passed. Line 15 assigns myBean.homePhone to the phoneRef attribute. Then within the phone.xhtml in Listing 6, lines 19, 27, and 37, use the phoneRef and bind the input field values to the corresponding fields contained within Phone homePhone. Lines 19-24 do the same thing only this time bind to the fields in Phone cellPhone.
Listing 7. /WebContent/example/example4.xhtml 01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 03 04 05 <html xmlns="http://www.w3.org/1999/xhtml" 06 xmlns:ui="http://java.sun.com/jsf/facelets" 07 xmlns:f="http://java.sun.com/jsf/core" 08 xmlns:h="http://java.sun.com/jsf/html"> 09 <body> 10 <h:form> 11 <f:view> 12 <ui:include src="/WEB-INF/template/phone.xhtml"> 13 <ui:param name="label" value="Home Phone" /> 14 <ui:param name="phoneRef" 15 value="#{myBean.homePhone}" /> 16 <ui:param name="id" value="homePhone" /> 17 </ui:include> 18 19 <ui:include src="/WEB-INF/template/phone.xhtml"> 20 <ui:param name="label" value="Cell Phone" /> 21 <ui:param name="phoneRef" 22 value="#{myBean.cellPhone}" /> 23 <ui:param name="id" value="cellPhone" /> 24 </ui:include> 25 </f:view> 26 27 ... 28 </h:form> 29 </body> 30 </html>
Putting it all Together
In this example we will show how to combine all the concepts we learned so far for maximum impact. The rendered form will look like Figure 6.

Figure 6. Putting it all together.
Listing 8 shows the code used to create the form. The code pulls together the concepts discussed in the previous sections. The form uses the decorator in 3 places. The decorator decorates each form section using the approach we saw earlier. In addition the modal panel decorator is nested within a decorator which further underscores the power and flexibility of Facelets.
Listing 8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:example="http://example.regex"> <body> <h:form> <f:view> <ui:decorate template="/WEB-INF/widget/formDecorator.xhtml "> <table> <td align="right" style="font-family:arial;font-size:11pt;" width="140"> Full Name: </td> <td align="left"> <h:inputText value="#{myBean.fullName}" maxlength="30" size="20" id="idFullName"> <example:regexValidator regex="([A-Za-z ]{0,30})" errorMessage="The full name is invalid." /> </h:inputText> </td> <td> </td> <tr> <td align="right" style="font-family:arial;font-size:11pt;" width="140"> Credit Card Number: </td> <td align="left"> <h:inputText value="#{myBean.creditCardNumber}" maxlength="20" size="20" id="idCreditCardNumber"> <example:regexValidator regex="([A-Za-z0-9 ]{0,20})" errorMessage="The credit card number is invalid." /> </h:inputText> </td> <td> </td>
</tr> <tr> <td align="right" style="font-family:arial;font-size:11pt;" width="140"> Secure Id: </td> <td align="left"> <h:inputText value="#{myBean.secureId}" maxlength="4" size="4" id="idSecureId"> <example:regexValidator regex="([0-9 ]{0,4})" errorMessage="The secure id is invalid." /> </h:inputText> </td>
<td align="left"> <ui:decorate template="/WEB-INF/widget/modalPanel.xhtml"> <ui:param name="linkText" value="How do I find my credit card's secure id?"/> <ui:param name="title" value="Credit Card Security Code "/> <ui:param name="id" value="creditCard"/> The security code is the four digit number shown above the credit card number on the right-hand. </ui:decorate> </td> </tr> </table> </ui:decorate> <ui:decorate template="/WEB-INF/widget/formDecorator.xhtml "> <table> <tr> <td colspan="3"> <ui:include src="/WEB-INF/template/phone.xhtml"> <ui:param name="label" value="Home Phone" /> <ui:param name="phoneRef" value="#{myBean.homePhone}" /> <ui:param name="id" value="homePhone" /> </ui:include> </td> </tr> <tr> <td colspan="3"> <ui:include src="/WEB-INF/template/phone.xhtml"> <ui:param name="label" value="Cell Phone" /> <ui:param name="phoneRef" value="#{myBean.cellPhone}" /> <ui:param name="id" value="cellPhone" /> </ui:include> </td> </tr> </table> </ui:decorate> </f:view> ... </h:form> </body> </html>
Facelets is replete with features that speed up development. To discover other interesting features please visit
http://facelets.java.net/nonav/docs/dev/docbook.html.
Nadine McKenzie has been a consultant in the software industry for more than 14 years. She is also a writer and an educator.
|
Agile Application Lifecycle Management (ALM) Date: 06/29/2011
Learn about agile Application Lifecycle Management (ALM) and its benefits.
Learn about agile Application Lifecycle Management (ALM) and its benefits.
Learn about agile Application Lifecycle Management (ALM) and its benefits.
Agile Application Lifecycle Management (ALM) gains more and more momentum. Remembering the time when I wrote the manuscript for my book "Agile ALM", almost nobody thought about enriching an ALM
with Agile, or finding a pragmatic approach to ALM at all. Meanwhile, more and more tool vendors find it helpful to label their tools to be Agile tools
or even Agile ALM tools. But what is Agile ALM? In my opinion, ALM synthesizes technical and functional elements to provide a comprehensive approach to common project activities and phases, addressing
build, configuration, deployment, release, test, quality, integration, and requirements management, see Figure 1.
With its interdisciplinary approach, Agile ALM integrates project roles, project phases and artifact types.
An Agile ALM enriches an ALM with agile values and strategies. An agile approach to ALM improves product quality, reduces time to market, and makes for
happier developers. My definition of Agile ALM results in processes and tool chains that are flexible, open to change and high in quality.
This is one of the ways in which ALM helps to provide structure for Agile.

Figure 1. ALM addresses different disciplines and development phases.
Some underlying aspects of Agile ALM are not completely new, and you should respect all the different struggles from previous decades, and put results together to get the best solution for today: in my opinion, ALM evolved from software configuration management (SCM), that in turn has its root in basic version control. You should define your processes and your requirements first, before selecting the tools that best
fit the given task.
Individuals and interactions over processes and tools
Above all, Agile ALM is a discipline and a mental approach. Working with Agile ALM should start with values and people as
well as concepts behind it. An Agile ALM tool is an ALM tool that fosters an agile process.
An Agile ALM tool must be able to add value to the system and improve the collaboration of the stakeholders.
In my opinion, an Agile ALM tool chain must implement the building blocks of Agile ALM, such as continuous integration (including continuous inspection and
continuous deployment), functional/technical releasing, stakeholder focus (and collaborative development) and task-based development.
Many projects feel comfortable with an orchestration of single best of breed tools. Integrating lightweight, configurable tools into flexible tool chains results in a mashup of tools that exactly offer
the features that are needed to solve a given task.
Agile ALM tools should have an open architecture that enables you to add further tools or functionality. Relying on lightweight tool chains can improve flexibility dramatically
because you can replace small units of the overall infrastructure easily without questioning other parts of that infrastructure. Now let's discuss some of the important building blocks of Agile ALM, and start with
task-based development.
Task-based development
With a task-based approach, the task is the unit of interaction and the base of work. Task-based development is the technique of traceably linking work items
to the specific set of changes that was made to complete the work item. One example use case can look like this: you are working on a task that
is listed in your ticket system and has the unique identifier AGILEALM-9. Your IDE (e.g. Eclipse, with Mylyn) is integrated with the
ticket system (e.g. JIRA). The CI server Jenkins integrates with JIRA, with the version control system (VCS) and with the component repository (e.g.
Artifactory) to make the progress of work and the dependencies of artifacts and work items transparent. With Jenkins, together with Artifactory, you can drive staged builds in order to deploy the release
to higher staging environments, without re-building the release ("build once, run everywhere"). Figure 2 shows how Jenkins integrates with
other tools. Zoomed in to a build result page in Jenkins, it is easy to navigate to the VCS (to look at the underlying changes), to the ticket system (to work on the
task) and to the component repository (to work on the binaries).

Figure 2. The CI server Jenkins integrates with VCS, ticket system and component repository.
Collaborative development
Software development is all about implementing requirements. The requirement is the central unit and the driver of a software release. Approaches like unit testing (to
validate that the right thing is developed correctly) and acceptance tests (to validate that the right thing is developed) are not new. But in the past, these approaches have often been
handled in an isolated or puristic way. Instead, a comprehensive, pragmatic solution should be prefered that focuses on the requirement itself, always having all stakeholders in mind.
You can use dedicated, lightweight tools to write acceptance tests, such as Fit. Or you can use specialized languages. Scala and Groovy, both languages offer interesting features for
setting up a polyglot ecosystem, leveraging existing platforms by providing solutions that involve special purpose languages. With Scala and Groovy, you can write tests, which helps
to overcome various barriers:
- Barriers between project phases and project activities (because coding and testing move together more closely)
- Barriers between artifact types (because code and executable specifications are written on the same unified infrastructure)
- Barriers between project roles (because tests are written collaboratively, with mechanisms to use terms close to the problem domain)
- Barriers between tools (because the same tools are used for programming and testing)
The following simple example gives you an impression of how it can look like to write acceptance tests with Scala and the specs2 library.
package alm
import org.specs2._
class AccSpec extends Specification { def is =
"This is a specification to check the 'Agile ALM' string" ^ p^ "The 'Agile ALM' string should" ^ "start with 'Agile'" ! e1^ "end with 'ALM'" ! e2^ end def e1 = "Agile" must startWith("Agile") def e2 = "Agile ALM" must endWith("ALM") }
The defined is method lists specification fragments which are either simple text (description of the target system), an example (including exectuable code that
returns a result) or a formatting fragment (the p for adding a blank line and starting a new block). Fragments are separated and linked by the ^ character.
For more details on specs2, see specs2.org.
Release management
Release management comprises producing software artifacts and releasing those artifacts according to a defined process. Release management can be differentiated into a functional and a
technical part. To deliver software successfully, both parts are important and should be integrated with each other. Automation and continuous integration are crucial facets of the software
release and delivery process.
Functional release management
Functional release management involves picking the customer's requirements, assigning them to releases and delivering the functionality to the customer, in
high quality. Often agile practices are used to support this process, and many projects achieve good results from using the management template Scrum. While defining a thin set
of rules, Scrum fosters discipline and makes defects (in software as well as in the process) visible. But Scrum is too abstract to apply it "out of the
book". You must implement Scrum and adopt it for software engineering. Implementation practices, for instance, may include distinguishing between special development phases,
on a micro level, inside a Scrum release: during a release, you may think about closing the develoment phase with a frozen zone which allows developers to only work on bug fixes,
instead of new features. Another helpful option is to use code freeze intervals, to complete and ship the final release.
Technical release management
Technical releasing consists of building the software and providing the final product to the user. Build management (comprised of compiling scripts, and packaging and distributing components)
is essential for Agile ALM. Technical release management describes activities to identify configuration items, track and audit changes on requirements and configuration items
and integrate and deliver the implementation. In software engineering change is more the rule than the exception. Because requirements change, it is important to keep the requirements in
sync with their implementations. Possible gaps between functional and technical release management should be bridged. Strategies like VCS hooks help to marry both parts of release management.
Continuous integration (including continuous inspection and continuous deployment)
To automate manual steps means results are delivered in an objective and reproducible way.
Automating the most error-prone, most repetitive and most time-consuming activities is essential. Continuous integration (CI) is the automation of the build, test
and release process and has the goal of integrating the activities of colleagues and the work items others produce.
This can result in a build ecosystem where a new code commit directly triggers a continuous build including compile, technical tests, audits, package, functional tests and deployment.
All different artifact types, platforms and languages, should be integrated, e.g. Java (Groovy, Scala, ..), .NET, PHP and Cobol, using an unified tool infrastructure, see Figure 3. If no native build system exists for a respective language/platform, non-native build technologies can be used to include these artifact types in the CI farm.

Figure 3. A comprehensive CI ecoystem that integrates different artifact types, on an unified infrastructure.
In a continuous integration process, build reports and notifiers should be in place, and information should be shared and aggregated. Aggregating information means that the integrated tool chain
spans the whole, heterogenous ecosystem. This enables the stakeholders to "zoom in" where needed, to get more information where necessary, and make knowledge out of information.
Examples for this are: given a specific build, you can browse to the underlying changes in the VCS, or: collect all produced binaries in the component repository that belong together
semantically, in order to perform operations on them as a group.
Conclusion
Agile ALM spans many disciplines in software engineering. Agile ALM is about people and strategies, and implementing these strategies with lightweight tool chains.
Agile ALM helps to provide structure for Agile and helps to approach ALM in a determined, pragmatic way. Using an Agile approach to ALM, you'll profit from a quicker win and better results.
There is a lot more to say, but I hope this article gave you an impression about what Agile ALM is, and what I desribe in much more depth in my book "Agile ALM".
Resources
Michael Huettermann is a freelance developer, architect, coach, author and tutor for Java/JEE, ALM/SCM and agile software development.
|
A Method for Reducing Contention and Overhead in Worker Queues for Multithreaded Java Applications Date: 06/14/2011
Learn about worker queue contention and methods for addressing worker queue issues.
Learn about worker queue contention and methods for addressing worker queue issues.
Learn about worker queue contention and methods for addressing worker queue issues.
[Editor's note: the following article was submitted by Sathiskumar Palaniappan, Kavitha Varadarajan, and Jayashree Viswanathan.]
Introduction
Many server applications, such as Web servers, application servers, database servers, file servers, and mail servers, maintain worker queues and thread pools to handle large numbers of short tasks that arrive from remote sources. In general, a "worker queue" holds all the short tasks that need to be executed, and the threads in the thread pool retrieve the tasks from the worker queue and complete the tasks.
Since multiple threads act on the worker queue, adding tasks to and deleting tasks from the worker queue needs to be synchronized, which introduces contention in the worker queue. This article explains the contention involved with the traditional approach (using a common queue for the thread pool) and helps you reduce the contention by maintaining one queue per thread. This article also explains a work stealing technique that is important for utilizing the CPU effectively in multicore systems.
Note: The source code for the examples described in this article can be downloaded here: workerqueue.zip
Common Worker Queue: The Traditional Approach
Today, most server applications use a common worker queue and thread pool to exploit the concurrency provided by the underlying hardware. As shown in Figure 1, server applications use a common worker queue to hold short tasks that arrive from remote sources. A pool of threads acts on the worker queue by retrieving tasks from the worker queue and running the tasks to completion. Threads are blocked on the queue if there is no task in the worker queue.
This method of using a common worker queue resolves the issues created by earlier approaches, such as creating a thread per task, which caused lots of threads to be spawned. However, the common worker queue method creates a bottleneck when the number of tasks is high and the task time is very short. The single background thread approach also has flaws when an application has a huge number of short-spanned, independent tasks.

Figure 1. Common Worker Queue.
Listing 1 shows how you can create a common worker queue with just few lines of code.
Listing 1. Creating a Common Worker Queue
/* * Defines common worker queue and pool of threads to execute tasks from remote sources */ public class SimpleWorkQueue { private final PoolWorker[] threads; private final BlockingDeque queue;
public SimpleWorkQueue(int nThreads) { queue = new LinkedBlockingDeque<Task>(); threads = new PoolWorker[nThreads]; for (int i=0; i<nThreads; i++) { threads[i] = new PoolWorker(); threads[i].start(); } }
/* * Worker thread to execute remote tasks */ private class PoolWorker extends Thread { /* * Method to retrieve task from worker queue and start executing it. * This thread will wait for a task if there is no task in the queue. */ public void run() { while (!stopNow) { try { Runnable r = (Runnable) queue.takeLast(); r.run(); } catch ( java.lang.Throwable e) { } } } } }
As shown in Listing 1, the SimpleWorkQueue class initializes a dequeue and starts a fixed number of threads at startup. Each thread then executes queue.takeLast() in a loop that retrieves a task from the worker queue (if there are tasks) or waits for a new task to arrive (if it finds the queue is empty). Once a task is retrieved, each thread then calls the run method, r.run(), of the task.
Worker Queues per Thread
The approach above is very simple and improves performance over the traditional approach of creating threads for each incoming task. However, as shown in Figure 2, this method creates contention. Contention is created when multiple threads use a single work queue to get their task. The condition is worse when the number of threads (cores) is higher.

Figure 2. Contention in a Common Worker Queue.
Today, with the advent of more multicore processors, it becomes a challenge for software applications to utilize the underlying cores effectively. (For example, IBM's Power7, Oracle's UltraSPARC, and Intel's Nehalem are multicore processors capable of running multiple threads.)
There are various solutions available for overcoming the contention in the common worker queue approach:
- Using lock-free data structures
- Using concurrent data structures with multiple locks
- Maintaining multiple queues to isolate the contention
In this article, we explain how to maintain multiple queuesa queue-per-thread approachto isolate the contention, as shown in Figure 3.

Figure 3. Queue-per-Thread Queue.
In this approach, each thread has its own worker queue and can retrieve tasks only from its own queue, not from any other queue. This approach isolates contention when retrieving tasks because there is no one to compete with. This guarantees that threads will not be in a sleeping state if there are tasks in the worker queue, which utilizes the cores effectively.
Listing 2 shows how you can easily migrate from the common worker queue approach to the queue-per-thread approach by making just a few modifications to the code that was shown in Listing 1. In Listing 2, the constructor initializes multiple queues (equal to the number of threads) at startup and each thread maintains an ID called thread_id. Then, thread_id is used to isolate the contention by helping each thread retrieve tasks from its own queue.
Listing 2. Creating a Queue-per-Thread Queue
/* Modification to number of queue initialization */ for (int i=0; i<nThreads; i++) { queue[i] = new LinkedBlockingDeque<Task>(); } ... ...... /* Modification in task retrieval */ r = (Runnable) queue[thread_id].takeLast();
Queue-per-Thread Queue with Work Stealing
Although the queue-per-thread approach greatly reduces the contention, it does not guarantee that the underlying cores are used effectively all the time, For example, what happens if a couple of queues get emptied long before other queues? This is a common situation, and in this case, only a few threads execute the tasks whereas other threads (emptied queues threads) wait for the new tasks to arrive. This can happen due to following:
- Unpredictable nature of the scheduling algorithm
- Unpredictable nature of the incoming tasks (short versus long)
A solution to this problem is work stealing.
Work stealing lets one thread steal work from another queue when it finds that its own queue is empty. This ensures that all the threads (and, in turn, the cores) are busy all the time. Figure 4 shows a scenario where Thread 2 steals a work from Thread 1’s queue because its own queue is empty. Work stealing can be implemented with standard queues, but using a dequeue greatly reduces the contention involved in stealing the work:
- Only the worker thread accesses the head of its own dequeue, so there is never contention for the head of a dequeue.
- The tail of the dequeue is accessed only when a thread runs out of work. There is rarely contention for the tail of any thread's dequeue either.

Figure 4. Work Stealing.
Listing 3 shows how you can steal work from other queues with just a few modifications to the queue-per-thread approach. As shown, each thread calls pollLast() instead to takeLast(). This is necessary because threads should not get blocked on a queue if there is no task in the queue. Once a thread finds that its own queue is empty, it steals work from another queue by calling pollFirst() on the other thread's queue.
Listing 3. Implementing Work Stealing
</code> /* do not block if there is no task in the current queue */ r = (Runnable) queue[thread_id].pollLast();
if(null == r) { /* There is no task in the current queue, steal one from another thread's queue */ r = stealWork(thread_id); }
/* * Method to steal work from other queues. */ Runnable stealWork(int index) { for (int i=0; i<nThreads; i++) { if(i != index) { Object o = queue[i].pollFirst(); if(o!=null) { return (Runnable) o; } } } return null; }
Building the Benchmark
In order to demonstrate these approaches, we developed a small test scenario for the three approaches mentioned in this article and studied the behavior. The test basically creates a lot of 10 x 10 matrix multiplication tasks and executes them using the three approaches.
Note: The source code for the examples described in this article can be downloaded here: workerqueue.zip
The test defines the following classes:
MainClass: A class that initiates, starts, and coordinates various elements of the benchmark.
WorkAssignerThread: A thread that creates a lot of 10 x 10 matrix multiplication tasks and queues them.
Task: A class that defines a 10 x 10 matrix multiplication.
WorkQueue: An interface that defines a set of methods any worker queue must implement.
WorkerQueueFactory: A factory class that returns the workQueue object based on the queue type.
SimpleWorkQueue: A class that defines a simple worker queue and initiates a set of threads. This depicts the first queue type mentioned in this article (common worker queue).
MultiWorkQueue: A class that isolates the contention by defining multiple worker queues (one per thread) and depicts the second queue type mentioned in this article.
WorkStealingQueue: A class that isolates the contention by defining multiple queues and steals work when it finds one of its thread's queues is empty. This depicts the third queue type mentioned in this article.
The test can be executed by specifying the queue type, number of threads, and number of tasks, as shown in Listing 4. Listing 4 also shows how to invoke a test with the first queue type (common worker queue), with the number of threads equal to 10 and the number of tasks equal to 10000.
Listing 4. Executing the Test
java MainClass <Queue type> <number of threads> <number of tasks>
/* for example: */
java MainClass 1 10 10000
Experimental Results
We evaluated the performance in different architectures and the results are very positive. Initially, we evaluated the performance on an AMD Opteron box, which had eight core processors and ran Linux, and we found that performance for queue type 3 was improved by 12 to 18.4% over queue type 1, depending on the load, as shown in Figure 5.

Figure 5. Performance Comparison Between Type 1 and Type 3 Queues on Linux AMD Opteron System with Eight Core Processors. [Disclaimer: This is not to compare any products or claim performance for any product; it is just to showcase the advantage of the techniques proposed in this article, which are purely the authors' views.]
We also evaluated the performance in a Linux power system that had four dual-core processors (Power4), and we found that performance was improved by 12 to16% for the same load, as shown in Figure 6.

Figure 6. Performance Comparisons Between Type 1 and Type 3 Queues on Linux System with Four Dual-Core Power Processors. [Disclaimer: This is not to compare any products or claim performance for any product; it is just to showcase the advantage of the techniques proposed in this article, which are purely the authors' views.
As shown in Figure 5 and Figure 6, we varied the tasks from 0.1 million to .5 million and measured the performance in seconds. The outcome of our experiment clearly indicates that a large amount of contention is created in queue type 1 and it can be eliminated by creating multiple queues and stealing work.
Summary
This article demonstrated the contention involved in the common worker queue approach and then isolated the contention by creating one queue per thread. This article also demonstrated, through a simple benchmark, why work stealing is important and how it improves the overall performance of an application.
Resources
- workerqueue.zip, the source code for the examples described in this article.
- Java theory and practice: Thread pools and work queues, by Brian Goetz.
- Java theory and practice: Stick a fork in it, Part 1, by Brian Goetz.
- A dynamic-sized nonblocking work stealing deque, by Danny Hendler, Yossi Lev, Mark Moir, and Nir Shavit.
- Double-ended queue, Wikipedia.
- Blocking doubly ended queue, Java documentation.
- Quick overview of IBM POWER7 processor, Wikipedia.
About the Authors
Jayashree Viswanathan is a System Software Engineer at IBM India Labs, Bangalore. She joined IBM in 2007 and has been part of Java Technology Center. She has worked on JAXB and JAXWS on JDK6, and currently she is part of JDK7 development.
Kavitha Varadarajan is an Advisory Software Engineer at IBM India labs Bangalore; she has been with IBM since December 2000 and has close to 10 years of experience in product development, support, testing, and performance engineering. Currently, she is part of IBM's Java Technology Center and is leading the performance analysis of IBM JDK5 and IBM JDK6, and she is contributing to the IBM JDK7 performance analysis.
Sathiskumar Palaniappan is a Software Engineer at IBM India Labs, Bangalore. He joined IBM's Java Technology Center in 2007 and has been part of Net.Data, NIO, and RMI library development. Currently, he is part of the JDK7 development effort and he enjoys working with run-time technologies.
|
Data Analysis and Data Mining Using Java, Jython and jHepWork Date: 05/15/2011
Learn how to apply jHepWork for analyzing and plotting data sets.
Learn how to apply jHepWork for analyzing and plotting data sets.
Learn how to apply jHepWork for analyzing and plotting data sets.
Introduction
Data mining (sometimes called knowledge discovery) is the process of analyzing and
summarizing data into useful information which can be used to understand common features,
the origin of data and to extract hidden predictive information.
Data mining is used in science, engineering, modeling and analysis of financial markets.
This article discusses a free data-analysis framework called jHepWork [1]
which is widely used to facilitate data analysis and data mining (see Figure 1).
It was designed for scientists, engineers and students who need numerical and statistical computations,
data and function visualization and even symbolic computation.
jHepWork is a 100% Java package, which means it is fully object-oriented and runs on any Java Virtual Machine regardless of computer architecture. Another notable feature - it uses the Python programming language [2] to call Java classes for numerical and statistical computation as well as for data visualization. To be more exact, jHepWork fully unitizes the power of Jython [3] which is an implementation of the Python programming language in Java.

Figure 1. jHepWork IDE with several interactive graphs.
Such merge of Java and Jython is not accidental.
According to the TIOBE Community Programming Community Index [4],
Java is the world’s most popular programming language.
Python is among popular scripting languages widely used in science, engineering and
education. It is also the fastest growing programming language of 2010 according to the same TIOBE index.
jHepWork uses the Python language due to its short and clear syntax which is handy for calling
numerical Java libraries. As the result, data-analysis programs written in such approach are short and clear,
while still utilizing the full strength of Java.
This is somewhat different from GUI-only type programs that
typically require walking through various menus and sub-menus to perform certain tasks.
In the jHepWork approach, one can write short commands using Python to perform computations
with arbitrary algorithmic logic that can be changed at runtime.
Such approach is also important for repetitive tasks when analysis code,
once saved into a file, can be executed multiple number of times depending on inputs
(which is a tedious task for GUI-only programs). In some sense, the scripting approach to data mining is
similar to the R-programming language [5],
but the difference is that jHepWork is based on Jython,
using the full advantage of its object-oriented design, the Python programming language with its high-level standard library,
the power of Java API and jHepWork Java libraries for data manipulation and visualization.
Saying all the above, one should also keep in mind that one can always use a pure Java approach to
develop data-mining analysis programs using jHepWork since all numerical and graphical
libraries of jHepWork are implemented in 100% Java. Or one can use an alternative scripting language,
such as BeanShell or the Java scripting API shipped with the javax.script package.
Finally, one can enjoy using the powerful Eclipse or Netbeans IDEs while editing
analysis programs.
Short tutorial
In this tutorial we will illustrate the full strength of jHepWork for data mining
using the Jython language.
We show how to analyze multidimensional data, display data on 2D and 3D canvases,
plot a function and how to perform a full-scale linear regression analysis widely in statistical interpretation of data.
Let us assume that we have a matrix of numbers organized as:
# this is a comment 1 2 3 4 5 6 7 8 .......
(the numbers of rows and columns can be arbitrary).
The goal of this tutorial is to analyze this data and to extract some useful information.
The numbers can be stored in a file which can be located on the Web.
First, make sure that the Java Virtual Machine http://www.java.com/ is installed.
Then download the jHepWork package from http://jwork.org/jhepwork/, unzip the package file
and run the script “jhepwork.sh” (Linux/Mac) or “jhepwork.bat” (Windows).
If you do this for the first time, Jython will start creating a cache directory. This process may take twenty to forty
seconds depending on the speed of your system.
Jython needs to document all Java classes visible for the Java Virtual Machine since this
will simplify programming (no need to specify every Java class in the import statements) and
will speed up the code execution.
After the start up, you will see the jHepWork IDE as shown in Figure 1.
It is bundled with a powerful code editor and a code assist based on the Java reflection technology.
It also has a Jython shell (below the main editor) and the Bean shell. Both help
interactive development of a data-mining analysis code and also can be used to call external commands.
For this tutorial,
we will use the Jython shell (“JythonShell”) since one can see the program response
immediately after entering commands line by line. The JythonShell is located below the main editor.
A first step is to read the data into a jHepWork data container designed to perform
some handy manipulation.
Our preference is to read our data from a prepared file located on the Web.
Make the JythonShell window bigger and enter the code shown below line by line and pressing [Enter]:
>>> from jhplot import * >>> pn=PND('data','http://jwork.org/jhepwork/examples/data/pnd.d') >>> print pn.toString()
Here we create a PND object using the input file “pnd.d”
stored on the Web and print the numbers stored in this container for checking.
The PND class is located in the "jhplot" package which is shipped together with jHepWork;
this is the main jHepWork package to perform data manipulation and visualization.
The input file has exactly the same structure as shown before, i.e. each row is separated by a new line.
From now on, we use the Python syntax
to print a string returned by the method toString().
Alternatively, one can use pn.toTable() method to display all numbers in a sortable and searchable table.
You will see the numbers printed out in the JythonShell (which is used for output of the print command).
Want to learn about methods of the “pn” object? Just type “pn.“ (the dot is important!)
and press [Ctrl]-[Space].
You will see a drop-down menu with the methods of this class.
Alternatively, one can look at the complete API of the PND class as
>>> pn.doc() # this brings up a widows with the class API
Let us continue with the analysis of our data. First thing we want to do is to extract the
numbers from the second column and display them as a histogram (or a bar-chart density plot)
in order to understand the statistical characteristics of the data.
Assuming that the “pn” object is created as shown before, we will
extract the second column using the index 1 (the first column has the index 0)
>>> p0=pn.getP0D(1) # extract 2nd column and put to a 1D array >>> print p0.getStat() # print a detailed statistical characteristics >>> c1=HPlot('Plot') # create a canvas to display a histogram >>> c1.visible() # pop-up canvas. c1.visible(False) creates the image in background >>> c1.setAutoRange() # set auto-range for the X and Y axis >>> h1=p0.getH1D(10) # convert 1D array into a histogram with 10 bins >>> c1.draw(h1) # draw the histogram
You will see a long list of statistical characteristics of the array of the first column (object p0) and a pop-up window with the histogram from the first array.
The code is self-explanatory and contains the necessary comments to explain each step.
For example, the method p0.getH1D() fills a one-dimensional histogram (the Java class H1D) using ten ranges
between a minimum and a maximum value of the array “p0” (the Java class P0D).
You will be surprised to find how many methods the H1D class contains.
According to the Java API, the histogram class
H1D has about 100 methods for data manipulation (excluding the methods for graphical representation).
If you want to make a file with a high-quality vector graphics,
use the method c1.export("fig.pdf") (for the PDF format) or c1.export("fig.ps") (for the PostScript format).
jHepWork supports about a dozen formats for image outputs. Figures can be generated in background without bringing up the canvas. In this case, use the method c1.visible(0). Finally, jHepWork has a powerful input-output mechanism for each data object (histograms, functions, data arrays) which allows storing all objects in files either using the Java serialized mechanism
or simple text-based files with compression.
Scatter plot and linear regression
The next step in our analysis is to extract two arbitrary columns and to make an X-Y scatter plot in
order find a correlation between the numbers from these columns.
In the example below we extract the second and third column, plot them on a X-Y canvas and
then perform a least-squared linear regression:
>>> from jhplot.stat import * >>> p1=pn.getP1D(1,2) # extract 2nd and 3rd columns >>> c1=HPlot('X-Y plot') >>> c1.visible(); c1.setAutoRange() # set autorange >>> c1.draw(p1) >>> r=LinReg(p1) >>> print "Intercept=",r.getIntercept(), "+/-",r.getInterceptError() >>> print "Slope=",r.getSlope(),"+/-",r.getSlopeError()
This code should follow after the code which creates the object “pn” as discussed before.
The execution of this example creates a X-Y graph with the values of the second and third columns, performs a least-squares regression and prints the values of the intercept and the slope (with their statistical uncertainties) of the linear-regression line.
But how to visualize this line? We can create a function using the values of the slope and the
intercept using the Python approach:
>>> func='%4.2f*x+%4.2f' % (r.getSlope(),r.getIntercept()) # a string representing a function a*x+b >>> f1=F1D( func, p1.getMin(0), p1.getMax(0)) # a function object in the data range >>> c1.draw(f1)
This part should follow after the code discussed before.
Here we build a function a*x+b using
the slope and the intercept values instead of the symbols “a” and “b”.
Note that we reduce the precision of these
values during the string formatting (which is not too important in this
example). Then we
build a function object from the string in the X-axis range given by the data
(p1.getMin(0) means the minimum value of our data on the X-axis and p1.getMax(0) is the maximum value).
Now we can do something more: we will calculate a 95% prediction interval of the regression line [6].
The 95% prediction interval is the area in which 95% of all data points are
expected to fall. Do not confuse it with the 95% confidence interval which is the area that has a 95% chance of containing the true regression line. The jHepWork can calculate both, but here we only discuss the 95% prediction interval and will try to plot this interval
in a form of band on top of data points.
>>> from java.awt import Color >>> p=r.getPredictionBand(Color.green) # extract 95% prediction band >>> p.setLegend(False) # do not draw the legend for this band >>> p.setErrColor(Color.green) # set green color for error bars >>> c1.draw(p) # show on the canvas
The method getPredictionBand() returns a P1D data container with a
95% prediction interval. We show this band using errors colored in
green using the “Color” class from the standard Java java.awt package.
Showing data in 3D
Let us continue with this example by displaying the data in three-dimensions (3D)
using three arbitrary columns.
This time we will display data for 1,2,3 and 1,3,4 columns using two separate interactive plot regions (the so-called “pads”).
As before, we assume that this code follows right after the previously discussed lines and
the object “pn” has already been created:
>>> c2=HPlot3D('3D plot',600,400,2,1) # create a 600x400 canvas and make 2 drawing pads >>> c2.visible() >>> c2.cd(1,1); c2.setAutoRange() # navigate to first pad and set autorange >>> p2=pn.getP2D(0,1,2) # extract 3 columns with index 1,2,3 >>> c2.draw(p2) >>> c2.cd(2,1); c2.setAutoRange() # navigate to second pad and set autorange >>> p3=pn.getP2D(0,2,3) # extract 3 columns with index 1,3,4 >>> c2.draw(p3)
The execution of the above code makes two interactive 3D pads which can be rotated and zoomed in.
Use the methods of the Java class “HPlot3D” to change its style. For example, one can change the color of the drawing box to a gray
using the java.awt.Color class as c2.setBoxColor(Color(200,210,210)) which can be inserted after the pad navigation method c2.cd().
It should be noted that, instead of using the JythonShell, one can use the jHepWork editor. Create a file called “example.py”
and copy and paste the lines above. To run this file using Jython, press [F8] or click on the icon on the tool-bar menu of the jHepWork IDE.
There is one essential advantage in using this approach: One can use the built-in code assist which contains detailed description
of all methods. For example, assuming that the “pn” object is created as shown before,
type a dot after “pn” in the editor and press [F4]:
>>> pn. # + press [F4] to display a list of methods
The execution of this script brings up a table showing all methods of this class.
One can get a detailed description of each method and insert a selected method into the code editor.
Later one can make necessary modifications of
the code and rerun it using [F8] or clicking on the icon .
Putting all together
Now let us run all examples of this tutorial in one go.
The above tutorial is given in the file “tutorial.py” which can be found on the jHepWork web page.
In the jHepWork IDE, go to the menu [File] and then [Open from URL]. Copy and paste this string to the URL window:
http://jwork.org/jhepwork/examples/tutorial.py
and press the button [Open] (to see the code in the editor) or [Run] (to run the code).
You will see images with our tutorial as shown in Figures 2 and 3.

Figure 2. Histogram (left) and linear regression analysis.

Figure 3. Showing data in 3D.
A final word. jHepWork comes with more than 200 example scripts, a detailed on-line tutorial and even a book describing all aspects of the Jython and jHepWork approach to data analysis.
To run the examples included in the jHepWork IDE,
simply go to the main Menu, select [Tools] and then [jHPlot examples]. Then one
can open a Jython example code and run it in the jHepWork IDE.
More details about the jHepWork data-analysis project can be found on the official web page [1]
and in the jHepWork book [7].
About the license: the core numerical and graphical Java libraries are licensed under the GNU General Public License v3.
Documentation, examples, installer, code assist database, language files used by the jHepWork editor
are licensed under the Creative Commons Attribution-Share Alike License; either version 3.0 and are
free for non-commercial usage (academic research, science and education).
References
[1] The jHepWork project, http://jwork.org/jhepwork/
[2] The Python language http://www.python.org/
[3] The Jython project http://www.jython.org/
[4] TIOBE index. http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
[5] The R statistics http://www.r-project.org/
[6] Confidence and Prediction band. Wikipedia http://en.wikipedia.org/wiki/Confidence_band
[7] S.V.Chekanov, Scientific Data analysis using Jython Scripting and Java. Book. 497p. Springer-Verlag, London 2010 ISBN 978-1-84996-286-5
Sergei Chekanov has been developing scientific software for analysis of large data volumes since 1995. He is a primary developer of the jHepWork data-analysis project and several open-source Java projects.
|
Using Spring’s AOP Features with Java EE Date: 04/18/2011
Learn about the Spring AOP framework related features.
Using Spring’s AOP Features with Java EE
Learn about the Spring AOP framework related features, which is one of the main components that distinguishes Spring from Java EE.
The popular Spring
framework complements and facilitates development on the Java EE
platform by providing a modular, object-based programming model.
Whereas Java EE is OOP (object-oriented programming) based, Spring is
AOP (aspect-oriented programming) based; in fact the AOP framework is
one of the main components of Spring. AOP complements OOP by
providing
an aspect
as the unit of modularity in addition to the
traditional OOP class. As explained in the Spring doc,
“Aspects enable modularization of concerns such as transaction
management that cut across multiple types and objects. “
A Spring bean may be a
JavaBean, a POJO, or any other object such as an EJB. Spring
implements the Inversion of Control (IoC) principle via dependency
injection. The Spring configuration file is used to specify the
configuration of the Spring beans with the Spring container and the
BeanFactory is used to manage the Spring beans. The BeanFactory
configures, instantiates, and assembles the dependencies among the
objects.
In this article we
shall explore the main AOP-related features in Spring: method
interception and the Spring AOP framework.
Setup
First you will need to
download and install the following:
Add the following JAR
files to the CLASSPATH variable in
C:\Oracle\Middleware\user_projects\domains\base_domain\bin\startWebLogic
batch script. (The Spring JAR files can be added after the Spring
Framework Library has been added to the Spring Web project as
discussed in a later section.)
C:\Spring\lib\aspectjweaver.jar
C:\Spring\lib\aspectjtools.jar
C:\Spring\lib\aspectjrt.jar
C:\Spring\lib\org.aspectj.matcher.jar
C:\Spring\asm-3.3.jar
C:\Spring\cglib-2.2.jar
C:\Spring\aspectj-1.6.10.jar
C:\Users\foo\workspace\libraries\Spring
Framework 2.5.6\spring-framework-2.5.6\dist\spring.jar
C:\Users\foo\workspace\libraries\Spring
Framework
2.5.6\spring-framework-2.5.6\dist\lib\jakarta-commons\commons-logging.jar
C:\Users\foo\workspace\libraries\Spring
Framework 2.5.6\spring-framework-2.5.6\dist\modules\spring-aop.jar;
Creating a
Web Project with Spring Facet
First, we need to
create a Web project in OEPE:
- Select Web>Dynamic
Web Project in the New wizard.
- In New Dynamic Web
Project specify a Project name, and configure a target runtime for
Oracle WebLogic Server 11gR1 Patch Set 2.
- Select the Default
Configuration... and click on Next.
- Select the default
Java settings (Source folder as src and output folder as
build/classes); click on Next.
- Specify a Context
Root and a Content directory.
- Select the
checkbox Generate web.xml deployment descriptor.
- Click on Finish.
A Web project for Spring is created.
Next, add the Spring
project facet to the Web project:
- Click on the
Further Configuration Required link.
- In Spring facet
configuration select Library type as User Library.
- Click on Download
Library.
- In Download
Library select the Spring Framework 2.5.6 library from Oracle.
Click on Next. The library gets added.
- Click on OK.
The Spring facet is installed.
- Click on Apply
and then OK. The Spring Framework 2.5.6 facet is now added to
the Web project, as shown below.

Figure 1
The Spring bean
definition file applicationContext.xml also gets created. For a
Spring JavaBeans application we shall define the SpringBean factory
configuration in the beanDefinition.xml file and not the
WEB-INF/applicationContext.xml file, which is more suitable for a Web
application. (The applicationContext.xml may be deleted for the
method interception example.)
Right-click on the
project node and select Properties. Select the Java Build
Path node - the spring.jar should be in the Java Build Path. Now
we're ready to explore these features.
Method
Interception
In this section we
shall discuss the method interceptor mechanism provided by Spring.
Creating a Spring Bean Class
First, we need to
create a Spring bean, which is an object managed, instantiated, and
configured by the framework. We shall create a JavaBean object for
the Spring bean; this object shall implement a magazine catalog with
properties representing the catalog’s journal name, publisher,
edition, title, author. The bean class shall also provide accessor
methods for the bean properties.
We need to create an
interface, CatalogInterface, for the bean class.
- Select the project
node and select File>New.
- In the New wizard
select Java>Interface and click on Next.
- Specify a package
name and a class name and click on Finish. A
spring.catalog.CatalogInterface interface gets added the src folder.
The interface CatalogInterface.java is listed below.
package spring.catalog; public interface CatalogInterface { public void setJournal(String journal); public String getJournal(); public void setPublisher(String publisher); public String getPublisher(); public void setEdition(String edition); public String getEdition(); public void setTitle(String title); public String getTitle(); public void setAuthor(String author); public String getAuthor(); }
Next, add the bean
class Catalog.java, which implements the interface.
- Select Java>Class
in New and click on Next.
- In New Java Class,
specify the package name and the class name and select the interface
spring.catalog.CatalogInterface. Click on Finish. The
spring.catalog.Catalog.java class gets added to the Web project.
In the Spring bean
class, provide implementation for the accessor methods for the bean
properties. Also, add a test method getTestMessage() that returns a
String message. The Catalog.java class is listed below.
package spring.catalog;
public class Catalog implements CatalogInterface {
public String journal; public String publisher; public String edition; public String title; public String author;
public Catalog(){} public Catalog(String journal, String publisher, String edition, String title, String author) {
this.journal = journal; this.publisher = publisher; this.edition = edition; this.title = title; this.author = author; }
public String getAuthor() { // TODO Auto-generated method stub return author; }
public String getEdition() { // TODO Auto-generated method stub return edition; }
public String getJournal() { // TODO Auto-generated method stub return journal; }
public String getPublisher() { // TODO Auto-generated method stub return publisher; }
public String getTitle() { // TODO Auto-generated method stub return title; }
public void setAuthor(String author) { // TODO Auto-generated method stub this.author = author; }
public void setEdition(String edition) { // TODO Auto-generated method stub this.edition = edition; }
public void setJournal(String journal) { // TODO Auto-generated method stub this.journal = journal; }
public void setPublisher(String publisher) { // TODO Auto-generated method stub this.publisher = publisher; }
public void setTitle(String title) { // TODO Auto-generated method stub this.title = title; }
public String getTestMessage() { return "Spring Bean Test"; }
}
Creating a Bean Definition File
In this section we
shall create a Spring bean definition file, beanDefinition.xml, to
configure the Spring bean, the Catalog JavaBean, with the Spring
framework. The root element of the beanDefinition.xml is beans
and each of the bean sub-elements represents a Spring bean. We shall
register three beans with the bean configuration file: Catalog
JavaBean, Interceptor bean, and Proxy bean.
To create a bean
configuration file:
- Select the project
node in the Project Explorer and select File>New.
- In New select
Spring>Spring Bean Configuration and click on Next.
- In New Spring Bean
Definition File select the project folder and specify File name
beanDefinition.xml; click on Next.
- In Select XSD
namespaces… select spring-beans-2.5.xsd and click on Next.
- Click on Finish. A
Spring bean definition file beanDefinition.xml gets created.
For each of the beans
to be registered with the Spring framework we need to add a <bean>
element. Add a < bracket within the <beans></beans>
element and in the pop-up select <bean>.

Figure 2
A <bean></bean>
element gets added. Next, add an id attribute to the <bean>
element. Select the Design tab, right-click on bean, and
select Add Attribute>id.

Figure 3
An id attribute gets
added to the bean element. Specify the id attribute value as
spring-bean. Similarly, add a class attribute to the bean element to
specify the JavaBean class spring.catalog.Catalog. Also add bean
elements for an interceptor bean and a proxy bean. The following
table lists details about the beans you should add.
bean
|
id
|
class
|
Catalog JavaBean
|
spring-bean
|
spring.catalog.Catalog
|
Interceptor bean
|
interceptor
|
spring.catalog.CatalogInterceptor
|
Proxy bean
|
proxyBean
|
org.springframework.aop.framework.ProxyFactoryBean
|
The bean definition
file with the beans added is shown in the Design view.

Figure 4
Next, we shall add the
following properties to the bean with id proxyBean.
Property
|
Value
|
Description
|
proxyInterfaces
|
spring.catalog.CatalogInterface
|
Set of interfaces being proxied
|
interceptorNames
|
interceptor
|
List of beans used as interceptor beans for the
proxied bean
|
target
|
spring.catalog
|
Id of the bean to be proxied
|
proxyTargetClass
|
true
|
Creates class based proxies
|
To add a property:
Right-click on the bean
with id proxyBean and select Add child>property.

Figure 5
To add a <list>
value right-click on property and select Add child>list.
To add a <value> element to the <list> element
right-click on list and select Add child>value. For
the interceptorName property add list value “interceptor”.
The target property
requires a ref sub-element. Right-click on property and select
Add child>ref. To the ref element we need to add the local
attribute. Right-click on ref and select Add
Attribute>local. Similarly add the proxyTargetClass property
and set its value to true. The proxyBean with properties is
shown below.

Fig 6
To the bean for
JavaBean Catalog add constructor-arg sub-elements for arguments to
the constructor for the JavaBean. The constructor has parameters for
journal, publisher, edition, title and author.
<constructor-arg index="0" value="Oracle Magazine" />> <constructor-arg index="1" value="Oracle Publishing" /> <constructor-arg index="2" value="November-December 2010" /> <constructor-arg index="3" value="Agile Architecture" /> <constructor-arg index="4" value="Bob Rhubart" />
The bean’s property
values may also be specified as property/value.
<property name="journal"> <value>Oracle Magazine</value> </property> <property name="publisher"> <value>Oracle Publishing</value> </property> <property name="edition"> <value>November-December 2010</value> </property> <property name="title"> <value>Agile Enterprise Architecture</value> </property>
<property name="author"> <value>Bob Rhubart</value> </property>
The bean definition
file is listed below.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="spring.catalog" class="spring.catalog.Catalog"> <constructor-arg index="0" value="Oracle Magazine" /> <constructor-arg index="1" value="Oracle Publishing" /> <constructor-arg index="2" value="November-December 2010" /> <constructor-arg index="3" value="Agile Architecture" /> <constructor-arg index="4" value="Bob Rhubart" /> </bean>
<bean id="interceptor" class="spring.catalog.CatalogInterceptor"></bean>
<bean id="proxyBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>spring.catalog.CatalogInterface</value> </property> <property name="interceptorNames"> <list> <value>interceptor</value> </list> </property>
<property name="target"> <ref local="spring.catalog"></ref> </property> <property name="proxyTargetClass"> <value>true</value> </property> </bean> </beans>
Creating a Method Interceptor
The
org.aopalliance.intercept.MethodInterceptor interface is used to
intercept calls on an interface prior to the target. The interceptor
bean class should implement the interface and implement the
invoke(MethodInvocation) method of the interface to modify the
behavior of a method.
Create an interceptor
Java class CatalogInterceptor that implements the MethodInterceptor
interface in the spring.catalog package. CatalogInterceptor.java get
added to the Spring project. In the invoke() method output the name
of the intercepted method and the name of the class containing the
intercepted method. The CatalogInterceptor method is listed below.
package spring.catalog;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;
public class CatalogInterceptor implements MethodInterceptor {
@Override public Object invoke(MethodInvocation inv) throws Throwable {
System.out.println("Intercepted method - " + inv.getMethod().getDeclaringClass()
+ " - " + inv.getMethod().getName());
return null; }}
Creating a Spring Client
In this section we
shall create a Java client for the Spring bean and invoke the bean
methods. We shall instantiate the Spring bean that represents the
JavaBean spring.catalog.Catalog and invoke its method. Subsequently,
we shall instantiate the proxy bean proxyBean, which is configured
with an interceptor. We shall invoke the methods of the target class
to demonstrate that the method interceptor intercepts the method
calls and outputs the method name and the name of the containing
class.
First, create a Spring
client class SpringClient in the same package as the JavaBean and the
interceptor class. Add external JARs asm-3.3.jar and cglib-2.2.jar to
the Java Build Path.
We shall create two
versions of the SpringClient.java class. In the first version we
shall instantiate the JavaBean Catalog and invoke its methods to
demonstrate that the interceptor is not invoked. Instantiate the
Catalog bean using the <constructor-arg > elements or the
property/value in beanDefinition.xml as discussed earlier. Add a
method loadContext() to instantiate the Spring container, which is
essentially creating an ApplicationContext.
private void loadContext() { String filename = "beanDefinition.xml"; context = new FileSystemXmlApplicationContext(filename); }
In the main method
create an instance of the SpringClient class and invoke the
loadContext method.
SpringClient client = new SpringClient(); client.loadContext();
Instantiate the
JavaBean with id spring.catalog using the getBean method.
Catalog catalog = (Catalog) context.getBean("spring.catalog");
Output the bean
properties’ values.
System.out.println(catalog.journal); System.out.println(catalog.publisher); System.out.println(catalog.edition); System.out.println(catalog.title); System.out.println(catalog.author);
Invoke the
getTestMessage() and output the message returned.
String test = catalog.getTestMessage(); System.out.println(test);
The SpringClient.java
class is shown below.
package spring.catalog;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext;
public class SpringClient {
private static ApplicationContext context;
/** * Load up the Spring container */
private void loadContext() { String filename = "beanDefinition.xml"; context = new FileSystemXmlApplicationContext(filename); }
public static void main(String[] args) {
SpringClient client = new SpringClient(); client.loadContext(); //getBean spring.catalog Interceptor method not invoked. Catalog catalog = (Catalog) context.getBean("spring.catalog"); System.out.println(catalog.journal); System.out.println(catalog.publisher); System.out.println(catalog.edition); System.out.println(catalog.title); System.out.println(catalog.author); String test = catalog.getTestMessage(); System.out.println(test);
} }
Right-click on the
SpringClient.java application and select Run As>Java
Application.
As the Catalog JavaBean
is not configured with a method interceptor the method calls do not
get intercepted and the values returned by the accessor methods get
output.

Figure 7
We could also have used
a XmlBeanFactory method to instantiate the Spring bean, and also used
setter methods to set the bean properties’s values instead of
instantiating the bean in the beanDefinition.xml. The output would be
the same, but would include the message “Loading XML bean
definitions from class path resource (beanDefinition.xml)”.
In the second version
of the SpringClient application we shall instantiate the proxy bean
that is configured with the interceptor method. We shall reference
the proxy through the Spring container. Create a XmlBeanFactory
object.
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanDefinition.xml"));
Instantiate the proxy
bean with the getBean method.
Catalog catalog = (Catalog) beanFactory.getBean("proxyBean");
Invoke the
getTestMessage method and output the value returned.
String test = catalog.getTestMessage(); System.out.println(test);
Invoke the setter
methods to set the values of the bean properties.
catalog.setJournal("Oracle Magazine"); catalog.setPublisher("Oracle Publishing"); catalog.setEdition("November-December 2010"); catalog.setTitle("Agile Enterprise Architecture"); catalog.setAuthor("Bob Rhubart");
Output the bean
properties.
System.out.println(catalog.journal); System.out.println(catalog.publisher); System.out.println(catalog.edition); System.out.println(catalog.title); System.out.println(catalog.author);
The SpringClient.java
is listed below.
package spring.catalog;
import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource;
public class SpringClient {
public static void main(String[] args) {
// reference the proxy through the Spring container //getBean proxyBean Interceptor method invoked. /** * Load up the Spring container */ XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanDefinition.xml"));
//getBean proxyBean Interceptor method invoked.
Catalog catalog = (Catalog) beanFactory.getBean("proxyBean");
String test = catalog.getTestMessage(); System.out.println(test);
catalog.setJournal("Oracle Magazine"); catalog.setPublisher("Oracle Publishing"); catalog.setEdition("November-December 2010"); catalog.setTitle("Agile Enterprise Architecture"); catalog.setAuthor("Bob Rhubart"); System.out.println(catalog.journal); System.out.println(catalog.publisher); System.out.println(catalog.edition); System.out.println(catalog.title); System.out.println(catalog.author); } }
Right-click on
SpringClient.java and select Run As>Java Application.
As the proxy bean is configured with the interceptor method, the
method invocations get intercepted. The invoke method of the
CatalogInterceptor class gets invoked. The method name and the name
of the containing class are the output. The bean properties’ values
are not in the output as the method invocations are intercepted.

Figure 8.
aop Namespace
Spring implements AOP
using a spring-aop schema and the aop namespace. Alternatively, AOP
may be implemented using the @Aspect annotation.
In this section we
shall use the aop namespace to implement AOP. We will develop a Web
application consisting of a JSF page for user input, and
applicationContext.xml to create a BeanFactory and an
ApplicationContext. Some of the aop namespace tags are discussed in
the following table.
Tag
|
Description
|
aop:aspectj-autoproxy
|
Enables @AspectJ aspects in Spring with
autoproxying beans.
|
aop:config
|
All aspects and advisors must be declared
within aop:config
|
aop:pointcut
|
Declares a pointcut
|
aop:aspect
|
Declares an aspect
|
aop:after-returning
|
Declares advice that runs after matched method
execution completes normally
|
aop:after-throwing
|
Declares advice that runs after matched method
execution exits by throwing an exception
|
aop:advisor
|
Declares an advisor
|
aop:before
|
Declares advice that runs before matched method
execution
|
aop:after
|
Declares advice that runs no matter how the
matched method execution exits
|
Creating a Spring & JSF Faceted Web Project
Now we will create a
Web project, SpringJSF, for the Spring AOP similar to the Spring
project that we created for the method interceptor example.
- Select Web>Dynamic
Web Project in New wizard.
- In New Dynamic Web
Project specify a Project name, SpringJSF, and configure a
target runtime for Oracle WebLogic Server 11gR1 Patch Set 2.
- Select the Default
Configuration… and click on Next.
- Accept the default
Java settings (source folder as src and output folder as
build/classes). Click on Next.
- Specify a Context
Root (SpringJSF) and a Content directory, select the checkbox
Generate web.xml deployment descriptor, and click on Finish.
A Web project for Spring AOP gets created.
- Now right-click on
SpringJSF in the Project Explorer and select Properties.
- Select Project
Facets. Configure the Spring facet as discussed previously. Also
select the JSF 1.2 facet.
- Click on Further
configuration required.
- In JSF Capabilites
select JSF Implementation Library Type as User Library and
click on the Download library... button.
- Select the JSF
1.2 (Mojarra JSF API Implementation) and click on Next.
- Accept the terms
of the license and click on Finish. The JSF 1.2 library gets
added to the project.
- Click on Next.
In the Spring configuration select the checkbox Create a Spring
bean definition file and select the default file
applicationContext.xml.
- Click on OK.
- In
Properties>Project Facets click on Apply to install the
project facets JSF 1.2 and Spring 2.5.
- Click on OK
to configure the target runtimes with the project facet libraries. A
Spring and JSF faceted Web project gets created. The JSF and Spring
libraries are also shown added to the project.

Figure 9.
The
web.xml file gets updated with a contextConfigLocation context
parameter that specifies the location of the applicationContext.xml
file. Also, a listener class
org.springframework.web.context.ContextLoaderListener gets
configured. The listener class is the bootstrap listener to start up
Spring’s root
org.springframework.web.context.WebApplicationContext. The Spring AOP
framework requires the AspectJ library in the classpath. Add the
AspectJ library and dependencies shown below to the Java Build path.

Figure 10.
Creating a Bean Class
In this section we
shall create a JavaBean that we shall configure as a Spring bean and
use in a pointcut expression.
Create a Java class
Catalog.java by selecting Java>Class in New wizard. To
Catalog.java JavaBean add properties for journal, publisher, edition,
title, and author. Also, add accessor methods for the JavaBean
properties. The getter accessor methods should return the initial
values for the bean properties. The Catalog JavaBean’s properties
may alternatively be instantiated using property/value or
constructor-arg in the applicationContext.xml. The JavaBean class
Catalog.java is shown below.
package spring.catalog;
public class Catalog {
public String journal; public String publisher; public String edition; public String title; public String author;
public Catalog() { }
public Catalog(String journal, String publisher, String edition, String title, String author) {
this.journal = journal; this.publisher = publisher; this.edition = edition; this.title = title; this.author = author; }
public java.lang.StringBuffer getAuthor() { return new StringBuffer("Bob Rhubart"); }
public java.lang.StringBuffer getEdition() { return new StringBuffer("November-December 2010"); }
public java.lang.StringBuffer getJournal() { return new StringBuffer("Oracle Magazine"); }
public java.lang.StringBuffer getPublisher() { return new StringBuffer("Oracle Publishing"); }
public java.lang.StringBuffer getTitle() { return new StringBuffer("Agile Enterprise Architecture"); }
public void setAuthor(String author) { this.author = author; }
public void setEdition(String edition) { this.edition = edition; }
public void setJournal(String journal) { this.journal = journal; }
public void setPublisher(String publisher) { this.publisher = publisher; }
public void setTitle(String title) { this.title = title; } }
Creating a AOP JavaBean
In this section we
shall create a JavaBean that we will configure with the Spring
framework in applicationContext.xml as a Spring AOP aspect. Create a
Java class CatalogAOP.java in the same package as the Catalog.java
JavaBean. The pointcut expression is used to match join
points and the advice is the action taken by the aspect.
The aspect’s pointcut expression and advice type are configured in
the applicationContext.xml, in the next section. We shall be
configuring aop:after-returning advice for each of the getter
accessor methods in the Spring bean Catalog that return values for
bean properties as SpringBuffer.
In the advice we shall
invoke the setter methods of the Spring aspect bean CatalogAOP.java
with the values returned by the getter methods of the Catalog
JavaBean as arguments. The Spring AOP framework shall invoke the
setter methods of the Spring aspect bean CatalogAOP dynamically after
returning from the getter methods of the Spring bean Catalog.
In the setter methods
in the aspect bean we shall first output the bean property values
returned by the Catalog bean prepended by the method name and
subsequently modify the bean property values by adding labels to
precede the bean properties. For example, the setTitle(String title)
method modifies the Catalog JavaBean’s title property by prepending
it with "Title: ".
public void setTitle(StringBuffer title) { System.out.println("setTitle method invoked" + title); title.insert(0, "Title: "); }
The CatalogAOP.java
Spring AOP aspect is shown below.
package spring.catalog;
public class CatalogAOP {
public String journal; public String publisher; public String edition; public String title; public String author;
public CatalogAOP() { }
public CatalogAOP(String journal, String publisher, String edition, String title, String author) {
this.journal = journal; this.publisher = publisher; this.edition = edition; this.title = title; this.author = author; }
public String getAuthor() { return author; }
public String getEdition() { return edition; }
public String getJournal() { return journal; }
public String getPublisher() { return publisher; }
public String getTitle() { return title; }
public void setEdition(StringBuffer edition) { System.out.println("setEdition method invoked" + edition); //edition.insert(0, "Edition: "); }
public void setJournal(StringBuffer journal) { System.out.println("setJournal method invoked" + journal); //journal.insert(0, "Journal: "); }
public void setPublisher(StringBuffer publisher) { System.out.println("setPublisher method invoked" + publisher); // publisher.insert(0, "Publisher: "); }
public void setTitle(StringBuffer title) { System.out.println("setTitle method invoked" + title); // title.insert(0, "Title: "); }
public void setAuthor(StringBuffer author) { System.out.println("setAuthor method invoked" + author); //author.insert(0, "Author: "); } }
Creating a Bean
Definition File
The Spring AOP
including the pointcuts, aspects, and advices are configured in the
Spring configuration file applicationContext.xml. For using the
Spring AOP framework we need to enable AspectJ support.
First, configure a
Spring bean for the CatalogAOP JavaBean, which we shall subsequently
configure as an aspect. To enable the AspectJ support add the
aop:aspectj-autoproxy element. Add the ‘<’ and select
aop:aspectj-proxy element from the pop-up.

Figure 11.
All aspects and
advisors are declared within the aop:config element. Add the
aop:config element to the Spring configuration file. Add a ‘<’
and select the aop:config element from the pop-up.

Figure 12.
If the target object
does not use any interfaces Spring AOP uses CGLIB to create the proxy
for the target object. To specify the use of CGLIB set the
proxy-target-class attribute of aop:config to “true”. Right-click
on aop:config and select Add Attribute>proxy-target-class.

Figure 13.
Next, add a pointcut
defintion to the aop:config element. A pointcut is used to match join
points; a join point in Spring AOP is a method execution.
A pointcut definition
within a aop:config may be used for several aspects and advisors. We
shall use the “bean” pointcut designator (PCD) to specify the
Catalog Spring bean for matching join points. Right-click on
aop:config and select Add Child>pointcut.

Figure 14.
Specify the value of
the expression attribute as bean(catalogBean). Next, add an aspect.
Right-click on aop:config and select Add Child>aspect.

Figure 15.
To the aop:aspect
element add a ref attribute to refer to the Spring bean
catalogBeanAOP, which is the aspect Spring bean. Right-click on
aop:aspect and select Add Attribute>ref. The Spring
bean catalogBeanAOP gets configured as an aspect.

Figure 16.
Next, we shall
configure after-returning advice for each of the getter methods of
Spring bean catalogBean, which is the JavaBean Catalog. Right-click
on aop:aspect and select Add Child>after-returning.
After returning advice is the advice to be run when a method returns
without throwing an exception.

Figure 17.
To the after-returning
element add the attributes explained in the following table, which
applies for one join point.
Attribute
|
Value
|
Description
|
pointcut
|
execution(java.lang.StringBuffer
getJournal(..))
|
Specifies the pointcut expression to match a
join point, which is the method call to getJournal that returns a
StringBuffer
|
method
|
setJournal
|
The method of the aspect to invoke
|
returning
|
journal
|
The advice method parameter to which the return
value of the getJournal method is passed as an argument. The type
of the returned value should match the parameter type.
|
arg-names
|
journal
|
Specifies argument names for the advice method
|
Similarly, add
after-returning advice for other join points. The Spring
configuration file with after-returning advice for all the join
points is listed below.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="<A HREF="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</A>" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="<A HREF="http://www.springframework.org/schema/aop">http://www.springframework.org/schema/aop</A>" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> &... id="catalogBean" class="spring.catalog.Catalog"> <!-- <property name="journal"> <value>Oracle Magazine</value> </property> <property name="publisher"> <value>Oracle Publishing</value> </property> <property name="edition"> <value>November-December 2010</value> </property> <property name="title"> <value>Agile Enterprise Architecture</value> </property> <property name="author"> <value>Bob Rhubart</value> </property> <constructor-arg index="0" value="Oracle Magazine" /> <constructor-arg index="1" value="Oracle Publishing" /> <constructor-arg index="2" value="November-December 2010" /> <constructor-arg index="3" value="Agile Enterprise Architecture" /> <constructor-arg index="4" value="Bob Rhubart" />--> </bean>
<bean id="catalogBeanAOP" class="spring.catalog.CatalogAOP"/>
<aop:aspectj-autoproxy /> <aop:config proxy-target-class="true"> <aop:pointcut expression="bean(catalogBean)" id="catalogBeanPc"></aop:pointcut> <aop:aspect ref="catalogBeanAOP" id="catalogBeanAspect"> <aop:after-returning pointcut="execution(java.lang.StringBuffer getJournal(..))" method="setJournal" returning="journal" arg-names="journal" /> <aop:after-returning pointcut="execution(java.lang.StringBuffer getPublisher(..))" method="setPublisher" returning="publisher" arg-names="publisher" /> <aop:after-returning pointcut="execution(java.lang.StringBuffer getEdition(..))" method="setEdition" returning="edition" arg-names="edition" /> <aop:after-returning pointcut="execution(java.lang.StringBuffer getTitle(..))" method="setTitle" returning="title" arg-names="title" /> <aop:after-returning pointcut="execution(java.lang.StringBuffer getAuthor(..))" method="setAuthor" returning="author" arg-names="author" /> </aop:aspect> </aop:config> </beans>
Creating a JSF Page
In this section we
shall create a JSF page to output the Spring bean catalogBean
(Catalog.java JavaBean) properties. We shall demonstrate the effect
of the aspect Spring bean catalogAOPBean on the catalogBean’s
propeties’ values.
- Select
File>New. In New wizard select Web>JSP and click on
Next.
- Select the
SpringJSF/WebContent folder and specify File name as catalog.jsp
and click on Next.
- Click on Finish.
A JSP catalog.jsp get added to the SpringJSF project.
In the catalog.jsp
output the values for the catalogBean properties using the
h:outputText element. Catalog.jsp is listed below.
<?xml version="1.0" encoding="ISO-8859-1" ?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" version="2.0"> <jsp:output omit-xml-declaration="true" doctype-root-element="HTML" doctype-system="http://www.w3.org/TR/html4/loose.dtd" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/> <jsp:directive.page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" /> <f:view> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/> <title>Catalog</title> </head> <body> <h:form><table> <tr><td> <h:outputText value="#{catalogBean.journal}"/></td></tr> <tr><td><h:outputText value="#{catalogBean.publisher}"/></td></tr> <tr><td> <h:outputText value="#{catalogBean.edition}"/></td></tr> <tr><td><h:outputText value="#{catalogBean.title}"/></td></tr> <tr><td><h:outputText value="#{catalogBean.author}"/></td></tr> </table></h:form> </body> </html> </f:view>
</jsp:root>
To the faces-config.xml
add the following application element so that EL expressions also
recognize Spring beans as managed beans.
<application><el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver></application>
Running the JSF Page
In this section we
shall run the catalog.jsp to demonstrate the effect of the aspect on
the Spring bean catalogBean’s properties. In the first run comment
out the modifications, which prepend labels to the Spring bean’s
property values in the CatalogAOP JavaBean’s setter methods.
//edition.insert(0, "Edition: "); //journal.insert(0, "Journal: "); //publisher.insert(0, "Publisher: "); //title.insert(0, "Title: "); //author.insert(0, "Author: ");
Right-click on
catalog.jsp and select Run As>Run on Server. Start
the WebLogic server if not already started and click on Finish.
The SpringJSF application gets deployed to the WebLogic server as an
auto-generated EAR file. The server output shows that the setter
methods of the Spring AOP aspect bean get invoked and the Spring bean
catalogBean’s property values are the output.

Figure 18.
Run the catalog.jsp
with url http://localhost:7001/SpringJSF/faces/catalog.jsp.
The Spring bean catalogBean’s property values are in the output.

Figure 19.
In the second run
uncomment the modifications to the catalogBean’s property values in
the aspect Spring bean catalogAOPBean; modifications that prepend
labels. The aspect gets applied and the catalogBean’s property
values get prepened with labels, as shown in the output.

Figure 20.
In this article you
learnt about the Spring AOP framework related features, which is one
of the main components that distinguishes Spring from Java EE.
Infact, SpringSource claims that "...Spring AOP provides an
excellent solution to most problems in Java EE applications that are
amenable to AOP."
|
OpenICOM: A JPA Framework for Integrated Collaboration Environments, Part 1 Date: 03/21/2011
This article introduces OpenICOM, a JPA framework for developing integrated collaboration environments.
Learn the fundamentals of the OpenICOM framework.
Learn the fundamentals of the OpenICOM framework.
Abstract
This article is the first part of the three parts series to present a new project http://java.net/projects/open-icom in java.net to incubate a JPA framework for developing integrated collaboration environments. The first part explains the advantages of the JPA programming model, which embodies the design patterns that are well-suited for managing integrated collaboration object model (ICOM). ICOM is a framework defined by the OASIS ICOM Technical Committee to integrate a broad range of domain models for a collaboration environment. ICOM JPA framework will lower the barrier for application developers to develop collaboration tools to support seamless transitions across collaboration activities with minimal context switching. It will encourage independent software vendors and open source communities to create common collaboration clients that interoperate with integrated collaboration platforms and standalone collaboration services across enterprise boundaries. The article provides an overview of ICOM with programming examples for the ICOM JPA framework. It covers the high-level concepts, directory, space, access control, metadata, content management, and unified message model. The second part of the series will present additional extension modules defined in the ICOM specification (ICOM specification is currently a working draft in OASIS ICOM TC workspace http://www.oasis-open.org/apps/org/workgroup/icom). The design of the ICOM JPA framework will be described in the third part of the series.
Introduction
An increasing number of application APIs are standardized on Java Persistence API[1][2], which is a JSR specification that incorporates the proven solutions from leading open source and commercial object-relational mapping (ORM) frameworks, including Hibernate and TopLink. JPA is an interoperability standard that affords developers greater choices of technologies, including the open ORM frameworks as well as proprietary implementations, without subjecting the developers to a lowest common denominator.
Although JPA is an API for management of persistence and object-relational mapping, its embodiment of the general information management design patterns, such as portable POJO domain model, delineation of managed and detached objects, in-memory transactions, eager and lazy loading of states, attribute level change tracking, cascade persist (a relatively newer notion than the cascade delete notion), persistence context and second-level caches, and object query language, makes it attractive for a broader array of information management domains that may not be implemented entirely by ORM. An infrastructure to support these information management capabilities will relieve the application developers from encumbrances of writing the plumbing codes so that they can instead focus on their business domains.
One such information management domain that can benefit from a common infrastructure based on JPA programming model is the integrated collaboration environment. The OASIS Integrated Collaboration Object Model for Interoperable Collaboration Services Technical Committee (ICOM TC)[3] is defining the normative standards for collaboration objects, along with the classes, attributes, relationships, constraints, and behavior, for an integrated and interoperable collaboration environment. The specification is intended for integrating a broad range of collaboration objects to enable seamless transitions across collaboration activities. This enables applications to provide continuity of conversations across multiple collaboration channels. For example, applications can aggregate conversation threads in email with other conversations on the same topic in instant message, over the phone or via real-time conferencing, by discussion threads in community forum, wiki, weblog or micro blog, and activity stream of participants from all channels.
The JPA infrastructure for ICOM provides a unified programming model as a frontend for a set of existing protocols/services that involve several domain models from disparate technologies such as LDAP, JCR, IMAP, SMTP, XMPP, iCalendar, CalDAV, WebDAV, vCard, FOAF, SIOC, Facebook Open Graph, OpenSocial, BPEL, BPEL4People, etc. In addition to unifying the domain model, JPA offers the infrastructure for lazy loading, change tracking, attach/detach/merge, cascade persist, L1 and L2 cache, etc, capabilities that are disjointed or non-existent in the existing protocols/services. To accommodate third-party integrated collaboration platforms as well as discrete protocols/services, the ICOM JPA framework supports pluggable data access connectors. A data access connector can be implemented using the proprietary API for a vendor's integrated collaboration platform or composed from the DAO components for discrete collaboration and content management services. Figure 1 shows a few example DAO components comprising a data access connector.

Figure 1. ICOM JPA Framework.
The JPA infrastructure for collaboration technologies will be an important addition to the Java technology. We call on the java.net community to contribute data access connectors or DAO components for third-party collaboration and content management services. The framework includes a prototype data access connector for Oracle Beehive Collaboration Platform using a proprietary collaboration service interface. An alternative data access connector can be implemented using the REST/SOAP interfaces[4]. To support a JPA level-2 shared cache for a multi-user environment, the ICOM JPA framework will need to be extended to support access control enforcement. ICOM standardization of access control model makes it feasible to implement such a second-level cache extension in server environments.
A JPA framework that uses a federation of data access connectors, which themselves can be composed of discrete data access objects through separate service protocols, with various levels of transaction support by the services, inevitably compromises the ACID transaction properties. The reader is referred to the experience and usability studies[5] of the weaker consistency properties, ranging from Eventual Consistency to single-entity ACID, of Not Only SQL (NoSQL) cloud storage systems. The NoSQL cloud services such as Amazon S3 and SimpleDB, Google Datastore, Microsoft Azure Storage, and Cassandra relax the data consistency requirements to achieve throughput, availability, and elasticity requirements.
Breaking down the barriers
Enterprises have been breaking down the walls between the internal organizations to get people to collaborate across stovepipes[6] sometimes by flattening the organizational structures and other times by deploying technologies such as team workspaces, forums, wikis, etc., that promote cross-department collaboration. They have also been opening up their enterprise information systems for coordination of product specifications, engineering drawings, computer-assisted design tools, order fulfillment, procurement, billing, inventory and delivery tracking, logistics, etc., with business partners to streamline the supply-chains. An empirical study[7] showed that these e-collaboration tools improved process innovation and performance of the supply chains and offered greater process flexibility for upstream partners in the supply chains. However, they still fall short of empowering the employees to collaborate across enterprise boundaries with agility to react to exceptions in the business processes, a capability which is required to extend benefits for downstream and upstream partners in the supply chains. Nowadays, enterprises are increasingly opening up and collaborating with external organizations on larger and specialized projects for the mutual benefit of all partners, sometimes by forming dynamic virtual teams. Boeing 787 project was an example where an old supply-chain gave way to a new value-network of partners who share information through inter-enterprise collaborative workspaces in a seamless community[13].
Organizations have incrementally deployed a mix of disjoint collaboration tools. The increasingly fragmented tools only erode the productivity. The fragmented collaboration tools are usually technology driven tools that require constant context switching for the users to perform a single task. The fragmentation leads to incomplete threads of conversations when users communicate through multiple tools. The silos of tool repositories prevent the users from relating, aggregating, and reasoning about diverse types of collaboration artifacts by project, task, metadata, or any relevant context. The data silos also prevent uniform relevance rankings of search results from the isolated repositories. The proliferation of web 2.0 content silos also weakens corporate governance. On the other hand the enterprises need to integrate the artifacts that the employees generate in the unstructured collaboration activities with the enterprise business objects of the structured business processes. They need a standardized API and model for developing composite applications for contextual collaboration and semi-structured, project-centric collaboration processes where unstructured collaboration activities intersect with structured business processes.
Many organizations are faced with the technical obstacles and high costs in their quests to integrate the disjoint tools and the silos of data each tool produces. Projects to integrate the silos of repositories encountered the soaring costs or technical barriers. To solve the fragmentation problem, various collaboration vendors have attempted to unify their platforms in order to build a single collaboration environment which provides the full range of collaboration activities. However, these vendor specific platforms still lack a standard model, interface, and protocol to support contextual collaboration within business processes. Without a standard collaboration model that can provide a complete range of collaboration activities, customers, independent software vendors, and system integrators face a difficult challenge to build contextual collaboration environments using service components from multiple vendors. OASIS ICOM TC was chartered two years ago to define a standard collaboration model to address the integration challenges. ICOM covers a broad, extensible range of collaboration activities encompassing, and in some cases improving on, a range of models in existing standards and technologies that were developed independently and had created the impedances between the components across standard and technology boundaries.
The walls between internal organizations and across enterprises have been coming down with the deployment of cross-boundary collaboration technologies. One of the technologies is the social networking service which let a user create a public or semi-public profile in an articulated network of profiles to share experience through activity streams, blogs in friends' dashboards, ratings and recommendations, and other shared media. Gartner report[10] projected that social networking tools will replace email as primary interpersonal communication tool for 20 percent of business users by 2014. In the consumer world, social networking activities have already surpassed email as the most popular online activities. Some external facing employees in marketing, sales, and customer care, have to use popular social networking sites, such as Facebook, Twitter, YouTube, etc., to interact with consumers. Integrated collaboration environments should provide an integration point to the consumer social networking sites to offer more open experience. The JPA infrastructure for ICOM can support data access objects for Open Graph and OpenSocial APIs[11][12] to integrate with consumer social networking sites.
ICOM can further accelerate the removal of the walls between the collaboration tools and also expose the data from behind the wall of applications. Exposing the data in machine readable form is what Semantic Web is about. OASIS ICOM TC includes representations from Digital Enterprise Research Institute (DERI) and Ontolog Forum, whose focus areas are in semantics technologies. ICOM ontology is defined from the outset for concomitant representation in UML and RDF. ICOM TC wiki page[3] discusses the mappings between UML and RDF representations. ICOM can bridge the object-oriented software engineering world with the semantic web world by providing bi-directional transformations between UML and RDF. Linked Data Community[8] is advancing the use of web, URI, and RDF to connect distributed data. There is a popular saying "a little semantic goes a long way" about enriching the data with inference capability. ICOM data with a seamless programming model like JPA and a concomitant RDF representation will lower the barrier for applying inference engines such as JESS, OWL, and SPARQL. Figuratively speaking, a rich vocabulary of "nouns" in ICOM makes up for the strong "verbs" in service interfaces. A well-defined set of classes of ICOM makes the API amenable for rule-based applications and declarative inference. ICOM containers are active or reactive entities, for example conference and chat rooms are highly active while outbox, calendar, and task list are reactive. Their behavior can be augmented by applications.
Overview of ICOM
ICOM specification defines a class called Entity which is the super class of any class that supports a persistent identifier, a change token for optimistic locking, and an access control list. The object identifier and change token are annotated, respectively, by "javax.persistence.Id" and "javax.persistence.Version," matching the ICOM concept of Entity with the JPA concept of Entity. ICOM Entity has another fundamental dimension for access control list, which together with JPA Id and Version, defines a unit of persistent information for concurrency and access control. The generation of object identifiers is implementation dependent; however, ICOM recommends that the object identifiers should be globally unique to support permanent references to the entities that may migrate amongst interoperable ICOM repositories. An object identifier is read only (immutable) once it is assigned and should never be duplicated or re-used for more than one object. The UML diagram in Figure 2 depicts the Entity class, properties, and cardinality of the properties. Entity's properties include name, created by, creation date, last modified by, last modification date, owner, parent, attached markers, category applications, tag applications, and access control list.

Figure 2. UML Class Diagram for Entity.
Here we explain the usage of each of the properties of Entity shown in Figure 2. ICOM relies on object identifier for persistent identification of an entity and allows the name string of the entity as an optional property. The actor who creates an entity is represented by the created by attribute. The created by and creation date attributes are set by the system and cannot be changed once they are set, hence created by and creation date are read-only attributes for applications. The last modified by and last modification date attributes can be updated by applications although ordinarily these attributes should be set by the system. The owner of an entity can be either a single actor or a group of actors. The parent of an entity can be a container, an extent, or a parental entity. The attached markers attribute of an entity represents the category and tag metadata entities associated with the entity. The category applications or tag applications attributes of an entity represent the instances of associations between categories or tags with the entity. These two attributes can also represent the multiple instances of associations between a category or tag with an entity, for example when different users apply the same tag on an entity, each instance is represented by a different tag application. Access control list of entity provides fine grained access control policy at individual entity level.
An access control list (ACL) is an object attached to an entity to specify a list of permissions to access the entity. See Figure 3. The subject of an access control entry is an Accessor, which includes Group and Actor.

Figure 3. UML Class Diagram of Access Control List.
The UML class diagram in Figure 4 depicts the top level classes of ICOM. The five subclasses of Entity, namely Relationship, EntityDefinition, Scope, Subject, and Artifact, inherit the properties from Entity. Of these five subclasses, Relationship and EntityDefinition are metadata concepts. Scope, Subject, and Artifact represent the forking of three major branches of ICOM.

Figure 4. Top-level Subclasses for Entity.
Parental, Extent, and Container are mixin classes depicted as Java interfaces in Figure 4. The parental concept avoids overloading two aspects of parent-child relationship on Extent or Container. There are a few classes in ICOM that are Parental but not Extent or Container. A unified message can be a parent of an attachment, such as a forwarded message, replied to message, or document. Similarly, a document can be a parent of parts of the document. A parent-child relationship between a unified message and its attachments is different from a parent-child relation between an extent or container and its elements: the elements of an extent or container can have their own ACLs to override the ACL of the extent or container; on the other hand, attachments in the unified message always share the same ACL with the parent message, such that if a user can read the message, he or she can also read the attachments in the message. UnifiedMessage and Document are defined as Parental instead of Extent or Container. Actor, which can be a parent of user credential's principals, pseudonyms, avatars, etc., is also defined as Parental. Community is defined as Extent while Space and Folder are defined as Container. See Figure 5.

Figure 5. Parental, Extent, and Container Interfaces
The three major branches of ICOM Entity are described below.
Scope Branch
Scope includes Community and Space as shown in Figure 6.

Figure 6. Scope Branch.
Scope: A scope is an extent of a role assignment such that the privileges of the role are applicable only for operations on the entities in the scope. A scope contains role definitions, roles, and groups. A scope is relationship bondable so has a property for a set of relationships of a scope. See Figure 7.

Figure 7. UML Class Diagram for Scope.
Community: A community is a scope that contains sub-communities, spaces, actors, groups, roles, and role definitions. See Figure 8. It is implementation-dependent whether or not a space in a community can include participating actors who are not members of a parent community or ancestor communities.

Figure 8. UML Class Diagram for Community.
Space: A space is a scope that defines a durable context and place for actors to work or collaborate. A space contains space items, which include sub-containers such as inbox, calendar, task list, conference, chat room, library, to name a few. See Figure 9.

Figure 9. UML Class Diagram for Space.
Subject Branch
Subject branch includes Role, Group, and Actor as shown in Figure 10.

Figure 10. Subject Branch.
Subject: A subject is an entity who can have rights to perform actions on entities. Subject is relationship bondable so has a property for a set of relationships of a subject. Subject can have an extensible list of properties. See Figure 11.

Figure 11. UML Class Diagram for Subject.
Role: A role assigns a named set of privileges to a set of accessors for operations within an assigned scope. A role definition associated with a role represents a named set of privileges. See Figure 12. The role definitions can be carefully designed with minimal sets of privileges needed to perform specific tasks. These role definitions can be created in the higher-level scopes to be used in assigning roles at the lower-level scopes. This practice promotes the principle of least privileges and uniformity of roles across spaces of a community. The role definitions can be part of the templates for creating new project spaces. For example, an implementation can supply a role definition for minimal privileges needed to coordinate the memberships of a project space. This role definition can be used to assign space coordinator role to any new project space. The privileges assigned by the role are applicable only for operations on entities in an assigned scope. A role is listed as a member of one or more communities or spaces.

Figure 12. UML Class Diagram for Role.
Group: A group is a named set of actors that can be assigned to a role, assigned as a subject in an access control list, and used as a buddy list, email distribution list, or participant list in collaboration activities. A group's properties include member actors, member groups, assigned groups, assigned roles, assigned scopes, addresses, and primary address. A group is listed as a member of one or more roles, communities, or spaces. It is addressable and can be an owner of one or more entities. See Figure 13.
Actor: An actor can act on entities according to the access rights that are derived from assigned roles and access control lists where it appears as a subject. An actor's properties include assigned groups, assigned roles, assigned communities, addresses, and primary address. An actor is listed as a member of one or more groups, roles, or communities. It is addressable and can be an owner of one or more entities. See Figure 13.

Figure 13. UML Class Diagram for Group and Actor.
The classes in Scope and Subject branches, including Community, Space, Role, Group, and Actor, are components for representing the Directory and Membership constructs as described below.
Directory: A directory is hierarchical classified listings of Role, Group, and Actor for administration, search and indexing, and uniform reference. ICOM model for hierarchy of communities represents the directory features similar to LDAP schema. A community's properties for roles, groups, member groups, actors, and member actors list the resources as directory entries. A space also has properties for roles, groups, and member groups. Discretionary access control (DAC) and role-based access control (RBAC) policies are defined in terms of the subjects from the directory (see Figures 3 and 13).
Membership: A membership in a community or space is represented by access control policies in the nested scopes of communities, spaces, and space items (space items are sub-containers in a space). The properties such as member groups and member actors are for indexing only while access control lists and roles define the operational aspects of membership. As a hypothetical example, let's define a "viewer" membership in a project to mean that an individual can view the artifacts and post discussions to the forums in the project space, but may not update artifacts in the space. We further define "participant" membership for active participants who may update any artifact in the space. The UML collaboration diagram in Figure 14 shows how such membership constructs can be configured by access control model. The "participant" and "viewer" groups in conjunction with the access control policy serve as the template for this hypothetical membership construct.

Figure 14. A Hypothetical Membership Construct.
Once the membership scheme is defined, the users can be added to one of the membership groups. In the configuration in Figure 14, both userA and userB are members of the project space. UserA is a member of the group which has read/write access to the whole space and so can actively participate in the project space. UserB is a viewing member who has read/write access in the forum but only read access in the space. Thus userB is a viewer who may only post discussions in the forum. The "participants" and "viewers" groups can be created in the project space if they are used only for this project space.
The following code snippet describes how to create a community and add a user to the community. Role definitions are usually created in the community to provide uniform role assignments across the spaces of the community. The JPA framework can sort the entities in the transaction by the dependency of the entities to avoid referential constraint violations when it creates the entities one by one in the collaboration services.
The code examples also illustrate the cascade persist mechanism in action. We have declared JPA CascadeType.PERSIST annotation on the parent-to-child containment properties of Community, Space, and other parental classes. When a new community object is created under an organization, the community becomes persistent without requiring an explicit call to EntityManager.persist() method because the parent organization is persistent. Similarly when user, group, role, role definition, and space objects are created in the community, these objects become persistent. This is one of the features that makes JPA programming model seamless.
SessionContext ctx; Community organization; Owner owner; ...
Date dt = new Date(); Community community = new Community(organization, dt); community.setName("ICOM Community"); community.setOwner(owner); community.setDescription("A developer community for ICOM");
User user = new User(community, dt); user.setName("Eric"); user.setFamilyName("Chan");
EntityAddress address1 = new EntityAddress(); URI emailAddress1 = new URI("mailto:" + "eric.s.chan" + "@" + "oracle.com"); address1.setAddress(emailAddress1); address1.setAddressType("BUSINESS_1"); user.addAddress(address1); EntityAddress address2 = new EntityAddress(); URI emailAddress2 = new URI("mailto:" + "eschan" + "@" + "acm.org"); address2.setAddress(emailAddress2); address2.setAddressType("BUSINESS_2"); user.addAddress(address2); EntityAddress address3 = new EntityAddress(); URI emailAddress3 = new URI("mailto:" + "eric.s.chan" + "@" + "oracle.com"); address3.setAddress(emailAddress3); address3.setAddressType(BUSINESS_1); user.setPrimaryAddress(address3); RoleDefinition participantRoleDef = new RoleDefinition(community, dt); participantRoleDef.setName("Participant"); participantRoleDef.addPrivilege(BeehivePrivilegeEnum.WORKSPACE_MGR); participantRoleDef.addPrivilege(BeehivePrivilegeEnum.CONTENT_MGR); participantRoleDef.addPrivilege(BeehivePrivilegeEnum.USER_MGR); participantRoleDef.setOwner(owner); RoleDefinition viewerRoleDef = new RoleDefinition(community, dt); viewerRoleDef.setName("Viewer"); viewerRoleDef.addPrivilege(BeehivePrivilegeEnum.CONTENT_USER); viewerRoleDef.addPrivilege(BeehivePrivilegeEnum.FORUM_WRITER); viewerRoleDef.setOwner(owner);
try { ctx.getUserTransaction().commit(); } catch (Exception ex) { ... }
The following code snippet describes how to create a space with participant and viewer members. It looks up the role definitions in the parent community. When the transaction is committed, the JPA framework creates the objects in the collaboration services through the data access connector.
SessionContext ctx; Community community; User user; User[] subscribers; ... RoleDefinition participantRoleDef = null; RoleDefinition viewerRoleDef = null;
Set<RoleDefinition> roleDefinitions = community.getRoleDefinitions(); for (RoleDefinition def : roleDefinitions) { if (def.getName().equals("Participant")) { participantRoleDef = def; } else if (def.getName().equals("Viewer")) { viewerRoleDef = def; } }
Date dt = new Date();
Space icomJPAProjectSpace = new Space(community, dt); icomJPAProjectSpace.setName("ICOM JPA Project Space"); icomJPAProjectSpace.setOwner(user);
Group participants = new Group(icomJPAProjectSpace, dt); participants.setName("Participants"); participants.setDescription("Participants of community"); participants.addMemberActor(user); participants.setOwner(user);
Role projectParticipant = new Role(icomJPAProjectSpace, participantRoleDef, dt); projectParticipant.setName("ICOM JPA Project Participant"); projectParticipant.addMemberAccessor(participants); projectParticipant.setAssignedScope(icomJPAProjectSpace); projectParticipant.setOwner(user);
Group viewers = new Group(icomJPAProjectSpace, dt); viewers.setName("Viewers"); viewers.setDescription("Viewers of project"); viewers.setOwner(user); for (User aUser : subscribers) { viewers.addMemberActor(aUser); }
EntityAddress address = new EntityAddress(); URI emailAddress = new URI("mailto:" + "icomJpaDev" + "@" + "java.net"); address.setAddress(emailAddress); address.setAddressType("BUSINESS_1"); viewers.setPrimaryAddress(address);
Role projectSubscriber = new Role(icomJPAProjectSpace, viewerRoleDef, dt); projectSubscriber.setName("ICOM JPA Subscribers"); projectSubscriber.addMemberAccessor(viewers); projectSubscriber.setAssignedScope(icomJPAProjectSpace); projectSubscriber.setOwner(user);
try { ctx.getUserTransaction().commit(); } catch (Exception ex) { ... }
Artifact Branch
The elements of the spaces are artifacts. Artifact includes generic components like Folder, Document, and Message. Heterogeneous folder is a common type of Folder. UnifiedMessage is a common type of Message. See Figure 15.

Figure 15. Artifact Branch.
Artifact: An artifact is a result of a communication, cooperation, content creation, or in general a collaboration activity. Sending a message is an example of a collaboration activity that results in a message artifact. An artifact's properties include description, user creation date, user last modification date, extensible properties, and viewer properties. See Figure 16. Unlike the read-only creation date and last modification date properties inherited from Entity, user creation date and user last modification date properties can be updated by applications. Artifact is relationship bondable so has a property for a set of relationships of an artifact.

Figure 16. UML Class Diagram for Artifact.
Folder: A folder is a class of artifact to contain other artifacts. Every folder except the root folder has at least one parent folder. The parent of the root folder is a space. Subclasses of folder should enforce their own semantics on elements of the folder.
HeterogeneousFolder: A heterogeneous folder is an unconstrained folder to contain any type of artifacts. It is typically used for document library, inbox, and trash containers of a space. Heterogeneous folder has a property to hold elements, including documents and unified messages. See Figure 17.

Figure 17. UML Class Diagram for HeterogeneousFolder.
ICOM specification defines many types of folders which can be elements of the spaces. A space aggregates the collaboration activities across different folders, folders that more or less represent technology or protocol channels, to support the continuity of conversations, projects, tasks, and contexts. The specialized folders are defined as extension modules in the ICOM specification. The repertoire of specialized folders can potentially grow to include other advanced collaboration activities, such as decision support, simulation, command and control, business process monitoring, to name a few. Heterogeneous folders can be used to support inbox, outbox, document library, wiki pages, and trash folders in spaces, in addition to the following types of folders which are also commonly used for composing project workspaces (see Figure 18):
AddressBook: An address book is a folder that contains contacts, which can include bookmarks to addressable entities in the directories, addresses, and other personal entries.
Calendar: A calendar is a folder that contains time management artifacts such as occurrences and occurrence series.
TaskList: A task list is a folder that contains task management artifacts such as tasks and task assignments.
Blog: A blog (a blend for the term web log) is a folder that contains journal or log entries for access through web channel.
Forum: A forum is a folder that contains sub-forums, topics, announcements, and discussions.
Conference: A conference is a folder for visual, audio, and chat transcripts of the conference sessions. It also specifies the current status, conference settings, past sessions, active session, and activity logs.

Figure 18. A Workspace Composed of Several Types of Folders.
In addition to the specialized folders for coordination, communication, and content management, ICOM specification includes the following general categories of model:
- metadata (formal taxonomy, social linking/tagging folksonomy),
- process integration (workflow, policy, subscription, content change notification), and
- activity streams.
ICOM defines the Relationship and Marker metadata model. Relationship can be associated with any relationship bondable entity. Almost all types of Entity, except Relationship type, are relationship bondable. Therefore, a relationship cannot be relationship bonded by other relationships. Marker, which includes Category and Tag, can be associated with any type of Entity.
A relationship is an entity that relates a set of entities by a predicate. A relationship definition is an entity that defines the type of a relationship, including a name and a description of the relationship type, types of source entity and target entities of the relationship, and definition of properties in the relationship. See Figure 19.

Figure 19. UML Class Diagram for Relationship.
A marker is an artifact that groups together entities by a criterion. Markers can be flat or hierarchical. Flat markers are modeled by tag and hierarchical markers are modeled by category. See Figure 20. In some cases when a user applies a marker to an entity, the marker application should be private such that only the user who applies the marker can browse or locate the entity through the marker, especially when a marker created by a user is visible only to the user. A marker is listed in the markers property of one or more entities.

Figure 20. Marker Classes.
A tag is a marker that labels entities by a keyword. A tag has properties for application count that records how many times a tag has been applied on entities. Each application is represented by a tag application object. See Figure 21. A tag application has properties for attached entity, applied by actor, and application date. A tag application is listed in the tag applications property of an entity.

Figure 21. UML Class Diagram for Tag.
A category is a marker that classifies entities by taxonomy. A category has properties for super category and sub-categories. It also has property definitions that specify the name, type, cardinality, and facet of the properties for category applications. See Figure 22. A category application is an instance of association between a category and a specific entity. A category application has properties for category, attached entity, and extensible properties corresponding to the property definitions in the category. A category application is listed in the category applications property of an entity.

Figure 22. UML Class Diagram for Category.
The following code snippet shows how to create a hierarchy of categories. The root category represents "Problem Domain" which has "Performance Problem" and "Security Problem" as two sub-categories. The classified by property for each category application can be specified by a property definition. These categories can be used to classify the documents in a library.
SessionContext ctx; Space space; ... Date dt = new Date(); Category rootCategory = new Category(space, dt, dt); rootCategory.setName("Problem Domain"); rootCategory.setIsAbstract(true); PropertyDefinition classifiedBy = new PropertyDefinition("Classified By"); classifiedBy.setDescription("The person who applies the category on the entity"); classifiedBy.setCardinality(Cardinality.Single); classifiedBy.setPropertyType(BeehivePropertyTypeEnum.ID); classifiedBy.setQueryable(true);
Category performanceProblem = new Category(rootCategory, dt, dt); performanceProblem.setName("Performance Problem"); performanceProblem.setIsAbstract(false); Category securityProblem = new Category(rootCategory, dt, dt); securityProblem.setName("Security Problem"); securityProblem.setIsAbstract(false); try { ctx.getUserTransaction().commit(); } catch (Exception ex) { ... }
Supposing we have also constructed a category hierarchy for solutions taxonomy, the following code snippet shows how to relate the "Performance Problem" domain with the "Tuning Guide" and "Capacity Planning" solution domains using a relationship.
SessionContext ctx; ...
Date dt = new Date(); RelationshipDefinition problemSolution = new RelationshipDefinition(space, dt); problemSolution.setName("Problem-Solution Association"); problemSolution.setDescription("Association from a problem domain to a solution domain"); String queryText1 = "select c from Category c where c.name = 'Performance Problem'"; Query query1 = entityManager.createQuery(queryText1); List<?> list1 = query1.getResultList(); Category performanceProblem = (Category) list1.get(0);
String queryText2 = "select c from Category c where c.name = ‘Tuning Guide' "; Query query2 = entityManager.createQuery(queryText2); List<?> list2 = query2.getResultList(); Category tuningSolution = (Category) list2.get(0);
String queryText3 = "select c from Category c where c.name = ‘Capacity Planning' "; Query query3 = entityManager.createQuery(queryText3); List<?> list3 = query3.getResultList(); Category capacityPlanning = (Category) list3.get(0);
... Relationship guide = new Relationship(problemSolution, performanceProblem, dt); guide.setName("solution guide"); guide.addTargetEntity(tuningSolution); guide.addTargetEntity(capacityPlanning); try { ctx.getUserTransaction().commit(); } catch (Exception ex) { ... }
The ICOM applications can let the user navigate from a problem report document classified under the "Performance Problem" domain to the performance tuning guides classified under the "Tuning Guide" and "Capacity Planning" domains.
String queryText1 = "select rd from RelationshipDefinition rd where rd.name = ‘Problem-Solution Association' "; Query query1 = entityManager.createQuery(queryText1); List<<?> list1 = query1.getResultList(); RelationshipDefinition problemSolution = (RelationshipDefinition) list1.get(0);
String queryText2 = "select c from Category c where c.name = 'Performance Problem' "; Query query2 = entityManager.createQuery(queryText2); List<?>> list2 = query2.getResultList(); Category performanceProblem = (Category) list2.get(0);
Document doc; ...
Set<CategoryApplication> problemClassifications = doc.getCategoryApplications(); for (CategoryApplication catApp : problemClassifications) { Category cat = catApp.getCategory(); if (cat == performanceProblem) { Set<Relationship> relations = cat.getRelationships(); for (Relationship bond : relations) { if (bond.getRelationshipDefinition() == problemSolution) { Set<RelationshipBondable> targets = bond.getTargetEntities(); for (RelationshipBondable target : targets) { Category solution = (Category) target; Collection<Entity> solutionGuides = solution.getMarkedEntities();
Content Model
The Content model in Figure 23 is a common component of Document model (Figure 24) and UnifiedMessage model (Figure 25). A content object represents a piece of data in a document or message. Content, multi-content, simple content, and online content form a composite design pattern. Among the properties of a content, a content id is a unique identifier for a part of content in multi-part contents; a media type is a two-part identifier for Internet file formats as defined in RFC 2046 and additional RFCs including RFC 3236, RFC 1847, etc; a content disposition is defined in RFC 2183 to specify a presentation style.
A multi-content object represents multiple parts of a message or document. It is a composite content that can contain a list of simple or composite contents. A simple content holds a single piece of data. Among the properties of SimpleContent, content encoding specifies RFC 2616 content encoding applied to a content; character encoding specifies RFC 2616 character set of a content (a missing value means that a content should be treated as binary or raw); content language specifies RFC 2616 content language for a content (a missing value means non-natural language content). An online content holds an online artifact attached to a document, message, or occurrence. An online artifact, such as a conference, chat room, or forum, must be rendered as a URL when a message or occurrence is delivered to external recipients.

Figure 23. Composite Design Pattern for Content.
Document Model
A document is a versionable artifact that can contain single or composite contents for any assortment of media types. See Figure 24. ICOM version control model follows the CMIS version control model specified in Section 2.1.9 of Content Management Interoperability Services Version 1.0[9].
ICOM extends the CMIS version control model with a concept called representative copy. A versionable artifact is a representative copy, specific versioned copy, or private working copy of an artifact version series. A container of a versionable artifact can contain a representative copy of a version series so that it provides an artifact view of the latest state of the version series. Starting from a representative copy in a container, an actor can traverse a version series to retrieve any versioned copy or private working copy.
When a versionable artifact is not under version control, a representative copy of a versionable artifact is the only version of a version series and represents the versionable artifact itself, i.e. there is only one object identifier so far. When a versionable artifact is placed under version control:
- A representative copy of a versionable artifact is a versionable artifact which has its own object identifier that is different from the object identifier of any versioned copy or private working copy of the versionable artifact. It retains the object identifier it has when the artifact is created. Its version type changes from RepresentativeCopy to ViewOnlyRepresentativeCopy.
- A representative copy of a versionable artifact provides a view of a version series, depending on the check out state of the version series and the user loading the artifact. If the current user loading a representative copy is the same user who checks out from a version series, the representative copy is a copy of the content and state of a private working copy. Otherwise, the representative copy is a copy of the content and state of the latest versioned copy in a version series.
A specific versioned copy of a versionable artifact is a "deep" copy of the content and state of a versionable artifact, preserving its content and state at a certain point in time. Each versioned copy of a versionable artifact is itself a versionable artifact, i.e. it has its own object identifier. A versioned copy has a version number, label, and check in comment.
A private working copy of a versionable artifact is a versionable artifact created by a checkout operation on a versionable artifact under version control. The properties for a private working copy can be identical to the properties of a versioned copy of a versionable artifact on which a checkout operation is performed. Its object identifier must be different from that of the representative copy or any versioned copy. A private working copy can be saved to the version series for sharing and co-editing, however, it needs not be visible to users who may only have permissions to view other versioned copies in a version series.

Figure 24. UML Class Diagram for Document.
The following code snippet shows how to create a new version series by creating a document and checking out the document. It shows that when a document is created, it becomes a representative copy. After the document is checked out to form a new version, the original document remains as the representative copy of the version series. The document folder continues to contain the representative copy of the document. The private working copy from the check out operation is a new artifact with a new object identifier.
public Version createDocumentVersion(SessionContext ctx, icom.Service service, HeterogeneousFolder documentFolder, String documentName, File file) { Date dt = new Date(); Document representativeCopy = new Document(documentFolder, dt, dt); representativeCopy.setName(documentName); representativeCopy.setDescription("A document created from ICOM JPA"); representativeCopy.setUserLastModificationDate(dt); SimpleContent content = new SimpleContent(); content.setDataFile(file); content.setMediaType("text/html"); content.setContentLanguage(Locale.getDefault()); content.setCharacterEncoding("UTF-8"); content.setContentEncoding("8bit"); representativeCopy.setContent(content); try { ctx.getUserTransaction().commit(); } catch (Exception ex) { ... } Document privateWorkingCopy = (Document) service.checkout(representativeCopy, "starting a new version series"); VersionControlMetadata metadata = privateWorkingCopy.getVersionControlMetadata(); Version v = (Version) metadata; return v; }
The following code snippet shows how to create a new version of a document from a private working copy. It shows that the state of the private working copy must be committed to the repository before calling the check in operation.
public Version addVersion(SessionContext ctx, icom.Service service, Document privateWorkingCopy) { privateWorkingCopy.setDescription("A new version of document created from ICOM JPA"); Version version = (Version) privateWorkingCopy.getVersionControlMetadata(); version.setName("Second version"); Date dt = new Date(); version.setCheckinComment("A check in comment"); try { ctx.getUserTransaction().commit(); // upload the private working copy } catch (Exception ex) { ... } Document versionedCopy = (Document) service.checkin(version); return version; }
The following code snippet shows how to navigate from a document to the version control metadata.
VersionControlMetadata metadata = doc.getVersionControlMetadata(); Versionable rep = metadata.getRepresentativeCopy(); if (metadata instanceof VersionSeries) { VersionSeries series = (VersionSeries) metadata; Date dt = series.getVersionSeriesCheckedOutOn(); Actor actor = series.getVersionSeriesCheckedOutBy(); String comment = series.getVersionSeriesCheckoutComment(); Version version = series.getLatestVersion(); } else { Version version = (Version) metadata; String name = version.getName(); String label = version.getVersionLabel(); Integer number = version.getVersionNumber(); }
Unified Message Module
A message is a unit of conversation that holds a simple content or multipart message contents in a content property. It has a single sender. The delivered time is the time when a message is delivered to a given recipient and the sent time of a message is represented by a user creation date and time of the message. The name property holds the subject of a message.
A unified message (see Figure 25) is a special type of message delivered electronically over a computer, voice, fax, and other networks. A unified message can be one of these types:
- Email is a type of message that is delivered electronically over a computer network.
- Voice is a type of message that contains a voice or audio stream.
- Fax is a type of message that contains an image transmitted via phone lines using the fax protocol.

Figure 25. UML Class Diagram for UnifiedMessage.
ICOM unified message supports a persistent object identifier. This differentiates ICOM from SMTP, IMAP, POP protocols and Java Mail API. RFC 2822 Internet Message Format specifies a MIME header "Message-ID" to identify the messages. The uniqueness of the message id should be guaranteed either by the client or server which generates it. IMAP on the other hand assigns a 32-bit UID to messages in the ascending order as they are added to a container. ICOM object identifier supersedes both MIME message id and IMAP UID. The MIME message id is preserved as part of MIME headers in the unified message. The IMAP UID can be associated with a unified message, and for that matter any MIME convertible artifact, using an extensible property on Artifact (Figure 16). RFC 2822 also specifies "References" and "In-Reply-To" MIME header attributes that use message id to represent the message threads. These two attributes are also preserved as part of MIME headers in the unified message. ICOM JPA framework allows the applications to create the reference and in-reply-to chains using the Relationship objects (see Figure 19), by crawling the messages as they are added to a workspace and correlating the "Message-ID," "References," and "In-Reply-To" attributes in the MIME headers. It is possible to find multiple unified messages with the same message id, for a legitimate reason when a message is sent to multiple recipients who then move or copy their messages into the same container. It can also result from a rogue client forging a message with the message id of another message. ICOM object identifier can be useful in resolving these conflicts.
ICOM defines UnifiedMessage and Document as MimeConvertible. This design represents another substantive departure from other API's such as Java Mail API. When a MimeConvertible artifact from a folder is attached to a message, the artifact contents are copied as an attachment into the message. The attached object in a message is semantically compatible with an embedded object in JPA, i.e. the attached object does not have object identifier, change token, and is not sharable among entities (nor among more than one attribute or level of MIME hierarchy in the containing message entity). In JPA specification, Entity and Embeddable categories are disjoint. Since UnifiedMessage and Document are annotated as JPA Entity, these classes cannot be used to represent embedded objects. In order for the ICOM POJO classes to be portable to standard compliant JPA providers, we need to introduce embeddable UnifiedMessageAttachment and DocumentAttachment classes for JPA binding.
It is a common scenario for ICOM applications to let a user forward email messages from her INBOX as attachments in a new email message. The following code snippet shows how the application can take a collection of UnifiedMessage entities, clone each entity, and add the clones as embedded objects in the MultiContent. The UnifiedMessage entities being cloned can contain nested structures of embedded UnifiedMessageAttachment objects (representing long message threads).
public UnifiedMessage forwardMessages(HeterogeneousFolder draftFolder, Collection<UnifiedMessage> attachments) { Date dt = new Date(); UnifiedMessage newMsg = new UnifiedMessage(draftFolder, dt, dt); ... MultiContent forwards = new MultiContent(); forwards.setMediaType(MultiContentType.Mixed); for (UnifiedMessage message : attachments) { message.getContent(); // make sure to load the content before cloning (analogous to detaching) UnifiedMessageAttachment msg = message.cloneEmbeddable(); // clone the message forwards.addPart(msg); // the clone is attached or embedded as a MIME part message.addFlag(UnifiedMessageFlag.Forwarded); // the original message is flagged as "Forwarded" } multiContent.addPart(forwards); newMsg.setContent(multiContent); ...
The following code snippet shows an application saving the document attachments in a message to a folder. This example also involves cloning an embedded document object and saving the clone as an artifact in a document folder.
MultiContent content = message.getContent(); if (content instanceof MultiContent) { for (MimeConvertible mime: content.getParts()) { if (mime instanceof DocumentAttachment) { Document doc = document.cloneEntity(); doc.setParent(documentFolder); entityManager.persist(doc); // this explicit persist operation is not needed with use of Cascade Persist } ...
These scenarios may represent the drag and drop activities in a user interface. Dragging and dropping a message or document from a folder into a message or from a message into a folder is a copy and paste (or clone) operation. The above examples involve cloneEmbeddable and cloneEntity methods, which are essentially clone operations. The cloneEmbeddable method shall clone a UnifiedMessageAttachment or DocumentAttachment, respectively, from UnifiedMessage or Document entities. Likewise, the cloneEntity method shall clone UnifiedMessage or Document entities, respectively, from UnifiedMessageAttachment or DocumentAttachment.
ICOM JPA framework can support improved fidelity for transporting artifact attachments by propagating the properties such as name, description, created by, creation date, last modified by, last modification date, user creation date, user last modification date, etc., defined on Entity and Artifact as MIME headers. As is normally the case when copying artifacts within folders, an artifact's properties for parent, owner, attached markers, category applications, tag applications, relationships, and access control list are not copied.
We introduced a method isEditable() in POJO implementation of ICOM Entity to represent that some ICOM entities are immutable under certain conditions. In particular, a versioned copy of a document (when versionType is VersionType.VersionedCopy or VersionType.ViewOnlyRepresentativeCopy) and a delivered unified message (when mode is UnifiedMessageEditMode.DeliveredCopy) are immutable. The ICOM JPA framework throws an uncheck exception when an application updates the state of an immutable entity. To provide the same functionality when the POJO classes are ported to a standard JPA provider, we need to deploy a JPA entity lifecycle callback listener for PreUpdate callbacks that will throw an unchecked/runtime exception when an application updates an immutable entity. If the immutable entity update exception is thrown while a transaction is active in the persistent context, the transaction will be marked for rollback.
Conclusion
This is part 1 of the three parts series introducing the java.net incubation project for JPA ICOM framework. Part 1 presents the high-level concepts of ICOM, including directory, space, access control, metadata, content management, and unified message model, with programming examples for the ICOM JPA framework. Part 2 of this series will describe the details of ICOM extension modules, including Forum, Wiki, Calendar, TaskList, AddressBook, Conference, Workflow, Policy, Subscription, and Activity Stream, to name some. Part 3 will describe the design of the ICOM JPA framework.
The JPA programming model embodies design patterns that are well-suited for managing integrated collaboration object model (ICOM). ICOM removes the walls between the collaboration tools and exposes the data from behind the wall of applications. The ICOM JPA framework lowers the barrier for application developers to create common collaboration clients to interoperate with integrated collaboration platforms and standalone collaboration services across enterprise boundaries. The ICOM JPA framework is an important initiative for the java.net community, ready to reap benefits from community contributions.
Acknowledgements
I am thankful to the OASIS ICOM TC members for their inputs to the ICOM specification. Many ideas in this article originated from stimulating discussions with Stefan Decker, Deirdre Lee, Laura Dragan, Patrick Durusau, Peter Yim, Anthony Ye, Marc Pallot, Peter Saint-Andre, and Chancellor Pascale. I will like to thank Mike Keith for the technical review and constructive feedbacks that led to important changes in the article. Many thanks to Martin Chapman for his advice to me on the OASIS standard processes and a legal framework for incubating the ICOM JPA source code.
References
- JSR 317: Java Persistence API, Version 2.0.
- Mike Keith and Merrick Schincariol, Pro JPA 2: Mastering the Java Persistence API, 2009, Apress.
- ICOM TC Wiki Page, http://wiki.oasis-open.org/icom.
- Oracle Beehive Collaboration Platform: SOAP and REST API, http://www.oracle.com/technetwork/middleware/beehive/platform-098968.html?ssSourceSiteId=ocomen.
- Hiroshi Wada, et. al. "Data Consistency Properties and the Trade offs in Commercial Cloud Storages: the Consumers' Perspective," 5th biennial Conference on Innovative Data Systems Research, CIDR'11 Asilomar, California, January 2011.
- ACM Queue "A Conversation with Ray Ozzie" http://queue.acm.org/detail.cfm?id=1105674.
- Elisabeth Lefebvre, et. al. "An Empirical Investigation of the Impact of Electronic Collaboration Tools on the Performance of a Supply Chain," Proceedings of the 36th HICSS, 2002 IEEE.
- Linked Data - Connect Distributed Data across the Web, http://linkeddata.org/.
- OASIS Standard, Content Management Interoperability Services (CMIS) Version 1.0, May 2010. http://docs.oasis-open.org/cmis/CMIS/v1.0/os/cmis-spec-v1.0.doc.
- Gartner Research, "Predicts 2010: Social Software Is an Enterprise Reality," http://www.gartner.com/resId=1243515.
- Moo Nam Ko, Gorrell P. Cheek, Mohamed Shehab, Ravi Sandhu, "Social-Networks Connect Services," IEEE Computer, August 2010.
- Matthias Hasel, "OpenSocial: An Enabler for Social Applications on the Web," Virtual Extension of Communications of the ACM, January 2011.
- Don Tapscott and Anthony D. Williams, Wikinomics: How Mass Collaboration Changes Everything, 2006, Portfolio.
Eric S. Chan is Chair of OASIS Integrated Collaboration Object Model for Interoperable Collaboration Services (ICOM) TC. He is also Object Model Architect for Oracle Collaboration Technologies.
|
Rapid Web Services Development with Moose XML Date: 04/28/2010
Learn how Moose XML can simplify the task of prototyping and rapidly developing XML web services
Rapid Web Services Development with Moose XML
Learn how Moose XML can simplify the task of prototyping and rapidly developing XML web services.
Moose XML is a framework that provides a set of components for
getting XML data into and out of Java applications. Moose XML was
created after I had experienced some of the rough edges in
existing XML marshalling solutions when used in web services
environments. Wherever possible, design choices have been made to
simplify Moose XML's support for "contract last" web services
development.
Moose XML's schema generator is what distinguishes it from the
other frameworks. The schema generator can generate an XML schema
directly from your annotated Java beans. These generated schemas
are useful for driving "contract last" web services development
approaches. When combined with the WSDL plumbing in your favorite
web services toolkit, the schema generator can make the rapid
development of web services applications a reality. Because the
stack is automatically managing your schemas, your mapping code is
easily refactored, expanded, and maintained alongside your other
Java code—changes flow directly from your annotated Java
beans into your generated WSDL.
This article will give you a quick tour of Moose XML. I'll start
by showing you the basics of creating a mapping. I'll finish by
showing you how this can be plugged into Spring Web Services,
creating a rapid web services development stack. We'll create a
simple "purchase order" web service, allowing for storage and
retrieval of simplified purchase order data.
More information is available at the Moose XML website. The full
source code of this example is available in the Moose XML source
distribution. Links are provided in the Resources section at the
bottom of the article.
Creating the Mapping
Our service stores and retrieves "purchase orders". Imagine that
these purchase orders are for software licenses. As such, each
purchase order contains a "licensee" and "license type" and a
currency "amount". Purchase orders are identified by a numeric
"identifier". The license type is represented using a Java 5
enum named LicenseType.
Each operation needs to include a "request" and "response"
message. We'll start with the
CreatePurchaseOrderRequest and
CreatePurchaseOrderResponse types:
package com.quigley.moose.example.service;
public class CreatePurchaseOrderRequest {
// getters and setters removed for brevity
private String licensee;
private LicenseType licenseType;
private Float amount;
}
package com.quigley.moose.example.service;
public class CreatePurchaseOrderResponse {
// getters and setters removed for brevity
private Long identifier;
}
Simple POJO classes like these make up our mapping layer. We'll
need to add a few annotations so that Moose XML understands how to
marshall and unmarshall instances of these classes:
package com.quigley.moose.example.service;
import com.quigley.moose.mapping.provider.annotation.*;
@XML(name="createPurchaseOrderRequest")
public class CreatePurchaseOrderRequest {
// getters and setters removed for brevity
@XMLField(name="licensee")
private String licensee;
@XMLField(name="licenseType")
private LicenseType licenseType;
@XMLField(name="amount")
private Float amount;
}
package com.quigley.moose.example.service;
import com.quigley.moose.mapping.provider.annotation.*;
@XML(name="createPurchaseOrderResponse")
public class CreatePurchaseOrderResponse {
// getters and setters removed for brevity
@XMLField(name="identifier")
private Long identifier;
}
The @XML annotation defines the class-level mapping
details. Each of the @XMLField annotations define the
field-level mapping details. The Moose XML developer guide contains
information on many other annotations, which are useful for more
complicated mapping scenarios.
Marshalling and Unmarshalling
In order to initialize Moose XML, the application will need to
acquire a Mapping instance. A Mapping
instance is typically obtained by instantiating and configuring a
MappingProvider instance. Here's an example:
StaticClassesProvider classesProvider =
new StaticClassesProvider();
classesProvider.addClass(CreatePurchaseOrderRequest.class);
AnnotationMappingProvider mappingProvider =
new AnnotationMappingProvider(classesProvider);
Mapping mapping = mappingProvider.getMapping();
The Mapping class is central to Moose XML. Once
your application has access to a Mapping, performing
operations with the framework is straightforward.
The following code snippet illustrates how to use a
Mapping to marshall a
CreatePurchaseOrderRequest object out to XML:
CreatePurchaseOrderRequest request = new CreatePurchaseOrderRequest();
request.setAmount(64.95F);
request.setLicensee("Benjamin Franklin");
request.setLicenseType(LicenseType.Renewal);
MarshallingContext ctx = new MarshallingContext();
mapping.marshall(request, ctx);
String xml = ctx.getOutput().toString();
Here's how to unmarshall a
CreatePurchaseOrderRequest from XML:
CreatePurchaseOrderRequest request = (CreatePurchaseOrderRequest)
mapping.unmarshall(xml);
Generating a XML schema from your Mapping instance
is no more difficult:
String xsd = SchemaGenerator.generate(mapping);
Spring Web Services Integration
For the remainder of this example, I'm going to assume that
you're familiar with the Spring Web Services framework and SOAP web
services. Instead of describing every part of the configuration,
we'll just look at the parts where Moose XML facilitates rapid web
services development.
Our example contains a single "endpoint" class, which is used to
expose the web service operations. This example uses the Spring
@Endpoint and @PayloadRoot annotations to
establish a service endpoint. Here is a snippet from the example
service endpoint to illustrate the pattern:
@Endpoint
public class ServiceEndpoint {
@PayloadRoot(localPart="createPurchaseOrderRequest",
namespace="http://quigley.com/moose/example/service/")
public CreatePurchaseOrderResponse
createPurchaseOrder(CreatePurchaseOrderRequest req) {
//
}
}
When configured, Spring will route incoming messages to the
method which matches the @PayloadRoot annotations
defined in your @Endpoint classes. Spring Web Services
also needs to know how to convert the incoming and outgoing XML to
and from the parameter types and return values of your endpoint
methods. Spring Web Services provides a nice
AbstractMarshaller class, which facilitates the
integration of various marshalling frameworks into Spring. Moose
XML extends AbstractMarshaller to provide a
MooseMarshaller type.
The bulk of the magic happens in our Spring context
configuration:
<beans> <!-- xmlns and schema location declarations removed for brevity -->
<context:annotation-config/>
<bean id="serviceEndpoint"
class="com.quigley.moose.example.service.ServiceEndpoint"/>
<bean id="service" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schema"><ref bean="mooseSchema"/></property>
<property name="portTypeName"><value>ExampleService</value></property>
<property name="locationUri"><value>http://localhost:8080/example/</value></property>
</bean>
<bean class="org.springframework.ws.server.endpoint.adapter.
GenericMarshallingMethodEndpointAdapter">
<constructor-arg ref="mooseMarshaller"/>
</bean>
<bean class="org.springframework.ws.server.endpoint.mapping.
PayloadRootAnnotationMethodEndpointMapping"/>
<bean id="mooseMarshaller" class="com.quigley.moose.spring.MooseMarshaller">
<property name="mappingProvider"><ref bean="mooseMappingProvider"/></property>
</bean>
<bean id="mooseMappingProvider"
class="com.quigley.moose.mapping.provider.annotation.AnnotationMappingProvider">
<property name="xmlNamespace">
<value>http://quigley.com/moose/example/service/</value></property>
<property name="xmlPrefix"><value>es</value></property>
<property name="annotatedClassesProvider"><ref bean="mooseClassesProvider"/></property>
</bean>
<bean id="mooseClassesProvider"
class="com.quigley.moose.mapping.provider.annotation.StaticClassesProvider">
<property name="classes">
<list>
<value>com.quigley.moose.example.service.CreatePurchaseOrderRequest</value>
<value>com.quigley.moose.example.service.CreatePurchaseOrderResponse</value>
<value>com.quigley.moose.example.service.RetrievePurchaseOrderRequest</value>
<value>com.quigley.moose.example.service.RetrievePurchaseOrderResponse</value>
</list>
</property>
</bean>
<bean id="mooseSchema" class="com.quigley.moose.spring.MooseXsdSchema">
<property name="mappingProvider"><ref bean="mooseMappingProvider"/></property>
</bean>
</beans>
Notice the GenericMarshallingMethodEndpointAdapter.
It's intended to take an instance of
AbstractMarshaller as a constructor argument. We're
configuring it to use our MooseMarshaller. This bean
configuration is what allows our service endpoint to magically
marshall and unmarshall XML to and from the methods of our
ServiceEndpoint class.
The most interesting bits are the mooseSchema bean
and the service bean. This combination of beans
connects Moose XML's schema generator to the WSDL generation
capabilities in Spring Web Services. With that linkage in place,
any changes you make to your mapping beans will be automatically
reflected in your WSDL.
Building the Example from the Source Distribution
Download the Moose XML source distribution from the link below.
Extract the distribution into a directory. From the directory where
you extracted the source distribution, execute:
$ ant -f build-example.xml example-service
When that completes successfully, you can start up a
fully-configured container, pre-loaded with this example, by
executing:
$ build/example-service/deploy/server/bin/run.sh
Conclusion
There are many tools and frameworks for getting XML data into
and out of Java applications. Moose XML tries to smooth some of the
rough edges that are typically encountered when prototyping and
rapidly developing XML web services. In these scenarios, generating
the schema and contract information from code ("contract last")
seems to be the least cumbersome methodology.
Development is currently underway extending Moose XML to support
"contract first" development approaches. The centerpiece is a new
tool which can ingest an existing XML schema, and generate an
annotated mapping layer. This functionality will be available
before Moose XML hits version 1.0.
- Moose XML Framework
Home
- Moose
XML Developer Guide
-
"http://quigley.com/releases/moose/0.4.0/quigley-moose-src-0.4.0.1128.zip">
Moose XML Source Distribution (Version 0.4.0 #1128)
-
"http://static.springsource.org/spring-ws/sites/1.5/reference/html/index.html">
Spring Web Services Reference Documentation
width="1" height="1" border="0" alt=" " /> |
Michael Quigley is a software architect, a musician, a sailor, and a lover of animals. He enjoys spending his time somewhere in the confluence of technology and the arts and wants your development projects to be awesome.
|
| Back |
|
|
|