DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

The Latest Languages Topics

article thumbnail
JavaScript: Wrap All Methods (functions) In A Class With An Error Handler.
Example of a way to wrap all methods in a class with an error handler. Could stand more improvement. /** @Description: Takes in an exception or string and turns it into an Error object, then appends the caller name to the message. @Returns: A new Error object or null. */ function wrapError (e, caller) { if (null === e) { return null; } var ret = ( (typeof e) === (typeof "") ) ? new Error(e) : new Error(e.message); ret.stackTrace = e.stackTrace || []; ret.stackTrace.push(caller); return ret; } /** @Description: Returns a method (function) wrapped in an error handler. Does not affect the behavior of the underlying function. Does not affec the function either, only returns the wrapped function, doesn't modify it directly. Usage: function foo() { throw new Error("bar"); }; foo = safeWrapMethod(foo, "foo"); @Param: fn The function pointer/object to wrap. @Param: name A string containing the name of fn as you wish it to be displayed in the call stack. @Return: The method/function fn wrapped in an error handler. */ function safeWrapMethod (fn, name) { try { return function () { /* Wrapper added by safeWrapMethod */ try { return fn.apply(this, arguments); } catch (e) { throw wrapError(e, name); } }; } catch (e) { throw wrapError(e, "ErrorHelpers.safeWrapMethod"); } } /** @Description: Wraps every method in an object with an error handler. Affects the instance of the object, but does not alter the underlying behavior of the methods. @Param: o The class instance (object) to wrap. @Param: name A string containing the name of the class. Method names will show as "name.methodName" in an error's stack trace. */ function safeWrapClass (o, name) { for (var m in o) { if (typeof(o[m]) === "function") { o[m] = safeWrapMethod(o[m], name + "." + m); } } }; safeWrapClass = safeWrapMethod(safeWrapClass, "ErrorHelpers.safeWrapClass"); // Example Usage function Foo() { safeWrapClass(this, "Foo"); }; Foo = safeWrapMethod(Foo, "Foo.ctor"); Foo.prototype.a = function () { throw new Error("oh noes!"); }; Foo.prototype.b = function () { this.a(); } Foo.prototype.c = function () { this.b(); } try { var f = new Foo(); f.c(); } catch (e) { var msg = e.message; if (e.stackTrace) { msg += "\r\n\r\nstackTrace: " + e.stackTrace.join("\r\n\tat "); } alert(msg); /* oh noes! stackTrace: Foo.a at Foo.b at Foo.c */ }
December 18, 2009
by Jason McDonald
· 8,350 Views
article thumbnail
How to Create a Swing CRUD Application on NetBeans Platform 6.8
this article shows you how to integrate a java db database into a netbeans platform application. we start by exploring a java db database, from which we create entity classes. next, we wrap the entity classes into a module, together with modules for the related jpa jars. note: these instructions are not applicable to java db only. rather, they are relevant to any relational database, such as oracle or mysql. several applications on the netbeans platform, many of which are listed here , use these databases too. java db was chosen for this article because it is easiest to get started with, since it comes with the jdk. once the above modules are part of our application, we create a new module that provides the user interface for our application. the new module gives the user a tree hierarchy showing data from the database. we then create another module that lets the user edit the data displayed by the first module. by separating the viewer from the editor in distinct modules, we will enable the user to install a different editor for the same viewer, since different editors could be created by external vendors, some commercially and some for free. it is this flexibility that the modular architecture of the netbeans platform makes possible. when we have a module for our editor, we begin adding crud functionality. first, the "r", standing for "read", is handled by the viewer described above. next, the "u" for "update" is handled, followed by the "c" for "create", and the "d" for "delete". at the end of the article, you will have learned about a range of netbeans platform features that help you in creating applications of this kind. for example, you will have learned about the undoredo.manager and the explorermanager , as well as netbeans platform swing components, such as topcomponent and beantreeview . contents setting up the application integrating the database creating entity classes from a database wrapping the entity class jar in a module creating other related modules designing the user interface setting dependencies running the prototype integrating crud functionality read update create delete the application you create in this article will look as follows: source code: http://kenai.com/projects/nbcustomermanager once you're at the stage shown above, you can simply download a netbeans module that provides office laf support ( ), add it to your application, and then when you redeploy the application, you will see this: note: it is advisable to watch the screencast series top 10 netbeans apis before beginning to work on this article. many of the concepts addressed in this article are discussed in more detail within the screencast series. setting up the application let's start by creating a new netbeans platform application. choose file > new project (ctrl+shift+n). under categories, select netbeans modules. under projects, select netbeans platform application. click next. in the name and location panel, type dbmanager in the project name field. click finish. the ide creates the dbmanager project. the project is a container for all the other modules you will create. run the application and notice that you have quite a few features out of the box already. open some of the windows, undock them, and get to know the basic components that the netbeans platform provides without you doing any work whatsoever: integrating the database in order to integrate the database, you need to create entity classes from your database and integrate those entity classes, together with their related jars, into modules that are part of your netbeans platform application. creating the entity classes in this section, you generate entity classes from a selected database. for purposes of this example, use the services window to connect to the sample database that is included with netbeans ide: note: alternatively, use any database you like and adapt the steps that follow to your particular use case. in the case of mysql, see connecting to a mysql database . in the ide, choose file | new project, followed by java | java class library to create a new library project named customerlibrary. in the projects window, right-click the library project and choose file | new file, followed by persistence | entity classes from database. in the wizard, select your database and the tables you need. here we choose "customer", and then "discount code" is added automatically, since there is a relationship between these two tables. specify the persistence strategy, which can be any of the available options. here, since we need to choose something, we'll choose eclipselink: specify "demo" as the name of the package where the entity classes will be generated. click finish. once you have completed this step, look at the generated code and notice that, among other things, you now have a persistence.xml file in a folder called meta-inf, as well as entity classes for each of your tables: build the java library and you will have a jar file in the library project's "dist" folder, which you can view in the files window: wrapping the entity class jar in a module in this section, you add your first module to your application! the new netbeans module will wrap the jar file you created in the previous section. right-click the dbmanager's modules node in the projects window and choose add new library. select the jar you created in the previous subsection and complete the wizard, specifying any values you like. let's assume the application is for dealing with customers at shop.org, in which case a unique identifier "org.shop.model" is appropriate for the code name base: you now have your first custom module in your new application, wrapping the jar containing the entity classes and the persistence.xml file: creating other related modules in this section, you create two new modules, wrapping the eclipselink jars, as well as the database connector jar. do the same as you did when creating the library wrapper for the entity class jar, but this time for the eclipselink jars, which are in the "customerlibrary" java library that you created earlier: note: in the library wrapper module wizard, you can use ctrl-click to select multiple jars. next, create yet another library wrapper module, this time for the java db client jar, which is available in your jdk distribution, at db/lib/derbyclient.jar. designing the user interface in this section, you create a simple prototype user interface, providing a window that uses a jtextarea to display data retrieved from the database. right-click the dbmanager's modules node in the projects window and choose add new. create a new module named customerviewer, with the code name base org.shop.ui. in the projects window, right-click the new module and choose new | window component. specify that it should be created in the editor position and that it should open when the application starts. set customer as the window's class name prefix. use the palette (ctrl-shift-8) to drag and drop a jtextarea on the new window: add this to the end of the topcomponent constructor: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); for (customer c : resultlist) { jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); } note: since you have not set dependencies on the modules that provide the customer object and the persistence jars, the statements above will be marked with red error underlines. these will be fixed in the section that follows. above, you can see references to a persistence unit named "customerlibrarypu", which is the name set in the persistence.xml file. in addition,there is a reference to one of the entity classes, called customer, which is in the entity classes module. adapt these bits to your needs, if they are different to the above. setting dependencies in this section, you enable some of the modules to use code from some of the other modules. you do this very explicitly by setting intentional contracts between related modules, i.e., as opposed to the accidental and chaotic reuse of code that tends to happen when you do not have a strict modular architecture such as that provided by the netbeans platform. the entity classes module needs to have dependencies on the derby client module as well as on the eclipselink module. right-click the customerlibrary module, choose properties, and use the libraries tab to set dependencies on the two modules that the customerlibrary module needs. the customerviewer module needs a dependency on the eclipselink module as well as on the entity classes module. right-click the customerviewer module, choose properties, and use the libraries tab to set dependencies on the two modules that the customerviewer module needs. open the customertopcomponent in the source view, right-click in the editor, and choose "fix imports". the ide is now able to add the required import statements, because the modules that provide the required classes are now available to the customertopcomponent. you now have set contracts between the modules in your application, giving you control over the dependencies between distinct pieces of code. running the prototype in this section, you run the application so that you can see that you're correctly accessing your database. start your database server. run the application. you should see this: you now have a simple prototype, consisting of a netbeans platform application that displays data from your database, which you will extend in the next section. integrating crud functionality in order to create crud functionality that integrates smoothly with the netbeans platform, some very specific netbeans platform coding patterns need to be implemented. the sections that follow describe these patterns in detail. read in this section, you change the jtextarea, introduced in the previous section, for a netbeans platform explorer view. netbeans platform explorer views are swing components that integrate better with the netbeans platform than standard swing components do. among other things, they support the notion of a context, which enables them to be context sensitive. representing your data, you will have a generic hierarchical model provided by a netbeans platform node class, which can be displayed by any of the netbeans platform explorer views. this section ends with an explanation of how to synchronize your explorer view with the netbeans platform properties window. in your topcomponent, delete the jtextarea in the design view and comment out its related code in the source view: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); //for (customer c : resultlist) { // jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); //} right-click the customerviewer module, choose properties, and use the libraries tab to set dependencies on the nodes api and the explorer & property sheet api. next, change the class signature to implement explorermanager.provider: final class customertopcomponent extends topcomponent implements explorermanager.provider you will need to override getexplorermanager() @override public explorermanager getexplorermanager() { return em; } at the top of the class, declare and initialize the explorermanager: private static explorermanager em = new explorermanager(); note: watch top 10 netbeans apis for details on the above code, especially the screencast dealing with the nodes api and the explorer & property sheet api. switch to the topcomponent design view, right-click in the palette, choose palette manager | add from jar. then browse to the org-openide-explorer.jar, which is in platform11/modules folder, within the netbeans ide installation directory. choose the beantreeview and complete the wizard. you should now see beantreeview in the palette. drag it from the palette and drop it on the window. create a factory class that will create a new beannode for each customer in your database: import demo.customer; import java.beans.introspectionexception; import java.util.list; import org.openide.nodes.beannode; import org.openide.nodes.childfactory; import org.openide.nodes.node; import org.openide.util.exceptions; public class customerchildfactory extends childfactory { private list resultlist; public customerchildfactory(list resultlist) { this.resultlist = resultlist; } @override protected boolean createkeys(list list) { for (customer customer : resultlist) { list.add(customer); } return true; } @override protected node createnodeforkey(customer c) { try { return new beannode(c); } catch (introspectionexception ex) { exceptions.printstacktrace(ex); return null; } } } back in the customertopcomponent, use the explorermanager to pass the result list from the jpa query in to the node: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); em.setrootcontext(new abstractnode(children.create(new customerchildfactory(resultlist), true))); //for (customer c : resultlist) { // jtextarea1.append(c.getname() + " (" + c.getcity() + ")" + "\n"); //} run the application. once the application is running, open the properties window. notice that even though the data is available, displayed in a beantreeview, the beantreeview is not synchronized with the properties window, which is available via window | properties. in other words, nothing is displayed in the properties window when you move up and down the tree hierarchy. synchronize the properties window with the beantreeview by adding the following to the constructor in the topcomponent: associatelookup(explorerutils.createlookup(em, getactionmap())); here we add the topcomponent's actionmap and explorermanager to the lookup of the topcomponent. run the application again and notice that the properties window is now synchronized with the explorer view: now you are able to view your data in a tree hierarchy, as you would be able to do with a jtree. however, you're also able to swap in a different explorer view without needing to change the model at all because the explorermanager mediates between the model and the view. finally, you are now also able to synchronize the view with the properties window. update in this section, you first create an editor. the editor will be provided by a new netbeans module. so, you will first create a new module. then, within that new module, you will create a new topcomponent, containing two jtextfields, for each of the columns you want to let the user edit. you will need to let the viewer module communicate with the editor module. whenever a new node is selected in the viewer module, you will add the current customer object to the lookup. in the editor module, you will listen to the lookup for the introduction of customer objects. whenever a new customer object is introduced into the lookup, you will update the jtextfields in the editor. next, you will synchronize your jtextfields with the netbeans platform's undo, redo, and save functionality. in other words, when the user makes changes to a jtextfield, you want the netbeans platform's existing functionality to become available so that, instead of needing to create new functionality, you'll simply be able to hook into the netbeans platform's support. to this end, you will need to use the undoredomanager, together with the savecookie. create a new module, named customereditor, with org.shop.editor as its code name base. right-click the customereditor module and choose new | window component. make sure to specify that the window should appear in the editor position and that it should open when the application starts. in the final panel of the wizard, set "editor" as the class name prefix. use the palette (ctrl-shift-8) to add two jlabels and two jtextfields to the new window. set the texts of the labels to "name" and "city" and set the variable names of the two jtextfields to jtextfield1 and jtextfield2. in the gui builder, the window should now look something like this: go back to the customerviewer module and change its layer.xml file to specify that the customertopcomponent window will appear in the explorer mode. note: right-click the application project and choose "clean", after changing the layer.xml file. why? because whenever you run the application and close it down, the window positions are stored in the user directory. therefore, if the customerviewer was initially displayed in the editor mode, it will remain in the editor mode, until you do a "clean", thus resetting the user directory (i.e., thus deleting the user directory) and enabling the customerviewer to be displayed in the position currently set in the layer.xml file. also check that the beantreeview in the customerviewer will stretch horizontally and vertically when the user resizes the application. check this by opening the window, selecting the beantreeview, and then clicking the arrow buttons in the toolbar of the gui builder. run the application and make sure that you see the following when the application starts up: now we can start adding some code. firstly, we need to show the currently selected customer object in the editor: start by tweaking the customerviewer module so that the current customer object is added to the viewer window's lookup whenever a new node is selected. do this by creating an abstractnode, instead of a beannode, in the customerchildfactory class. that enables you to add the current customer object to the lookup of the node, as follows (note the "lookups.singleton(c)" below): @override protected node createnodeforkey(customer c) { node node = new abstractnode(children.leaf, lookups.singleton(c)); node.setdisplayname(c.getname()); node.setshortdescription(c.getcity()); return node; // try { // return new beannode(c); // } catch (introspectionexception ex) { // exceptions.printstacktrace(ex); // return null; // } } now, whenever a new node is created, which happens when the user selects a new customer in the viewer, a new customer object is added to the lookup of the node. let's now change the editor module in such a way that its window will end up listening for customer objects being added to the lookup. first, set a dependency in the editor module on the module that provides the entity class, as well as the module that provides the persistence jars. next, change the editortopcomponent class signature to implement lookuplistener: public final class editortopcomponent extends topcomponent implements lookuplistener override the resultchanged so that the jtextfields are updated whenever a new customer object is introduced into the lookup: @override public void resultchanged(lookupevent lookupevent) { lookup.result r = (lookup.result) lookupevent.getsource(); collection coll = r.allinstances(); if (!coll.isempty()) { for (customer cust : coll) { jtextfield1.settext(cust.getname()); jtextfield2.settext(cust.getcity()); } } else { jtextfield1.settext("[no name]"); jtextfield2.settext("[no city]"); } } now that the lookuplistener is defined, we need to add it to something. here, we add it to the lookup.result obtained from the global context. the global context proxies the context of the selected node. for example, if "ford motor co" is selected in the tree hierarchy, the customer object for "ford motor co" is added to the lookup of the node which, because it is the currently selected node, means that the customer object for "ford motor co" is now available in the global context. that is what is then passed to the resultchanged, causing the text fields to be populated. all of the above starts happening, i.e., the lookuplistener becomes active, whenever the editor window is opened, as you can see below: @override public void componentopened() { result = utilities.actionsglobalcontext().lookupresult(customer.class); result.addlookuplistener(this); resultchanged(new lookupevent(result)); } @override public void componentclosed() { result.removelookuplistener(this); result = null; } since the editor window is opened when the application starts, the lookuplistener is available at the time that the application starts up. finally, declare the result variable at the top of the class, like this: private lookup.result result = null; run the application again and notice that the editor window is updated whenever you select a new node: however, notice what happens when you switch the focus to the editor window: because the node is no longer current, the customer object is no longer in the global context. this is the case because, as pointed out above, the global context proxies the lookup of the current node. therefore, in this case, we cannot use the global context. instead, we will use the local lookup provided by the customer window. rewrite this line: result = utilities.actionsglobalcontext().lookupresult(customer.class); to this: result = windowmanager.getdefault().findtopcomponent("customertopcomponent").getlookup().lookupresult(customer.class); the string "customertopcomponent" is the id of the customertopcomponent, which is a string constant that you can find in the source code of the customertopcomponent. one drawback of the approach above is that now our editortopcomponent only works if it can find a topcomponent with the id "customertopcomponent". either this needs to be explicitly documented, so that developers of alternative editors can know that they need to identify the viewer topcomponent this way, or you need to rewrite the selection model, as described here by tim boudreau. if you take one of the above approaches, you will find that the context is not lost when you switch the focus to the editortopcomponent, as shown below: note: since you are now using abstractnode, instead of beannode, no properties are shown in the properties window. you need to provide these yourself, as described in the nodes api tutorial . secondly, let's work on the undo/redo functionality. what we'd like to have happen is that whenever the user makes a change to one of the jtextfields, the "undo" button and the "redo" button, as well as the related menu items in the edit menu, become enabled. to that end, the netbeans platform makes the undoredo.manager available. declare and instantiate a new undoredomanager at the top of the editortopcomponent: private undoredo.manager manager = new undoredo.manager(); next, override the getundoredo() method in the editortopcomponent: @override public undoredo getundoredo() { return manager; } in the constructor of the editortopcomponent, add a keylistener to the jtextfields and, within the related methods that you need to implement, add the undoredolisteners: jtextfield1.getdocument().addundoableeditlistener(manager); jtextfield2.getdocument().addundoableeditlistener(manager); run the application and show the undo and redo functionality in action, the buttons as well as the menu items. the functionality works exactly as you would expect. you might want to change the keylistener so that not all keys cause the undo/redo functionality to be enabled. for example, when enter is pressed, you probably do not want the undo/redo functionality to become available. therefore, tweak the code above to suit your business requirements. thirdly, we need to integrate with the netbeans platform's save functionality: by default, the "save all" button is available in the netbeans platform toolbar. in our current scenario, we do not want to save "all", because "all" refers to a number of different documents. in our case, we only have one "document", which is the editor that we are reusing for all the nodes in the tree hirerarchy. remove the "save all" button and add the "save" button instead, by adding the following to the layer file of the customereditor module: when you now run the application, you will see a different icon in the toolbar. instead of the "save all" button, you now have the "save" button available. set dependencies on the dialogs api and the nodes api. in the editortopcompontn constructor, add a call to fire a method (which will be defined in the next step) whenever a change is detected: public editortopcomponent() { ... ... ... jtextfield1.getdocument().adddocumentlistener(new documentlistener() { public void insertupdate(documentevent arg0) { fire(true); } public void removeupdate(documentevent arg0) { fire(true); } public void changedupdate(documentevent arg0) { fire(true); } }); jtextfield2.getdocument().adddocumentlistener(new documentlistener() { public void insertupdate(documentevent arg0) { fire(true); } public void removeupdate(documentevent arg0) { fire(true); } public void changedupdate(documentevent arg0) { fire(true); } }); //create a new instance of our savecookie implementation: impl = new savecookieimpl(); //create a new instance of our dynamic object: content = new instancecontent(); //add the dynamic object to the topcomponent lookup: associatelookup(new abstractlookup(content)); } ... ... ... here are the two methods referred to above. first, the method that is fired whenever a change is detected. an implementation of the savecookie from the nodes api is added to the instancecontent whenever a change is detected: public void fire(boolean modified) { if (modified) { //if the text is modified, //we add savecookie impl to lookup: content.add(impl); } else { //otherwise, we remove the savecookie impl from the lookup: content.remove(impl); } } private class savecookieimpl implements savecookie { @override public void save() throws ioexception { confirmation message = new notifydescriptor.confirmation("do you want to save \"" + jtextfield1.gettext() + " (" + jtextfield2.gettext() + ")\"?", notifydescriptor.ok_cancel_option, notifydescriptor.question_message); object result = dialogdisplayer.getdefault().notify(message); //when user clicks "yes", indicating they really want to save, //we need to disable the save action, //so that it will only be usable when the next change is made //to the jtextarea: if (notifydescriptor.yes_option.equals(result)) { fire(false); //implement your save functionality here. } } } run the application and notice the enablement/disablement of the save button: note: right now, nothing happens when you click ok in the dialog above. in the next step, we add some jpa code for handling persistence of our changes. next, we add jpa code for persisting our change. do so by replacing the comment "//implement your save functionality here." the comment should be replaced by all of the following: entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); entitymanager.gettransaction().begin(); customer c = entitymanager.find(customer.class, customer.getcustomerid()); c.setname(jtextfield1.gettext()); c.setcity(jtextfield2.gettext()); entitymanager.gettransaction().commit(); note: the "customer" in customer.getcustomerid() is currently undefined. add the line "customer = cust;" in the resultchanged (as shown below), after declaring customer customer; at the top of the class, so that the current customer object sets the customer, which is then used in the persistence code above to obtain the id of the current customer object. @override public void resultchanged(lookupevent lookupevent) { lookup.result r = (lookup.result) lookupevent.getsource(); collection c = r.allinstances(); if (!c.isempty()) { for (customer customer : c) { customer = cust; jtextfield1.settext(customer.getname()); jtextfield2.settext(customer.getcity()); } } else { jtextfield1.settext("[no name]"); jtextfield2.settext("[no city]"); } } run the application and change some data. currently, we have no "refresh" functionality (that will be added in the next step) so, to see the changed data, restart the application. here, for example, the tree hierarchy shows the persisted customer name for "toyota motor co": fourthly, we need to add functionality for refreshing the customer viewer. you might want to add a timer which periodically refreshes the viewer. however, in this example, we will add a "refresh" menu item to the root node so that the user will be able to manually refresh the viewer. in the main package of the customerviewer module, create a new node, which will replace the abstractnode that we are currently using as the root of the children in the viewer. note that we also bind a "refresh" action to our new root node. public class customerrootnode extends abstractnode { public customerrootnode(children kids) { super(kids); setdisplayname("root"); } @override public action[] getactions(boolean context) { action[] result = new action[]{ new refreshaction()}; return result; } private final class refreshaction extends abstractaction { public refreshaction() { putvalue(action.name, "refresh"); } public void actionperformed(actionevent e) { customertopcomponent.refreshnode(); } } } add this method to the customertopcomponent, for refreshing the view: public static void refreshnode() { entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); em.setrootcontext(new customerrootnode(children.create(new customerchildfactory(resultlist), true))); } now replace the code above in the constructor of the customertopcomponent with a call to the above. as you can see, we are now using our customerrootnode instead of the abstractnode. the customerrootnode includes the "refresh" action, which calls the code above. in your save functionality, add the call to the method above so that, whenever data is saved, an automatic refresh takes place. you can take different approaches when implementing this extension to the save functionality. for example, you might want to create a new module that contains the refresh action. that module would then be shared between the viewer module and the editor module, providing functionality that is common to both. run the application again and notice that you have a new root node, with a "refresh" action: make a change to some data, save it, invoke the refresh action, and notice that the viewer is updated. you have now learned how to let the netbeans platform handle changes to the jtextfields. whenever the text changes, the netbeans platform undo and redo buttons are enabled or disabled. also, the save button is enabled and disabled correctly, letting the user save changed data back to the database. create in this section, you allow the user to create a new entry in the database. right-click the customereditor module and choose "new action". use the new action wizard to create a new "always enabled" action. the new action should be displayed anywhere in the toolbar and/or anywhere in the menu bar. in the next step of the wizard, call the action newaction. note: make sure that you have a 16x16 icon available, which the wizard forces you to select if you indicate that you want the action to be invoked from the toolbar. in the new action, let the topcomponent be opened, together with emptied jtextfields: import java.awt.event.actionevent; import java.awt.event.actionlistener; public final class newaction implements actionlistener { public void actionperformed(actionevent e) { editortopcomponent tc = editortopcomponent.getdefault(); tc.resetfields(); tc.open(); tc.requestactive(); } } note: the action implements the actionlistener class, which is bound to the application via entries in the layer file, put there by the new action wizard. imagine how easy it will be when you port your existing swing application to the netbeans platform, since you'll simply be able to use the same action classes that you used in your original application, without needing to rewrite them to conform to action classes provided by the netbeans platform! in the editortopcomponent, add the following method for resetting the jtextfields and creating a new customer object: public void resetfields() { customer = new customer(); jtextfield1.settext(""); jtextfield2.settext(""); } in the savecookie, ensure that a return of null indicates that a new entry is saved, instead of an existing entry being updated: public void save() throws ioexception { confirmation message = new notifydescriptor.confirmation("do you want to save \"" + jtextfield1.gettext() + " (" + jtextfield2.gettext() + ")\"?", notifydescriptor.ok_cancel_option, notifydescriptor.question_message); object result = dialogdisplayer.getdefault().notify(msg); //when user clicks "yes", indicating they really want to save, //we need to disable the save button and save menu item, //so that it will only be usable when the next change is made //to the text field: if (notifydescriptor.yes_option.equals(result)) { fire(false); entitymanager entitymanager = persistence.createentitymanagerfactory("customerlibrarypu").createentitymanager(); entitymanager.gettransaction().begin(); if (customer.getcustomerid() != null) { customer c = entitymanager.find(customer.class, cude.getcustomerid()); c.setname(jtextfield1.gettext()); c.setcity(jtextfield2.gettext()); entitymanager.gettransaction().commit(); } else { query query = entitymanager.createquery("select c from customer c"); list resultlist = query.getresultlist(); customer.setcustomerid(resultlist.size()+1); customer.setname(jtextfield1.gettext()); customer.setcity(jtextfield2.gettext()); //add more fields that will populate all the other columns in the table! entitymanager.persist(customer); entitymanager.gettransaction().commit(); } } } run the application again and add a new customer to the database. delete in this section, let the user delete a selected entry in the database. using the concepts and code outlined above, implement the delete action yourself. create a new action, deleteaction. decide whether you want to bind it to a customer node or whether you'd rather bind it to the toolbar, the menu bar, keyboard shortcut, or combinations of these. depending on where you want to bind it, you will need to use a different approach in your code. read the article again for help, especially by looking at how the "new" action was created, while comparing it to the "refresh" action on the root node. get the current customer object, return an 'are you sure?' dialog, and then delete the entry. for help on this point, read the article again, focusing on the part where the "save" functionality is implemented. instead of saving, you now want to delete an entry from the database. see also this concludes the article. you have learned how to create a new netbeans platform application with crud functionality for a given database. you have also seen many of the netbeans apis in action. for more information about creating and developing applications on the netbeans platform, see the following resources: netbeans platform learning trail netbeans api javadoc
December 8, 2009
by Geertjan Wielenga
· 231,764 Views
article thumbnail
Lombok Reduces Your Boilerplate Code
In this article, I show you the power of the product I stumbled upon this week: Project Lombok enables you to modify bytecode at compile code. First, I will detail what features Lombok brings you out-of-the-box. In the second part of this article, I will describe how to extend it to generate you own code. Introduction Since the dawn of JEE, complaints have been filed regarding the complexity of coding components. I consider EJB v2 a very good example of this complexity: for just a simple EJB, you have to provide the EJB class itself and a home and an interface for each access type (local and remote). This makes it complex, error-prone and more importantly gives you less time to focus on business code where the real value is. Two initiatives show the will to decrease the amount of boilerplate code needed when coding: the Spring Framework’s motto is to decrease JEE complexity. The boilerplate code is written once in the Spring framework and only used by projects. EJB v3 has taken into account the lessons from Spring and aim to reduce boilerplate code too, making local and remote interfaces unnecessary. Eventually, the next version of the specification will make the local and remote home optional too. The goal of Project Lombok is exactly the same as the previous initiatives but in order to do so, it uses another mechanism. Annotation processing Version 5 of the Java language introduced the concept of annotations, code meta-data that could be processed at compile time and/or runtime. Unfortunately, in JDK 5, processing annotations at compile is a 2-step process. First, you have to run the apt executable to process annotations, perhaps creating or modifying source files, then compile your sources with javac. That was not the best approach, so Java 6 removes apt and make javac able to manage annotations, streamlining the process to obtain a simpler single step computing. This is the path taken by Lombok. Project Lombok Lombok’s driving feature is to create code you need from annotations in order to reduce the amount of boilerplate code you have to write. It provides you with the following annotations that will change your code (if not your life) forever: @Getter and @Setter: create getters and setters for your fields @EqualsAndHashCode: implements equals() and hashCode() @ToString: implements toString() @Data: uses the four previous features @Cleanup: closes your stream @Synchronized: synchronize on objects @SneakyThrows: throws exceptions For example, while learning to code the OO way, you were drilled into making your fields private and into writing public accessors to access these fields: public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Since this is a bother to write, some (if not all) IDE have a feature to generate the accessors. It has some drawbacks: You have to manually remove the accessors if you remove the field It clutters your real code with boilerplate code Corollary: it takes a real effort to check whether an accessor already exist for a field in a long class Moreover, creating accessors manually is error-prone: I once searched for hours for a bug in code developed by a fellow developer and finally found the setter was wrong. Since getter / setter is only meta-data for a field, Lombok’s stance is to treat it like such: in Java, meta-data is managed with annotations. Look at the following code: import org.lombok.Getter; import org.lombok.Setter; public class Person { @Getter @Setter private String name; } I decompiled the generated class (using JAD) and it creates exactly the same bytecode, only the source code is more concise and less error-prone. When thinking, I found 3 arguments against using Lombok: The first argument against using such a strategy is that you can’t create a protected accessor like that. You’re wrong, Lombok is configurable: import lombok.AccessLevel; import org.lombok.Getter; import org.lombok.Setter; public class Person { @Getter @Setter(AccessLevel.PROTECTED) private String name; } And its true for all the provided annotations! Just look at them. The second argument against using Lombok is that you don’t know what it does behind the scene. It’s true, but the same could be said for AOP or CGLIB or whatever framework you’re using. The last argument and IMHO the only one valid enough is that it renders debugging more complex: but so is the use of Java dynamic proxies that Spring uses throughout its code, and still many projects use them. Use and installation Using Lombok is a 3-step process: Put the JAR on the classpath Add the annotation you want to use Compile with javac There’s a catch, though. Notice the last statement and the emphasis on javac. Since most (if not all) the developers you and I know focus a little bit on productivity, chances are you’re using a IDE. I do not know about NetBeans and fellows, but my favorite IDE Eclipse does not use javac to compile but its own internal compiler. Our friends from Lombok thought about that and Lombok is able to hook into Eclipse compiling process too. In order to do so, just launch lombok.jar and follow the instructions on you screen: it will just add 2 lines to your eclipse.ini. A word of advice (since I made the mistake): if you launch Eclipse with a command that takes parameters, such as a Windows shortcut, these parameters take precedence and eclipse.ini is silently ignored. Just to let you know… Lombok extensions To my knowledge, there’s currently only a single extension of Lombok called Morbok. It lets you create your classical private static final logger with just an annotation. The advantage of this is that Morbok automatically uses the fully qualified class name as the name of the logger so no more copy paste error. The disadvantage is that if you do not use Commons Logging as you logging framework, you have to configure each @Logger annotation with the framework you want to use, there’s no overall configuration: IMHO, that’s something that could be covered in the next version (is there’s one). Architecture First things first, Lombok needs a JDK 6 to compile since annotation processing is done in Java 5 with APT. For now, Lombok hooks into the compiling process immediately after the environment has built the AST for the class. It then passes the structure thus formed to each of its referenced handlers. There’s a single handler for each annotation: HandleGetter for @Getter, HandlerSetter for @Setter and so on. Handlers are, guess what, responsible for handling annotations. Extending Lombok Extending Lombok is a 3-step process: Create the annotation. Since the annotation is used at compile-time, it can be safely be discarded afterwards so its retention policy can be left to its default value (namely RetentionPolicy.SOURCE) Create the handler. A handler is a class that directly implements lombok.javac.JavacAnnotationHandler. Why directly? Because Lombok uses the ServiceProvider service and it’s one of its limitations Reference the fully qualified class name of the handler in a file named lombok.javac.JavacAnnotationHandler under META-INF/services The real coding takes place in step 2: the interface has a single method handle(AnnotationValues annotation, com.sun.tools.javac.tree.JCTree.JCAnnotation ast, JavacNode annotationNode). Notice the 2nd parameter package? It’s denotes Sun private implementation. It has some big drawbacks: The documentation is sparse if not completely unavailable. You go into unknown territory here Since the com.sun.tools.javac is not part of the public API, it can change at a moment’s notice. You can break your code with each update Remember that previously, I talked about this being only good for Java? That’s still true. If you want this new annotation to work under Eclipse, that’s another handler to write Example As an example, I coded an embryo for a @Delegate annotation. Such an annotation on a field indicates that the declaring class should have the same public methods as the field’s class and each method’s body should be a call to its delegate’s method. public class Delegator { @Delegate private DelegateObject object; ... } public class DelegateObject { public void doSomething() { ... } } The previous code should generate the same bytecode as the following code: public class Delegator { private DelegateObject object; public void doSomething() { object.doSomething(); } ... } As yet: it does not handle generics the only handler provided is for javac it is not configurable The final implementation is left for the brave readers: original sources are here in Eclipse/Maven format. Conclusion Some improvements could quickly be made to Lombok. First, I don’t like the monolithic structure the JAR has. IMHO, it could be nicely decoupled into 3 separate JARs: the Lombok agent itself, the provided annotations and associated handlers and finally, the installer. Moreover, coding two handlers for each annotation is a lost of time. What if you need to support NetBeans too? Perhaps using the Service Provider is a mistake… Finally, depending on Sun’s internal compiler API is too big a risk. I think that if Lombok could provide a facade to this API, it could be less risky for enterprise to take this road and the bridging could be made by people who understand the API (the Lombok team) and not base developers (like myself). All in all, and despite these flaws, Lombok looks like a very promising project that could well mimic Spring’s success. That’s what I wish it anyway because it’s real sideway thinking that brings much added value: good luck for the future! To go further: Project Lombok Lombok’s Javadoc Morbok From http://blog.frankel.ch
December 7, 2009
by Nicolas Fränkel
· 21,111 Views · 1 Like
article thumbnail
JAXB Customization of xsd:dateTime
A small JAXB puzzle: how to define a custom element to serialize Date objects with the TimeZone information? Piece of cake, isn't it? Try it yourself and you will be surprised with the tricky details. A friend of mine gave me a JAXB challenge this week: his company already uses a customization of the xsd:date type in a legacy code - mapped to a proprietary type instead of the default Calendar type. Now they also need to represent Calendar objects in their application schema, so they need to model the date objects as a custom type. My first thought was about a five minutes hack, just defining an element based on the xsd:date and use the JAXB customization to map the new type to the Java Calendar type. After my five minutes I got few issues: The default customization of Calendar in JAXB doesn't serialize the Time information of a date. Ok, let's create a custom binder class and hack the way we want to write and read our data. If you use xsd:dateTime instead of a simple xsd:date, the default adapter of JAXB doesn't work anymore. Other surprise: you can't use the java.text.SimpleDateFormat to serialize Date objects because the String representation of the TimeZone provided by Java is not compatible with the XML specification. - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") produces 2009-12-06T15:59:34+0100 - the expected format for the Schema xsd:dateTime type is 2009-12-06T15:59:34+01:00 You got the difference? Yes, the stupid missed colon in the time zone representation makes the output of the SimpleDateFormat incompatible with the XSD Schema specification. Yes, unbelievable but you need to handle that detail programatically. You can try by yourself but instead of proving you the details I wrote down my hack solution. If you know a more elegant solution, please give me your feedback. Remember the original problem: to not use the xsd:dateTime directly since it is already in use by other customization. Also: your customization should support a date and time representation, including the time zone. Below you find a transcription of the sample project I created to illustrate the solution, to facilitate the copy paste and also to allow you to check the solution in case you don't want or you can't compile and run the project. Otherwise, just download the complete project. To compile and run the project, open a terminal and type the following line commands in the folder you unzipped the project: mvn clean compile test eclipse:eclipse The sample Maven project First step, to create the maven project and configure the JAXB plugin in the pom.xml. To create the project I used the Maven default J2SE archetype: mvn archetype:create -DgroupId=cejug.org -DartifactId=jaxb-example mvn compile eclipse:eclipse Then you can import the project in your preferred IDE and configure the JAXB plugin in the pom.xml: 4.0.0 cejug.org jaxb-example jar 1.0-SNAPSHOT jaxb-example http://maven.apache.org junit junit 3.8.1 test maven2-repository.dev.java.net Java.net Maven 2 Repository http://download.java.net/maven/2 org.apache.maven.plugins maven-compiler-plugin 2.0.2 1.6 1.6 org.jvnet.jaxb2.maven2 maven-jaxb2-plugin generate ${basedir}/src/main/resources/schema **/*.xsd true false true yes true After that, I created the sample schema /jaxb-example/src/main/resources/schema/sample-binding.xsd: Inspired by this blog I created the custom binder org.cejug.binder.XSDateTimeCustomBinder: package org.cejug.binder; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class XSDateTimeCustomBinder { public static Date parseDateTime(String s) { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); try { return formatter.parse(s); } catch (ParseException e) { return null; } } // crazy hack because the 'Z' formatter produces an output incompatible with the xsd:dateTime public static String printDateTime(Date dt) { DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); DateFormat tzFormatter = new SimpleDateFormat("Z"); String timezone = tzFormatter.format(dt); return formatter.format(dt) + timezone.substring(0, 3) + ":" + timezone.substring(3); } } Then I created a JUnit class with the following test method: package cejug.org; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.cejug.sample.ElementType; import org.cejug.sample.ObjectFactory; import org.xml.sax.SAXException; public class JaxbSampleTest extends TestCase { private static final String UTF_8 = "UTF-8"; private static final File TEST_FILE = new File("target/test.xml"); public JaxbSampleTest(String testName) { super(testName); } public static Test suite() { return new TestSuite(JaxbSampleTest.class); } @Override protected void setUp() throws Exception { super.setUp(); if (TEST_FILE.exists()) { if (!TEST_FILE.delete()) { fail("impossible to delete the test file, please release it and run the test again"); } } } public void testApp() { ObjectFactory xmlFactory = new ObjectFactory(); ElementType type = new ElementType(); Date calendar = GregorianCalendar.getInstance(TimeZone.getDefault()) .getTime(); type.setJdate(calendar); JAXBElement element = xmlFactory.createElement(type); try { writeXml(element, TEST_FILE); JAXBElement result = read(TEST_FILE); assertEquals(calendar.toString(), result.getValue().getJdate().toString()); } catch (Exception e) { fail(e.getMessage()); } } private void writeXml(JAXBElement sample, File file) throws JAXBException, IOException { FileWriter writer = new FileWriter(file); try { JAXBContext jc = JAXBContext.newInstance(ElementType.class .getPackage().getName(), Thread.currentThread() .getContextClassLoader()); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_ENCODING, UTF_8); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(sample, writer); } finally { writer.close(); } } @SuppressWarnings("unchecked") public JAXBElement read(File file) throws JAXBException, SAXException, IOException { InputStreamReader reader = new InputStreamReader(new FileInputStream( file)); try { JAXBContext jc = JAXBContext.newInstance(ElementType.class .getPackage().getName(), Thread.currentThread() .getContextClassLoader()); Unmarshaller unmarshaller = jc.createUnmarshaller(); SchemaFactory sf = SchemaFactory .newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema(Thread.currentThread() .getContextClassLoader().getResource( "../classes/schema/sample-binding.xsd")); unmarshaller.setSchema(schema); JAXBElement element = (JAXBElement) unmarshaller .unmarshal(reader); return element; } finally { reader.close(); } } } That's it, I hope it can save your next five minutes of hack :) From http://weblogs.java.net/blog/felipegaucho
December 7, 2009
by Felipe Gaúcho
· 40,396 Views
article thumbnail
A Groovy ride on Camel
Apache Camel is a routing and mediation engine which implements the Enterprise Integration Patterns. But don't let the words Enterprise Integration scare you off. Camel is designed to be really light weight and has a small footprint. It can be reused anywhere, whether in a servlet, in a Web services stack, inside a full ESB or a standalone messaging application. Camel makes it really simple to implement messaging application. So there are not many reasons why you could not use it in non-enterprise application. In fact, it is possible to use Camel as a tool, similar to the way you use scripting languages. For example, you could fire up the Camel Web Console and define a messaging application without write a single line of code. This article is a getting-started type of tutorial. As you might have guessed, I'm going to use Groovy as the programming language. And the programs in this article are intend to be ran with Groovysh, the Groovy Shell. Reasons: Groovy is concise, expressive and has less noice than Java. All programs in this article are just a couple dozen lines long and should be real easy to follow along. Using Groovysh allows the reader to interact with the application. I'm a Linux guy and am comfortable with VIM and working in command line. So bare with me. Putting the pieces together First, I'm going to write a simple program to make sure I'm able to talk to Camel in Groovy. I'm not using an IDE like Eclipse, nor creating a project, nor going to use any build tools like Maven. Any text editor will be sufficient. Save the following code to a file named CamelDemo.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://foo").to("mock://result") } } mrb = new MyRouteBuilder() ctx = new org.apache.camel.impl.DefaultCamelContext() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() p.sendBody "direct:foo", "Camel Ride for beginner" e = ctx.getEndpoint("mock://result") ex = e.exchanges.first() println "INFO> ${ex}" This little program does a couple things: Imports the camel-core jar using Grape.grab() Defines a our custom RouteBuilder, which defines a simple route between a direct:foo and a mock:result enpoints. Instantiates the CamelContext, adds our custom RouteBuilder to it and starts Camel by ctx.start(). Tests the route by sending a message exchange using the producerTemplate obtained from the CamelContext Lookups the mock:result endpoint (ctx.getEndpoint("mock:result")) and dislays the first Exchange, which should contain the message we just sent. Now start the groovysh in a command window and load the program: $ groovysh groovy:000> load CamelDemo.groovy you should see a bunch of output and then the output from the script: INFO> Exchange[Message: Camel Ride for beginner] ===> null groovy:000> At this point, you can interact with the program via groovysh. For example the following shows a few things you can do. groovy:000> ctx.routes ===> [EventDrivenConsumerRoute[Endpoint[seda://foo] -> UnitOfWork(Channel[sendTo(Endpoint[mock://result])])]] groovy:000> ctx.components ===> {mock=org.apache.camel.component.mock.MockComponent@14f2bd7, seda=org.apache.camel.component.seda.SedaComponent@c759f5} groovy:000> ctx.endpoints ===> [Endpoint[seda://foo], Endpoint[mock://result]] groovy:000> ctx.endpoints[1].exchanges ===> [Exchange[Message: Camel Ride for beginner]] groovy:000> ctx.endpoints[1].exchanges[0].in.body ===> Camel Ride for beginner groovy:000> p.sendBody("seda:foo", "Camel Kicking") ===> null groovy:000> e.exchanges ===> [Exchange[Message: Camel Ride for beginner], Exchange[Message: Camel Kicking]] This is it for our first Groovy/Camel program. For the curious, you can actually modify the program and reload it without terminating and restarting groovysh. Camel Stock Quote This is a simple stock quote application. Initially, I planed to walk you thru the development steps, from adding a simple bean as a Processor to transforming it to a Multi-Channel, Multi-Data-Format service application. But after I've finished developing the program, it turns out that it is too simple to justify for such elaboration. To save your time and mine, I'm just going to show you the final version right here. Take a look at it, and if you can understand what it does, then may be you should skip the rest of this article :) Save the following code to a file named StockQuote.groovy (source download). import groovy.grape.Grape Grape.grab(group:"org.apache.camel", module:"camel-core", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") class QuoteServiceBean { public String usStock(String symbol) { "${symbol}: 123.50 US\$" } public String hkStock(String symbol) { "${symbol}: 90.55 HK\$" } } class MyRouteBuilder extends org.apache.camel.builder.RouteBuilder { void configure() { from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") //curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() } } ctx = new org.apache.camel.impl.DefaultCamelContext() mrb = new MyRouteBuilder() ctx.addRoutes mrb ctx.start() p = ctx.createProducerTemplate() //p.sendBody("direct:quote", "00005.HK") //p.sendBody("direct:xmlquote", "") //p.sendBody("direct:xmlquote", "") e = ctx.getEndpoint("mock://result") //e.exchanges.each { ex -> // println "INFO> in.body='${ex.in.body}'" //} OK, you are still here. It is assumed that: We have two market data providers, one for U.S. market and the other for Hong Kong market. An existing QuoteServiceBean class has been implemented as a POJO. It has two methods, usStock() and hkStock(). It is part of a legacy system, it works great, it hides the underlying details of interacting with the data providers. No one understands it and no one dares to modify it. We would like to use the existing QuoteServiceBean to provide a stock quote service that can be consume easily. i.e. Multi-Channel and Multi-Data-Format. Content Based Router and Message Translator from("direct://quote").choice() .when(body().contains(".HK")).bean(QuoteServiceBean.class, "hkStock") .otherwise().bean(QuoteServiceBean.class, "usStock") .end().to("mock://result") The first route (start at line 17) represented by the direct:quote endpoint. It routes the message according to the content of the body of the exchange, which it's assumed to contain the stock symbol. When the body of the exchange contains the string ".HK" the hkStock(String symbol) of QuoteServiceBean is called, otherwise the usStock(String symbol) of QuoteServiceBean is called. Notice that the route DSL almost reads like plain English! Let us try it out. First start groovysh, load the program and send two messages to the direct:quote endpoint: jack@localhost tmp]$ groovysh Groovy Shell (1.6.6, JVM: 1.6.0_11) groovy:000> load StockQuote.groovy .............. groovy:000> p.sendBody("direct:quote", "00001.HK") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: 00001.HK: 90.55 HK$] groovy:000> p.sendBody("direct:quote", "SUNW") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: SUNW: 123.50 US$] groovy:000> That is it, our simple content-based router successfully routes request to the corresponding processor methods. XML Quote Request, message Transform from("direct://xmlquote").transform().xpath("//quote/@symbol", String.class).to("direct://quote") This next route simply accepts requests in XML, transforms the request and chains it to direct://quote. With this, we've added the capability to accept requests in XML format! We are using XPath here to expression our transform. Check out the hosts of Expression Langauges supported by Camel. Let us try it out: groovy:000> p.sendBody("direct:xmlquote", "") ===> null groovy:000> e.exchanges.last() ===> Exchange[Message: GOOG: 123.50 US$] groovy:000> Multi-Channel, Multi-Data-Format Provisioning Grape.grab(group:"org.apache.camel", module:"camel-jetty", version:"2.0.0") Grape.grab(group:"org.apache.camel", module:"camel-freemarker", version:"2.0.0") // ........... lines removed for brevity ............. from('jetty:http://localhost:8080/quote').transform() .simple('').to("direct://xmlquote").choice() .when(header("Content-Type").isEqualTo("text/xml")).to("freemarker:xmlquote.ftl") .otherwise().to("freemarker:htmlquote.ftl") .end() Here we use the camel-jetty to expose an endpoint jetty:http://localhost:8080/quote to our quote service. Note that camel-jetty is not part of camel-core. That is why we have to grab it into our program. The HTTP request is translate into XML using simple expression. Note that the camel-jetty has kindly extracted the request parameters as well as the HTTP header and placed them on the Message header. So the request parameter symbol is access as ${header.symbol} in the expression. Next we simply chain the message exchange to the direct:xmlquote endpoint. The result from direct:xmlquote went thru another translation, which depends on the content-type of the orginating HTTP request. Here, I make use of the camel-freemarker to generate the desire output. So we need to create the two Freemarker templates: htmlquote.ftl ${body} xmlquote.ftl ${body} So let us see it in action, I'm going to use curl to make HTTP requests. Do this on another command window: [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ curl http://localhost:8080/quote?symbol=00001.HK 00001.HK: 90.55 HK$ [jack@localhost tmp]$ And to request XML content: [jack@localhost tmp]$ curl -H "Content-Type: text/xml" http://localhost:8080/quote?symbol=IBM IBM: 123.50 US$ [jack@localhost tmp]$ That's about it for our multi-channel/multi-data-format ser vice provision. Summary In this tutorial, I hoped to illustrate how Camel supports message passing paradigm style of application development. Camel provides all sort of components to help you build processing pipelines. All you need is to implement your business logic as simple POJOs and let Camel handle all the translating, routing, filtering, spliting and forwarding for you. Not shown in this tutorial is how to consume external resources and services from within a route. No sweat, it is just as easy. Camel integrates nicely with Spring as well as Guice, but works nicely on its own. It won't be in your way if you don't need DI support in your application. As they say: Keep the simple easy. Camel works nicely in a JBI environment like ServiceMix and OpenESB. Camel is OSGI-ready and tracks newly deployed bundles for Route definitions at runtime. So you can gear it all to way up to be part of an enterprise SOA infrastructure. Disclaimer, I'm not an experienced Camel user and still learning. Thank you for staying up with me.
December 3, 2009
by Jack Hung
· 25,949 Views
article thumbnail
Fill Data Into An XML Template With VTD-XML
This example shows you how to edit an XML template to fill in the data to generate an output XML file. /* This is the template */ /* Output XML file Empire Burlesque Bob Dylan USA Columbia 10.9 1985 Still Got the Blues Gary More UK Virgin Records 10.2 1990 */ import com.ximpleware.*; import java.io.*; public class editTemplate { public static void main(String[] args) throws Exception { VTDGen vg = new VTDGen(); FileOutputStream fos = new FileOutputStream("new_cd.xml"); AutoPilot ap = new AutoPilot(); ap.selectXPath("/CATALOG/CD"); if (vg.parseFile("cd_Template.xml", false)) { VTDNav vn = vg.getNav(); ap.bind(vn); if (ap.evalXPath() == -1) { System.out.println("XPath eval failed"); System.exit(0); } fillTemplate(vn, "Empire Burlesque", "Bob Dylan", "USA", "Columbia", 10.90, 1985); if (ap.evalXPath() == -1) { System.out.println("XPath eval failed"); System.exit(0); } fillTemplate(vn, "Still Got the Blues", "Gary More", "UK", "Virgin Records", 10.20, 1990); // dump out the XML fos.write(vn.getXML().getBytes()); fos.close(); } } public static void fillTemplate(VTDNav vn, String title, String artist, String country, String company, double price, int year) throws NavException { int i = -1; if (vn.toElement(VTDNav.FIRST_CHILD)) { vn.overWrite(vn.getText(), title.getBytes()); vn.toElement(VTDNav.NEXT_SIBLING); vn.overWrite(vn.getText(), artist.getBytes()); vn.toElement(VTDNav.NEXT_SIBLING); vn.overWrite(vn.getText(), country.getBytes()); vn.toElement(VTDNav.NEXT_SIBLING); vn.overWrite(vn.getText(), company.getBytes()); vn.toElement(VTDNav.NEXT_SIBLING); vn.overWrite(vn.getText(), (price + "").getBytes()); vn.toElement(VTDNav.NEXT_SIBLING); vn.overWrite(vn.getText(), (year + "").getBytes()); } vn.toElement(VTDNav.PARENT); } }
November 30, 2009
by Jimmy Zhang
· 3,541 Views
article thumbnail
An Introduction to Feature-Driven Development
Feature-Driven Development (FDD) is one of the agile processes not talked or written about very much. Often mentioned in passing in agile software development books and forums, few actually know much about it. However, if you need to apply agile to larger projects and teams, it is worthwhile taking the time to understand FDD a little more The natural habitat of Scrum and XP-inspired approaches is a small team of skilled and disciplined developers. It remains a significant challenge to scale these approaches to larger projects and larger teams. Some have been successful but many have struggled. Feature-Driven Development (FDD) invented by Jeff De Luca is different. While just as applicable for small teams, Jeff designed FDD from the ground up to work for a larger team. Larger teams present different challenges. For example, a small team of disciplined and highly skilled developers by definition is likely to succeed regardless of which agile method they use. In contrast, it is unrealistic to expect that everyone in a larger team is equally skilled and disciplined. For this and other reasons, FDD makes different choices to Scrum and XP in a number of areas. In the first part of this two-part article, we briefly introduce the ‘just enough’ upfront activities that FDD uses to support the additional communication that inevitably is needed in a larger project/team. In the second part of the article, we cover how the highly iterative delivery part of FDD differs from Scrum and XP-inspired approaches. Iteration Zero:Getting Set to Deliver Most experienced agile teams are familiar with the concept of an iteration zero, a relatively short period for a team to put in place what they need to start delivering client-valued functionality in subsequent iterations. Despite general acceptance within the agile community that some form of iteration zero is a pragmatic necessity on most projects, neither Scrum nor eXtreme Programming formally have much to say about it. In contrast, an FDD project is organized around five 'processes', of which the first three can be considered roughly the equivalent of iteration zero activities. FDD does not use the term, iteration zero. It calls these three ‘processes’ initial project-wide activities. Each of the FDD processes is described so that it can be printed, in a typical-sized font, on no more than two sides of letter-sized paper. The most recent versions of the FDD processes are available from the FDD section of the Nebulon website, but very briefly an FDD project: … starts with the creation of a domain object model in collaboration with Domain Experts. Usinginformation from the modeling activity, and from any other requirements activities that have taken place, the developers go onto create a features list. Then a rough plan is drawn up and responsibilities assigned. Now we are ready to repeatedly take small groups of features through a design and build iteration that lasts no longer than two weeks and is often much shorter, sometimes only a matter of hours...[Palmer-1] FDD Process #1: Develop an Overall Model For many who have escaped from the perils of large, upfront analysis and design phases to the freedom and discipline of Scrum and eXtreme Programming-inspired approaches, the idea of developing a domain object model at the start of a project is controversial. In FDD, however, the building of an object model is not a long, drawn-out, activity performed by an elite few using expensive CASE tools. The modelers do not format the resulting model into a large document and throw it over the wall for developers to implement. Instead, building an initial object model in FDD is an intense, highly iterative, collaborative and generally enjoyable activity involving ‘domain and development members under the guidance of an experienced object modeler in the role of Chief Architect' [Nebulon]. FDD Process #1 describes the tasks and quality checks for executing this work, and while not mandatory, the object model is typically built using Peter Coad's modeling in color technique (modeling in color needs an introductory article all of its own [Palmer-2]). The idea is for both domain and development members of the team to gain a good, shared understanding of the problem domain. It is important that everyone understands the key problem domain concepts, relationships, and interactions. In doing so, the team as a whole learn to communicate with each other and start to establish a shared vocabulary, what Eric Evans calls a Ubiquitous Language [Evans]. The object model developed at this point concentrates on breadth rather than depth; depth is added iteratively through the lifetime of the project. The model is, therefore, a living artifact. Throughout the project, the model becomes the primary vehicle around which the team discusses, challenges, and clarifies requirements. FDD Process #2: Build a Features List With the first activity being to build an object model, some may conclude FDD is a model-driven process. It is not. While the model is central to the process, an FDD project is like a Scrum or eXtreme Programming project in being requirement-driven. Small, client-valued requirements referred to as features drive the project; the model merely helps guide. Formally, FDD defines a feature as a small, client-valued function expressed in the form:
November 20, 2009
by Stephen Palmer
· 109,075 Views · 6 Likes
article thumbnail
Groovy, Sometimes You Still Need a Semicolon.
Like Javascript, semicolons are optional in Groovy except for when they aren't optional. These examples are both pretty contrived, though I found both because they're actually something that I've written, and could both be written better. That's not really the point I'm making though. When something doesn't compile when it looks like it clearly should sometimes it's hard to track down why, and it's surprising to learn that it's because you need a semicolon. Example the first: Generics at the end of a line: def list = [1,2,3] as List println list If you try to compile this in Groovy it will give you the error message: 'unexpected token: println', however this: def list = [1,2,3] as List; println list Gives the expected output. Example the second: Ambiguous Closures {-> assert GroovyClosureTest == owner.getClass() }() {-> assert GroovyClosureTest == delegate.getClass() }() I don't think you'd really ever need to do something like this, but a closure can be defined and called on a single line. Because of Groovy's special closure parameter syntax (e.g. list.each() {} being synonomous with list.each({})) the compiler thinks I'm passing the second closure into the first as an argument. Again a semicolon is needed to seperate the two lines: {-> assert GroovyClosureTest == owner.getClass() }(); {-> assert GroovyClosureTest == delegate.getClass() }() From
November 6, 2009
by Scott Leberknight
· 32,011 Views · 1 Like
article thumbnail
Fluent Navigation in JSF 2
In this article, the third in a series covering JavaServer Faces (JSF) 2.0 features contributed by Red Hat, or which Red Hat participated in extensively, you'll discover that getting around in a JSF 2 application is much simpler and requires less typing. With improved support for GET requests and bookmarkability, which the previous article covered, JSF 2 is decidely more nimble. But not at the cost of good design. JSF no longer has to encroach on your business objects by requiring action methods to return navigation outcomes, but can instead reflect on the state of the system when selecting a navigation case. This article should give you an appreciation for how intelligent the navigation system has become in JSF 2. Read the other parts in this article series: Part 1 - JSF 2: Seam's Other Avenue to Standardization Part 2 - JSF 2 GETs Bookmarkable URLs Part 3 - Part 4 - Part 5 - Three new navigation variants are going to be thrown at you in this article: implicit, conditional and preemptive. These new options are a sign that the JSF navigation system is becoming more adaptable to the real world. There's also a touch of developer convenience thrown in. Implicit navigation is particularly useful for developing application prototypes, where navigation rules just get in the way. This style of navigation interprets navigation outcomes as view IDs. As you move beyond prototyping, conditional navigation removes the coupling between the web and transactional tier because the navigation handler pulls information from your business components to select a navigation case. Preemptive navigation, which you were introduced to in the last article, can use either implicit navigation or declarative navigation rules to produce bookmarkable URLs at render time. Leveraging the navigation system to generate bookmarkable URLs allows JSF to add GET support while maintaining consistent, centralized navigation rules. Even with these new options, there's no telling what requirements your application might have for navigation. Thus, in JSF 2, you can finally query and modify the navigation cases; a new API has been introduced in JSF 2 that exposes the navigation rule set. Before we get into customizations, let's find out how these new variants make the navigation system more flexible and help prepare the user's next move. Hopefully you won't need those customizations after all. Flexible navigation choices The declarative navigation model in JSF was a move away from the explicit navigation "forward" selection by the action in Struts. Navigation transitions in JSF, which get matched based on current view ID, logical outcome and/or action expression signature, are described in the JSF descriptor (faces-config.xml) using XML-based rules. The matched transition indicates the next view to render and whether a client-side redirect should proceed rendering. Here's a typical example: /guess.xhtml #{numberGuessGame.guess} correct /gameover.xhtml While the JSF navigation model is clearer and arguably more flexible than in Struts, two fundamental problems remain. First, the action method is still required to return a navigation directive. The directive just happens to be a more "neutral" string outcome rather than an explicit type (i.e., ActionForward), but the coupling is just as tight and you loose type safety in the process, so is it really an improvement? The other issue is that you must define a navigation case to match that outcome, even in the simplest cases, which can be really tedious. So you can't make the argument that the navigation model is less obtrusive or more convenient. It's just stuck somewhere in between. To sum it up, the JSF navigation model is not flexible enough. It needs to accommodate different development styles better and it needs to be more self sufficient. On the one hand, your style or development phase may dictate waiving the declarative navigation rule abstraction. On the other hand, you may want to completely decouple your business objects from the navigation model, eradicating those arbitrary return value directives. JSF 2 gives you this broad range of options, and even let's you settle for a happy medium. The first option is provided by implicit navigation and the second conditional navigation. With implicit navigation, you can even use the current model without having to define the navigation rule right away. Let's unbox these two new alternatives, starting with implicit navigation. Implicit navigation JSF will post a form back to the current view (using the POST HTTP method) whenever the user performs an action, such a clicking a command button (hence the term "postback"). In the past, the only way to get JSF to advance to another view after the action is invoked (i.e., following the Invoke Application phase) was to define a navigation case in faces-config.xml. Navigation cases are matched based on the EL signature of the action method invoked and the method's return value converted to a string (the logical outcome). To cite an example, assume the user clicks on a button defined as follows: The preview() method on the bean named commandHandler returns a value to indicate the outcome of processing: public String preview() { // tidy, translate and/or validate comment return "success"; } These two criteria are joined in a navigation case that dictates which view is to be rendered next. /entry.xhtml #{commentHandler.preview} success /previewComment.xhtml If no navigation case can be matched, all JSF knows to do is render the current view again. So without a navigation case, there is no navigation. A quick shorthand, which is present in Seam, is to have the action method simply return the target view ID directly. In this case, you're effectively treating the logical outcome value as a view ID. This technique has been adopted in JSF 2 as implicit navigation. It's improved since Seam because you can choose to drop the view extension (e.g., .xhtml) and JSF will automatically add it back on for you when looking for a view ID. Therefore, it's no more invasive than the string outcome values you are currently returning. Implicit navigation comes into play when a navigation case cannot be matched using the existing mechanism. Here's how the logic outcome is processed in the implicit navigation case: Detect the presence of the ? character in the logical outcome If present, capture the query string parameters that follow it the ? character The special query string parameter faces-redirect=true indicates that this navigation should be issued using a client-side redirect If the logical outcome does not end with a file extension, append file extension of current view ID (e.g., .xhtml) If the logical outcome does not begin with a /, prepend the location of current view id (e.g., /, /admin/, etc.) Attempt to locate the template for the view ID If the template is found, create a virtual navigation case that targets the resolved view ID If the template is not found, skip implicit navigation Carry out the navigation case If the navigation case is not a redirect, build and render the target view in the same request If the navigation case is a redirect, build a redirect URL, appending the query string parameters captured earlier, then redirect to it Implicit navigation can be leveraged anywhere a logical outcome is interpreted. That includes: The return value of an action method The action attribute of a UICommand component (e.g., ) The outcome attribute of a UIOutcomeTarget (e.g., ) The handleNavigation() method of the NavigationHandler API Here's an example of the navigation to the preview comment view translated into implicit navigation. The return value is automatically decorated with a leading / and a trailing .xhtml. public String preview() { // tidy, translate and/or validate comment return "previewComment"; } The /previewComment.xhtml view will be rendered in the same request. If you want to redirect first, add the following flag in the query string of the return value: public String preview() { // tidy, translate and/or validate comment return "previewComment?faces-redirect=true"; } You can accomplish any navigation scenario using implicit navigation that you can today with a formal navigation case defined in faces-config.xml. Implicit navigation is designed as the fall-through case (after the explicit navigation rules are consulted). If it fails (i.e., the template cannot be located), and the JSF 2 ProjectStage is set to development, a FacesMessage is automatically generated to warn the developer of a possible programming error. Implicit navigation is great for prototyping and other rapid development scenarios. The major downside of implicit navigation is that you are further tying your business objects into the navigation model. Next we'll look conditional navigation, which provides an alternative that keeps your tiers loosely coupled. Conditional navigation Implicit navigation spotlights how invasive it is to put the onus on your business object to return a logic outcome just to make JSF navigation happy (and work). This coupling is especially problematic when you want to respond to user interface events using components in your business tier, a simplified architecture that is supported by both Seam and Java EE 6 to reduce the amount of glue code without increasing coupling. What would be more "logical" is to invert the control and have the navigation handler consult the state of the bean to determine which navigation case is appropriate. The navigation becomes contextual rather than static. That's what conditional navigation gives you. Conditional navigation introduces a condition as a new match criteria on the navigation case. It's defined in the element as a child of and expressed using an EL value expression. The value expression is evaluated each time the navigation case is considered. For any navigation case that matches, if a condition is defined, the condition must resolve to true for the navigation case to be considered a match. Here's an example of a conditional navigation case: #{registration.register} #{currentUser.registered} /account.xhtml As you can see, the condition doesn't necessarily have to reference a property on the bean that was invoked. It can be any state reachable by EL. Conditional navigation solves a secondary problem with the JSF navigation model, one of those little annoyances in JSF that was tedious to workaround. In JSF 1.2 and earlier, if your action method is a void method or returns a null value, interpreted in both cases as a null outcome, the navigation is skipped entirely. As a result, the current view is rendered again. The only workaround is to override the navigation handler implementation and change the behavior. That really throws a wrench in being able to cut the glue code between your UI and transactional tier. That changes with the introduction of conditional navigation. Since the condition provides either an alternative, or supplemental, match criteria to the logical outcome, navigation cases that have a condition are consulted even when the logical outcome is null or void. When the outcome is null, you can emulate switch statement to match a navigation case, switching on the condition criteria: #{identity.login} #{currentUser.admin} /admin/home.xhtml #{identity.login} #{currentUser.vendor} /vendor/home.xhtml #{identity.login} #{currentUser.client} /client/home.xhtml If you intend to simply match the null outcome in any case, you can use a condition that is verily true (which, admittedly, could be improved in JSF 2.1): #{identity.logout} #{true} /home.xhtml You can also use this fixed condition to provide a fall-through case. But wait, there's more! Having to itemize all the possible routes using individual navigation cases causes death by XML (a quite painful death). What if you wanted to delegate the decision to a navigation helper bean or involve a scripting language? There's good news. You can! The target view ID can be resolved from an EL value expression. Let's return to the login example and use a helper bean to route the user using one navigation case: #{identity.login} #{navigationHelper.userHomeViewId} Oh my goodness, how much nicer is that? The navigation helper can encapsulate the logic of inspecting the currentUser bean and determining the correct target view ID. In this section, we looked at two additional ways a navigation case is matched, increasing the overall flexibility of the navigation model. Implicit navigation maps logical outcomes directly to view IDs and conditional navigation reflects on contextual data to select a navigation case without imposing unnecessary coupling with the transactional tier. We're still looking at the same fundamental navigation model, though. In the next section, you'll see the navigation model used in a new role, and in a new place in the JSF life cycle, to generate bookmarkable links. Anticipating the user's next move Up to this point, the navigation handler only comes into play on a postback. Since user interface events trigger a "postback" to the current view, as mentioned earlier, the navigation handler kicks in after the Invoke Application phase to route the user to the next view. JSF 2 introduces a completely new use of the navigation handler by evaluating the navigation rules during the Render Response phase. This render-time evaluation is known as preemptive (or predetermined) navigation. Preemptive navigation The spec defines preemptive navigation as a mechanism for determining the target URL at Render Response, typically for a hyperlink component. The current view ID and specified outcome are used to determine the target view ID, which is then translated into a bookmarkable URL and used as the hyperlink's target. This process happens, of course, before the user has activated the component (i.e., click on the hyperlink). In fact, the user may never activate the component. The idea is to marry the declarative (or implicit) navigation model with the support for generating bookmarkable links. Based on what was just described, you should now understand why you declare the target view ID in an attribute named outcome on the new bookmarkable component tags (and why those components inherit from a component class named UIOutcomeTarget). You are not targeting a view ID directly, but rather a navigation outcome which may be interpreted as a view ID if the matching falls through to implicit navigation. Let's consider an example. Assume that you want to create a link to the home page of the application. You could define the link using one the new bookmarkable link component: This definition would match the following navigation case if it existed: * home /home.xhtml Of course, with implicit navigation available, this navigation case would be redundant. We could exclude it and the result would be the same. Home But if the target view ID depends on the context, such as the user's credentials, you might choose to reintroduce the navigation case to leverage conditional logic as we did earlier. In either case, the key is that the target view ID is not hard-coded in the template. As it turns out, you've already been using preemptive navigation when you explored bookmarkability in the last article. But there's a critical part of preemptive navigation that we haven't yet fully explored: the assembly of the query string. As it turns out, this topic also applies to redirect navigation rules. In a sense, preemptive navigation has the same semantics as redirect navigation rules because both produces URL that lead to a non-faces request. The only difference is that a bookmarkable URL is a deferred request, whereas a redirect happens immediately. In both cases, the payload in the query string is an essential part of the URLs identity. Building the query string As a result of the new GET support in JSF 2, there are now a plethora of ways to tack on values to the query string. Options can collide when heading into the navigation funnel. What comes out on the other side? There's a simple conflict resolution algorithm to find out. Each parameter source is given a precedence. When a conflict occurs, meaning two sources define the same parameter name, the parameter from the source with the highest precedence is used. The query string parameters are sourced using the following order of precedence, from highest to lowest: Implicit query string parameter (e.g., /blog.xhtml?id=3) View parameter (defined in the of the target view ID) Nested in UIOutcomeTarget (e.g., ) or UICommand component (e.g., ) Nested within the navigation case element in faces-config.xml Granted, this appears to be a lot of options. Don't worry, we'll walk you through the cases in which you would use each option in this article. We recommend you choose a single style of providing navigation parameters that best suits your architecture and keep the others in the back of your mind, so that when an edge case comes up, you can tap into their power. In the last article, you learned that you can use view parameters to let JSF manage the query string for you. Instead of using view parameters, you could just tack on the query string yourself when building a link to a blog entry. You could even abstract the parameter away from the view and define it in the navigation case instead, but it again it presents a challenge to tooling: permalink /entry.xhtml?id=#{blog.entryId} A nested would also work here, especially if you want to centralized your parameters. In terms of navigation, the most important point to emphasize here is that you can finally add query string parameters to a redirect URL in the navigation rules. This need likely appears in your existing applications. No longer do you have to resort to using the programmatic API to issue a redirect with a query string payload. Let's consider the case of posting a comment to an entry. This example demonstrates the case when you are submitting a form and want to redirect to a bookmarkable page which displays the result of submitting the form: #{commentHandler.post} /entry.xhtml id #{blog.entryId} Note: Don't confuse with a UIViewParameter. Think of it more as a redirect parameter (the tag should probably be called not , something to address in JSF 2.1). There are now plenty of options to pass the user along with the right information. But the spec can't cover everything. That's why you can now query the navigation rule base at runtime to do with it what you like. Peeking into the navigation cases You've now seen a number of ways in which the navigation cases themselves have become more dynamic. Regardless of how dynamic they are, the fact remains that once you ship the application off for deployment, the navigation cases that you defined in faces-config.xml are set in stone. That's no longer the case in JSF 2. A new navigation handler interface, named ConfigurableNavigationhandler, has been introduced that allows you to query and make live modifications to the registered NavigationCase objects. Not that you necessarily want to make changes in production. Having a configurable navigation rule set means that you can incorporate a custom configuration scheme such as a DSL or even a fluent, type-safe navigation model from which rules can be discovered at deployment time. In short, the navigation rule set is pluggable, and it's up to you what to plug into it. NavigationCase is the model that represents a navigation case in the JSF API. When JSF starts up, the navigation cases are read from the JSF descriptor, encapsulated into NavigationCase objects and registered with the ConfigurableNavigationHandler. You can retrieve one of the registered NavigationCase objects by the action expression signature and logical outcome under which it is registered. NavigationCase case = navigationHandler.getNavigationCase( facesContext, "#{commandBoard.post}", "success"); You can also access the complete navigation rule set as a Map>, where the keys are the values. Map> cases = navigationHandler.getNavigationCases(); You can use this map to register your own navigation cases dynamically. For example, a framework might read an alternative navigation descriptor (such as Seam's pages descriptor) and contribute additional navigation cases. With an individual NavigationCase object in hand, you can either read its properties or use it to create an action or redirect URL, perhaps to feed into your own navigation handler. There are a lot of possiblities here. The slightly awkward part is how you reference this new API (ConfigurableNavigationHandler). The default NavigationHandler implementation in a standard JSF implementation must implement this interface. But you still have to cast to it when you retrieve it from the Application object, as follows: ConfigurableNavigationHandler nh = (ConfigurableNavigationHandler) FacesContext.getCurrentInstance() .getApplication().getNavigationHandler(); Obviously, something to revisit in JSF 2.1. Once you get a handle on it, the navigation model is your oyster. You can define new ways to navigate or use it to generate bookmarkable URLs in your own style. Forging ahead The JSF navigation model had the right idea in spirit, but lacked a couple of elements that would allow it to truly realize loose coupling, it's required use slowed down prototyping, and you had no control to query or modify the navigation rule set at runtime. Your going to find that in JSF 2, the navigation system is much more flexible. You could argue that it finally accomplishes its original goals. For prototype applications, you can get navigation working without touching the faces-config.xml descriptor with implicit navigation. Just use a view ID, with or without an extension, as the logical outcome and away you go. As the application matures, you can establish a clean separation between JSF and your transactional tier by using conditional navigation to select a navigation case. You can trim the number of navigation cases by defining the target view ID as a value expression and having JSF resolve the target view ID from a navigation helper bean. If the design of your application calls for bookmarkable support, you can leverage the navigation handler in its new role to produce bookmarkable URLs at render time. In JSF 2, it's a lot easier to route the user around the application. While that may be good for some applications, other applications never advance the user beyond a single page. These single page applications transform in place using Ajax and partial page updates. The next article in this series will open your eyes to how well Ajax and JSF fit together, and what new Ajax innovations made their way into the spec.
November 2, 2009
by Dan Allen
· 139,488 Views · 2 Likes
article thumbnail
Integrating JBoss RESTEasy and Spring MVC
Building websites is a tough job. It's even tougher when you also have to support XML and JSON data services. Developers need to provide increasingly sophisticated AJAXy UIs. Marketing groups and other business units are becoming more savvy to the benefits of widgets and web APIs. If you're a Java developer who needs to implement those sexy features, you're likely going to accomplish that work with a dizzying variety of frameworks for web development, data access and business logic. The Spring Framework has a strong presence based on the premise of seamless (no pun intended) integration of all of those frameworks. The Spring framework integrates with a host of JEE standard technologies, such as EJBs and JSP. Spring MVC is a sub-project of the larger Spring Framework that has its own Controller API and also integrates other web development frameworks such as JSF, Struts and Tiles. While the Spring Framework also integrates with new JEE technologies as they develop, however, for a variety of reasons the Spring framework has not integrated with the tour de force JAX-RS standard which delivers an API for constructing RESTful services. There are six implementations of the JAX-RS standard, and each provides some level of integration with Spring. Most of those integrations work with the Spring framework proper, but don't take advantage of the benefits of Spring MVC. JBoss RESTEasy integrates with both the Spring Framework proper and also with the Spring MVC sub-project. In this article, we're going to explore how to use RESTEasy along with Spring MVC application. We'll deep dive into the internals of Spring MVC, we'll discuss JAX-RS and how they related to MVC web development. We'll also touch on quite a few technologies beyond Spring MVC and RESTEasy, including Jetty and maven. We're also going to discuss theoretical concepts relating to REST and Dependency Injection. This article has to cover quite a bit of ground and you'll be gaining quite a few tools you can use to develop complex web applications. If you follow this article, you'll be constructing an end-to-end web application, however, feel free to skim the article to find material that's relevant to you. REST and JAX-RS REST has been an increasingly trendy topic over the last three years. We as a development community have been looking at REST as an effective way to perform distributed programming and data-oriented services. In fact, the Java community's REST leaders got together and created a standard spec to standardize some RESTful ideas in JSR 311 - JAX-RS the Java API for XML and RESTful Services. The focus of JAX-RS was to create an API that Java developers could use to perform RESTful data exchanges. However, the Java community quickly saw the similarities between JAX-RS and MVC (Model View Control) infrastructures. James Strachan, a long time Java community member and open source contributor (to things like DOM4J, Groovy - he created the language, and recently the Apache Camel and CXF ESBs) suggested that JAX-RS as the one Java web framework to rule them all?. Jersey, the production ready JAX-RS reference implementation, has a built in JSP rendering mechanism. The RESTEasy community built a similar mechanism in HTMLEasy. The Jersey and and HTMLEasy approaches work well for simpler websites, but they don't solve some of the more complex needs of an application. If you want more complex functionality, you'll need a more sophisticated web-development platform, such as Spring MVC. A combination of Spring MVC and RESTEasy will have the following benefits compared to the simpler approaches: Session based objects Freedom of choice - chose the right tool for the job Spring MVC integrates with a whole bunch of MVC frameworks, including Spring MVC, Struts2 and now RESTEasy Spring MVC integrates with a whole bunch of View frameworks, including JSP, JSF, Tiles and much more Integrated AJAX components - the freedom of choice can make end-to-end AJAX calls a breeze, assuming you chose the appropriate framework More control over URL mapping This article tackles some more advanced topics. If you want some relevant background, we have a reference section at the end of this article. Before we take a look at code, let's take a more in depth view of Spring MVC. Spring MVC Spring MVC is broken down into three pluggable sub-systems: Handler Mapping - Map a URL to Spring Bean/Controller. Spring allows quite a few methods to perform this mapping. It can be based on the name of a Spring bean, it could be a URL to bean map, it could be based on an external configuration file or it could be based on annotations. Handler Mappings allow you to configure complex mappings without resorting to complex web.xml files. Handler Adapter - Invoke the Controller. Hander Adapters know what type of spring beans they can call and performs invocations on the types of beans it knows about. There are Handler Adapters for Spring MVC classic, spring @MVC, Struts, Struts2, Servlets, Wicket, Tapestry, DWR and more. View Mapping - Invoke the View. View Mappers know how to translate a logical view name produced by a Controller into a concrete View implementation. A name like "customers" may translate into any of the following technologies: JSP/JSTL, JSF, Velocity, FreeMarker, Struts Tiles, Tiles2, XSLT, Jasper Reports, XML, JSon, RSS, Atom, PDF, Excel, and more RESTEasy plugs into Spring MVC in all three sub-systems. JAX-RS Resources/Controllers are defined by annotations; therefore RESTEasy provides a ResteasyHandlerMapper that knows how to convert a URL to a RESTEasy managed JAX-RS controller method. Once RESTEasy determines which method to invoke, the ResteasyHandlerMapping performs the invocation. The invocation can either be an object, which invokes the default JAX-RS behavior which transforms the resulting Object to a Represetation such as XML or JSON. Additionally, you return a traditional Spring ModelAndView which can refer to a logical view name and a map of data to be rendered by the View. The default JAX-RS behavior creates a ResteasyView which uses JAX-RS's configurable MessageBodyReader and MessageBodyWriter transformation framework. RESTEasy can produce XML and JSON using JAXB, but can be configured to use other view technologies such as Jackson, which is a performant and flexible JSON provider, Flex AMF. This separation of Controller and View concepts allows you to mix and match your Controller and View technologies. RESTEasy Resources can call any Spring managed Views and other Controller technologies can be rendered by a ResteasyView. You can either use RESTEasy as your sole MVC framework, if it fits your needs, or you can augment an existing Controller infrastructure with data services provided by RESTEasy. Just as importantly, you can leverage all of the other functionality that Spring provides, such as DAO abstraction, transaction management and AOP. Your First SpringMVC/RESTEasy Application Before we start reviewing the project, let's review a quick checklist of items we will be reviewing. The project files fall into two categories: configuration and source code. All of the code that will be covered is available in the RESTEasy repository and can be downloaded (as a tar.gz file), or browsed. Here is a list of files that each category will require. Configuration Files: web.xml - servlet configuration with Spring MVC artifacts - Spring MVC's DispatcherServlet, and map to /contacts/* springmvc-servlet.xml - a Spring application context configuration with all of the Spring beans this project needs, including RESTEasy setup (one line) and JSP configuration pom.xml - maven 2 dependency configuration, including required repositories, RESTEasy dependencies and embedded Jetty setup Source Code: The code we're going to show you can be broken down into four layers: Controller - Controlling the flow between the HTTP request, the Model and the View ContactsResource.java - a RESTful Controller with JAX-RS annotations and some traditional HTML controller methods. It will be annotated with Spring's @Controller and @Autowired annotations as well. Model - the domain model and service objects in our case. In our case, we have 2 domain objects: Contact and Contacts; and 1 Service object: ContractService Contact.java - a JAXB domain object with contact information Contacts.java - a JAXB wrapper object that wraps a Contact List ContactService.java - a Map based repository of Contact instances View - How the domain model is transformed for consumer use. JAX-RS performs automated conversion to XML based on annotations on our domain model. We'll be using JSP for object to HTML conversion. contacts.jsp - a bare bones HTML view of our Contacts Test - JAX-RS provides quite a bit of functionality, we're writing quite a bit of code, and all of that is wrapped in quite a bit of configuration. This article will focus on testing our code, configuration and deployment in an automated JUnit test. ContractTest.java - a RESTEasy ReSTful Unit test for the ContractsResource functionality, embedded server included There's a lot of ground to cover, and we'll cover the most interesting pieces of the source first. Our first pass will cover the web.xml and springmvc-servlet.xml configuration files as well as the ContactsResource.java and ContactTest.java source files. Our second pass will cover the remaining topics. Core RESTEasy/Spring MVC artifacts web.xml Spring MVC's entry point is the DispatcherServlet. There are two parts in setting up the DispatcherServlet, the first is to map the servlet to the URL pattern which must follow the rules specified in Section 11.2 of Servlet API Specification. The next step is configure the behavior of the the servlet by providing the configuration file which we call 'springmvc-servlet.xml'. By default, DispatcherServlet looks for a configuration file at "WEB-INF/{servlet-name}-servlet.xml" to find it's configuration, but we're going to use a Spring configuration from the classpath so that the configuration can be reused later in our junit test case. springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-servlet.xml springmvc /contacts/* All requests will be forwarded to the Spring MVC DispatcherServlet. One can get much more sophisticated, but this is one of the simplest simplest web.xml you can create to integrate with Spring. Note that there isn't any reference here to a RESTEasy servlet. Other JAX-RS/Spring integrations require you to have an implementation specific Servlet to serve XML or JSon and a separate Spring MVC DispatcherServlet mapping to server HTML requests. RESTEasy integrates with DispatcherServlet to allow Spring MVC to direct the URL to either RESTEasy Resources or Spring MVC Controllers. Next, let's take a look at the Spring MVC configuration. springmvc-servlet.xml In our basic project, there are five things we need to do in the springmvc-servlet.xml file. Register the Spring namespace Register the package(s) to scan for Spring MVC annotations. Configure the context annotation processor. Import the springmvc-resteasy.xml configuration file which specifies the default RESTEasy/Spring MVC integration Spring beans. Configure the ViewResolver bean to configure the presentation layer to use JSP. Let's inspect the springmvc-servlet.xml file and focus on each of the above items. The springmvc-servlet.xml file itself is pretty short and shows off some of the features from Spring 2.5: Demystifying the Spring Configuration Spring allows for custom namespaces to reduce the verbosity of the configuration files. We make use of the namepsace by registering it in lines 3 and 4. Line 6 (component-scan) informs spring about which package(s) we want to scan and create the custom component object instances, such as controllers and service objects. We tell Spring about the packages we're interested in by using the custom namespace and set the base-package attribute with the packages we're interested in (org.jboss.resteasy.examples.springmvc ). Later on, you'll see that we're going to be using two Spring annotations that allow the Spring runtime to glean Dependency Management information directly from the object itself: @Controller and @Service. Line 7 (annotation-config) tells Spring that our application will be using annotations on how to configure the beans created by the (component-scan) operation of line 6. Spring looks for annotations such as Spring's @Autowired and @Required; JEE's @Resource; and JPA's @PersistenceContext and @PersistenceUnit to describe dependencies between bean instances. annotation-configSpring also looks for life-cycle annotations such as JSR 250's @PostConstruct and @PreDestroy. Our environment requires a dependency between our Controller and Service objects, and the annotation-config declaration will assist us to configure that relationship in Java code. Line 8 (import) is all the XML that is necessary to configure a RESTEasy environment in Spring MVC. The nice thing about the integration with RESTEasy is that most of the configuration is done for you within an embedded configuration file called springmvc-resteasy.xml. Lines 9-14 tell Spring how we intend to handle the rendering of our presentation layer. In our case, we want to use JSTL views that translate view names (such as "contact") to a JSP page found in the /WEB-INF/ directory (specifically /WEB-INF/contacts.jsp in our case). For more information about setting up Spring views, take a look at the spring documentation. Next, let's take a look at how you can mix and match Spring and JAX-RS annotations in a Controller/Resource. ContactsResource.java MVC Controllers control the flow between the Model and the View. Resource is REST's equivalent to Controllers, and we'll be using the term Resource and Controller interchangably. In our case, our resource handles requests to /contracts and /contracts/{id}. Our ContractsResource must perform quite a few functions on those two URL templates: Retrieve all Contacts - Display the results in either HTML, XML or JSon. For clarity, we'll break out the data oriented functionality (XML and JSon) from the user oriented functionality (HTML) into two distinct URLs - /contacts for HTML and /contacts/data for XML and JSon. REST allows a client to select which format it prefers to receive the data in through a process called Content Negotiation. Content Negotiation can happen through HTTP headers, URI or query parameters. Our ContractsResource will use different URIs to differentiate between data oriented and user views, and will use HTTP headers to differentiate between XML and JSon data views. Save a Contact - Create or Updating data is a pretty standard requirement. The Save a Contact functionality mirrors the Content Negotiation needs of Retrieve all Contacts. User oriented data exchange comes in the form of HTML form data, and data oriented exchange usually occurs in XML and JSon. These differing requirements require ContractResource to have two distinct JAX-RS Java methods; we'll also separate the URLs for clarity purposes. View a Contact - We'll create a single view for viewing a single contact that returns XML or JSon. We leave the user oriented view as an exercise for the reader. Here's another view of our requirements: Functionality URL Format Java Method User Oriented View All /contacts HTML viewAll() Data Oriented View All /contacts/data XML or JSon getAll() User Oriented Save /contacts/ Form data saveContactForm() Data Oriented Save /contacts/data XML or JSon saveContact() Data Oriented View Single /contacts/data/{lastName} XML or JSon get() Note that we mixed and matched HTML and data oriented functionality in this requirement. Now that we have our requirements in place, let's take a look at the ContactsResource code. There are quite a few new Spring and JAX-RS annotations which we'll explain right after the code: @Controller @Path(ContactsResource.CONTACTS_URL) public class ContactsResource { public static final String CONTACTS_URL = "/contacts"; @Autowired ContactService service; @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data") public Contacts getAll() { return service.getAll(); } @GET @Produces(MediaType.TEXT_HTML) public ModelAndView viewAll() { // forward to the "contacts" view, with a request attribute named // "contacts" that has all of the existing contacts return new ModelAndView("contacts", "contacts", service.getAll()); } @PUT @POST @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data") public Response saveContact(@Context UriInfo uri, Contact contact) throws URISyntaxException { service.save(contact); URI newURI = UriBuilder.fromUri(uri.getPath()).path(contact.getLastName()).build(); return Response.created(newURI).build(); } @POST @PUT @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.TEXT_HTML) public ModelAndView saveContactForm(@Form Contact contact) throws URISyntaxException { service.save(contact); return viewAll(); } @GET @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Path("data/{lastName}") public Contact get(@PathParam("lastName") String lastName) { return service.getContact(lastName); } } This code is packed with annotations and Java code that's indicative of JAX-RS Resources and Spring applications. There is also a RESTEasy custom annotation. The Spring IoC annotations are well documented, but we are using them in unusual ways for our integration: @Controller tells the Spring runtime that it needs to create an instance of ContractsResource at startup time. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractsResource must be created at startup. Spring has a more generic @Component, but the use of @Controller allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting. While @Controller is usually associated with Spring @MVC annotated controllers and not other Controller infrastructures, but even thought it's not a Spring MVC controller, we use it to tell Spring that this indeed is a Controller That association of @Controller to Spring MVC annotated controllers is a loose coupling in the Spring runtime. We'll use JAX-RS annotations to configure the handling of URL and HTTP handling behavior. You could theoretically add additional Spring @MVC annotations such as @RequestMapping (which is an equivalent of JAX-RS @Path) to our ContactsResource, if you really wanted to @Autowired tells the Spring runtime that instances of ContractResource require an instance of ContactService. We'll be coding the ContactService later in this article. You can take a look at the Spring reference documentation for more information about @Autowired and @Controller. The last Spring artifact that we use is ModelAndView: It is Spring MVC's encapsulation of which logical View to use and which Model variables should be passed into the View. In our case, we're going to create a Model variable called "contacts" that is a List of all Contact objects we have in the system. We're passing that variable to the a logical view named "contacts" which will map to "/WEB-INF/contacts.jsp" based on the Spring configuration that we previously discussed. The JAX-RS annotations are also well documented, but it's definitely worth while to give a brief overview: @Path tells the RESTEasy (or other JAX-RS environments) how to map URLs to java methods. Adding @Path at the class level tells, in our case "/contacts", indicates that all methods must be prefixed with that URL. The @Path value can either be a hard coded URL such as "/contacts" or it can be a URI template such as "data/{lastName}". You can even specify regular expressions for more sophisticated filtering in the URI template. @GET, @PUT and @POST are used in combination with @Path to indicate which specific HTTP methods are handled by individual Java methods @Produces and @Consumes are used to further filter how a request should be handled based on content negotiation based on the Accept and Content_Type HTTP header. JAX-RS provides a set of default mime type values in the MediaType class. @PathParam is a method parameter annotation that indicates how a URI template variable is mapped to a method parameter. There are quite a few other method parameter level annotations that you could use to map HTTP headers, cookies, query parameters and form parameters to member variables @Context is an interesting JAX-RS parameter that allows dependency injection of request level information such as HttpRequest, HttpResponse and UriInfo (which as you can probably guess encapsuldates information about the request URI). It's important to note that Spring by default manages beans such as ContactsResource as a singleton; if ContactsResource was a Prototype or Request scoped bean, you would be able to use the @Context annotation on member variables in addition to method variables. For more on Spring scoping see the Spring Framework documentation. The last annotation we need to talk about is @Form. It's a RESTEasy custom annotation that describes that a member variable encapsulates data from HTML forms. If you recall, we used the JAX-RS @FormParam annotation on our Contact domain object. @Form and @FormParam are used in concert to allow for better maintenance of form based processing systems. JAX-RS 2.0's stated goals include a more robust, uniform Form processing annotation system. The functionality to code ratio is pretty high because of all of the declarative coding conventions of these annotations. Now that we've discussed the most involved pieces of the puzzle, let's take a look at completing the project. Additional Artifacts pom.xml Our pom.xml includes dependency management, description of required Maven repositories, a description of which JDK we're going to use and a Jetty web server configuration. We'll cover the repository selection, the dependencies specific to RESTEasy and a jetty-maven integration External Repositories jboss jboss repo http://repository.jboss.org/maven2 scannotation http://scannotation.sf.net/maven2 java.net http://download.java.net/maven/1 legacy maven repo maven repo http://repo1.maven.org/maven2/ Project Dependencies Now that we've informed Maven which additional repositories are required, we can now include the dependencies the our sample project will require. The section of the pom.xml file, should include the following two dependencies for Spring and RESTEasy functionality - resteasy-spring and resteasy-jaxb-provider: org.jboss.resteasy resteasy-spring 1.2.RC1 org.jboss.resteasy resteasy-jaxb-provider 1.2.RC1 org.mortbay.jetty maven-jetty-plugin 6.1.15 test The resteasy-spring dependency includes the adapter that integrates RESTEasy into Spring's MVC and provides most the required Java dependencies for RESTEasy and Spring. It also contains Spring configuration needed within the embedded spring-resteasy.xml file that will be used in the Spring configuration section. The other RESTEasy dependency that's included, resteasy-jaxb-provider, contains classes that convert the payload into various formats before sending it to the client. The last dependency to focus on is the maven-jetty-plugin which allows us to easily startup our project in a Jetty webserver environment. Note: If you're follow the link above to the RESTEasy repository's version of pom.xml, you will have to modify the version of resteasy-spring and resteasy-jaxb-provider to the latest version that has been deployed, specifically 1.2.RC1 at the time this article was written. The RESTEasy repository contains a soon-to-be-deployed version number which will not work unless you build the entire RESTEasy project. Maven Jetty Plugin One last interesting item of pom.xml is the configuration of the Jetty web server resteasy-springMVC org.mortbay.jetty maven-jetty-plugin 6.1.15 / 2 ... This will allow us to startup Jetty against localhost:8080. You can learn more about the maven Jetty plugin and a variety of configuration options. Let's start with the domain model and move on to the service object. From there, we'll discuss the JAX-RS Resource/Controller. From there, we'll explore the unit test and finally we'll write the JSP View and start up our server. Contact.java Our DTO is going to be deceptively simple. It will perform a dual responsiblity of JAXB XML binding and Form parameter binding. Both sets of functionality will be configured through annotations and will be managed through JAXB and JAX-RS: import javax.ws.rs.FormParam; import javax.xml.bind.annotation.XmlRootElement; @XMLRootElement public class Contact { private String firstName, lastName; // default constructor for JAXB (also required by JPA/Hibernate if you use them) public Contact(){} // helper constructor for our Controller/Service operations public Contact(String firstName, String lastName){ this.firstName = firstName; this.lastName = lastName; } @FormParam("firstName") public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } @FormParam("lastName") public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } // equals and hasCode are added for the Map based Service object public boolean equals(Object other){ .. } public long hashCode(){ .. } } The annotation on the setters tells JAX-RS to bind any incoming form parameters to the appropriate setter. The @XMLRootElement annotation is enough to tell JAXB that the Contract object must be bound to getters and setters must be bound to an XML document that will look like: Richard Burton Contacts.java The Contacts class is a simple wrapper around a List of Contact instances: @XmlRootElement public class Contacts { private Collection contacts; public Contacts() { this.contacts = new ArrayList(); } public Contacts(Collection contacts) { this.contacts = contacts; } @XmlElement(name="contact") public Collection getContacts() { return contacts; } public void setContacts(Collection contact){ this.contacts = contact; } } Contacts has the @XmlRootElement, just like Contact. The @XmlRootElement annotation tells JAXB to transform objects of this type to an XML structure that has as its top level element. In addition, we've added the @XmlElement annotation to the getContacts() method. By default, JAXB renders all JavaBean elements and uses the JavaBean name as the element. JAXB handles Lists as special cases: all List elements are translated to XML elements using the JavaBean name. @XmlElement(name="contact") tells JAXB that we opted to override the default name ("contracts") in favor of our own name ("contract" - no 's'). The Contracts object will bind to XML that looks like: Richard Burton Solomon Duskis Now that we have our Domain model in place, let's start using it in our Service tier. ContactService.java Since the purpose of this article is JAX-RS centric, we're not going to create an elaborate service layer, but we'll add once since creating more robust Spring applications do require service or data access layers. If you're interested in seeing a RESTEasy/Spring application with database access, look here. Our ContractService performs simple in-memory storage of Contacts by last name: @Service public class ContactService { private Map contactMap = new ConcurrentHashMap(); public void save(Contact contact){ contactMap.put(contact.getLastName(), contact); } public Contact getContact(String lastName){ return contactMap.get(lastName); } public Contacts getAll() { return new Contacts(contactMap.values()); } } There are two items of interest that are noteworthy: Notice the use of Spring's @Service annotation. Do you remember the component-scan directive that was used in the Spring configuration section? The combination of the directive and the annotation tell Spring that a singleton instance of ContractService must be created at startup. Spring has a more generic @Component, but the use of @Service allows for more precise definition of bean usage and also allows for future upgrades that involve AoP to create more precise targeting. Notice the use of ConcurrentHashMap. It's a JDK 1.5 addition that adds performance in multi-threaded environments. It's an easy way to boost performance in distributed REST applications Next, let's take a look at the JSP that contacts.jsp We've explored the Model and Controller aspects of MVC. The last piece to the puzzle is the View. Most JAX-RS based interactions perform a more automated conversion of objects like our Contact to a data-oriented view, such as XML or JSon. Traditionally, Java EE MVC has been done with a more manual View management with languages such as JSP. Our JSP will take a Contracts instance created in ContractsResources.viewAll() and render it in basic HTML: Hello Contacts! Hello ${contact.firstName} ${contact.lastName} Save a contact, save the world: First Name: Last Name: This JSP loops over all contacts and adds links to their data-oriented View. It also creates a simple HTML form for creating a new Contact. While this JSP is simple, it will help us exercise three of our ContactsResource Controller: viewAll(), .saveContactForm(), and get(). It could also be a spring board for more complicated AJAX/JSon interaction, but that's beyond the scope of this article. The code and configuration is now complete, so let's run this project! Jetty Running Jetty is rather simple. You've seen most of the details of the pom.xml when we previously discussed it. Running jetty through maven involves running the following command: mvn jetty:run (If you haven't done so already, download the file as a tar ball, and change the pom.xml's version of the two RESTEasy dependencies to 1.2.RC1) That command will launch Jetty, and allow you to browse our project at http://localhost:8080/contacts. Add a few contacts, and view them either as a group at /contacts in HTML, as a group in XML at /contact/data, or individually as XML by following the links found at /contacts. Congratulations. You now have a running Spring MVC/RESTEasy application. We need one more thing to consider this application complete: a JUnit test. ContractTest.java RESTEasy provides a mechanism for easily launching a Spring MVC/RESTEasy application. RESTEasy also comes with a robust REST client framework. This article will cover bits and pieces of the test, but you can view the entire code in the RESTEasy SVN. To start, we're going to set up an interface that the RESTEasy client can use to create a client for our application. It consists of abstract methods annotated with JAX-RS annotations: @Path(ContactsResource.CONTACTS_URL) public interface ContactProxy { @Path("data") @POST @Consumes(MediaType.APPLICATION_XML) Response createContact(Contact contact); @GET @Produces(MediaType.APPLICATION_XML) Contact getContact(@ClientURI String uri); @GET String getString(@ClientURI String uri); } All methods on ContactProxy inherit the ContactsResource.CONTACTS_URL path ("/contacts") as the root URL, just like a server-side JAX-RS resource. This interface's has three methods: Create a contact - the createContact method maps to a POST to "/contacts/data". The method accepts a Contact object which will be converted to XML before it's sent to the server. The result is a JAX-RS Response object which contains the response status and headers. One of those headers includes the LOCATION of the new contact Get an XML Contact - Given a URL to a Contact, such as the URL returned by the createContact method's response's LOCATION header, GET an XML response and create a Contact object from it. Get a Response as a String - Given a URL, such as a Contact URL or anything else on the server, retrieve a String result. This interface will be used by RESTEasy to construct a concrete instance that uses the JAX-RS annotations to perform the actual HTTP calls. Next, let's create the embedded server and use RESTEasy to create that instance of a ContactProxy: private static ContactProxy proxy; private static TJWSEmbeddedSpringMVCServer server; public static final String host = "http://localhost:8080/"; @BeforeClass public static void setup() { server = new TJWSEmbeddedSpringMVCServer("classpath:springmvc-servlet.xml", 8080); server.start(); RegisterBuiltin.register(ResteasyProviderFactory.getInstance()); proxy = ProxyFactory.create(ContactProxy.class, host); } @AfterClass public static void end() { server.stop(); } JUnit invokes methods annotated by @BeforeClass before any test methods run. Methods annotated by @AfterClass are triggered by JUnit before after all test methods are complete. In our case, the setup method will instantiate a server that contains a SpringMVC Servlet on port 8080 that is configured by the same Spring XML configuration file we used in Jetty. It also invokes the two lines of code required to create a RESTEasy client. RegisterBuiltin sets up the RESTEasy run time, and must be run one time per client. ProxyFactory.create tells RESTEasy to read the annotations on the ContactProxy interface and to create a Java Proxy instance that knows how to perform the HTTP requests we'll need for our test: @Test public void testData() { Response response = proxy.createContact(new Contact("Solomon", "Duskis")); String duskisUri = (String) response.getMetadata().getFirst(HttpHeaderNames.LOCATION); Assert.assertTrue(duskisUri.endsWith(ContactsResource.CONTACTS_URL + "/data/Duskis")); Assert.assertEquals("Solomon", proxy.getContact(duskisUri).getFirstName()); ... } This test creates a new Contact, checks the server's response to make sure that the URL is consistent with the test's expectations. It then re-retrieves the Contact and confirms that the firstName is indeed what was sent sent in. While this is a pretty trivial looking test, it performs quite a bit of HTTP activity and business logic. Conclusion This article discussed quite a bit of philosophy and design considerations in building a RESTful web application with RESTEasy and Spring MVC. We also built an end to end application with RESTEasy, Spring MVC, Maven, Jetty and JUnit. Even though the content in this article was significant, the code presented here is relatively short compared to other Java alternatives. We touched on subjects like designing REST Applications, creating Spring applications, the RESTEasy client infrastructure and testing RESTful applications. Each of those subjects merit their own articles. There were also other subjects that we simply couldn't fit into this article (as long as it is), including JavaScript to the toolkit to allow closer integration between the browser and your RESTful application, integrating with Flex and more. The code presented in this article can serve as a spring board (again, no pun intended) for all of those ideas. About the Authors Solomon Duskis Solomon Duskis is a Senior Manager at SunGard Consulting Services. He's been developing for 22 years -- 12 years in professional capacity. He has experience in various industries such as Finance, Media, Insurance and Health. He contributes to Open Source projects such as JBoss Resteasy and the Spring framework. He is a published author of Spring Persistence - A Running Start, and the upcoming book Spring Persistence with Hibernate. Richard Burton Richard Burton is the co-founder of a small independent consulting firm called SmartCode LLC. He is an Open Source fanatic with over 10 years of experience in various industries such as Automotive, Insurance, Finance and fondly remembers the .com era. In his spare time, he contributes to Open Source projects such as SiteMesh 3, Struts 2, and more. Reference REST Roy Fielding's REST Thesis - Architectural Styles and the Design of Network-based Software Architectures(December 2000) Bill Burke's (August 2008 - DZone) How to GET a cup of coffee (October 2008 - InfoQ) Roy Fielding REST APIs Must Be Hypertext Driven (October 2008 - Untagled Roy's blog - take a look at the URI: roy.gbiv.com ) JAX-RS Bill Burke's (September 2008 - DZone) An overview of JAX-RS 1.0 Features James Strachan's JAX-RS as the one Java web framework to rule them all? (January 2009 - James' blog) RESTEasy RESTEasy project A blog about Spring + RESTEasy Getting Started with RESTEasy Spring Spring 2.5 reference Oh, just search google for "spring framework" Spring MVC Spring MVC Reference Spring MVC Step By Step Spring MVC Tutorial
October 15, 2009
by Solomon Duskis
· 141,176 Views · 1 Like
article thumbnail
Use Python Win32gui Draw Something And Get Info On Some Window Specialized By Points
import win32gui from re import match def draw_line(): print 'x1,y1,x2,y2?' s=raw_input() if match('\d+,\d+,\d+,\d+',s): x1,y1,x2,y2=s.split(',') x1=int(x1) y1=int(y1) x2=int(x2) y2=int(y2) hwnd=win32gui.WindowFromPoint((x1,y1)) hdc=win32gui.GetDC(hwnd) x1c,y1c=win32gui.ScreenToClient(hwnd,(x1,y1)) x2c,y2c=win32gui.ScreenToClient(hwnd,(x2,y2)) win32gui.MoveToEx(hdc,x1c,y1c) win32gui.LineTo(hdc,x2c,y2c) win32gui.ReleaseDC(hwnd,hdc) main() def draw_point(): print 'x,y,color?' s=raw_input() if match('\d+,\d+,\d+',s): x,y,color=s.split(',') x=int(x) y=int(y) color=int(color) hwnd=win32gui.WindowFromPoint((x,y)) hdc=win32gui.GetDC(hwnd) x1,y1=win32gui.ScreenToClient(hwnd,(x,y)) win32gui.SetPixel(hdc,x1,y1,color) win32gui.ReleaseDC(hwnd,hdc) main() def get_pixel_col(): print 'x,y?' s=raw_input() if match('\d+,\d+',s): x,y=s.split(',') x=int(x) y=int(y) hwnd=win32gui.WindowFromPoint((x,y)) hdc=win32gui.GetDC(hwnd) x1,y1=win32gui.ScreenToClient(hwnd,(x,y)) color=win32gui.GetPixel(hdc,x1,y1) win32gui.ReleaseDC(hwnd,hdc) print color main() def get_current_pos_info(): x,y=win32gui.GetCursorPos() hwnd=win32gui.WindowFromPoint((x,y)) hdc=win32gui.GetDC(hwnd) x1,y1=win32gui.ScreenToClient(hwnd,(x,y)) print x,y,win32gui.GetPixel(hdc,x1,y1) win32gui.ReleaseDC(hwnd,hdc) main() def main(): print ('''l. draw line p. draw point g. get pixel color c. get current mouse position's info''') s=raw_input() if s.lower()=='l': draw_line() if s.lower()=='p': draw_point() if s.lower()=='g': get_pixel_col() if s.lower()=='c': get_current_pos_info() main()
October 15, 2009
by Snippets Manager
· 5,972 Views
article thumbnail
Understanding the NHibernate Type System
This article is taken from NHibernate in Action from Manning Publications. This article delves into the NHibernate type system. For the table of contents, the Author Forum, and other resources, go to http://www.manning.com/kuate/. It is being reproduced here by permission from Manning Publications. Manning ebooks are sold exclusively through Manning. Visit the book's page for more information. Softbound print: February 2009 | 400 pages ISBN: 1932394923 Use code "dzone30" to get 30% off any version of this book. Entities are the coarse-grained classes in a system. You usually define the features of a system in terms of the entities involved: “the user places a bid for an item” is a typical feature definition that mentions three entities - user, bid and item. In contrast, value types are the much more fine grained classes in a system, such as strings, numbers, dates and monetary amounts. These fine grained classes can be used in many places and serve many purposes; the value type string can store email address, usernames and many other things. Strings are simple value types, but it is possible (but less common) to create value types that are more complex. For example, a value type could contain several fields, like an Address. So how do we differentiate between value types and entities? From a more formal standpoint, we an say an entity is any class whose instances have their own persistent identity, and a value type is a class who’s instances do not. The entity instances may therefore be in any of the three persistent lifecycle states: transient, detached, or persistent. However, we don’t consider these lifecycle states to apply to the simpler value type instances. Furthermore, because entities have their own lifecycle, the Save() and Delete() methods of the NHibernate ISession interface will apply to them, but never to value type instances. To illustrate, lets consider Figure A. Figure A – An order entity with TotalAmount value type TotalAmount is an instance of value type Money. Because value types are completely bound to that their owning entities, TotalAmount is only saved when the Order is saved. Associations and Value Types As we said, not all value types are simple. It’s possible for value types to also define associations. For example, our Money value type could have a property called Currency that is an association to a Currency entity as shown in figure 6.1.2 Figure B – The Money value type with association to a Currency entity. If your value types have associations, they must always point to entities. The reason is that, if those associations could point from entities to value types, a value type could potentially belong to several entities, which isn’t desirable. This is one of the great things about value types; if you update a value type instance, you know that it only affects the entity that owns it. For example, changing the TotalAmount of one Order simply cannot accidentally affect others. So far we’ve talked about value types and entities from an object oriented perspective. To build a more complete picture, we shall now take a look at how the relational model sees value types and entities, and how NHibernate bridges the gap. Bridging from objects to database You may be aware that a database architect would see the world of value types and entities slightly differently to this object oriented view of things. In the database, tables represent the entities, and columns represent the values. Even join tables and lookup tables are entities. So, if all tables represent entities in the database, does that mean we have to map all tables to entities in our .NET domain model? What about those value types we wanted in our model? NHibernate provides constructs for dealing with this. For example, a many-to-many association mapping hides the intermediate association table from the application, so we don’t end up with an unwanted entity in our domain model. Similarly, a collection of value typed strings behaves like a value type from the point of view of the .NET domain model even though it’s mapped to its own table in the database. These features have their uses and can often simplify your C# code. However, over time we have become suspicious of them; these “hidden” entities often end up needing exposure in our applications as business requirements evolve. The many-to-many association table, for example, often has additional columns added as the application matures, so the relationship itself becomes an entity. You might not go far wrong if you make every database-level entity be exposed to the application as an entity class. For example, we’d be inclined to model the many-to-many association as two one-to-many associations to an intervening entity class. We’ll leave the final decision to you, and return to the topic of many-to-many entity associations later in this chapter. Mapping types So far we’ve discussed the differences between value types and entities, as seen from the object oriented and relational database perspectives. We know that mapping entities is quite straight forward – entity classes are simply always mapped to database tables using , , and mapping elements. Value types need something more, which is where mapping types enter the picture. Consider this mapping of the CaveatEmptor User and email address: In ORM, you have to worry about both .NET types and SQL data types. In the example above imagine that the Email field is a .NET string, and EMAIL column is an SQL varchar. We want to tell NHibernate know how to carry out this conversion, which is where NHibernate mapping types come in. In this case, we’ve specified the mapping type "String", which we know is appropriate for this particular conversion. The String mapping type isn’t the only one built into NHibernate; NHibernate comes with various mapping types that define default persistence strategies for primitive .NET types and certain classes, such as like DateTime. Built-in mapping types NHibernate’s built-in mapping types usually reflect the name of the .NET type they map. Sometimes you’ll have a choice of mapping types available to map a particular .NET type to the database. However, the built-in mapping types aren’t designed to perform arbitrary conversions, such as mapping a VARCHAR field value to a .NET Int32 property value. If you want this kind of functionality, you will have to define your own custom value types. We will get to that topic a little later in this chapter. We’ll now discuss the basic types; date and time, objects, large objects, and various other built-in mapping types and show you what .NET and System.Data.DbType data types they handle. DbTypes are used to infer the data provider types (hence SQL data types). .NET primitive mapping types The basic mapping types in table A map .NET primitive types to appropriate DbTypes. Table A Primitive types Mapping Type .NET Type System.Data.DbType Int16 System.Int16 DbType.Int16 Int32 System.Int32 DbType.Int32 Int64 System.Int64 DbType.Int64 Single System.Single DbType.Single Double System.Double DbType.Double Decimal System.Decimal DbType.Decimal Byte System.Byte DbType.Byte Char System.Char DbType.StringFixedLength - 1 character AnsiChar System.Char DbType.AnsiStringFixedLength - 1 character Boolean System.Boolean DbType.Boolean Guid System.Guid DbType.Guid PersistentEnum System.Enum (an enumeration) The DbType for the underlying value TrueFalse System.Boolean DbType.AnsiStringFixedLength - either 'T' or 'F' YesNo System.Boolean DbType.AnsiStringFixedLength - either 'Y' or 'N' You’ve probably noticed that your database doesn’t support some of the DbTypes listed in table A. However, ADO.NET provides a partial abstraction of vendor-specific SQL data types, allowing NHibernate to work with ANSI-standard types when executing data manipulation language (DML). For database-specific DDL generation, NHibernate translates from the ANSI-standard type to an appropriate vendor-specific type, using the built-in support for specific SQL dialects. (You usually don’t have to worry about SQL data types if you’re using NHibernate for data access and data schema definition.) NHibernate supports a number of mapping types coming from Hibernate for compatibility (useful for those coming over from Hibernate or using Hibernate tools to generate hbm.xml files). Table B lists the additional names of NHibernate mapping types. Table B Additional names of NHibernate mapping types Mapping type Additional name Binary binary Boolean boolean Byte byte Character character CultureInfo locale DateTime datetime Decimal big_decimal Double double Guid guid Int16 short Int32 int Int32 integer Int64 long Single float String string TrueFalse true_false Type class YesNo yes_no From this table, you can see that writing type="integer" or type="int" is identical to type="Int32". Note that this table contains many mapping types that will be discussed in the following sections. Date/time mapping types Table C lists NHibernate types associated with dates, times, and timestamps. In your domain model, you may choose to represent date and time data using either System.DateTime or System.TimeSpan. As they have different purposes, the choice should be easy. Table C Date and time typesExcerptOpenSourceSOAch5-6.doc Mapping Type .NET Type System.Data.DbType DateTime System.DateTime DbType.DateTime - ignores the milliseconds Ticks System.DateTime DbType.Int64 TimeSpan System.TimeSpan DbType.Int64 Timestamp System.DateTime DbType.DateTime - as specific as database supports Object mapping types All .NET types in tables A and C are value types (i.e. derived from System.ValueType). This means that they can’t be null; unless you use the .NET 2.0 Nullable structure or the Nullables add-in, as discussed in the next section. Table D lists NHibernate types for handling .NET types derived from System.Object (which can store null values). Table D Nullable object typesExcerptOpenSourceSOAch5-6.doc Mapping Type .NET Type System.Data.DbType String System.String DbType.String AnsiString System.String DbType.AnsiString This table is completed by tables E and F which also contain nullable mapping types. Large object mapping types Table E lists NHibernate types for handling binary data and large objects. Note that none of these types may be used as the type of an identifier property. Table E Binary and large object typesExcerptOpenSourceSOAch5-6.doc Mapping Type .NET Type System.Data.DbType Binary System.Byte[] DbType.Binary BinaryBlob System.Byte[] DbType.Binary StringBlob System.String DbType.String Serializable Any System.Object marked with SerializableAttribute DbType.Binary BinaryBlob and StringClob are mainly supported by SQL Server. They can have a very large size and are fully loaded in memory. This can be a performance killer if used to store very large objects. So use this feature carefully. Note that you must set the NHibernate property "prepare_sql" to "true" to enable this feature. You can find up-to-date design patterns and tips for large object usage on the NHibernate website. Various CLR mapping types Table F lists NHibernate types for various other types of the CLR that may be represented as DbType.Strings in the database. Table F Other CLR-related typesExcerptOpenSourceSOAch5-6.doc Mapping Type .NET Type System.Data.DbType CultureInfo System.Globalization.CultureInfo DbType.String - 5 chars for culture Type System.Type DbType.String holding Assembly Qualified Name Certainly, isn’t the only NHibernate mapping element that has a type attribute. Using mapping types All of the basic mapping types may appear almost anywhere in the NHibernate mapping document, on normal property, identifier property, and other mapping elements. The , , , , , and elements all define an attribute named type. (There are certain limitations on which mapping basic types may function as an identifier or discriminator type, however.) You can see how useful the built-in mapping types are in this mapping for the BillingDetails class: ... The BillingDetails class is mapped as an entity. Its discriminator, id, and Number properties are value typed, and we use the built-in NHibernate mapping types to specify the conversion strategy. It’s often not necessary to explicitly specify a built-in mapping type in the XML mapping document. For instance, if you have a property of .NET type System.String, NHibernate will discover this using reflection and select String by default. We can easily simplify the previous mapping example: .... For each of the built-in mapping types, a constant is defined by the class NHibernate. NHibernateUtil. For example, NHibernate.String represents the String mapping type. These constants are useful for query parameter binding, as discussed in more detail in chapter 8: session.CreateQuery("from Item i where i.Description like :desc") .SetParameter("desc", desc, NHibernate.String) .List(); These constants are also useful for programmatic manipulation of the NHibernate mapping metamodel, as discussed in chapter 3. Of course, NHibernate isn’t limited to the built-in mapping types; you can create your own custom mapping types for handling certain scenarios. We’ll take a look this next, and explain how the mapping type system is a central to NHibernates flexibility. Creating custom mapping types Object-oriented languages like C# make it easy to define new types by writing new classes. Indeed, this is a fundamental part of the definition of object orientation. If you were limited to the predefined built-in NHibernate mapping types when declaring properties of persistent classes, you’d lose much of C#’s expressiveness. Furthermore, your domain model implementation would be tightly coupled to the physical data model, since new type conversions would be impossible. In order to avoid that, NHibernate provides a very powerful feature called custom mapping types. NHibernate provides two user-friendly interfaces that applications may use when defining new mapping types, the first being NHibernate.UserTypes.IUserType. IUserType is suitable for most simple cases and even for some more complex problems. Let’s use it in a simple scenario. Our Bid class defines an Amount property and our Item class defines an InitialPrice property, both monetary values. So far, we’ve only used a simple System.Double to represent the value, mapped with Double to a single DbType.Double column. Suppose we wanted to support multiple currencies in our auction application and that we had to refactor the existing domain model for this change. One way to implement this change would be to add new properties to Bid and Item: AmountCurrency and InitialPriceCurrency. We would then map these new properties to additional VARCHAR columns with the built-in String mapping type. Imagine if we had currency stored in 100 places, this would be lots of changes. We hope you never use this approach! Creating an implementation of IUserType Instead, we should create a MonetaryAmount class that encapsulates both currency and amount. This is a class of the domain model and doesn’t have any dependency on NHibernate interfaces: [Serializable] public class MonetaryAmount { private readonly double value; private readonly string currency; public MonetaryAmount(double value, string currency) { this.value = value; this.currency = currency; } public double Value { get { return value; } } public string Currency { get { return currency; } } public override bool Equals(object obj) { ... } public override int GetHashCode() { ... } } We’ve also made life simpler by making MonetaryAmount an immutable class, meaning it can’t be changed after it’s instantiated. We would have to implement Equals() and GetHashCode() to complete the class - but there is nothing special to consider here aside that they must be consistent, and GetHashCode() should return mostly unique numbers. We will use this new MonetaryAmount to replace the Double, as defined on the InitialPrice property for Item. We would benefit by using this new class in other places, such as the Bid.Amount. The next challenge is in mapping our new MonetaryAmount properties to the database. Suppose we’re working with a legacy database that contains all monetary amounts in USD. Our new class means our application code is no longer restricted to a single currency, but it will take time to get the changes done by the database team. Until this happens, we’d like to store just the Amount property of MonetaryAmount to the database. Because we can’t store the currency yet, we’ll convert all Amounts to USD before we save them, and from USD when we load them. The first step to handling this is to tell NHibernate how to handle our Monetarymount type. To do this, we create a MonetaryAmountUserType class that implements the NHibernate interface IUserType. Our custom mapping type is shown in listing A. Listing A Custom mapping type for monetary amounts in USD using System; using System.Data; using NHibernate.UserTypes; public class MonetaryAmountUserType : IUserType { private static readonly NHibernate.SqlTypes.SqlType[] SQL_TYPES = { NHibernateUtil.Double.SqlType }; public NHibernate.SqlTypes.SqlType[] SqlTypes { |1 get { return SQL_TYPES; } } public Type ReturnedType { get { return typeof(MonetaryAmount); } } |2 public new bool Equals( object x, object y ) { |3 if ( object.ReferenceEquals(x,y) ) return true; if (x == null || y == null) return false; return x.Equals(y); } public object DeepCopy(object value) { return value; } |4 public bool IsMutable { get { return false; } } |5 public object NullSafeGet(IDataReader dr, string[] names, object owner){ |6 object obj = NHibernateUtil.Double.NullSafeGet(dr, names[0]); if ( obj==null ) return null; double valueInUSD = (double) obj; return new MonetaryAmount(valueInUSD, "USD"); } public void NullSafeSet(IDbCommand cmd, object obj, int index) { |7 if (obj == null) { ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; } else { MonetaryAmount anyCurrency = (MonetaryAmount)obj; MonetaryAmount amountInUSD = MonetaryAmount.Convert( anyCurrency, "USD" ); ((IDataParameter)cmd.Parameters[index]).Value = amountInUSD.Value; } } public static MonetaryAmount Convert( MonetaryAmount m, string targetCurrency) { ... |8 } } The SqlTypes property tells NHibernate what SQL column types to use for DDL schema generation, as seen in #1. The types are subclasses of NHibernate.SqlTypes.SqlType. Notice that this property returns an array of types. An implementation of IUserType may map a single property to multiple columns, but our legacy data model only has a single Double. In #2, we can see that ReturnedType tells NHibernate what .NET type is mapped by this IUserType. The IUserType is responsible for dirty-checking property values (#3). The Equals() method compares the current property value to a previous snapshot and determines whether the property is dirty and must by saved to the database. The IUserType is also partially responsible for creating the snapshot in the first place, as shown in #4. Since MonetaryAmount is an immutable class, the DeepCopy() method returns its argument. In the case of a mutable type, it would need to return a copy of the argument to be used as the snapshot value. This method is also called when an instance of the type is written to or read from the second level cache. NHibernate can make some minor performance optimizations for immutable types. The IsMutable (#5) property tells NHibernate that this type is immutable. The NullSafeGet() method shown near #6 retrieves the property value from the ADO.NET IDataReader. You can also access the owner of the component if you need it for the conversion. All database values are in USD, so you have to convert the MonetaryAmount returned by this method before you show it to the user. In #7, the NullSafeSet() method writes the property value to the ADO.NET IDbCommand. This method takes whatever currency is set and converts it to a simple Double USD value before saving. Note that, for briefness, we haven’t provided a Convert function as shown in #8. If we were to implement it, it would have code that converts between various currencies. Mapping the InitialPrice property of Item can be done as follows: This is the simplest kind of transformation that an implementation of IUserType could perform. It takes a Value Type class and maps it to a single database column. Much more sophisticated things are possible; a custom mapping type could perform validation, it could read and write data to and from an Active Directory, or it could even retrieve persistent objects from a different NHibernate ISession for a different database. You’re limited mainly by your imagination and performance concerns! In a perfect world, we’d prefer to represent both the amount and currency of our monetary amounts in the database, so we’re not limited to storing just USD. We could still use an IUserType for this, but it’s limited; If an IUserType is mapped with more than one property, we can’t use them our HQL or Criteria queries. The NHibernate query engine wouldn’t know anything about the individual properties of MonetaryAmount. You still access the properties in your C# code (MonetaryAmount is just a regular class of the domain model, after all), but not in NHibernate queries. To allow for a custom value type with multiple properties that can be accessed in queries, we should use the ICompositeUserType interface. This interface exposes the properties of our MonetaryAmount to NHibernate. Creating an implementation of ICompositeUserType To demonstrate the flexibility of custom mapping types, we won’t have to change our MonetaryAmount domain model class at all—we change only the custom mapping type, as shown in listing B. Listing B Custom mapping type for monetary amounts in new database schemas using System; using System.Data; using NHibernate.UserTypes; public class MonetaryAmountCompositeUserType : ICompositeUserType { public Type ReturnedClass { get { return typeof(MonetaryAmount); } } public new bool Equals( object x, object y ) { if ( object.ReferenceEquals(x,y) ) return true; if (x == null || y == null) return false; return x.Equals(y); } public object DeepCopy(object value) { return value; } public bool IsMutable { get { return false; } } public object NullSafeGet(IDataReader dr, string[] names, NHibernate.Engine.ISessionImplementor session, object owner) { object obj0 = NHibernateUtil.Double.NullSafeGet(dr, names[0]); object obj1 = NHibernateUtil.String.NullSafeGet(dr, names[1]); if ( obj0==null || obj1==null ) return null; double value = (double) obj0; string currency = (string) obj1; return new MonetaryAmount(value, currency); } public void NullSafeSet(IDbCommand cmd, object obj, int index, NHibernate.Engine.ISessionImplementor session) { if (obj == null) { ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value; ((IDataParameter)cmd.Parameters[index+1]).Value = DBNull.Value; } else { MonetaryAmount amount = (MonetaryAmount)obj; ((IDataParameter)cmd.Parameters[index]).Value = amount.Value; ((IDataParameter)cmd.Parameters[index+1]).Value = amount.Currency; } } public string[] PropertyNames { |1 get { return new string[] { "Value", "Currency" }; } } public NHibernate.Type.IType[] PropertyTypes { |2 get { return new NHibernate.Type.IType[] { NHibernateUtil.Double, NHibernateUtil.String }; } } public object GetPropertyValue(object component, int property) { |3 MonetaryAmount amount = (MonetaryAmount) component; if (property == 0) return amount.Value; else return amount.Currency; } public void SetPropertyValue(object comp, int property, object value) { |4 throw new Exception("Immutable!"); } public object Assemble(object cached, |5 NHibernate.Engine.ISessionImplementor session, object owner) { return cached; } public object Disassemble(object value, |6 NHibernate.Engine.ISessionImplementor session) { return value; } } #1 shows how an implementation of ICompositeUserType has its own properties, defined by PropertyNames. Similarly, the properties each have their own type, as defined by PropertyTypes (#2). The GetPropertyValue() method, shown in #3, returns the value of an individual property of the MonetaryAmount. Since MonetaryAmount is immutable, we can’t set property values individually (see #4) This isn’t a problem because this method is optional anyway. In #5, the Assemble() method is called when an instance of the type is read from the second-level cache. The Disassemble() method is called when an instance of the type is written to the second-level cache, as shown in #6. The order of properties must be the same in the PropertyNames, PropertyTypes, and GetPropertyValues() methods. The InitialPrice property now maps to two columns, so we declare both in the mapping file. The first column stores the value; the second stores the currency of the MonetaryAmount. Note that the order of columns must match the order of properties in your type implementation: In a query, we can now refer to the Amount and Currency properties of the custom type, even though they don’t appear anywhere in the mapping document as individual properties: from Item i where i.InitialPrice.Value > 100.0 and i.InitialPrice.Currency = 'XAF' In this example we’ve expanded the buffer between the .NET object model and the SQL database schema with our custom composite type. Both representations can now handle changes more robustly. If implementing custom types seems complex, relax; you rarely need to use a custom mapping type. An alternative way to represent the MonetaryAmount class is to use a component mapping, as in section 4.4.2, “Using components.” The decision to use a custom mapping type is often a matter of taste. There are few more interfaces that can be used to implement custom types; they are introduced in the next section. Other interfaces to create custom mapping types You may find that the interfaces IUserType and ICompositeUserType do not allow you to easily add more features to your custom types. In this case, you will need to use some of the other interfaces which are in the NHibernate.UserTypes namespace: The IParameterizedType interface allows you to supply parameters to your custom type in the mapping file. This interface has a unique method: SetParameterValues(IDictionary parameters) that will be called at the initialization of your type. Here is an example of mapping providing a parameter: Euro This mapping tells the custom type to use Euro as currency if it isn’t specified. The IEnhancedUserType interface makes it possible to implement a custom type that can be marshalled to and from its string representation. This functionality allows this type to be used as identifier or discriminator type. To create a type that can be used as version, you must implement the IUserVersionType interface. The INullableUserType interface allows you to interpret non-null values in a property as null in the database. When using dynamic-insert or dynamic-update, fields identified as null will not be inserted or updated. This information may also be used when generating the where clause of the SQL command when optimistic locking is enabled. The last interface is different from the previous because it is meant to implement user defined collection types: IUserCollectionType. For more details, take a look at the implementation NHibernate.Test.UserCollection.MyListType in the source code of NHibernate. Now, let’s look at an extremely important application of custom mapping types. Nullable types are found in almost all enterprise applications. Using Nullable types With .NET 1.1, primitive types can not be null; but this is no longer the case in .NET 2.0. Let’s say that we want to add a DismissDate to the class User. As long as a user is active, its DismissDate should be null. But the System.DateTime struct can not be null. And we don’t want to use some "magic" value to represent the null state. With .NET 2.0 (and 3.5 of course), you can simply write: public class User { ... private DateTime? dismissDate; public DateTime? DismissDate { get { return dismissDate; } set { dismissDate = value; } } ... } We omit other properties and methods because we focus on the nullable property. And no change is required in the mapping. If you work with .NET 1.1, the Nullables add-in (in the NHibernateContrib package for versions prior to NHibernate 1.2.0) contains a number of custom mapping types which allow primitive types to be null. For our previous case, we can use the Nullables.NullableDateTime class: using Nullables; [Class] public class User { ... private NullableDateTime dismissDate; [Property] public NullableDateTime DismissDate { get { return dismissDate; } set { dismissDate = value; } } ... } The mapping is quite straightforward: ... It is important to note that, in the mapping, the type of DismissDate must be Nullables.NHibernate.NullableDateTimeType (from the file Nullables.NHibernate.dll). This type is a wrapper used to translate Nullables types from/to database types. But if when using the NHibernate.Mapping.Attributes library, this operation is automatic, that’s why we just had to put the attribute [Property]. The NullableDateTime type behaves exactly like System.DateTime; there are even implicit operators to easily interact with it. The Nullables library contains nullable types for most .NET primitive types supported by NHibernate. You can find more details in NHibernate documentation. Using enumerated types An enumeration (enum) is a special form of value type, which inherits from System.Enum and supplies alternate names for the values of an underlying primitive type. For example, the Comment class defines a Rating. If you recall, in our CaveatEmptor application, users are able to give other comments about other users. Instead of using a simple int property for the rating, we create an enumeration: public enum Rating { Excellent, Ok, Low } We then use this type for the Rating property of our Comment class. In the database, ratings would be represented as the type of the underlying value. In this case (and by default), it is Int32. And that’s all we have to do. We may specify type="Rating" in our mapping, but it is optional; NHibernate can use reflection to find this. One problem you might run into is using enumerations in NHibernate queries. Consider the following query in HQL that retrieves all comments rated “Low”: IQuery q = session.CreateQuery("from Comment c where c.Rating = Rating.Low"); This query doesn’t work, because NHibernate doesn’t know what to do with Rating.Low and will try to use it as a literal. We have to use a bind parameter and set the rating value for the comparison dynamically (which is what we need for other reasons most of the time): IQuery q = session.CreateQuery("from Comment c where c.Rating = :rating"); q.SetParameter("rating", Rating.Low, NHibernateUtil.Enum(typeof(Rating)); The last line in this example uses the static helper method NHibernateUtil.Enum() to define the NHibernate Type, a simple way to tell NHibernate about our enumeration mapping and how to deal with the Rating.Low value. We’ve now discussed all kinds of NHibernate mapping types: built-in mapping types, user-defined custom types, and even components. They’re all considered value types, because they map objects of value type (not entities) to the database. With a good understanding of what value types are, and how they are mapped, you can now move on to the more complex issue of collections of value typed instances.
October 8, 2009
by Alvin Ashcraft
· 69,175 Views · 1 Like
article thumbnail
Creating a Custom JSF 1.2 Component - With Facets, Resource Handling, Events and Listeners
I occasionally create custom JavaServer Faces components. Just enough to sort of remember what the steps are, but not nearly frequently enough to quickly put a new component together. This article demonstrates the quick step approach to creating a new custom component in the old fashioned way (that means: it is not a Facelets template based or an ADF Faces 11g Declarative Component). Its primary purpose is to help me quickly retrace my steps. But perhaps it will benefit some of you as well. The Shuffler component I will develop supports facets. It will render its facet children - one after the other. Which one is rendered first can be indicated through an attribute facetOrder (values normal, reverse and random), which is EL enabled. A shuffler-method-expression can optionally be set to provide the Shuffler with a shuffle-order-processor: the method is invoked with the list of facets to shuffle and will return it in the order in which to render the children. The component can render with a shuffle icon that when pressed causes the children to be shuffled. The Shuffler component allows registration of Shuffle Event Listeners, custom listeners that are informed whenever the shuffle event occurs. An example of how the Shuffler can be used inside a JSF page: Some elements of custom JSF components that are explicitly discussed in this article: dynamic attributes of type ValueExpression (EL enabled) attributes of type MethodExpression (also EL enabled) facets (custom) events and listeners Bare essentials for custom JSF components A custom JSF component is represented by a Java Class - one that extends from UIComponentBase. An instance of this class is created whenever a new page is rendered that contains the component (and for each occurrence of the component in the page, a new instance of the class is created). The component class holds the attributes that are set by the page developer and that determine the behavior and appearance of the component. The component class has the internal logic of the component and it deals for example with events and listeners. This class may also render the markup (HTML) for the component - though it is a better practice to leave the actual rendering to a Renderer class. public class Shuffler extends UIComponentBase { ... } Most custom JSF component will also have an associated Renderer class, that extends from Renderer. Note that some components will not actually be rendered (such as Listeners, Iterators or Parameters) and therefore will not have a Renderer class. The Renderer is not only responsible for rendering the HTML, it will also inspect (decode) the incoming request from the browser to see whether the request parameter map contains values that are of interest to the component - that indicate for example that a value has been entered or set on the component(’s representation in the browser) or an action has been executed against it. Note that one JSF component may have multiple Renderers, for example for different channels and protocols (to render a representation of the component in plain XML, in WML, in JavaFX or XUL) or for different user agents (Firefox, Internet Explorer) or themes (professional user, internet surfer). public class ShufflerRenderer extends SuperRenderer { ... } JavaServer Faces pages can be created in various ways - including programmatically, using Facelets and using JSP pages. The latter option, through JSP, is still the most common one, though that is about to change with JSF 2.0 favoring Facelets. Page developers using JSPs will describe the JSF component tree that will need to be instantiated in memory for rendering a certain View using a plain JSP page. The tags in the JSP page are normal JSP tags - described by TLD (tag library descriptors) - corresponding to JSF components and therefore JSF component classes. Every JSF component that needs to be used in JSPs has to have a corresponding JSP tag-class, one that will typically extend from UIComponentELTag (or just from TagSupport when no JSF component is added to the component tree for a certain tag, for example when that tag represents a listener or parameter). The Tag Class specifies which JSF Component it represents. It also indicates which Renderer should be used to render the component. This means that one component can have multiple JSP tags associated with it, each providing a different way of rendering the component. Note: the renderer can also be specified dynamically - taking user preferences or characteristics into account public class ShufflerTag extends UIComponentELTag { public static final String COMPONENT_TYPE = "nl.amis.jsf.UIShuffler"; public static final String RENDERER_TYPE = "nl.amis.jsf.ShufflerRenderer"; public String getComponentType() { return COMPONENT_TYPE; } public String getRendererType() { return RENDERER_TYPE; } ... } Tags representing JSF components need to be described in TLD files (Tag Library Descriptors) just like any other JSP tag.The entry in the TLD defines the tag label to use in the page, whether the tag can contain child-tags, some descriptive meta data and every attribute that can be configured in the tag. For each attribute the TLD-entry specifies the type, whether it is required and if the attribute can contain an EL expression passing in a value or an EL expression passing in a method; in the latter case, the entry also prescribes the signature of the method: ShufflerLib 1.0 ShufflerLib /nl.amis,jsf/ShufflerLib Writes a DIV element that contains the facets in a specific order. shuffler nl.amis.jsf.shuffler.ShufflerTag JSP id false true rendered false boolean binding false javax.faces.component.UIComponent styleClass false java.lang.String .... JSF components need to be registered in a special faces-config.xml file (special in the sense that it is not the faces-config.xml that drives a web application but rather one that acts like a repository of components and their renderers. Note however that all entries in this special faces-config.xml is merged together with the ‘normal’ faces-config.xml. That means in turn that while the special file is primarily seen as the registry of components, it can also configure PhaseListeners, Navigation Rules (hard to see the value in that) and Managed Beans (which can be very useful). The component registration in faces-config.xml consists of a component type that is associated with a the component class. nl.amis.jsf.UIShuffler nl.amis.jsf.shuffler.Shuffler Renderers can also be registered in this file. A renderer entry registers a renderer-type (corresponding to the value returned by the getRendererType() method in the tag class) associated with the RendererClass. Based on the value (rendererType) returned by the tag class, the correct class to instantiate can be determined from this entry: nl.amis.Shuffler nl.amis.jsf.ShufflerRenderer nl.amis.jsf.shuffler.ShufflerRenderer Implementing the Classes: Component, Renderer and TagHandler The TagHandler ShufflerTag is the intermediary between the world of JSP pages (and the Servlet/JSP engine that translates the JSP file into a servlet class) and the JSF realm. Every tag in the JSP page needs to be turned into its corresponding JSF representation. The tag handler needs to override the setProperties() method inherited from the UIComponentELTag class; this method takes all the values set on the tag attributes in the page and passes them onwards to the Component. In our initial case, the tag is used in JSPs like this: ... other content The styleClass attribute is the only one we defined - id and rendered are defined on every JSP-tag based on JSF’s UIComponentELTag. Thye styleClass attribute is also the only attribute we need to take responsibility for in the tag class, by providing a setter method that sets a private member and by passing the value of that private member to the component in the setProperties() method. The code for the ShufflerTag class now becomes: package nl.amis.jsf.shuffler; import javax.el.ValueExpression; import javax.faces.component.UIComponent; import javax.faces.webapp.UIComponentELTag; public class ShufflerTag extends UIComponentELTag { public static final String COMPONENT_TYPE = "nl.amis.jsf.UIShuffler"; public static final String RENDERER_TYPE = "nl.amis.jsf.ShufflerRenderer"; private ValueExpression styleClass; public String getComponentType() { return COMPONENT_TYPE; } public String getRendererType() { return RENDERER_TYPE; } protected void setProperties(UIComponent component) { super.setProperties(component); processProperty(component, styleClass, Shuffler.STYLECLASS_ATTRIBUTE_KEY); } public void release() { super.release(); styleClass= null; } protected final void processProperty(final UIComponent component, final ValueExpression property, final String propertyName) { if (property != null) { if(property.isLiteralText()) { component.getAttributes().put(propertyName, property.getExpressionString()); } else { component.setValueExpression(propertyName, property); } } } public void setStyleClass(ValueExpression styleClass) { this.styleClass = styleClass; } } We cater for the fact that styleClass can contain a ValueExpression - as all attributes can, starting from JSF 1.2. In the method processProperty we check whether the string passed for styleClass is a literal string or should be considered an EL expression. In the latter case, we pass a ValueExpression to the component, otherwise a ‘normal’ attribute. Also note that the super class takes care of the attributes id, rendered and binding. However, we do have to specify them in the tag-library. The component class in our case leads a pretty comfortable life: the tag handler informs him of all the attribute values and the actual rendering is left to a special Renderer class. The component is a pretty passive element in this simple example: package nl.amis.jsf.shuffler; import javax.faces.component.UIComponentBase; import javax.faces.context.FacesContext; public class Shuffler extends UIComponentBase { public static final String FAMILY = "nl.amis.Shuffler"; public static final String STYLECLASS_ATTRIBUTE_KEY = "styleClass"; public String getFamily() { return FAMILY; } @Override public Object saveState(FacesContext facesContext) { Object values[] = new Object[2]; values[0] = super.saveState(facesContext); values[1] = this.getAttributes().get(STYLECLASS_ATTRIBUTE_KEY); return values; } @Override public void restoreState(FacesContext facesContext, Object state) { Object values[] = (Object[])state; super.restoreState(facesContext, values[0]); this.getAttributes().put(STYLECLASS_ATTRIBUTE_KEY, values[1]); } } The only really useful thing the component does is implementing the saveState and restoreState methods. These methods play an important part in turning the state of the component into a serializable object array and restoring that state of the component in the RestoreView phase, based on the serialized array. The Tag Handler specifies in its getRendererType() method that the renderer to use for this component when using the shuffler tag, is one called nl.amis.jsf.ShufflerRenderer. In the faces-config.xml file, we have indicated that this renderer type is associated with the class nl.amis.jsf.shuffler.ShufflerRenderer that extends Renderer. The renderers in JSF can override methods like encodeBegin(), encodeEnd(), encodeChildren() and decode() - the latter only when we have to process the incoming request, looking for new values set on or events that occurred on the component. In our case, we initially will simply have the ShufflerRenderer render a DIV element with a class attribute (based on the styleClass attribute). The DIV will allow the children of the Shuffler component to render - by not overriding the encodeChildren() method. package nl.amis.jsf.shuffler; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.Renderer; public class ShufflerRenderer extends Renderer { @Override public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException { super.encodeBegin(facesContext, component); final ResponseWriter writer = facesContext.getResponseWriter(); writer.startElement("DIV", component); String styleClass = (String)attributes.get(Shuffler.STYLECLASS_ATTRIBUTE_KEY); writer.writeAttribute("class", styleClass, null); } @Override public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException { final ResponseWriter writer = facesContext.getResponseWriter(); writer.endElement("DIV"); } } Next steps - working with facets The Shuffler component is created to dynamically (re)order its child contents. It will do so using facets. The content you want this component to shuffle is passed in two or more facets. The facets are named using string representations of integers, so for example: ... content ... content ... content Facets are automatically supported on JSF components. The getFacets() method is available inside the Shuffler component class and will return a collection of facet UIComponents. Facets are special children for a JSF component: the framework will never render the contents of facets on its own. It is up to the component to determine when and how to render the contents of its facets. So, there is some work to do for the ShuffleRenderer class. But first we need to add support for the new facetOrder attribute. Adding an attribute means: adding an attribute entry in the TLD adding support for processing the attribute in the Tag Handler (a setter and a line of code in setProperties()) adding the attribute in saveState() and restoreState() in the Component class Here we go: In the tld entry, add: facetOrder false java.lang.String In the tag-handler class ShufflerTag add: private ValueExpression facetOrder; public void setFacetOrder(ValueExpression facetOrder) { this.facetOrder = facetOrder; } and in setProperties(): processProperty(component, facetOrder, Shuffler.FACETORDER_ATTRIBUTE_KEY); Finally in the component class Shuffler , add: public static final String FACETORDER_ATTRIBUTE_KEY = "facetOrder"; @Override public Object saveState(FacesContext facesContext) { Object values[] = new Object[3]; values[0] = super.saveState(facesContext); values[1] = this.getAttributes().get(STYLECLASS_ATTRIBUTE_KEY); values[2] = this.getAttributes().get(FACETORDER_ATTRIBUTE_KEY); return values; } @Override public void restoreState(FacesContext facesContext, Object state) { Object values[] = (Object[])state; super.restoreState(facesContext, values[0]); this.getAttributes().put(STYLECLASS_ATTRIBUTE_KEY, values[1]); this.getAttributes().put(FACETORDER_ATTRIBUTE_KEY, values[2]); } The Shuffler also needs to make the facets available to the renderer, in the order that is prescribed by the facetOrder attribute. This attribute supports three values: normal, reverse and random. public List getOrderedFacets(FacesContext facesContext) { // allowable values: normal (default) and reverse // the normal order of the facets is determined by ordering the facets by name (assuming the facetnames are string representations of integers) // create a sorted list with the integers representing the facets List facetIndexValues = new ArrayList(); List facetNames = new ArrayList(getFacets().keySet()); for (String facetName : facetNames) { facetIndexValues.add(new Integer(facetName)); } Collections.sort(facetIndexValues); // create the list of facets corrresponding to the sorted list of facet index values List orderedFacets = new ArrayList(); for (Integer index : facetIndexValues) { orderedFacets.add(getFacets().get(index.toString())); } // depending on the value for the facetOrder attribute, we may need to reorganize the orderedFacets list String facetOrder = (String)this.getAttributes().get(Shuffler.FACETORDER_ATTRIBUTE_KEY); if ("reverse".equalsIgnoreCase(facetOrder)) { Collections.reverse(orderedFacets); } else if ("random".equalsIgnoreCase(facetOrder)) { Collections.shuffle(orderedFacets); } else if ("normal".equalsIgnoreCase(facetOrder)) { // need to do nothing as with normal the order returned by getFacets() is the correct one } return orderedFacets; } The ShufflerRenderer will have to do the real work. It will retrieve the facets - in the proper order - from the Shuffler Component class and ask JSF to render them. package nl.amis.jsf.shuffler; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.Renderer; import javax.faces.component.UIComponent; public class ShufflerRenderer extends Renderer { @Override public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException { super.encodeBegin(facesContext, component); final ResponseWriter writer = facesContext.getResponseWriter(); writer.startElement("DIV", component); String styleClass = (String)attributes.get(Shuffler.STYLECLASS_ATTRIBUTE_KEY); writer.writeAttribute("class", styleClass, null); List orderedFacets = ((Shuffler)component).getOrderedFacets(facesContext); for (UIComponent facet:orderedFacets) { facet.encodeAll(facesContext); } } @Override public void encodeEnd(final FacesContext facesContext, final UIComponent component) throws IOException { final ResponseWriter writer = facesContext.getResponseWriter(); writer.endElement("DIV"); } } With these changes, we can now add real content to the Shuffler and have it rendered, in the order we specified - which can be random. Also note that we can use an EL expression to have the facetOrder dynamically derived: facetOrder="#{bean.liveFacetOrder}" id="s1" > ... content ... content ... content Downloading Resources The next step in our exploration of the development of custom JSF components is the addition of resources like images and JavaScript libraries. Note that in JavaServer Faces 2.0 a new facility is available, especially for this purpose. However, in our 1.2 setting we have to come up with something ourselves. That is not to say no solutions exist for JSF 1.2; almost every library comes with a form of resource handling. Then there is the Weblet framework that was introduced especially for this purpose. Another option leverages JSF itself: its capability through PhaseListeners to intercept a request, interpret the requested ViewId and optionally serve up an image or JS file in response to the request. This approach is proposed in JavaServer Faces, The Complete Reference by Ed Burns and Chris Schalk. I have slightly modified there code for my own purposes. However, the central idea clearly is theirs. My objective is to add an image to the Shuffler component. The next step will be to allow the user to click on the image and by doing so tgrigger a re-shuffle. But that part is for later, first add the image itself. The HTML rendered by the ShufflerRenderer needs to be extended with the IMG tag, that is easy enough. Less trivial is the value for the SRC attribute on the IMG tag. The change in the encodeBegin method in the ShufflerRenderer: writer.startElement("IMG", component); writer.writeAttribute("src", imageUrl( facesContext,SHUFFLE_IMAGE), null); writer.writeAttribute("alt", "Click to reshuffle", null); writer.writeAttribute("width", "20px", null); writer.endElement("IMG"); With SHUFFLE_IMAGE specified as: private static String SHUFFLE_IMAGE = "shuffleIcon.png"; The imageUrl() method is defined as follows private final static String IMAGE_PATH ="/faces/images/"; protected String imageUrl(FacesContext facesContext, String image) { ViewHandler handler = facesContext.getApplication().getViewHandler(); String imageUrl = handler.getResourceURL(facesContext, IMAGE_PATH + image); return imageUrl; } The URLs for images are now constructed to look like this: http://somehost:7101/CustomJSFConsumer/faces/images/shuffleIcon.png The request for the shuffleIcon.png that is sent by the browser should be intercepted by a component that knows how to handle it. Because of the /faces/ part, this request is sent to the FacesServlet and processed through the JSF lifecycle. The componoent to intercept it will be a phaseListener that fires after restore view. It inspects the ViewId. When the ViewId contains the predefined indicator ("/images/") it steps in and takes over processing of the request. It will find the name of the image that is requested by taking the part of the ViewId that comes after /images/. It will then locate the image file on the classpath (that works well for a component packaged in a jar file, it can have the images packaged in the jar file too), looking for a directory called /images/ - as specified by the IMAGE_PATH constant. It copies the image from the file to the outputstream after setting the content type. package nl.amis.jsf; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletResponse; public class ResourceServerPhaseListener implements PhaseListener { public ResourceServerPhaseListener() { super(); } public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } public void afterPhase(PhaseEvent event) { // If this is restoreView phase if (PhaseId.RESTORE_VIEW == event.getPhaseId()) { if (-1 != event.getFacesContext().getViewRoot().getViewId().indexOf(RENDER_IMAGE_TAG)) { // extract the name of the image resource from the ViewId String image = event.getFacesContext().getViewRoot().getViewId().substring(event.getFacesContext() .getViewRoot().getViewId().indexOf(RENDER_IMAGE_TAG) + RENDER_IMAGE_TAG.length()); // render the script writeImage(event, image); event.getFacesContext().responseComplete(); } } } public void beforePhase(PhaseEvent event) { } public static final String RENDER_IMAGE_TAG = "/images/"; public static final String IMAGE_PATH = "/images/"; private void writeImage(PhaseEvent event, String resourceName) { URL url = getClass().getResource(IMAGE_PATH + resourceName); URLConnection conn = null; InputStream stream = null; HttpServletResponse response = (HttpServletResponse)event.getFacesContext().getExternalContext().getResponse(); try { conn = url.openConnection(); conn.setUseCaches(false); stream = conn.getInputStream(); ServletContext servletContext = (ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext(); String mimeType = servletContext.getMimeType(resourceName); response.setContentType(mimeType); response.setStatus(200); // Copy the contents of the file to the output stream byte[] buf = new byte[1024]; int count = 0; while ((count = stream.read(buf)) >= 0) { response.getOutputStream().write(buf, 0, count); } response.getOutputStream().close(); } catch (Exception e) { String message = null; message = "Can't load image file:" + url.toExternalForm(); try { response.sendError(HttpServletResponse.SC_BAD_REQUEST, message); } catch (IOException f) { f.printStackTrace(); } } } } PhaseListeners need to be configured in order to be active. This configuration usually is done in the faces-config.xml of the application. Fortunately, we can also configure the PhaseListener in the faces-config.xml file that we create for the custom component. This faces-config.xml is part of the jar file in which the custom component is shipped and deployed. Its contents are merged with the application’s own faces-config.xml. The registration of our PhaseListener looks like this: nl.amis.jsf.ResourceServerPhaseListener ... Triggering events on the custom component Time to take another big step. We will support clicking the image by the end user and turn that event into a reshuffle of the facets of the Shuffler component. In the next section we will not only act on that click ourselves, but also publish an event that others can listen to. We will have to add a JavaScript event listener in the HTML rendered for the Shuffler. This client side code is triggered when the image is clicked. It will submit the form - after it has added an input element to the DOM and set a value on it. Note: this approach to have a custom component trigger an event that can be received by the server side renderer class has been described in Pro JSF and Ajax: Building Rich Internet Components - by John R. Fallows and Jonas Jacobi, the guys who first introduced me to JavaServer Faces. The JavaScript for the Shuffler component looks like this: /** * The onclick handler for ShufflerRenderer. * * @param formClientId the clientId of the enclosing UIForm component * @param clientId the clientId of the Shuffler component */ function _shuffle_click( formClientId, clientId) { var form = document.forms[formClientId]; var input = form[clientId]; if (!input) // if the input element does not already exist, create it and add it to the form { input = document.createElement("input"); input.type = 'hidden'; input.name = clientId; form.appendChild(input); } input.value = 'clicked'; form.submit(); } The JavaScript is not be directly included in the page - as it is part of the jar file in which the Shuffler component is shipped. We need a way to attach this JavaScript (it is in a file called shuffle.js) to the page from within the custom component, or in this case rather its Renderer class. We extend the ResourceServerPhaseListener to also handle JavaScript resources, just like it can handle images. public class ResourceServerPhaseListener implements PhaseListener { public static final String RENDER_SCRIPT_TAG = "/js/"; public static final String RENDER_IMAGE_TAG = "/images/"; public static final String SCRIPT_PATH = "/js/"; public static final String IMAGE_PATH = "/images/"; public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } public void afterPhase(PhaseEvent event) { // If this is restoreView phase if (PhaseId.RESTORE_VIEW == event.getPhaseId()) { // if the request is for a JavaScript library if (-1 != event.getFacesContext().getViewRoot().getViewId().indexOf(RENDER_SCRIPT_TAG)) { // extract the name of the script from the ViewId String script = event.getFacesContext().getViewRoot().getViewId().substring(event.getFacesContext() .getViewRoot().getViewId().indexOf(RENDER_SCRIPT_TAG) + RENDER_SCRIPT_TAG.length()); // render the script writeScript(event, script); event.getFacesContext().responseComplete(); } ... image handling, same as before } } public void beforePhase(PhaseEvent event) { } private void writeScript(PhaseEvent event, String resourceName) { URL url = getClass().getResource(SCRIPT_PATH + resourceName); URLConnection conn = null; InputStream stream = null; BufferedReader bufReader = null; HttpServletResponse response = (HttpServletResponse)event.getFacesContext().getExternalContext().getResponse(); OutputStreamWriter outWriter = null; String curLine = null; try { outWriter = new OutputStreamWriter(response.getOutputStream(), response.getCharacterEncoding()); conn = url.openConnection(); conn.setUseCaches(false); stream = conn.getInputStream(); bufReader = new BufferedReader(new InputStreamReader(stream)); response.setContentType("text/javascript"); response.setStatus(200); while (null != (curLine = bufReader.readLine())) { outWriter.write(curLine + "\n"); } outWriter.close(); } catch (Exception e) { String message = null; message = "Can't load script file:" + url.toExternalForm(); try { response.sendError(HttpServletResponse.SC_BAD_REQUEST, message); } catch (IOException f) { f.printStackTrace(); } } } private void writeImage(PhaseEvent event, String resourceName) { ... same as before } } The Renderer class is responsible for rendering the markup that will include the JavaScript resources to the page (the script element). We could have multiple occurrences of our custom component in a page. However, the JavaScript file shuffle.js should be loaded only once, to prevent excessive and completely pointless browser requests. In order to make that happen, the Renderer indicates to a method writeScriptResource that it has a JavaScript resource that should be included. This method verifies whether a script tag for downloading that same resource has already been added in the current request. If so, it will not add another script tag. If not [already included] then the tag is added with its src attribute referring to the proper PhaseListener controlled url: protected void writeScriptResource( FacesContext context, String resourcePath) throws IOException { Set scriptResources = _getScriptResourcesAlreadyWritten(context); // Set.add() returns true only if item was added to the set // and returns false if item was already present in the set if (scriptResources.add(resourcePath)) { ViewHandler handler = context.getApplication().getViewHandler(); String resourceURL = handler.getResourceURL(context, SCRIPT_PATH +resourcePath); ResponseWriter out = context.getResponseWriter(); out.startElement("script", null); out.writeAttribute("type", "text/javascript", null); out.writeAttribute("src", resourceURL, null); out.endElement("script"); } } private Set _getScriptResourcesAlreadyWritten( FacesContext context) { ExternalContext external = context.getExternalContext(); Map requestScope = external.getRequestMap(); Set written = (Set)requestScope.get(_SCRIPT_RESOURCES_KEY); if (written == null) { written = new HashSet(); requestScope.put(_SCRIPT_RESOURCES_KEY, written); } return written; } static private final String _SCRIPT_RESOURCES_KEY = ShufflerRenderer.class.getName() + ".SCRIPTS_WRITTEN"; With these helper methods in place, the ShufflerRenderer can be extended to include the client side click handling code: @Override public void encodeBegin(final FacesContext facesContext, final UIComponent component) throws IOException { super.encodeBegin(facesContext, component); final Map attributes = component.getAttributes(); final ResponseWriter writer = facesContext.getResponseWriter(); String formClientId = _findFormClientId(facesContext, component); String shuffleClientId = component.getClientId(facesContext); writeScriptResource(context, "shuffle.js"); writer.startElement("DIV", component); String styleClass = (String)attributes.get(Shuffler.STYLECLASS_ATTRIBUTE_KEY); writer.writeAttribute("class", styleClass, null); writer.startElement("SPAN", component); writer.writeAttribute("onClick", "_shuffle_click('" + formClientId + "'," + "'" + shuffleClientId + "')", null); writer.startElement("IMG", component); writer.writeAttribute("src", imageUrl( facesContext,SHUFFLE_IMAGE), null); writer.writeAttribute("alt", "Click to reshuffle", null); writer.writeAttribute("width", "20px", null); writer.endElement("IMG"); writer.endElement("SPAN"); List orderedFacets = ((Shuffler)component).getOrderedFacets(facesContext); for (UIComponent facet:orderedFacets) { facet.encodeAll(facesContext); } } protected void encodeResources(FacesContext context, UIComponent component) throws IOException { writeScriptResource(context, "shuffle.js"); } /** * Finds the parent UIForm component client identifier. * * @param context the Faces context * @param component the Faces component * * @return the parent UIForm or RichForm (for usage in ADF) client identifier, if present, otherwise null */ private String _findFormClientId(FacesContext context, UIComponent component) { if (component==null) { return null; } if (component instanceof UIForm || component.getClass().getName().endsWith("RichForm")) { return component.getClientId(context); } else { return _findFormClientId(context, component.getParent()); } } The image is wrapped in a SPAN and the onclick event handler is defined on that SPAN element (this allows us to later on add more clickable stuff to the SPAN). When the image is clicked, the _shuffle_click function is invoked - that was loaded from shuffle.js. The element is added to the form and the form is submitted. The HTML rendered from this renderer now looks like this:
October 7, 2009
by Wouter Van Reeven
· 45,517 Views
article thumbnail
Multithreading and the Java Memory Model
At the New England Software Symposium, I attended Brian Goetz's session called "The Java Memory Model". When I saw the phrase "memory model" in the title I thought it would be about garbage collection, memory allocation and memory types. Instead, it is really about multithreading. The difference is that this presentation focuses on visibility, not locking or atomicity. This is my attempt to summarize his talk. The importance of visibility Visibility here refers to the memory that an executing thread can see once it is written. The big gotcha is that when thread A writes something before thread B reads it, it does not mean thread B will read the correct value. You could ensure that threads A and B are ordered with locking but you can still be in deep doo doo because the memory is not written and read in order, or is read in a partially written state. A big part of this peril comes from the layered memory architecture of modern hardware: multi-CPU, multi-core CPUs, multi-level caches on and off chip etc. Instructions could be executed in parallel or out of order. The memory being written may not even be in RAM at all: it could be on a remote core's register. But the danger could also come from old-fashioned compiler optimizations. One of Brian's examples is the following loop which depends on another thread to set the boolean field asleep: while (!asleep) ++sheep; The compiler may notice that asleep is loop-invariant and optimize its evaluation out of the loop if (!asleep) while (true) ++sleep; The result is an infinite loop. The fix in this case is to use a volatile variable. The Java Memory Model A memory model describes when one thread's actions are guaranteed to be visible to another. The Java memory model (JMM) is quite an achievement: previously, memory models were specific to each processor architecture. A cross-platform memory model takes portability well beyond being able to compile the same source code: you really can run it anywhere. It took until Java 5 (JSR 133) to get the JMM right. The JMM defines a partial ordering on program actions (read/write, lock/unlock, start/join threads) called happens-before. Basically, if action X happens-before Y, then X's results are visible to Y. Within a thread, the order is basically the program order. It's straightforward. But between threads, if you don't use synchronized or volatile, there are no visibility guarantees. As far as visible results go, there is no guarantee that thread A will see them in the order that thread B executes them. Brian even invoked special relativity to describe the disorienting effects of relative views of reality. You need synchronization to get inter-thread visibility guarantees. The basic tools of thread synchronization are: The synchronized keyword: an unlock happens-before every subsequent lock on the same monitor. The volatile keyword: a write to a volatile variable happens-before subsequent reads of that variable. Static initialization: done by the class loader, so the JVM guarantees thread safety In addition to the above, the JMM offers a guarantee of initialization safety for immutable objects. The Rules Here are points that Brian emphasized: If you read or write a field that is read/written by another thread, you must synchronize. This must be done by both the reading and writing threads, and on the same lock. Don't try to reason about ordering in undersynchronized programs. Avoiding synchronization can cause subtle bugs that only blow up in production. Do it right first, then make it fast. Case study: double-checked locking One example of synchronization avoidance gone bad is the popular double-checked locking idiom for lazy initialization, which we now know is broken: private Thing instance = null; public Thing getInstance() { if (instance == null) { synchronized (this) { if (instance == null) instance = new Thing(); } } return instance; } This idiom can result in a partially constructed Thing object, because it only worries about atomicity at the expense of visibility. There are ways to fix this, of course, such as using a volatile field or switching to using static initializers. But it's easy to get it wrong, so Brian questions why we would want to do something like this in the first place. The main motivation was to avoid synchronization in the common case. While it used to be expensive in the past, uncontended synchronization is much cheaper now. There is still a lot of advice to avoid supposedly expensive Java operations out there, but the JVM has improved tremendously and a lot of old performance tips (like object pooling) just don't make sense anymore. Beware of reading years-old advice when you Google for Java tips. Remember Brian's advice above against premature optimization. That said, he also showed a couple of better alternatives for lazy initialization. Some thoughts This talk was a reminder to me that low-level multithreading is hard. It's hard enough that it took years to get the JMM right. It's hard enough that a university professor would say "don't do it". And if you faithfully follow Brian's rules and use synchronization primitives everywhere, you might find yourself vulnerable to thread deadlocks (hmmm ... why does JConsole have a deadlock detection function?). The primary danger in multithreading is in shared, mutable state. Without shared mutable data, threads might as well be separate processes, and the danger evaporates. So while it's wonderful what JMM has done for cross-platform visibility guarantees, I think we would do ourselves a favor if we tried to minimize shared mutable data. There are often higher level alternatives. For example, Scala's Actor construct relies on passing immutable messages instead of sharing memory. From http://chriswongdevblog.blogspot.com/
October 5, 2009
by Christopher Wong
· 47,161 Views
article thumbnail
Sorting Collections in Hibernate Using SQL in @OrderBy
When you have collections of associated objects in domain objects, you generally want to specify some kind of default sort order. For example, suppose I have domain objects Timeline and Event: @Entity class Timeline { @Required String description @OneToMany(mappedBy = "timeline") @javax.persistence.OrderBy("startYear, endYear") Set events } @Entity class Event { @Required Integer startYear Integer endYear @Required String description @ManyToOne Timeline timeline } In the above example I've used the standard JPA (Java Persistence API) @OrderBy annotation which allows you to specify the order of a collection of objects via object properties, in this example a @OneToMany association . I'm ordering first by startYear in ascending order and then by endYear, also in ascending order. This is all well and good, but note that I've specified that only the start year is required. (The @Required annotation is a custom Hibernate Validator annotation which does exactly what you would expect.) How are the events ordered when you have several events that start in the same year but some of them have no end year? The answer is that it depends on how your database sorts null values by default. Under Oracle 10g nulls will come last. For example if two events both start in 2001 and one of them has no end year, here is how they are ordered: 2001 2002 Some event 2001 2003 Other event 2001 Event with no end year What if you want to control how null values are ordered so they come first rather than last? In Hibernate there are several ways you could do this. First, you could use the Hibernate-specific @Sort annotation to perform in-memory (i.e. not in the database) sorting, using natural sorting or sorting using a Comparator you supply. For example, assume I have an EventComparator helper class that implements Comparator. I could change Timeline's collection of events to look like this: @OneToMany(mappedBy = "timeline") @org.hibernate.annotations.Sort(type = SortType.COMPARATOR, comparator = EventCompator) Set events Using @Sort will perform sorting in-memory once the collection has been retrieved from the database. While you can certainly do this and implement arbitrarily complex sorting logic, it's probably better to sort in the database when you can. So we now need to turn to Hibernate's @OrderBy annotation, which lets you specify a SQL fragment describing how to perform the sort. For example, you can change the events mapping to : @OneToMany(mappedBy = "timeline") @org.hibernate.annotations.OrderBy("start_year, end_year") Set events This sort order is the same as using the JPA @OrderBy with "startYear, endYear" sort order. But since you write actual SQL in Hibernate's @OrderBy you can take advantage of whatever features your database has, at the possible expense of portability across databases. As an example, Oracle 10g supports using a syntax like "order by start_year, end_year nulls first" to order null end years before non-null end years. You could also say "order by start_year, end year nulls last" which sorts null end years last as you would expect. This syntax is probably not portable, so another trick you can use is the NVL function, which is supported in a bunch of databases. You can rewrite Timeline's collection of events like so: @OneToMany(mappedBy = "timeline") @org.hibernate.annotations.OrderBy("start_year, nvl(end_year , start_year)") Set events The expression "nvl(end_year , start_year)" simply says to use end_year as the sort value if it is not null, and start_year if it is null. So for sorting purposes you end up treating end_year as the same as the start_year if end_year is null. In the contrived example earlier, applying the nvl-based sort using Hibernate's @OrderBy to specify SQL sorting criteria, you now end with the events sorted like this: 2001 Event with no end year 2001 2002 Some event 2001 2003 Other event Which is what you wanted in the first place. So if you need more complex sorting logic than what you can get out of the standard JPA @javax.persistence.OrderBy, try one of the Hibernate sorting options, either @org.hibernate.annotations.Sort or @org.hibernate.annotations.OrderBy. Adding a SQL fragment into your domain class isn't necessarily the most elegant thing in the world, but it might be the most pragmatic thing.
September 16, 2009
by Scott Leberknight
· 102,212 Views
article thumbnail
Calcular A Idade Em SQL
Faz o cálculo da idade de uma pessoa utilizando sql oracle Select Trunc ( (SYSDATE - to_date('14/07/1980','dd/mm/yyyy')) /365, 0 ) as "age" from Dual
September 13, 2009
by Erico Marineli
· 6,281 Views
article thumbnail
Java Performance Tuning, Profiling, and Memory Management
Get a perspective on the aspects of JVM internals, controls, and switches that can be used to optimize your Java application.
September 1, 2009
by Vikash Ranjan
· 257,699 Views · 17 Likes
article thumbnail
JPA Performance, Don't Ignore the Database
Good Database schema design is important for performance. One of the most basic optimizations is to design your tables to take as little space on the disk as possible , this makes disk reads faster and uses less memory for query processing. Data Types You should use the smallest data types possible, especially for indexed fields. The smaller your data types, the more indexes (and data) can fit into a block of memory, the faster your queries will be. Normalization Database Normalization eliminates redundant data, which usually makes updates faster since there is less data to change. However a Normalized schema causes joins for queries, which makes queries slower, denormalization speeds retrieval. More normalized schemas are better for applications involving many transactions, less normalized are better for reporting types of applications. You should normalize your schema first, then de-normalize later. Applications often need to mix the approaches, for example use a partially normalized schema, and duplicate, or cache, selected columns from one table in another table. With JPA O/R mapping you can use the @Embedded annotation for denormalized columns to specify a persistent field whose @Embeddable type can be stored as an intrinsic part of the owning entity and share the identity of the entity. Database Normalization and Mapping Inheritance Hiearchies The Class Inheritance hierarchy shown below will be used as an example of JPA O/R mapping. In the Single table per class mapping shown below, all classes in the hierarchy are mapped to a single table in the database. This table has a discriminator column (mapped by @DiscriminatorColumn), which identifies the subclass. Advantages: This is fast for querying, no joins are required. Disadvantages: wastage of space since all inherited fields are in every row, a deep inheritance hierarchy will result in wide tables with many, some empty columns. In the Joined Subclass mapping shown below, the root of the class hierarchy is represented by a single table, and each subclass has a separate table that only contains those fields specific to that subclass. This is normalized (eliminates redundant data) which is better for storage and updates. However queries cause joins which makes queries slower especially for deep hierachies, polymorphic queries and relationships. In the Table per Class mapping (in JPA 2.0, optional in JPA 1.0), every concrete class is mapped to a table in the database and all the inherited state is repeated in that table. This is not normlalized, inherited data is repeated which wastes space. Queries for Entities of the same type are fast, however polymorphic queries cause unions which are slower. Know what SQL is executed You need to understand the SQL queries your application makes and evaluate their performance. Its a good idea to enable SQL logging, then go through a use case scenario to check the executed SQL. Logging is not part of the JPA specification, With EclipseLink you can enable logging of SQL by setting the following property in the persistence.xml file: With Hibernate you set the following property in the persistence.xml file: Basically you want to make your queries access less data, is your application retrieving more data than it needs, are queries accessing too many rows or columns? Is the database query analyzing more rows than it needs? Watch out for the following: queries which execute too often to retrieve needed data retrieving more data than needed queries which are too slow you can use EXPLAIN to see where you should add indexes With MySQL you can use the slow query log to see which queries are executing slowly, or you can use the MySQL query analyzer to see slow queries, query execution counts, and results of EXPLAIN statements. Understanding EXPLAIN For slow queries, you can precede a SELECT statement with the keyword EXPLAIN to get information about the query execution plan, which explains how it would process the SELECT, including information about how tables are joined and in which order. This helps find missing indexes early in the development process. You should index columns that are frequently used in Query WHERE, GROUP BY clauses, and columns frequently used in joins, but be aware that indexes can slow down inserts and updates. Lazy Loading and JPA With JPA many-to-one and many-to-many relationships lazy load by default, meaning they will be loaded when the entity in the relationship is accessed. Lazy loading is usually good, but if you need to access all of the "many" objects in a relationship, it will cause n+1 selects where n is the number of "many" objects. You can change the relationship to be loaded eagerly as follows : However you should be careful with eager loading which could cause SELECT statements that fetch too much data. It can cause a Cartesian product if you eagerly load entities with several related collections. If you want to override the LAZY fetch type for specific use cases, you can use Fetch Join. For example this query would eagerly load the employee addresses: In General you should lazily load relationships, test your use case scenarios, check the SQL log, and use @NameQueries with JOIN FETCH to eagerly load when needed. Partitioning The main goal of partitioning is to reduce the amount of data read for particular SQL operations so that the overall response time is reduced Vertical Partitioning splits tables with many columns into multiple tables with fewer columns, so that only certain columns are included in a particular dataset, with each partition including all rows. Horizontal Partitioning segments table rows so that distinct groups of physical row-based datasets are formed. All columns defined to a table are found in each set of partitions. An example of horizontal partitioning might be a table that contains historical data being partitioned by date. Vertical Partitioning In the example of vertical partitioning below a table that contains a number of very wide text or BLOB columns that aren't referenced often is split into two tables with the most referenced columns in one table and the seldom-referenced text or BLOB columns in another. By removing the large data columns from the table, you get a faster query response time for the more frequently accessed Customer data. Wide tables can slow down queries, so you should always ensure that all columns defined to a table are actually needed. The example below shows the JPA mapping for the tables above. The Customer data table with the more frequently accessed and smaller data types is mapped to the Customer Entity, the CustomerInfo table with the less frequently accessed and larger data types is mapped to the CustomerInfo Entity with a lazily loaded one to one relationship to the Customer. Horizontal Partitioning The major forms of horizontal partitioning are by Range, Hash, Hash Key, List, and Composite. Horizontal partitioning can make queries faster because the query optimizer knows what partitions contain the data that will satisfy a particular query and will access only those necessary partitions during query execution. Horizontal Partitioning works best for large database Applications that contain a lot of query activity that targets specific ranges of database tables. Hibernate Shards Partitioning data horizontally into "Shards" is used by google, linkedin, and others to give extreme scalability for very large amounts of data. eBay "shards" data horizontally along its primary access path. Hibernate Shards is a framework that is designed to encapsulate support for horizontal partitioning into the Hibernate Core. Caching JPA Level 2 caching avoids database access for already loaded entities, this makes reading frequently accessed unmodified entities faster, however it can give bad scalability for frequent or concurrently updated entities. You should configure L2 caching for entities that are: read often modified infrequently Not critical if stale You should also configure L2 (vendor specific) caching for maxElements, time to expire, refresh... References and More Information: JPA Best Practices presentation MySQL for Developers Article MySQL for developers presentation MySQL for developers screencast Keeping a Relational Perspective for Optimizing Java Persistence Java Persistence with Hibernate Pro EJB 3: Java Persistence API Java Persistence API 2.0: What's New ? High Performance MySQL book Pro MySQL, Chapter 6: Benchmarking and Profiling EJB 3 in Action sharding the hibernate way JPA Caching Best Practices for Large-Scale Web Sites: Lessons from eBay
August 31, 2009
by Carol McDonald
· 41,749 Views · 1 Like
article thumbnail
JPA Implementation Patterns: Lazy Loading
Model your complete database with all its relations with this JPA pattern for lazy loading.
August 19, 2009
by Vincent Partington
· 120,415 Views · 6 Likes
article thumbnail
Urlencode/urldecode As MySQL Stored Functions
DELIMITER ; DROP FUNCTION IF EXISTS multiurldecode; DELIMITER | CREATE FUNCTION multiurldecode (s VARCHAR(4096)) RETURNS VARCHAR(4096) DETERMINISTIC CONTAINS SQL BEGIN DECLARE pr VARCHAR(4096) DEFAULT ''; IF ISNULL(s) THEN RETURN NULL; END IF; REPEAT SET pr = s; SELECT urldecode(s) INTO s; UNTIL pr = s END REPEAT; RETURN s; END; | DELIMITER ;
August 18, 2009
by Snippets Manager
· 13,658 Views · 5 Likes
  • Previous
  • ...
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • ...
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×