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 Java Topics

article thumbnail
Versioning Static Assets with UrlRewriteFilter
A few weeks ago, a co-worker sent me interesting email after talking with the Zoompf CEO at JSConf. One interesting tip mentioned was how we querystring the version on our scripts and css. Apparently this doesn't always cache the way we expected it would (some proxies will never cache an asset if it has a querystring). The recommendation is to rev the filename itself. This article explains how we implemented a "cache busting" system in our application with Maven and the UrlRewriteFilter. We originally used querystring in our implementation, but switched to filenames after reading Souders' recommendation. That part was figured out by my esteemed colleague Noah Paci. Our Requirements Make the URL include a version number for each static asset URL (JS, CSS and SWF) that serves to expire a client's cache of the asset. Insert the version number into the application so the version number can be included in the URL. Use a random version number when in development mode (based on running without a packaged war) so that developers will not need to clear their browser cache when making changes to static resources. The random version number should match the production version number formats which is currently: x.y-SNAPSHOT-revisionNumber When running in production, the version number/cachebust is computed once (when a Filter is initialized). In development, a new cachebust is computed on each request. In our app, we're using Maven, Spring and JSP, but the latter two don't really matter for the purposes of this discussion. Implementation Steps 1. First we added the buildnumber-maven-plugin to our project's pom.xml so the build number is calculated from SVN. org.codehaus.mojo buildnumber-maven-plugin 1.0-beta-4 validate create false false javasvn 2. Next we used the maven-war-plugin to add these values to our WAR's MANIFEST.MF file. maven-war-plugin 2.0.2 true ${project.version} ${buildNumber} ${timestamp} 3. Then we configured a Filter to read the values from this file on startup. If this file doesn't exist, a default version number of "1.0-SNAPSHOT-{random}" is used. Otherwise, the version is calculated as ${project.version}-${buildNumber}. private String buildNumber = null; ... @Override public void initFilterBean() throws ServletException { try { InputStream is = servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"); if (is == null) { log.warn("META-INF/MANIFEST.MF not found."); } else { Manifest mf = new Manifest(); mf.read(is); Attributes atts = mf.getMainAttributes(); buildNumber = atts.getValue("Implementation-Version") + "-" + atts.getValue("Implementation-Build"); log.info("Application version set to: " + buildNumber); } } catch (IOException e) { log.error("I/O Exception reading manifest: " + e.getMessage()); } } ... // If there was a build number defined in the war, then use it for // the cache buster. Otherwise, assume we are in development mode // and use a random cache buster so developers don't have to clear // their browswer cache. requestVars.put("cachebust", buildNumber != null ? buildNumber : "1.0-SNAPSHOT-" + new Random().nextInt(100000)); 4. We then used the "cachebust" variable and appended it to static asset URLs as indicated below. The injection of /v/[CACHEBUSTINGSTRING]/(assets|compressed) eventually has to map back to the actual asset (that does not include the two first elements of the URI). The application must remove these two elements to map back to the actual asset. To do this, we use the UrlRewriteFilter. The UrlRewriteFilter is used (instead of Apache's mod_rewrite) so when developers run locally (using mvn jetty:run) they don't have to configure Apache. 5. In our application, "/compressed/" is mapped to wro4j's WroFilter. In order to get UrlRewriteFilter and WroFilter to work with this setup, the WroFilter has to accept FORWARD and REQUEST dispatchers. rewriteFilter /* WebResourceOptimizer /compressed/* FORWARD REQUEST Once this was configured, we added the following rules to our urlrewrite.xml to allow rewriting of any assets or compressed resource request back to its "correct" URL. ^/v/[0-9A-Za-z_.\-]+/assets/(.*)$ /assets/$1 ^/v/[0-9A-Za-z_.\-]+/compressed/(.*)$ /compressed/$1 /compressed/** /compressed/$1 Of course, you can also do this in Apache. This is what it might look like in your vhost.d file: RewriteEngine on RewriteLogLevel 0! RewriteLog /srv/log/apache22/app_rewrite_log RewriteRule ^/v/[.A-Za-z0-9_-]+/assets/(.*) /assets/$1 [PT] RewriteRule ^/v/[.A-Za-z0-9_-]+/compressed/(.*) /compressed/$1 [PT] Whether it's a good idea to implement this in Apache or using the UrlRewriteFilter is up for debate. If we're able to do this with the UrlRewriteFilter, the benefit of doing this at all in Apache is questionable, especially since it creates a duplicate of code. From http://raibledesigns.com/rd/entry/versioning_static_assets_with_urlrewritefilter
June 5, 2010
by Matt Raible
· 11,797 Views
article thumbnail
Handling Exceptions in Java Using Eclipse
What exactly is an exception? Exceptions are irregular or unusual events that happen in a method the program is calling which usually occurs at runtime. The method throws the Exception back to the caller to show that it is having a problem. If the programmer runs into this case, then they will need to extend an Exception from the Exception class that is already in the Java class library. In Eclipse, on the class declaration panel, the coder and request “constructors from superclass” and it will give the programmer constructors in a child Exception class that will accept error messages or the address of another Exception as a constructor parameter. When creating an Exception class, the programmer has to designate a kind of exception that must be caught or optionally caught. If you declare the Exception class to extend Exception as shown below, the compiler will insist that the method that is being thrown should also be in a caught in catch block. public class CodeName extends Exception { ……. } The compiler gives the programmer two choices when they call a method that throws an Exception that must be caught: 1. Add a try/catch in the code that is being call to catch the Exception 2. Pass the Exception back on to the caller If the programmer chooses option two then they can do this by adding a "throws" clause to end of the method declaration line. The compiler will generate the code to pass the Exception back to the caller at run-time. In the code below, the AnApplcation program is calling a Java Bean object's openFile() method, passing it the file name. The compiler will say to the openFile() method at compile time: "How do you want to handle the Exception?" The AJavaBean should realize there is nothing they can do in the openFile() method to fix the problem so the programmer should throw the Exception back to AnApplication. Eclipse can see the myProgram() in AnApplication is calling the openFile() method and when openFile() adds "throws FileNotFoundException" to its method declaration line, the compiler gives myProgram() method an error message asking the application method how it would like to handle the Exception. public class AnApplication { public void myProgram() { bean.openFile(filename); …… } } public class AJavaBean { public void openFile(String filename) throws FileNotFoundException { file.open(filename); //open() may throw FileNotFoundException …. } } If the programmer choose the first method then they can see below that all the code to process, open, and read are put into a try block. Once a method is called that might throw and Exception, the call has to be from within a try block because there is a chance of failure. If an Exception has been thrown by a method that is called in the try block shown below, the execution jumps out of the try block and into one of the catch blocks. The code that is left below that point in the try block is skipped as you can tell from the structure below. Execution will continue out the bottom of the catch block which branches to the bottom of the catch group if the catch block doesn’t stop the method processing by doing a return. Try/Catch example in Java: public void myProgram() { try { bean.openFile(fileName); // throws FileNotFoundException help.readFileContents(); // throws ReadException do.processFileData(); // throws ProcessException } catch(FileNotFoundException ex) { System.out.println(ex); // calls toString() on ex } catch(ReadException ex) { System.out.println(ex); // calls toString() on ex } catch(ProcessException ex) { System.out.println(ex); // calls toString() on ex } } } What happen if it was really vital that we close the file we open at the top of the try block? If you close it at the bottom of the try block, an exception is thrown and the execution will never get to the bottom of the try block. To guarantee the file gets closed, you would have to repeat the close() action in every one of the catch blocks which becomes repetitive coding. So you could remove all the close() and include a finally block at the bottom like shown below. After the try block has been entered, the finally code will be executed. The finally code will also be executed also if a catch block is entered, even if the catch does a return. public void myProgram() { try { bean.openFile(fileName); // throws FileNotFoundException help.readFileContents(); // throws ReadException do.processFileData(); // throws ProcessException } catch(FileNotFoundException ex) { System.out.println(ex); // calls toString() on ex } catch(ReadException ex) { System.out.println(ea); // calls toString() on ex } catch(ProcessException ex) { System.out.println(ex); // calls toString() on ex } finally { bean.close(filename); } } All the catch blocks print the Exception object’s toString() on the console as an error message. If you are not going to differentiate processing for different kinds of Exceptions, then you could use a “catch-all” block. Since all exception objects are type Exception then they will be directed into this catch block as shown below. Any unanticipated types of exception will be caught also. public void myProgram() { try { bean.openFile(fileName); // throws FileNotFoundException helper.readFileContents(); // throws ReadException do.processFileData(); // throws ProcessException } catch(Exception ex) { System.out.println(ex); // calls toString() on ex } finally { bean.close(filename); } }
June 4, 2010
by Joseph Randolph
· 24,804 Views
article thumbnail
Iterator Pattern Tutorial with Java Examples
Learn the Iterator Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
June 3, 2010
by James Sugrue
· 62,218 Views · 1 Like
article thumbnail
Bridge Pattern Tutorial with Java Examples
Learn the Bridge Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
June 1, 2010
by James Sugrue
· 108,506 Views · 3 Likes
article thumbnail
Creating Master-Detail Forms with Vaadin and Grails
In the article, Groovy, Grails and Vaadin, Petter Holmström outlined an example of using Vaadin with Grails, to build a simple data bound UI for a single database table. This was a great article that showed how one can quickly build a web-based solution that behaves very much like a typical client-server application. However, there are many instances where we need to be able to build an entry screen which allows the user to update both the master record and its detail records at the same time, such as in an Invoice entry screen. In this article I looked at extending the example in the above article, leveraging the simplicity of the Vaadin framework and the GORM capabilities, to build a master-detail example. After years of doing development using Oracle Forms, I liked the way it provides generic functions on each form (or data block) to allow users to add new records, delete them, query them and navigate from one record to the next. Furthermore, in Oracle Forms, you could provide a data grid to allow the user to edit the related detail table (such as the invoice lines in an Invoice document) and keeps these records in sync with the Invoice header (master) record. This is a first attempt at reproducing some of these capabilities using Vaadin and Grails. The master-detail data model The example here is an extension of the Petter Holmström model of the Trip Planner. In the original example, there is a table holding information on trips taken by the user. We will extend that example by having a one-to-many relation with a table of the places that are visited in each trip. This is the code for the Trip domain class. Notice that we are using Grails 1.3.1 which, by default, puts the domain class into the tripplanner package. package tripplanner class Trip { static constraints = { name(nullable: true) city(nullable: true) startDate(nullable: true) endDate(nullable: true) purpose(nullable: true) notes(nullable: true) } String name String city Date startDate Date endDate String purpose String notes static hasMany = [ places : Place ] static mapping = { places lazy:false, cascade:"all,delete-orphan" } } We have made the fields nullable for ease of inserting the record into the table. We also created the one-to-many relation with the Place domain class, and put in the mapping to cascade the deletion and updates to the sub-table class. We also need to change the relation from lazy to eager to ensure that the all detail records are loaded at the same time as the master (header) record. As for the Place domain class, we have 2 fields; name of the place we visited and a description field. In addition, we also put in a transient field, "_deleted", hich we will use to mark a detail record for deletion. package tripplanner class Place { static constraints = { name(nullable: true) description(nullable: true) } String name String description boolean _deleted static transients = [ '_deleted' ] static belongsTo = [trip:Trip] } The master-detail form Now, we need to change the VaadinApp class. Instead of listing the master record in a table to be selected for editing, I have opted to follow the Oracle Forms style for letting the user query for master records using Query By Example (QBE). The standard GORM and Hibernate infrastructure allows the use of a "example" object as a query pattern to extract a subset of records. This unfortunately is not exactly how Oracle Forms QBE works as Oracle Forms allows the user to put in "A%" patterns to query for values that starts with "A" and ">999" to query for values that is bigger than 999. The QBE in GORM only allows exact matches. We will accept this limitation for this example. So now we need a set of buttons to allow the user to: New - Add a new record data entry Save - Saves the current record to the database, including the changes done to the detail table Del - Deletes the current master record and the associated detail records EnterQ - Enters into Query mode which allows the user to provide a pattern for a QBE search ExecQ - Executes the Query and shows the first matching record from the query ExitQ - Exits out of Query mode and goes back to New record mode Prev - Go to previous record if there any queried records Next - Go to next record if there are any queried records These buttons are located at the top of the master record form. Error messages which arise from the save / update button are listed at the top of the master record form fields (in the "description field" of the Vaadin Form). There is also a status indicator label located at the footer of the master record form ("footer section" of the Vaadin Form). The status label will show the current mode of the master record entry screen and also the current record number if this is part of a query set. Below the master record form is the editable, selectable detail records table which is located in its own panel. Users are allowed to edit the detail record table only if the master record is in Edit mode. This means that users need to save the newly created master (header) record before that they can add any detail records. The detail record table has a column for all the editable, visible records excluding the "_deleted" field which is for internal use only. To manipulate the detail records, we provide 2 buttons to add a new detail record (the "+" button) or delete the selected detail record (the "-" button). All additions, deletions or even updates are only saved to the database after the user clicks on the "Save" button in the master (header) record form. As the user moves from one master record to the next using the "Prev" and "Next" buttons in the master table form, the detail table will be synchronized accordingly. package tripplanner import com.vaadin.ui.* import com.vaadin.data.* import com.vaadin.data.util.* class VaadinApp extends com.vaadin.Application { def query def rec_pos def container = new BeanItemContainer(Place.class) def master_fields = ["name", "purpose", "startDate", "endDate", "city", "notes"] def saveButton def newButton def delButton def entQButton def exeQButton def extQButton def prevButton def nextButton def statusLabel def pnlDetail void new_mode(editor) { def tripInstance = new Trip() editor.itemDataSource = new BeanItem(tripInstance) editor.visibleItemProperties = master_fields editor.description = "" container.removeAllItems() saveButton.setEnabled(true) delButton.setEnabled(false) entQButton.setEnabled(true) extQButton.setEnabled(false) statusLabel.setValue "New Mode" pnlDetail.setEnabled(false) } void init() { //def window = new Window("Trip Maintenance", new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL)) def window = new Window("Trip Maintenance") setMainWindow window // Form Panel def panel = new Panel("Trip Maintenance") panel.setSizeFull() panel.setLayout(new VerticalLayout()); // Trip editor def tripEditor = new Form() tripEditor.setSizeFull() tripEditor.layout.setMargin true tripEditor.immediate = true tripEditor.visible = true // status bar - shows the mode of the form statusLabel = new Label("New Mode") // define master form buttons saveButton = new Button("Save") newButton = new Button("New") delButton = new Button("Del") entQButton = new Button("EnterQ") exeQButton = new Button("ExecQ") extQButton = new Button("ExitQ") prevButton = new Button("Prev") nextButton = new Button("Next") // set initial state of buttons delButton.setEnabled(false) extQButton.setEnabled(false) // default is New Mode def v_tripInstance = new Trip() tripEditor.itemDataSource = new BeanItem(v_tripInstance) tripEditor.visibleItemProperties = master_fields //new_mode(tripEditor) // panel for detail form pnlDetail = new Panel() pnlDetail.setEnabled(false) // table to hold the detail form rows def table = new Table() table.containerDataSource = container table.selectable = true table.editable = true table.setSizeFull() table.visibleColumns = ["name", "description"] table.immediate = true // toolbar for the detail form manipulation def toolbar = new HorizontalLayout() // buttons for detail form // button to add new row to detail form def addRowButton = new Button("+", new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { def placeInstance = new Place() def tripInstance = tripEditor.itemDataSource.bean tripInstance.addToPlaces(placeInstance) container.addBean placeInstance } }) toolbar.addComponent addRowButton // button to delete current row from detail form def delRowButton = new Button("-", new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { if (table.value) { def placeInstance = table.value placeInstance._deleted = true container.removeItem(placeInstance) table.value = null } } }) toolbar.addComponent delRowButton // detail panel has the table rows and the toolbar pnlDetail.addComponent toolbar pnlDetail.addComponent table // master form buttons // save record button saveButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { Trip.withTransaction { status -> table.commit() def tripInstance = tripEditor.itemDataSource.bean def _toBeDeleted = tripInstance.places.findAll {it._deleted} if (_toBeDeleted) { tripInstance.places.removeAll(_toBeDeleted) } if (!tripInstance.save(flush:true)) { tripEditor.description = "Error:" tripInstance.errors.allErrors.each { error -> tripEditor.description = tripEditor.description + "" + "Field [${error.getField()}] with value [${error.getRejectedValue()}] is invalid" } tripEditor.description = tripEditor.description + "" window.showNotification "Could not save changes" } else { tripEditor.description = "" window.showNotification "Changes saved" delButton.setEnabled(true) statusLabel.setValue("Edit Mode"); pnlDetail.setEnabled(true) populate_container(container,tripInstance.places) } } } }) // new record button newButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { new_mode(tripEditor) } }) // delete record button delButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { if (tripEditor.itemDataSource.bean) { Trip.withTransaction { status -> def tripInstance = tripEditor.itemDataSource.bean tripInstance.delete(flush:true) } } new_mode(tripEditor) } }) // enter query mode entQButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { def tripInstance = new Trip() def newBean = new BeanItem(tripInstance) tripEditor.itemDataSource = newBean tripEditor.visibleItemProperties = master_fields tripEditor.description = "" saveButton.setEnabled(false) delButton.setEnabled(false) entQButton.setEnabled(false) extQButton.setEnabled(true) statusLabel.setValue("Query Mode"); pnlDetail.setEnabled(false) } }) // execute query exeQButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { tripEditor.commit() def example = (Trip) tripEditor.itemDataSource.bean query = Trip.findAll(example) rec_pos = 0 tripEditor.description = "" entQButton.setEnabled(true) extQButton.setEnabled(false) if (query.size > 0) { def next_rec = query[rec_pos] tripEditor.itemDataSource = new BeanItem(next_rec) tripEditor.visibleItemProperties = master_fields saveButton.setEnabled(true) delButton.setEnabled(true) statusLabel.setValue("Edit Mode. Record " + (rec_pos+1) + "/" + query.size); pnlDetail.setEnabled(true) populate_container(container,next_rec.places) } else { window.showNotification "No record found" new_mode(tripEditor) } } }) // exit query mode. Back to New mode extQButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { new_mode(tripEditor) } }) // edit mode, previous record prevButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { if (!query) { window.showNotification "No query result" return } if (rec_pos > 0) { rec_pos-- def next_rec = query[rec_pos] tripEditor.itemDataSource = new BeanItem(next_rec) tripEditor.visibleItemProperties = master_fields saveButton.setEnabled(true) statusLabel.setValue("Edit Mode. Record " + (rec_pos+1) + "/" + query.size) pnlDetail.setEnabled(true) populate_container(container,next_rec.places) } } }) // edit mode, next record nextButton.addListener(new Button.ClickListener() { void buttonClick(Button.ClickEvent event) { if (!query) { window.showNotification "No query result" return } if (rec_pos < query.size - 1) { rec_pos++ def next_rec = query[rec_pos] tripEditor.itemDataSource = new BeanItem(next_rec) tripEditor.visibleItemProperties = master_fields saveButton.setEnabled(true) statusLabel.setValue("Edit Mode. Record " + (rec_pos+1) + "/" + query.size) pnlDetail.setEnabled(true) populate_container(container,next_rec.places) } } }) // put the status bar on the footer of the master form tripEditor.footer = new HorizontalLayout() tripEditor.footer.addComponent statusLabel // put all master form buttons into a horizontal panel def btnPanel = new HorizontalLayout() btnPanel.addComponent saveButton btnPanel.addComponent newButton btnPanel.addComponent delButton btnPanel.addComponent entQButton btnPanel.addComponent exeQButton btnPanel.addComponent extQButton btnPanel.addComponent prevButton btnPanel.addComponent nextButton // construct master-detail form panel panel.addComponent btnPanel panel.addComponent tripEditor panel.addComponent pnlDetail // set panel to main window mainWindow.addComponent panel } // routine to populate the container with the detail records void populate_container(container, details) { container.removeAllItems() details.each { if (!it._deleted) container.addBean it } } } A walkthrough of the above VaadinApp code is as follows. The query object stores the list of "Trip" instances that is returned from a QBE query. The rec_pos is an index into the above list for the currently displayed record. The master_fields stores the list of master record fields that is visible on the form We put some of the buttons, status label and detail panel object as the object variables so that they can be access by helper routines The new_mode routine is to put the form into the New mode, which occurs multiple times in the whole code The init routine is where the whole window and form is defined The form is laid out with the master record buttons at the top, followed by the master record form, and then the detail table sub-panel below that In the detail sub-panel, there are 2 buttons, "+" and "-" which adds a detail to the Table and the master record instance and removes a detail record, respectively. These are not put into a GORM Transaction as we only want to save (flush) the record when the "Save" button is saved. The really tricky part of the whole form is in the master record buttons. For the "Save" button, we first force the detail table to update the source records in the master collection. Then we delete all the detail records which are marked for deletion, where the "_deleted" field is set to true. Finally the master record is saved by calling the "save" method in the tripInstance bean object. Any error messages are put into the "description field" of the master record form. If everything is fine, then the form is put into "Edit" mode for further editing including adding detail records into the Table below. The new button just puts a new Trip instance into the master record form (and disables the detail table panel) The delete button just deletes the master record. There is no need to "commit" the transaction as it is done automatically, and this differs from Oracle Forms The enter-query button just clears the fields to collect the parameters to search. If all the fields are null, then the QBE will match all records in the database Executing the query will run the "findAll(object)" method of the GORM domain instance. The return result is a List of matching instances. This is not quite scalable as the List needs to be stored in memory for the duration of the session or until the next query is run. This will need to be improved further. If there are any returned records, then the master form will display the first record and put it in "Edit" mode Exiting the Query mode will return the form to the New mode The previous and next buttons will update the master record form and the container of the detail table panel, thus keeping both screens in synchrony. The picture on the left shows the data entry screen with the detail records for the current master record. Future Direction To improve on this, we will need to componentize the whole form so that developers do not need to copy and paste the above template code and modify it for each form. Furthermore the "container" object above should be changeable to allow for other types of containers to be used but they should not be data-bound and leave the data-binding to the GORM objects and layer. Another suggestion is to create a Container component which is manipulated by the master table form buttons (add, save, delete, enter query, execute query, previous record, next record) and it then controls the master table entry Form. Finally, as mentioned in the Petter Holmström article, we are not really using any feature of Grails other than the GORM, and so, this entire example can be build using just Groovy, GORM and Vaadin.
May 31, 2010
by Chee-keong Lee
· 39,688 Views · 1 Like
article thumbnail
JMS Clustering by Example
It's amazing how the JBoss Team put together an easy way to do JMS Clustering, out of the box!!. I'll start with an easy example, creating a Queue named "MyClusteredQueue". In this example I'm using JBoss AS 5.1. and two computers connected on the same network, with these IP's: - Computer A: 192.168.0.143 - Computer B: 192.168.0.210 So, here are the steps: 1) Install the JBoss on both computers. We are going to use the "all" configuration for both computers. 2) We create our Queue on both servers. Go to $JBOSS_HOME/server/all/deploy/messaging/ and edit the destinations-service.xml file. Add the MyClusteredQueue before the last server tag. It looks like this: jboss.messaging:service=ServerPeer jboss.messaging:service=PostOffice true This is how you add a Queue to the JBoss, and the people how are familiar with this, the only new thing is to add the attribute "Clustered". This step must be set on both computers. At the end of the article you can find the files. 3) Write the MDB to consume the messages, and deploy it on the two computers. (I'm using an EJB 3 - MDB style). import java.net.InetAddress; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import org.apache.log4j.Logger; /** * @author felipeg * */ @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty(propertyName="destination", propertyValue="queue/MyClusteredQueue") }) public class JMSClusterClientHandler implements MessageListener { Logger log = Logger.getLogger(JMSClusterClientHandler.class); @Override public void onMessage(Message message) { try{ if (message instanceof ObjectMessage) { InetAddress addr = InetAddress.getLocalHost(); log.info("########## Processing Host: " + addr.getHostName() + " ##########" ); ObjectMessage objMessage = (ObjectMessage) message; Object obj = objMessage.getObject(); log.info("Object received:" + obj.toString()); } } catch (Exception e) { e.printStackTrace(); } } } 4) Start the jboss with the following options: Computer A: $ cd $JBOSS_HOME/bin $ ./run.sh -c all -b 192.168.0.143 -Djboss.messaging.ServerPeerID=1 Computer B: $ cd $JBOSS_HOME/bin $ ./run.sh -c all -b 192.168.0.210 -Djboss.messaging.ServerPeerID=2 It is necesary to give an ID to each server and this is accomplished with this directive: -Djboss.messaging.ServerPeerID When you start the jboss on computer A, you should see the logs (server.log) telling you that there is one node ready and listening, and once you start the jboss on computer B, on the log will appear the two nodes, the two IP's ready to consume messages. 5) Now it's time to send a Message to the Queue. To accomplish this it's necessary to change the connection factory to "ClusteredConnectionFactory" (JMSDispatcher.java - See the code below). Also on the jndi.properties (if you are using the default InitialContext) file it's necessary to add the two computers ip's separated by comma to the java.naming.provider.url property. (In my case a create a Properties variable and I set all the necessary properties, JMSDispatcher.java - see the code below). java.naming.provider.url=192.168.0.143:1099,192.168.0.210:1099 The client that I wrote is a web application, that consist in one index.jsp page, which contains a form that prompts you for the name of the queue, the type of messaging (Queue or Topic), the server ip and port, how many times it will send the message and the actual message to be sent; also the web application has a Servlet (JMSClusteredClient.java - see code below) that receives the postback and helper class (JMSDispatcher.java - see code below) that sends the message to the jboss servers. You can to deploy it in any computer. In my case I deployed it on the Computer A. And you can access it through this URL: http://192.168.0.143:8080/JMSWeb/ (just modify the IP where the client war was deployed). If you notice (on the index.jsp - code below) I've already put some default values that reflects the name of the Queue, and the IP's of my two computers. Now, If you increment the number of times that the message will be sent (maybe a 10) and fill out the message box, and click "Send" you should see on the two servers some of the messages being consumed by the MDB. Here are the Files to create the client: index.jsp JMS Clustered - Test Client Server: QueueTopic Times:Message: Servlet: JMSClusteredClient.java public class JMSClusteredClient extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response) */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); String topicqueue = request.getParameter("topicqueue"); String message = request.getParameter("message"); String server = request.getParameter("server"); String messageType = request.getParameter("messageType"); String times = request.getParameter("times"); int intTimes = Integer.parseInt(times); JMSDispatcher dispatcher = new JMSDispatcher(); dispatcher.setTopicQueueName(topicqueue); dispatcher.setServer(server); dispatcher.setMessageType(messageType); try { for(int count =1; count <= intTimes;count++){ dispatcher.sendMessage( count + " of " + times + " " + message); } out.println("Message [" + message + "] sent successfully to [" + topic + "] to the [" + server + "] server " + times + " times."); } catch (JMSException e) { e.printStackTrace(); out.println("Error:" + e.getMessage()); } catch (NamingException e) { out.println("Error:" + e.getMessage()); e.printStackTrace(); } finally{ out.close(); } } } A utility to send the messages: JMSDispatcher.java public class JMSDispatcher { /** * */ private static final long serialVersionUID = 7105145023422143880L; private static Logger log = Logger.getLogger(JMSDispatcher.class); private final String CONNECTION_FACTORY_CLUSTERED = "ClusteredConnectionFactory"; private final String CONNECTION_FACTORY = "ConnectionFactory"; private final String TOPIC = "TOPIC"; private final String QUEUE = "QUEUE"; private String topicQueueName; private String server; private String messageType; public void setTopicQueueName(String value){ this.topicQueueName = value; } public void setServer(String value){ this.server = value; } public void setMessageType(String value){ this.messageType = value; } public void sendMessage(Object objectMessage) throws JMSException, NamingException{ log.debug("##### Setting up a Queue/Topic Message: #####"); if (TOPIC.equals(messageType)){ sendTopicMessage(objectMessage); } else if (QUEUE.equals(messageType)){ sendQueueMessage(objectMessage); } log.debug("##### Publishing Message: Done #####"); } private void sendQueueMessage(Object objectMessage) throws JMSException, NamingException{ try{ InitialContext initialContext = getInitialContext(); QueueConnectionFactory qcf = (QueueConnectionFactory) initialContext.lookup(CONNECTION_FACTORY_CLUSTERED); QueueConnection queueConn = qcf.createQueueConnection(); Queue queue = (Queue) initialContext.lookup(topicQueueName); QueueSession queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queueConn.start(); QueueSender send = queueSession.createSender(queue); ObjectMessage om = queueSession.createObjectMessage((Serializable)objectMessage); setMessageProperties(om); log.debug("##### Publishing Message to a Queue: " + queueName + "#####"); send.send(om); send.close(); queueConn.stop(); queueSession.close(); queueConn.close(); }catch(MessageFormatException ex){ log.error("##### The MESSAGE is not Serializable ####"); throw ex; }catch(MessageNotWriteableException ex){ log.error("##### The MESSAGE is not Readable ####"); throw ex; }catch(JMSException ex){ log.error("##### JMS provider fails to set the object due to some internal error. ####"); throw ex; } } private void sendTopicMessage(Object objectMessage) throws JMSException, NamingException{ try{ InitialContext initialContext = getInitialContext(); TopicConnectionFactory tcf = (TopicConnectionFactory)initialContext.lookup(CONNECTION_FACTORY_CLUSTERED); TopicConnection topicConn = tcf.createTopicConnection(); Topic topic = (Topic) initialContext.lookup(topicQueueName); TopicSession topicSession = topicConn.createTopicSession(false,TopicSession.AUTO_ACKNOWLEDGE); topicConn.start(); TopicPublisher send = topicSession.createPublisher(topic); ObjectMessage om = topicSession.createObjectMessage(); om.setObject((Serializable)objectMessage); setMessageProperties(om); log.debug("##### Publishing Message to a Topic: " + topicName + "#####"); send.publish(om); send.close(); topicConn.stop(); topicSession.close(); topicConn.close(); }catch(MessageFormatException ex){ log.error("##### The MESSAGE is not Serializable ####"); throw ex; }catch(MessageNotWriteableException ex){ log.error("##### The MESSAGE is not Readable ####"); throw ex; }catch(JMSException ex){ log.error("##### JMS provider fails to set the object due to some internal error. ####"); throw ex; } } private InitialContext getInitialContext() throws NamingException{ Properties jboss = new Properties(); jboss.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); jboss.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); jboss.put("java.naming.provider.url", server); return new InitialContext(jboss); } } And the web.xml JMSWeb index.jsp JMSClusteredClient JMSClusteredClient com.blogspot.felipeg48.jms.web.JMSClusteredClient JMSClusteredClient /JMSClusteredClient Happy Clustering!!
May 26, 2010
by Felipe Gutierrez
· 16,766 Views
article thumbnail
A Look Inside JBoss Microcontainer - The Scanning Library
Today's JEE doesn't require configuration files any more. Most of the configuration, if not all, is done over properly annotated classes. As such, it's the responsibility of the underlying containers to find these annotations and act accordingly. At a first glance it appears that there is no other way for a container to implement that than to fully scan a given deployment. And we all know this can be very time consuming, especially if there are multiple container components that require this information, and have no integration hooks available to get to a container's already gathered information. From requirements collected here, I've introduced a new MC Scanning sub-project. The main goal or idea behind this lib is very simple: unify all of JBossAS component scanning into a single-pass scan. Instead of doing the resource scanning for every component, we just do it once, properly delegating the work to various container components. Another goal was to also enable usage of pre-indexed information, so that there would actually be no need for the scanning itself - e.g. one could pre-index all of jar's annotations during the build. Read the other parts in DZone's exclusive JBoss Microcontainer Series: Part 1 -- Component Models Part 2 –- Advanced Dependency Injection and IoC Part 3 -- the Virtual File System Project structure scanning-spi - Contains a simple scanner, metadata SPI, and initial helpers to help you extend / use a simple version of this lib. scanning-impl - Provides component agnostic scanning API. It also includes generic metadata implementation and its usage. plugins - This module holds custom component-scanning implementations. Current implementations are: Annotations Hibernate Hierarchy JSF Web Weld deployers - Integration with VDF; new custom deployers. indexer - This module contains utils for creating pre-indexed handles, and merging them into existing jars. It includes Ant task and Maven plugin. testsuite - Tests for all other modules. Basic building blocks The org.jboss.scanning.spi.Scanner class is the most abstract - most basic interface to interact with any scanner implementation. It only has scan() method. For any really useful operation one will have to use some concrete implementation's constructors, properties ... and then use scan() to trigger the scan operation. The main interface of interest for us is org.jboss.scanning.spi.ScanningPlugin: package org.jboss.scanning.spi; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.jboss.classloading.spi.visitor.ResourceFilter; import org.jboss.classloading.spi.visitor.ResourceVisitor; /** * Scanning plugin. * Defines what to do with a resource. * * @param exact handle type * @param exact handle interface * @author Ales Justin */ public interface ScanningPlugin extends ResourceFilter, ResourceVisitor { /** * Create plugins handle/utility. * e.g. AnnotationRepository for annotations scanning * * @return new handle instance */ T createHandle(); /** * Read serialized handle. * * @param is the serialized handle's input stream. * @return de-serialized handle * @throws Exception for any error */ ScanningHandle readHandle(InputStream is) throws Exception; /** * Write / serialize handle. * * @param os the output stream to serialize handle. * @param handle the handle * @throws IOException for any IO error */ void writeHandle(OutputStream os, T handle) throws IOException; /** * Cleanup handle. * * @param handle the handle to cleanup */ void cleanupHandle(U handle); /** * Get handle interface. * * @return the handle interface */ Class getHandleInterface(); /** * Get handle's key. * Used to attach handle to map/attachments. * * @return the handle's key */ String getAttachmentKey(); /** * Get handle's file name. * Used to attach handle to jar and/or get pre-indexed. * * @return the handle's file name */ String getFileName(); /*** * Get recurse filter. * * @return the recurse filter */ ResourceFilter getRecurseFilter(); } Most of the functionality is already implemented in its abstract form (AbstractScanningPlugin) so you only need to provide the custom logic. As you can already see from the plugin's signature, the plugin introduces a handle. A handle is what will hold the scanning information for particular component; e.g. an annotation repository. We can see handle's implementation defined as parameter T, where handle's interface is parameter U. /** * Scanning handle. * * Represents a simple interface resource scanning results must implement * in order to be able to merge pre-existing results. * * @param exact handle type * @author Ales Justin */ public interface ScanningHandle { /** * Merge existing handle with sub-handle / pre-existing handle. * * @param subHandle the sub handle */ void merge(T subHandle); } The main purpose of handle introduction is to allow for pre-existing handle's merging in type safe manner. How to make usage of plugins as easy as possible in MC? As we can see Scanner (or its actual implementations) takes a set of plugins to handle artifacts. But since plugins are mostly mutable, we need some sort of factory to help use create these plugins. For VDF based usage this is how our factory looks like: import org.jboss.deployers.structure.spi.DeploymentUnit; import org.jboss.scanning.spi.ScanningHandle; import org.jboss.scanning.spi.ScanningPlugin; /** * Deployment based scanning plugin factory. * Used for incallback automatching. * * @param exact handle type * @author Ales Justin */ public interface DeploymentScanningPluginFactory { /** * Is this plugin relevant to unit. * * @param unit the unit to check against * @return true if it's relevant, false otherwise */ boolean isRelevant(DeploymentUnit unit); /** * Create scanning plugin from deployment unit. * * @param unit the deployment unit * @return new scanning plugin */ ScanningPlugin create(DeploymentUnit unit); } Also, as the javadoc says, this interface is nicely used for MC's incallback usage (incallback is a kind of dependency injection where one component can insert itself into another via a method call, as explained in one of the previous articles on JBoss Microcontainer). Usage example Let's see what we need to implement in order to get annotation scanning into the repository. public class AnnotationsScanningPluginFactory implements DeploymentScanningPluginFactory { public boolean isRelevant(DeploymentUnit unit) { // any better check? -- metadata complete is already done elsewhere // see JBossMetaDataDeploymentUnitFilter in JBossAS return true; } public ScanningPlugin create(DeploymentUnit unit) { ReflectProvider provider = DeploymentUtilsFactory.getProvider(unit); ResourceOwnerFinder finder = DeploymentUtilsFactory.getFinder(unit); return new AnnotationsScanningPlugin(provider, finder, unit.getClassLoader()); } } public class AnnotationsScanningPlugin extends AbstractClassLoadingScanningPlugin { /** The repository */ private final DefaultAnnotationRepository repository; /** The visitor */ private final ResourceVisitor visitor; public AnnotationsScanningPlugin(ClassLoader cl) { this(IntrospectionReflectProvider.INSTANCE, ClassResourceOwnerFinder.INSTANCE, cl); } public AnnotationsScanningPlugin(ReflectProvider provider, ResourceOwnerFinder finder, ClassLoader cl) { repository = new DefaultAnnotationRepository(cl); visitor = new GenericAnnotationVisitor(provider, finder, repository); } protected DefaultAnnotationRepository doCreateHandle() { return repository; } protected ClassLoader getClassLoader() { return repository.getClassLoader(); } @Override public void cleanupHandle(AnnotationIndex handle) { if (handle instanceof DefaultAnnotationRepository) DefaultAnnotationRepository.class.cast(handle).cleanup(); } public Class getHandleInterface() { return AnnotationIndex.class; } public ResourceFilter getFilter() { return visitor.getFilter(); } public void visit(ResourceContext resource) { visitor.visit(resource); } } public class GenericAnnotationVisitor extends ClassHierarchyResourceVisitor { /** The mutable repository */ private MutableAnnotationRepository repository; public GenericAnnotationVisitor(ReflectProvider provider, ResourceOwnerFinder finder, MutableAnnotationRepository repository) { super(provider, finder); if (repository == null) throw new IllegalArgumentException("Null repository"); this.repository = repository; } protected boolean isRelevant(ClassInfo classInfo) { return repository.isAlreadyChecked(classInfo.getName()) == false; } public ResourceFilter getFilter() { return ClassFilter.INSTANCE; } @Override protected void handleAnnotations(ElementType type, Signature signature, Annotation[] annotations, String className, URL ownerURL) { if (annotations != null && annotations.length > 0) { for (Annotation annotation : annotations) { repository.putAnnotation(annotation, type, className, signature, ownerURL); } } } } While the repository is just a-bit-smarter Map. Integration with VDF Using the Indexer public class Main { private static final Logger log = Logger.getLogger(Main.class.getName()); /** * Usage */ private static void usage() { System.out.println("Usage: Indexer "); } /** * Main. * The output is file named .jar.mcs. * * @param args the program arguments */ public static void main(String[] args) { try { int offset = 2; if (args.length < offset) { File input = new File(args[0]); String[] providers = args[1].split(","); URL[] urls = new URL[args.length - offset]; // add the rest of classpath for (int i = 0; i < urls.length; i++) urls[i] = new File(args[i + offset]).toURI().toURL(); ScanUtils.scan(input, Constants.applyAliases(providers), urls); } else { usage(); } } catch (Throwable t) { log.log(Level.SEVERE, t.getMessage(), t); } } } Pre-existing or pre-indexed information For each scanning plugin we look for artifact's META-INF/ entry. String fileName = plugin.getFileName(); for (URL root : roots) { InputStream is = getInputStream(root, Scanner.META_INF + fileName); if (is != null) { ScanningHandle pre = plugin.readHandle(is); handle.merge(pre); It's plugin's responsibility to know how to read pre-existing handle. By default we use plain Java serialization together with gzip. public ScanningHandle readHandle(InputStream is) throws Exception { try { GZIPInputStream gis = new GZIPInputStream(is); ObjectInputStream ois = createObjectInputStream(gis); return (ScanningHandle) ois.readObject(); } finally { is.close(); } } public void writeHandle(OutputStream os, T handle) throws IOException { GZIPOutputStream gos = new GZIPOutputStream(os); ObjectOutputStream oos = new ObjectOutputStream(gos); try { oos.writeObject(handle); oos.flush(); } finally { oos.close(); } } How to limit scanning? There already was a jboss-scanning.xml, I've just enhanced it a bit. The recurse filter is now a bit smarter, and consequently faster, than it used to be in previous version. package org.jboss.scanning.plugins.filter; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.classloading.spi.visitor.ResourceContext; import org.jboss.classloading.spi.visitor.ResourceFilter; import org.jboss.scanning.spi.metadata.PathEntryMetaData; import org.jboss.scanning.spi.metadata.PathMetaData; import org.jboss.scanning.spi.metadata.ScanningMetaData; import org.jboss.vfs.util.PathTokenizer; /** * Simple recurse filter. * * It searches for path substring in url string, * and tries to match the tree structure as far as it goes. */ public class ScanningMetaDataRecurseFilter implements ResourceFilter { /** Path tree roots */ private Map roots; public ScanningMetaDataRecurseFilter(ScanningMetaData smd) { if (smd == null) throw new IllegalArgumentException("Null metadata"); List paths = smd.getPaths(); if (paths != null && paths.isEmpty() == false) { roots = new HashMap(); for (PathMetaData pmd : paths) { RootNode pathNode = new RootNode(); roots.put(pmd.getPathName(), pathNode); Set includes = pmd.getIncludes(); if (includes != null && includes.isEmpty() == false) { pathNode.explicitInclude = true; for (PathEntryMetaData pemd : includes) { String name = pemd.getName(); String[] tokens = name.split("\\."); Node current = pathNode; for (String token : tokens) current = current.addChild(token); if (pemd.isRecurse()) current.recurse = true; // mark last one as recurse } } } } } public boolean accepts(ResourceContext resource) { if (roots == null) return false; URL url = resource.getUrl(); String urlString = url.toExternalForm(); for (Map.Entry root : roots.entrySet()) { if (urlString.contains(root.getKey())) { RootNode rootNode = root.getValue(); if (rootNode.explicitInclude) // we have explicit includes in path, try tree path { String resourceName = resource.getResourceName(); List tokens = PathTokenizer.getTokens(resourceName); Node current = rootNode; // let's try to walk some tree path for (String token : tokens) { // if we're here, the rest is recursively matched if (current.recurse) break; current = current.getChild(token); // no fwd path if (current == null) return false; } } return true; } } return false; } private static class Node { private Map children; private boolean recurse; public Node addChild(String value) { if (children == null) children = new HashMap(); Node child = children.get(value); if (child == null) { child = new Node(); children.put(value, child); } return child; } public Node getChild(String child) { return children != null ? children.get(child) : null; } } private static class RootNode extends Node { private boolean explicitInclude; } } Javassist based JBoss Reflect In order to avoid loading the actual resource's underlying class, we use Javassist under the hood - via JBoss Refect project. DeploymentUnit unit = assertDeploy(jar); try { TIFScanningPlugin plugin = unit.getAttachment(TIFScanningPlugin.class); assertNotNull(plugin); Kernel kernel = assertBean("Kernel", Kernel.class); KernelConfigurator configurator = kernel.getConfigurator(); ClassLoader cl = unit.getClassLoader(); String name = JarMarkOnClass.class.getName(); TypeInfo ti = configurator.getTypeInfo(name, cl); TypeInfo visited = plugin.getResources().get(name); assertSame(ti, visited); // let's check if the cache is working Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); findLoadedClass.setAccessible(true); Object clazz = findLoadedClass.invoke(cl, name); assertNull(clazz); // should not be loaded } finally { undeploy(unit); } But the overall usage of helper utils is pluggable: /** * Find the util for deployment. * Newly created utils are grouped per module. * * @author Ales Justin */ public class DeploymentUtilsFactory { /** The default impls */ private static Map, UtilFactory> defaults = new WeakHashMap, UtilFactory>(); static { addImplementation(ReflectProvider.class, new ReflectProviderUtilFactory()); addImplementation(ResourceOwnerFinder.class, new ResourceOwnerFinderUtilFactory()); } /** * Add the util impl. * * @param iface the interface * @param factory the util factory */ public static void addImplementation(Class iface, UtilFactory factory) { defaults.put(iface, factory); } /** * Remove the util impl. * * @param iface the interface */ public static void removeImplementation(Class iface) { defaults.remove(iface); } /** * Get util. * * @param unit the deployment unit * @param utilType the util type * @return util instance */ public static T getUtil(DeploymentUnit unit, Class utilType) { if (utilType == null) throw new IllegalArgumentException("Null util type"); DeploymentUnit moduleUnit = getModuleUnit(unit); T util = moduleUnit.getAttachment(utilType); if (util == null) { UtilFactory factory = defaults.get(utilType); if (factory == null) throw new IllegalArgumentException("No util factory defined for " + utilType); Object instance = factory.create(moduleUnit); util = utilType.cast(instance); moduleUnit.addAttachment(utilType, util); } return util; } /** * Get module unit. * * @param unit the current unit * @return unit containing Module, or exception if no such unit exists */ public static DeploymentUnit getModuleUnit(DeploymentUnit unit) { if (unit == null) throw new IllegalArgumentException("Null unit"); // group util per module DeploymentUnit moduleUnit = unit; while(moduleUnit != null && moduleUnit.isAttachmentPresent(Module.class) == false) moduleUnit = moduleUnit.getParent(); if (moduleUnit == null) throw new IllegalArgumentException("No module in unit: " + unit); return moduleUnit; } /** * Wrap util lookup in lazy lookup. * * @param unit the deployment unit * @param utilType the util type * @return lazy util proxy */ public static T getLazyUtilProxy(DeploymentUnit unit, Class utilType) { // null check is in handler LazyUtilsProxyHandler handler = new LazyUtilsProxyHandler(unit, utilType); Object proxy = Proxy.newProxyInstance(unit.getClassLoader(), new Class[]{utilType}, handler); return utilType.cast(proxy); } /** * Get reflect provider. * * @param unit the depoyment unit * @return the provider */ public static ReflectProvider getProvider(DeploymentUnit unit) { return getUtil(unit, ReflectProvider.class); } /** * Get finder. * * @param unit the depoyment unit * @return the finder */ public static ResourceOwnerFinder getFinder(DeploymentUnit unit) { return getUtil(unit, ResourceOwnerFinder.class); } /** * Cleanup the util. * * @param util the util to cleanup */ public static void cleanup(Object util) { if (util instanceof CachingResourceOwnerFinder) CachingResourceOwnerFinder.class.cast(util).cleanup(); } } Meaning it's easy to swap utils behavior for particular deployment unit. e.g. different ResourceOwnerFinder or ReflectProvider Reporting issues As usual, use the forums: MC user forum MC dev forum In my previous article I've actually promised an article on our current native OSGi framework work, but since I was heavily into writing this new scanning lib I though I could share my thoughts / ideas on it while they were still hot. Specially with scanning being a constantly present topic in today's enterprise usage. One thing to note here - all of this is still at prototype stage, with no real release yet, although the main concepts have been in the making for a while, from initial support in VDF, to custom Papaki library, Scannotations, ... hence they've grown from experience. But this doesn't mean feedback is not welcome. :-) I'll be trying to fulfill my promise next time with an OSGi article, unless our Reflect gets the best of me. ;-) P.S.: As usual, again thanks to Marko for doing the editing of this article. About the Author Ales Justin was born in Ljubljana, Slovenia and graduated with a degree in mathematics from the University of Ljubljana. He fell in love with Java eight years ago and has spent most of his time developing information systems, ranging from customer service to energy management. He joined JBoss in 2006 to work full time on the Microcontainer project, currently serving as its lead. He also contributes to JBoss AS and is Seam, Weld and Spring integration specialist. He represent JBoss on 'OSGi' expert groups.
May 11, 2010
by Ales Justin
· 24,154 Views
article thumbnail
Interpreter Pattern Tutorial with Java Examples
Learn the Interpreter Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
May 11, 2010
by James Sugrue
· 54,661 Views
article thumbnail
The Power of Proxies in Java
In this article, I’ll show you the path that leads to true Java power, the use of proxies. They are everywhere but only a handful of people know about them. Hibernate for lazy loading entities, Spring for AOP, LambdaJ for DSL, only to name a few: they all use their hidden magic. What are they? They are… Java’s dynamic proxies. Everyone knows about the GOFProxy design pattern: Allows for object level access control by acting as a pass through entity or a placeholder object. Likewise, in Java, a dynamic proxy is an instance that acts as a pass through to the real object. This powerful pattern let you change the real behaviour from a caller point of view since method calls can be intercepted by the proxy. Pure Java proxies Pure Java proxies have some interesting properties: They are based on runtime implementations of interfaces They are public, final and not abstract They extend java.lang.reflect.Proxy In Java, the proxy itself is not as important as the proxy’s behaviour. The latter is done in an implementation of java.lang.reflect.InvocationHandler. It has only a single method to implement: public Object invoke(Object proxy, Method method, Object[] args) proxy: the proxy instance that the method was invoked on method: the Method instance corresponding to the interface method invoked on the proxy instance. The declaring class of the Method object will be the interface that the method was declared in, which may be a superinterface of the proxy interface that the proxy class inherits the method through args: an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or null if interface method takes no arguments. Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper class, such as java.lang.Integer or java.lang.Boolean Let’s take a simple example: suppose we want a List that can’t be added elements to it. The first step is to create the invocation handler: public class NoOpAddInvocationHandler implements InvocationHandler { private final List proxied; public NoOpAddInvocationHandler(List proxied) { this.proxied = proxied; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith("add")) { return false; } return method.invoke(proxied, args); } } The invoke method will intercept method calls and do nothing if the method starts with “add”. Otherwise, it will the call pass to the real proxied object. This is a very crude example but is enough to let us understand the magic behind. Notice that in case you want your method call to pass through, you need to call the method on the real object. For this, you’ll need a reference to the latter, something the invoke method does not provide. That’s why in most cases, it’s a good idea to pass it to the constructor and store it as an attribute. Note: under no circumstances should you call the method on the proxy itself since it will be intercepted again by the invocation handler and you will be faced with a StackOverflowError. To create the proxy itself: List proxy = (List) Proxy.newProxyInstance( NoOpAddInvocationHandlerTest.class.getClassLoader(), new Class[] { List.class }, new NoOpAddInvocationHandler(list)); The newProxyInstance method takes 3 arguments: the class loader an array of interfaces that will be implemented by the proxy the power behind the throne in the form of the invocation handler Now, if you try to add elements to the proxy by calling any add methods, it won’t have any effect. CGLib proxies Java proxies are runtime implementations of interfaces. Objects do not necessarily implement interfaces, and collections of objects do not necessarily share the same interfaces. Confronted with such needs, Java proxies fail to provide an answser. Here begins the realm of CGLib. CGlib is a third-party framework, based on bytecode manipulation provided by ASM that can help with the previous limitations. A word of advice first, CGLib’s documentation is not on par with its features: there’s no tutorial nor documentation. A handful of JavaDocs is all you can count on. This said CGLib waives many limitations enforced by pure Java proxies: you are not required to implement interfaces you can extend a class For example, since Hibernate entities are POJO, Java proxies cannot be used in lazy-loading; CGLib proxies can. There are matches between pure Java proxies and CGLib proxies: where you use Proxy, you use net.sf.cglib.proxy.Enhancer class, where you use InvocationHandler, you use net.sf.cglib.proxy.Callback. The two main differences is that Enhancer has a public constructor and Callback cannot be used as such but only through one of its subinterfaces: Dispatcher: Dispatching Enhancer callback FixedValue: Enhancer callback that simply returns the value to return from the proxied method LazyLoader: Lazy-loading Enhancer callback MethodInterceptor: General-purpose Enhancer callback which provides for “around advice” NoOp: Methods using this Enhancer callback will delegate directly to the default (super) implementation in the base class As an introductory example, let’s create a proxy that returns the same value for hash code whatever the real object behind. The feature looks like a MethodInterceptor, so let’s implement it as such:
May 11, 2010
by Nicolas Fränkel
· 153,558 Views · 1 Like
article thumbnail
Concurrent JUnit Tests With RunnerScheduler
JUnit has a very cool feature called RunnerScheduler. A custom RunnerScheduler can be set on a ParentRunner to control how child elements are executed. If you are on a Suite, the child elements would be each test class. If you are on a simple class (Junit4 runner) the child elements are all the test methods. Thus, with a RunnerScheduler you are able to control the overall execution of your test flow. As an example, suppose you want to execute your test methods concurrently on a given test. You could have a runner called ConcurrentJunitRunner. @RunWith(ConcurrentJunitRunner.class) @Concurrent(threads = 6) public final class ATest { @Test public void test0() throws Throwable { printAndWait(); } @Test public void test1() throws Throwable { printAndWait(); } @Test public void test2() throws Throwable { printAndWait(); } @Test public void test3() throws Throwable { printAndWait(); } @Test public void test4() throws Throwable { printAndWait(); } @Test public void test5() throws Throwable { printAndWait(); } @Test public void test6() throws Throwable { printAndWait(); } @Test public void test7() throws Throwable { printAndWait(); } @Test public void test8() throws Throwable { printAndWait(); } @Test public void test9() throws Throwable { printAndWait(); } void printAndWait() throws Throwable { int w = new Random().nextInt(1000); System.out.println(String.format("[%s] %s %s %s", Thread.currentThread().getName(), getClass().getName(), new Throwable().getStackTrace()[1].getMethodName(), w)); Thread.sleep(w); } } The @Concurrent annotation controls the thread count. The runner implements a custom RunnerScheduler which delegates to a thread pool and Java Concurrent API each test method. Thus all test are executed concurrently and the RunnerScheduler waits for all tests to finish. But wait ! There's even more ! This runner just makes the test methods of a class runnable concurrently. But if you have a lot of tests in your project, you would probably want to also run all these tests concurrently ! Here come the ConcurrentSuite runner ! @RunWith(ConcurrentSuite.class) @Suite.SuiteClasses({ATest.class, ATest2.class, ATest3.class}) public class MySuite { } This runner will run all the tests in your suite. If a test class uses the ConcurrentJunitRunner or is annotated by @Concurrent then its method will be run concurrently. Otherwise it will be run sequentially. The runners provided on this article demonstrates how to use a custom RunnerScheduler, but can be safely used in any projects and be modified according to your needs. All the code for this article can be found here. You can also checkout the classes: svn co http://mycila.googlecode.com/svn/sandbox/ sandbox Mathieu Carbou http://blog.mycila.com/ http://www.junit.org/node/589
May 10, 2010
by Mathieu Carbou
· 39,438 Views · 2 Likes
article thumbnail
Two Ways to Convert Java Map to String
This article shows 2 ways to convert Java Map to String. Approach 1: simple, lightweight – produces query string like output, but restrictive. Approach 2: uses Java XML bean serialization, more robust but produces overly verbose output. Approach 1: Map to query string format Approach 1 converts a map to a query-string like output. Here’s what an output looks like: name1=value1&name2=value2 Full Code: import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; public class MapUtil { public static String mapToString(Map map) { StringBuilder stringBuilder = new StringBuilder(); for (String key : map.keySet()) { if (stringBuilder.length() > 0) { stringBuilder.append("&"); } String value = map.get(key); try { stringBuilder.append((key != null ? URLEncoder.encode(key, "UTF-8") : "")); stringBuilder.append("="); stringBuilder.append(value != null ? URLEncoder.encode(value, "UTF-8") : ""); } catch (UnsupportedEncodingException e) { throw new RuntimeException("This method requires UTF-8 encoding support", e); } } return stringBuilder.toString(); } public static Map stringToMap(String input) { Map map = new HashMap(); String[] nameValuePairs = input.split("&"); for (String nameValuePair : nameValuePairs) { String[] nameValue = nameValuePair.split("="); try { map.put(URLDecoder.decode(nameValue[0], "UTF-8"), nameValue.length > 1 ? URLDecoder.decode( nameValue[1], "UTF-8") : ""); } catch (UnsupportedEncodingException e) { throw new RuntimeException("This method requires UTF-8 encoding support", e); } } return map; } } Example usage code Map map = new HashMap(); map.put("color", "red"); map.put("symbols", "{,=&*?}"); map.put("empty", ""); String output = MapUtil.mapToString(map); Map parsedMap = MapUtil.stringToMap(output); for (String key : map.keySet()) { Assert.assertEquals(parsedMap.get(key), map.get(key)); } Output with Approach 1: symbols=%7B%2C%3D%26*%3F%7D&color=red∅= Caveat Only supports String keys and values. Due to the nature of serialization, null keys and values are not supported. Null will be converted to an empty String. This is because there is no way to distinguish between a null and an empty String in the serialized form. If you need support for null keys and values, use java.beans.XMLEncoder as shown below. Approach 2: Java Bean XMLEncoder: Map to String Java provides XMLEncoder and XMLDecoder classes as part of the java.beans package as a standard way to serialize and deserialize objects. This Map map = new HashMap(); map.put("color", "red"); map.put("symbols", "{,=&*?}"); map.put("empty", ""); ByteArrayOutputStream bos = new ByteArrayOutputStream(); XMLEncoder xmlEncoder = new XMLEncoder(bos); xmlEncoder.writeObject(map); xmlEncoder.flush(); String serializedMap = bos.toString() System.output.println(serializedMap); Output with Approach 2 The serialized value is shown below. As you can see this is more verbose, but can accommodate different data types and null keys and values. symbols {,=&*?} color red empty symbols {,=&*?} color red empty Java Bean XMLDecoder: String to Map XMLDecoder xmlDecoder = new XMLDecoder(new ByteArrayInputStream(serializedMap.getBytes())); Map parsedMap = (Map) xmlDecoder.readObject(); for (String key : map.keySet()) { Assert.assertEquals(parsedMap.get(key), map.get(key)); } Summary While Java provides a standard (and overly verbose) way to serialize and deserialize objects, this articles discusses an alternative lightweight way to convert a Java Map to String and back. If you are serializing a map with non-null String keys and values, then you should be able to use this alternative way, otherwise use the Java bean serialization. From http://www.vineetmanohar.com/2010/05/07/2-ways-to-convert-java-map-to-string
May 8, 2010
by Vineet Manohar
· 139,136 Views
article thumbnail
Finalization and Phantom References
Memory management is done automatically in Java. The programmer doesn't need to worry about reference objects that have been released. One downside to this approach is that the programmer cannot know when a particular object will be collected. Moreover, the programmer has no control over memory management. However, the java.lang.ref package defines classes that provide a limited degree of interaction with the garbage collector. The concrete classes SoftReference, WeakReferenceand PhantomReference are subclasses of Reference that interact with the garbage collector in different ways. In this article we will discuss the functionality and behavior of the PhantomReferenceclasses and see how it can be used. Problem with Finalization To perform some postmortem cleanup on objects that garbage collector consider as unreachable, one can use finalization. This feature can be utilized to reclaim native resources associated with an object. However, finalizers have many problems associated. Firstly, we can’t foresee the call of finalize(). Since the Garbage Collection is unpredictable, the calling of finalize() cannot be predicted. There is no guarantee that the object will be garbage collected. The object might never become eligible for GC because it could be reachable through the entire lifetime of the JVM. It is also possible that no garbage collection actually runs from the time the object became eligible and before JVM stops. Secondly, Finalization can slowdown an application. Managing objects with a finalize() method takes more resources from the JVM than normal objects. As per doc, You should also use finalization only when it is absolutely necessary. Finalization is a nondeterministic -- and sometimes unpredictable -- process. The less you rely on it, the smaller the impact it will have on the JVM and your application In Effective Java, 2nd ed., Joshua Bloch says, there is a severe performance penalty for using finalizers... So what should you do instead of writing a finalizer for a class whose objects encapsulate resources that require termination, such as files or threads? Just provide an explicit termination method, and require clients of the class to invoke this method on each instance when it is no longer needed. In short, Finalize() isn't used often, and also there is no much reason to use it. If we have a class with methods like close() or cleanup() and that should be called once user done with the object then placing these methods call in finalize() can be used as a safety measure, but not necessary. Phantom Reference phantom reachable, phantomly reachable An object is phantom reachable if it is neither strongly nor softly nor weakly reachable and has been finalized and there is a path from the roots to it that contains at least one phantom reference. The PhantomReference constructor accepts two arguments: referent - the object the new phantom reference will refer to q - the reference is registered with the given queue. The argument q represents the instance of the ReferenceQueue class. If the garbage collector determines that the referent of a phantom reference is phantom reachable, then the PhantomReference will be added to this ReferenceQueue. You can then retrieve the PhantomReference by using the remove() methods of the ReferenceQueue class. Consider the following example, ReferenceQueue q = new ReferenceQueue(); PhantomReference pr = new PhantomReference(object, referenceQueue); // Later on another point Reference r = q.remove(); // Now, clear up any thing you want PhantomReference, when to use? Phantom Reference can be used in situations, where sometime using finalize() is not sensible thing to do.This reference type differs from the other types defined in java.lang.ref Package because it isn't meant to be used to access the object, but as a signal that the object has already been finalized, and the garbage collector is ready to reclaim its memory. As per API doc, Phantom reference objects, which are enqueued after the collector determines that their referents may otherwise be reclaimed. Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism. People usually attempt to use finalize() method to perform postmortem cleanup on objects which usually not advisable. As mentioned earlier, Finalizers have an impact on the performance of the garbage collector since Objects with finalizers are slow to garbage collect. Phantom references are safe way to know an object has been removed from memory. For instance, consider an application that deals with large images. Suppose that we want to load a big image in to memory when large image is already in memory which is ready for garbage collected. In such case, we want to wait until the old image is collected before loading a new one. Here, the phantom reference is flexible and safely option to choose. The reference of the old image will be enqueued in the ReferenceQueue once the old image object is finalized. After receiving that reference, we can load the new image in to memory. Similarly we can use Phantom References to implement a Connection Pool. We can easily gain control over the number of open connections, and can block until one becomes available. Reference Objects and Garbage Collection Soft Reference can be garbage collected after there are no strong references to the referent. However, it typically retained until memory is low. All softly reachable objects will be reclaimed before an OutOfMemoryException is thrown. Therefore, it can be used to implement caches of objects that can be recreated if needed. Weak Reference can be garbage collected when there are no strong or soft references to the referent. However, unlike Soft Reference, they are garbage collected on a gc even when memory is abundant. They often can be used for “canonical mappings” where each object has a unique identifier (one-to-one), and in collections of “listeners” On the other hand, Phantom Reference, can be garbage collected once there are no strong, soft or weak references to the referent. When object is phantomly reachable, it means the object is already finalized but not yet reclaimed, so the GC enqueues it in a ReferenceQueue for post-finalization processing. As per Java Doc, Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable. A PhantomReference is not automatically cleared when it is enqueued, so when we remove a PhantomReference from a ReferenceQueue, we must call its clear() method or allow the PhantomReference object itself to be garbage-collected. Summary In short, we should avoid finalize() as much as possible. There is no guarantee if the finalize() method will be called promptly following garbage collection, or even it will be called. If the finalize method runs for a long time, it can delay execution of finalize methods of other objects. Instead of relying on finalize(), we can use reference types define in java.lang.ref package. Beside java.lang.ref package, Google collection library also provide some alternatives. For example, FinalizablePhantomReference extends java.lang.ref.PhantomReference, deals with processing the ReferenceQueue and call back a convenient method finalizeReferent(). So if we want to do some cleanup operation when an object is claimed by the garbage collector (GC) then we just need to override the finalizeReferent() method. Resources Garbage Collection PhantomReference http://docstore.mik.ua/orelly/java-ent/jnut/ch13_01.htm Understanding Weak References - See more at: http://muhammadkhojaye.blogspot.com/2010/05/understanding-phantom-references.html
May 7, 2010
by Muhammad Ali Khojaye
· 65,724 Views · 9 Likes
article thumbnail
Add Comments and Javadocs in Eclipse With a Single Keystroke
When you want to work with comments in Eclipse, you could use the slow way of moving to the start of the line, pressing // and then repeating this for all the lines you have. Or you could use the quick way of adding a comment with a single keystroke no matter where the cursor’s positioned in the statement. The same goes for Javadocs – there are just too many things to type before you can start commenting the good stuff. That’s why Eclipse also has a shortcut that let’s you add Javadoc to a field, method or class. Keyboard shortcuts for comments and JavaDocs Here are the keyboard shortcuts for manipulating comments. Shortcut Command Description Ctrl+/ Toggle Comment Add/remove line comments (//…) from the current line. The position of the cursor can be anywhere on the line. Works with multiple selected lines as well. Ctrl+Shift+/ Add Block Comment Wrap the selected lines in a block comment (/*… */). Ctrl+Shift+\ Remove Block Comment Remove a block comment (/*… */) surrounding the selected lines. Alt+Shift+J Add Javadoc Comment Add a Javadoc comment to the active field/method/class. See the notes below for more details on where to position the cursor. Bear the following in mind when using Add Javadoc comment (Alt+Shift+J): To add a comment to a field, position the cursor on the field declaration. To add a comment to a method, position the cursor anywhere in the method or on its declaration. To add a comment to a class, the easiest is to position the cursor on the class declaration. Also works if you’re in the class, but not in a method, field or nested type. The Javadoc comment inserted is based on the Code Templates defined under Window > Preferences > Java > Code Style > Code Templates. If you expand the Comments section, you can change the default for Fields, Methods, Types (eg. classes), etc. Here’s a video to give you an idea of how fast and easy it is to add/remove comments using these shortcuts. The video shows toggling of single line comments, block comments and also adding a Javadoc comment to the method and class. Once I’ve commented out lines, I often find myself copying them and moving them around (eg. to try different variations of the code). You can do this faster by moving and copying lines using with a single keystroke. You can also have Eclipse format the comments whenever you save, saving you formatting time. From http://eclipseone.wordpress.com/2010/05/05/add-comments-and-javadocs-in-eclipse-with-a-single-keystroke/
May 6, 2010
by Byron M
· 178,201 Views · 2 Likes
article thumbnail
Mediator Pattern Tutorial with Java Examples
Learn the Mediator Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
April 26, 2010
by James Sugrue
· 113,642 Views · 3 Likes
article thumbnail
Grouping Tests Using JUnit Categories
In a well-organized build process, you want lightning-fast unit tests to run first, and provide whatever feedback they can very quickly. A nice way to do this is to be able to class your tests into different categories. For example, this can make it easier to distinguish between faster running unit tests, and slower tests such as integration, performance, load or acceptance tests. This feature exists in TestNG, but, until recently, not in JUnit. Indeed, this has been missing from the JUnit world for a long time. Using JUnit, I typically use test names (integration tests end in 'IntegrationTest', for example) or packages to identify different types of test. It is easy to configure a build script using Maven or Ant to run different types of test at different points in the build lifecycle. However it would be nice to be able to do this in a more elegant manner. JUnit 4.8 introduced a new feature along these lines, called Categories. However, like most new JUnit features, it is almost entirely undocumented. In this article we'll see how it works and what it can do for you. In JUnit 4.8, you can define your own categories for your tests. Categories are implemented as classes or interfaces. Since they simply act as markers, I prefer to use interfaces. One such category interface might look like this: public interface IntegrationTests {} You can also use inheritance to organize your test categories: public interface SlowTests {} public interface IntegrationTests extends SlowTests {} public interface PerformanceTests extends SlowTests {} So far so good. Now you can use these categories in your tests. In this example we flag a particular test class as containing integration tests: @Category(IntegrationTests.class) public class AccountIntegrationTest { @Test public void thisTestWillTakeSomeTime() { ... } @Test public void thisTestWillTakeEvenLonger() { .... } } You can also flag individual test methods if you prefer: public class AccountTest { @Test @Category(IntegrationTests.class) public void thisTestWillTakeSomeTime() { ... } @Test @Category(IntegrationTests.class) public void thisTestWillTakeEvenLonger() { ... } @Test public void thisOneIsRealFast() { ... } } To run tests in a particular category, you need to set up a test suite. In JUnit 4, a test suite is essentially an empty annotated class. To run only tests in a particular category, you use the @Runwith(Categories.class) annotation, and specify what category you want to run using the @IncludeCategory annotation @RunWith(Categories.class) @IncludeCategory(SlowTests.class) @SuiteClasses( { AccountTest.class, ClientTest.class }) public class LongRunningTestSuite {} You can also ask JUnit not to run tests in a particular category using the @ExcludeCategory annotation @RunWith(Categories.class) @ExcludeCategory(SlowTests.class) @SuiteClasses( { AccountTest.class, ClientTest.class }) public class UnitTestSuite {} Test categories are great if you use JUnit test suites. I haven't used test suites for years: Maven can find all my tests by itself, thank you very much, so I don't have to remember to add my test classes to the right test suite each time a create a new one. However, test suites do give you finer control over what order your tests are executed in, so you might still find them useful in that regard. Once you've done this, it is then easy to run tests in a particular category from within your IDE simply by running the test suite. On the tooling and build automation side of things, JUnit categories are not supported as well as TestNG groups. For example, the Maven surefire plugin lets you specify the TestNG groups you want to run in a particular phase, but no such support exists as yet for JUnit categories. You can of course configure the Surefire plugin to run a particular test suite (or test suites) in a particular phase, but it doesn't dispense you with the need to write and maintain a test suite. So test categories are great, but having to run them via a test suite (and to remember to add new test classes to the test suite) seems a bit clunky in these days of annotations and reflection. From http://weblogs.java.net/blog/johnsmart/archive/2010/04/25/grouping-tests-using-junit-categories-0
April 26, 2010
by John Ferguson Smart
· 22,285 Views
article thumbnail
“When a class with type parameters is not a parameterized class” – a Java Generics Puzzler
while recently fiddling with some more runtime generic type extraction for deployit , i was caught out by some unexpected behaviour by the reflection api. a check of the javadocs quickly revealed that i had once again been too hasty in relying on "common sense". still, the case seems sufficiently unintuitive to merit discussion. in this case, the issue centres on the interplay between class.gettypeparameters and parameterizedtype . the gist of the code looks something like: interface spying {} // small class hierarchy class person {} class professional extends person {} class agent extends professional {} class assassin extends professional {} class bystander extends person {} ... person jbond = new agent(); system.out.println("generic superclass type argument: " + trygetsuperclassgenerictypeparam(jbond)); person joepublic = new bystander(); system.out.println("generic superclass type argument: " + trygetsuperclassgenerictypeparam(joepublic)); person oddjob = new assassin(); system.out.println("generic superclass type argument: " + trygetsuperclassgenerictypeparam(oddjob)); ... type trygetsuperclassgenerictypeparam(object obj) { class clazz = obj.getclass(); class superclass = clazz.getsuperclass(); // elvis would be preferred, but for the sake of clarity... if (superclass.gettypeparameters().length > 0) { return ((parameterizedtype) clazz.getgenericsuperclass()).getactualtypearguments()[0]; } else { return null; } } so...what happens? trygetsuperclassgenerictypeparam is where the action happens. it seems fairly straightforward: see if the object's superclass is generic (i.e. takes type parameters) and, if so, cast its type representation to parameterizedtype to extract the actual value for the type parameter. if the superclass is not generic, simply return null. when this code is run, the first two invocations of trygetsuperclassgenerictypeparam result in the expected: generic superclass type argument: interface spying generic superclass type argument: null what about the third one? well, given the fact that we've omitted to specify a generic type parameter for professional we might assume 1 that we'd also get null. the actual output, however, is: exception in thread "main" java.lang.classcastexception: java.lang.class cannot be cast to java.lang.reflect.parameterizedtype at trygetsuperclassgenerictypeparam(...) huh? in order to figure out what's going on here, let's have a look at the javadoc for class.gettypeparameters: returns an array of typevariable objects that represent the type variables declared by the generic declaration represented by this genericdeclaration object, in declaration order. returns an array of length 0 if the underlying generic declaration declares no type variables. in other words, this is returning class-level information about the declaration of, in our case, the professional class, which of course does have a type parameter. however, if we look at class.getgenericsuperclass 2 , which we invoke next, we find that it: returns the type representing the direct superclass of the entity [...] represented by this class. if the superclass is a parameterized type, the type object returned must accurately reflect the actual type parameters used in the source code. here, the information returned is specific to the actual declaration of the class, which may (or may not, as in our case) specify type paramaters for its superclass. and therein lies the problem: professional.class.gettypearguments looks at the declaration of the professional class, discovering a type argument, whereas assassin.class.getgenericsuperclass looks at the occurrence of professional in the declaration of assassin and discovers no type parameters. hence, it returns a class rather than a parameterizedtype and blows up our code. ergo to cut a long story short: if an object's superclass has type arguments as determined by class.gettypearguments that does not mean that object.getclass().getgenericsuperclass() will be a parameterizedtype. footnotes read "i assumed" it's a pity that class.getgenericsignature , which determines the "generic or not" behaviour of class.getgenericsuperclass, is private, native and undocumented. from http://blog.xebia.com/2010/04/22/when-a-class-with-type-parameters-is-not-a-parameterized-class-a-java-generics-puzzler/
April 22, 2010
by Andrew Phillips
· 28,494 Views
article thumbnail
Memento Pattern Tutorial with Java Examples
Learn the Memento Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
April 21, 2010
by James Sugrue
· 63,371 Views · 2 Likes
article thumbnail
PubSub with Redis and Akka Actors
Redis (the version on the trunk) offers publish/subscribe based messaging. This is quite a big feature compared to the typical data structure oriented services that it had been offering so far. This also opens up lots of possibilities to use Redis as a messaging engine of a different kind. The sender and the receiver of the messages are absolutely decoupled from each other in the sense that senders do not send messages to specific receivers. Publishers publish messages on specific channels. Subscribers who subscribe to those channels get them and can take specific actions on them. As Salvatore notes in his weekly updates on Redis, this specific feature has evolved from lots of user requests who had been asking for a general notification mechanism to trap changes in the key space. Redis already offers BLPOP (Blocking list pop operation) for similar use cases. But still it's not sufficient to satisfy the needs of a general notification scheme. Salvatore explains it in more details in his blog post. I have been working on a Scala client, which I forked from Alejandro Crosa's repository. I implemented pubsub very recently and also have integrated it with Akka actors. The full implementation of the pubsub client in Scala is in my github repository. And if you like to play around with the Akka actor based implementation, have a look at the Akka repository. You define your publishers and subscribers as actors and exchange messages over channels. You can define your own callbacks as to what you would like to do when you receive a particular message. Let's have a look at a sample implementation at the client level .. I will assume that you want to implement your own pub/sub application on top of the Akka actor based pubsub substrate that uses the redis service underneath. Implementing the publisher interface is easy .. here is how you can bootstrap your own publishing service .. object Pub { println("starting publishing service ..") val p = new Publisher(new RedisClient("localhost", 6379)) p.start def publish(channel: String, message: String) = { p ! Publish(channel, message) } } The publish method just sends a Publish message to the Publisher. Publisher is an actor defined in Akka as follows: class Publisher(client: RedisClient) extends Actor { def receive = { case Publish(channel, message) => client.publish(channel, message) reply(true) } } The subscriber implementation is a bit more complex since you need to register your callback as to what you would like to do when you receive a specific type of message. This depends on your use case and it's your responsibility to provide a proper callback function downstream. Here is a sample implementation for the subscriber. We need two methods to subscribe and unsubscribe from channels. Remember in Redis the subscriber cannot publish - hence our Sub cannot do a Pub. object Sub { println("starting subscription service ..") val s = new Subscriber(new RedisClient("localhost", 6379)) s.start s ! Register(callback) def sub(channels: String*) = { s ! Subscribe(channels.toArray) } def unsub(channels: String*) = { s ! Unsubscribe(channels.toArray) } def callback(pubsub: PubSubMessage) = pubsub match { //.. } } I have not yet specified the implementation of the callback. How should it look like ? The callback will be invoked when the subscriber receives a specific type of message. According to Redis specification, the types of messages which a subscriber can receive are: a. subscribe b. unsubscribe c. message Refer to the Redis documentation for details of these message formats. In our case, we model them as case classes as part of the core Redis client implementation .. sealed trait PubSubMessage case class S(channel: String, noSubscribed: Int) extends PubSubMessage case class U(channel: String, noSubscribed: Int) extends PubSubMessage case class M(origChannel: String, message: String) extends PubSubMessage Our callback needs to take appropriate custom action on receipt of any of these types of messages. The following can be one such implementation .. It is customized for a specific application which treats various formats of messages and gives appropriate application dependent semantics .. def callback(pubsub: PubSubMessage) = pubsub match { case S(channel, no) => println("subscribed to " + channel + " and count = " + no) case U(channel, no) => println("unsubscribed from " + channel + " and count = " + no) case M(channel, msg) => msg match { // exit will unsubscribe from all channels and stop subscription service case "exit" => println("unsubscribe all ..") r.unsubscribe // message "+x" will subscribe to channel x case x if x startsWith "+" => val s: Seq[Char] = x s match { case Seq('+', rest @ _*) => r.subscribe(rest.toString){ m => } } // message "-x" will unsubscribe from channel x case x if x startsWith "-" => val s: Seq[Char] = x s match { case Seq('-', rest @ _*) => r.unsubscribe(rest.toString) } // other message receive case x => println("received message on channel " + channel + " as : " + x) } } Note in the above implementation we specialize some of the messages to give additional semantics. e.g. if I receive a message as "+t", I will interpret it as subscribing to the channel "t". Similarly "exit" will unsubscribe me from all channels. How to run this application ? I will assume that you have the Akka master with you. Also you need to have a version of Redis running that implements pubsub. You can start the subscription service using the above implementation and then use any other Redis client to publish messages. Here's a sample recipe for a run .. Prerequisite: Need Redis Server running (the version that supports pubsub) 1. Download redis from http://github.com/antirez/redis 2. build using "make" 3. Run server as ./redis-server For running this sample application :- Starting the Subscription service 1. Open up another shell similarly as the above and set AKKA_HOME 2. cd $AKKA_HOME 3. sbt console 4. scala> import sample.pubsub._ 5. scala> Pub.publish("a", "hello") // the first shell should get the message 6. scala> Pub.publish("c", "hi") // the first shell should NOT get this message Another publishing client using redis-cli Open up a redis-client from where you installed redis and issue a publish command ./redis-cli publish a "hi there" ## the first shell should get the message Have fun with the message formats 1. Go back to the first shell 2. Sub.unsub("a") // should unsubscribe the first shell from channel "a" 3. Study the callback function defined below. It supports many other message formats. 4. In the second shell window do the following: scala> Pub.publish("b", "+c") // will subscribe the first window to channel "c" scala> Pub.publish("b", "+d") // will subscribe the first window to channel "d" scala> Pub.publish("b", "-c") // will unsubscribe the first window from channel "c" scala> Pub.publish("b", "exit") // will unsubscribe the first window from all channels The full implementation of the above is there as a sample project in Akka master. And in case you are not using Akka, I also have a version of the above implemented using Scala actors in the scala-redis distribution. Have fun!
April 20, 2010
by Debasish Ghosh
· 15,616 Views
article thumbnail
Using Hibernate Validator to Cover Your Validation Needs
Recently I had to choose a validation framework or write one by myself. First I thought, no big deal, validation is not a complicated issue. But the more you think about it, the more you come to the conclusion that it is not as shallow as you think – you need to validate different types, you have different groups and many more issues… In short, writing a validation framework by yourself demands a lot of work. Luckily, JSR 303 solves this and the Hibernate implementation of the JSR does a pretty good job. Hibernate Validator is a JSR 303 implementation for bean validation. The way to work with this framework is first, to define constraints for java bean fields, and then, validating the bean. JSR 303 JSR 303 – defines a metadata model and API for entity validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML. The API is not tied to a specific application tier or programming model. It is specifically not tied to either the web tier or the persistence tier, and is available for both server-side application programming, as well as for rich client Swing application developers. Hibernate Validator features Defining validation data using annotation and/or XML. Full object validation (including inner objects using recursion) Create customized constraints and validators. Customized error messages. Define groups(profiles). Create a Traversable Resolver. Using constraints Using XML Here is a simple example of a constraint using xml: com.mytest 2 In this example the field x can not be null. The field y can not be less than 2. Notice that the “Min” constraint has inner element – “value”. Notice the tag “”. It indicates the root path of all the beans. See also directions on how to load the XML file while using the validator. Using annotations Here is a simple code example: public class MyBean{@NotNullString x;@Min(2)int y;} This example is the equivalent to the previous xml example. Using both Using both annotations and XML constraints is possible. By default if you are using both only the XML is taken, unless you are using the attribute ‘ignore-annotations’ in the XML. Example: com.mytest.beans 2 2 Notice that the attribute ignore-annotations appears twice – for a bean and for a field. The default for a bean is ignore-annotations=”true” – this means that if you have an XML constraint for a bean, it will cancel the attribute constraint, Unless you will indicate that by ignore-annotations=”false” (look at the example). The default for a field is ignore-annotations=”false”. This means that by default annotations for a field are stronger (this is of course after you indicated that that the bean itself wont ignore annotations). If you wont that the XML will be stronger than you have to indicate that by ignore-annotations=”true” (look at the example in the “x2″ constraint). Existing constraints These constraints are a part of the hibernate validation framework: Constraint path Parameters javax.validation.constraints.AssertTrue (none) javax.validation.constraints.AssertFalse (none) javax.validation.constraints.NotNull (none) javax.validation.constraints.Null (none) javax.validation.constraints.Max value(mandatory) javax.validation.constraints.Min value(mandatory) javax.validation.constraints.DecimalMax value(mandatory) javax.validation.constraints.DecimalMin value(mandatory) javax.validation.constraints.Pattern regexp(mandatory) flags(optional) javax.validation.constraints.Past (none) javax.validation.constraints.Future (none) javax.validation.constraints.Size min(optional) max(optional) javax.validation.constraints.Digits integer(mandatory) fraction(mandatory) org.hibernate.constraints.Email (none) org.hibernate.constraints.Length min(optional) max(optional) org.hibernate.constraints.NotEmpty (none) org.hibernate.constraints.Range min(optional) max(optional) Inner objects constraints If you have nested beans (beans which contain other beans) you can easily let the system validate also the inner objects by using the constraint ‘valid’. XML example: com.mytest.beans Annotation example: public class MyBean{@Valid //inner bean to be validated separatelyprivate InnerBean innerBean; public InnerBean getInnerBean() {return innerBean;}public void setInnerBean(InnerBean innerBean) {this.innerBean = innerBean;}public class InnerBean { @NotNullString xx; public String getXx() {return xx;}public void setXx(String xx) {this.xx = xx;} Validating Example of a simple validation: ValidatorFactory factory = Validation.buildDefaultValidatorFactory();Validator validator = factory.getValidator();Set> constraintViolations = validator.validate(bean); Loading a constraints XML file As mentioned, you don’t have to use an XML file for defining constraints, you can just use annotations. But if you do want an XML file, you will have to load the file. Example: Configuration config = Validation.byDefaultProvider().configure();FileInputStream in = new FileInputStream( new File("resources/demo-constraints.xml"));config.addMapping(in);// Building the customized factory// (along with the changed configuration)ValidatorFactory factory = config.buildValidatorFactory();Validator validator = factory.getValidator(); The result The result(as you can see in the example above) is a collection of ConstraintViolation. Each ConstraintViolation holds the problematic field, it’s value and the error message itself. Example of reading the result: Set> constraintViolations = validator.validate(bean);//printing the resultsfor (ConstraintViolation constraintViolation : constraintViolations) {System.out.println(constraintViolation.getPropertyPath() + " -> " +constraintViolation.getMessage());} This object can be easily transformed to a more generic object like ValidationException or CyotaSoapException and so on. Customized constraints and validators If you want to create a new constraint you will have to create the constraint annotation interface and the validator class. Creating the constraint interface Here is a simple constraint example @Target( { METHOD, FIELD, ANNOTATION_TYPE })@Retention(RUNTIME)@Constraint(validatedBy = MyValidator.class)@Documentedpublic @interface MyConstraint{// These next parameters exist in every constraintString message() default "{com.mytest.MyConstraint.message}";Class[] groups() default {};Class[] payload() default {};// These next parameters are added// They are the constraint's attributesString myOptionalValue() default ""; //this parameter has a default valueString myMustValue(); //this parameters need to get input from the user} Notice the @Constraint annotation. It signifies the class that suppose to validates this constraint. Notice the message class member. It holds an error message or, like in this case, an error code. It will later be interpreted as a literal error message. The payload member holds payload objects. These objects carry additional data attached to the constraints that can be fetched when validating. Nested constraints You can also overload constraints very easily. For example, let’s say I want to create a new constraint which also checks that the value is not null. In this case, all I have to do is this: @Target( { METHOD, FIELD, ANNOTATION_TYPE })@Retention(RUNTIME)@Constraint(validatedBy = MyValidator.class)@Documented@NotNullpublic @interface MyConstraint{String message() default "{com.mytest.MyConstraint.message}";Class[] groups() default {};Class[] payload() default {};} In the example, notice the @NotNull annotation. Creating the validator class Here is an example of a simple validator: public class MyValidatorimplements ConstraintValidator {MyConstraint MyConstraint;/** * This function recives the constraint instance * (along with the user values) */public void initialize(MyConstraint MyConstraint) {this.MyConstraint=MyConstraint;}/** * The value is the actual object instance. * */public boolean isValid(String value, ConstraintValidatorContext arg1) { //using input from the userreturn value!=null && value.startsWith(MyConstraint.myMustValue());} The above code shows an example of a validator which validates that the value of the given string starts with a given character. The validator implements the ConstraintValidator interface. Notice that the constraint is given as input to the initialize() function. The value itself is input to the isValid() function Customizing error messages Each error has an error template. The error template is defined in the constraint annotation interface. This error template is later translated into an error message. The actual error message may be defined in 2 places: 1. Inside the constraint deceleration. The error message be defined when defining the constraint, whether it you are using XML or annotations. XML example: x is too small 2 Java example: public class MyBean{@Min(value = 2, message="x is too small")private String x;public String getX() {return x;}public void setX(String x) {this.x = x;} 2. Using a separate properties message. You may want to load a separate properties file containing the error messages according to the error template. loading the messages properties file is done using the validation factory configuration: Configuration config = Validation.byDefaultProvider().configure();// Using a properties file for customized error messagesFileInputStream in = new FileInputStream(new File("resources/messages.properties"));ResourceBundleMessageInterpolator messageInterpolator =new ResourceBundleMessageInterpolator( new PropertyResourceBundle(in));// Setting a messages properties fileconfig.messageInterpolator(messageInterpolator);in = new FileInputStream(new File("resources/demo-constraints.xml"));config.addMapping(in);// Building the customized factory (along with the changed configuration)ValidatorFactory factory = config.buildValidatorFactory();Validator validator = factory.getValidator(); Using groups There may be occasions when you will want to create a single constraint but with different values for different situations. For example, let’s say you want to create a username field and let him a minimum constraint. But, one time it will have minimum of 5 characters and another time it will have minimum of 6 characters. For cases like this you will want to use groups. To do so, you will have to create a group, create constraints for that group and last, validate objects by attaching the group. Please follow the steps below Create a group To create a group you simply create a new interface. example: public interface MyBeanGroup{} Create a constraint for the group XML example: com.mytest.groups.MyBeanGroup Annotations example: public class MyBean{@NotNull(groups = MyBeanGroup.class)private String x; public String getX() {return x;}public void setX(String x) {this.x = x;} Validate an object using the group Set> constraintViolations = validator.validate(bean, MyBeanGroup.class); The default group The default group is javax.validation.groups.Default. If you don’t assign a constraint any group it applies to the default group. If you are validating an object without using any group, it is validated as a part of the default group. Groups inheritance You can also create an group inheritance tree. In this way, if you validate an object using a group it will prefer constraints that are defined to it. But if there are no such constraints, then it will also take the constraints of it’s parents. Example, this is a group which inherits the default group: public interface MyBeanGroupextends javax.validation.groups.Default{} All the constraints that are defined for that group will apply to it. But also all the constraints which do not apply to any group(and by which apply to the default group), will also apply to it, since it exteds the default group. Jar dependency validation-api-1.0.0.GA.jar hibernate-validator-4.0.2.GA slf4j-api-1.4.2.jar slf4j-simple-1.4.2.jar log4j-1.2.15.jar Only for java5 jaxb-xjc-2.1.6.jar jaxb-impl-2.1.6.jar jaxb-api-2.1.jar activation-1.1.jar geronimo-stax-api_1.0_spec-1.0.1.jar References JSR 303 specification- Bean validation Product main page Hibernate Validator documentation Download demo project from http://www.aviyehuda.com/
April 15, 2010
by Avi Yehuda
· 134,458 Views
article thumbnail
Debugging Hibernate Generated SQL
In this article, I will explain how to debug Hibernate’s generated SQL so that unexpected query results be traced faster either to a faulty dataset or a bug in the query. There’s no need to present Hibernate anymore. Yet, for those who lived in a cave for the past years, let’s say that Hibernate is one of the two main ORM frameworks (the second one being TopLink) that dramatically ease database access in Java. One of Hibernate’s main goal is to lessen the amount of SQL you write, to the point that in many cases, you won’t even write one line. However, chances are that one day, Hibernate’s fetching mechanism won’t get you the result you expected and the problems will begin in earnest. From that point and before further investigation, you should determine which is true: either the initial dataset is wrong or the generated query is or both if you’re really unlucky Being able to quickly diagnose the real cause will gain you much time. In order to do this, the greatest step will be viewing the generated SQL: if you can execute it in the right query tool, you could then compare pure SQL results to Hibernate’s results and assert the true cause. There are two solutions for viewing the SQL. Show SQL The first solution is the simplest one. It is part of Hibernate’s configuration and is heavily documented. Just add the following line to your hibernate.cfg.xml file: ... true The previous snippet will likely show something like this in the log: select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ Not very readable but enough to copy/paste in your favourite query tool. The main drawback of this is that if the query has parameters, they will display as ? and won’t show their values, like in the following output: select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=? and this_.PER_T_FIRST_NAME=? and this_.PER_T_LAST_NAME=?) If they’re are too many parameters, you’re in for a world of pain and replacing each parameter with its value will take too much time. Yet, IMHO, this simple configuration should be enabled in all environments (save production), since it can easily be turned off. Proxy driver The second solution is more intrusive and involves a third party product but is way more powerful. It consists of putting a proxy driver between JDBC and the real driver so that all generated SQL will be logged. It is compatible with all ORM solutions that rely on the JDBC/driver architecture. P6Spy is a driver that does just that. Despite its age (the last release dates from 2003), it is not obsolete and server our purpose just fine. It consists of the proxy driver itself and a properties configuration file (spy.properties), that both should be present on the classpath. In order to leverage P6Spy feature, the only thing you have to do is to tell Hibernate to use a specific driver: com.p6spy.engine.spy.P6SpyDriver ... This is a minimal spy.properties: module.log=com.p6spy.engine.logging.P6LogFactory realdriver=org.hsqldb.jdbcDriver autoflush=true excludecategories=debug,info,batch,result appender=com.p6spy.engine.logging.appender.StdoutLogger Notice the realdriver parameter so that P6Spy knows where to redirect the calls. With just these, the above output becomes: 1270906515233|3|0|statement|select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=? and this_.PER_T_FIRST_NAME=? and this_.PER_T_LAST_NAME=?)|select this_.PER_N_ID as PER1_0_0_, this_.PER_D_BIRTH_DATE as PER2_0_0_, this_.PER_T_FIRST_NAME as PER3_0_0_, this_.PER_T_LAST_NAME as PER4_0_0_ from T_PERSON this_ where (this_.PER_D_BIRTH_DATE=’2010-04-10′ and this_.PER_T_FIRST_NAME=’Johnny’ and this_.PER_T_LAST_NAME=’Be Good’) Of course, the configuration can go further. For example, P6Spy knows how to redirect the logs to a file, or to Log4J (it currently misses a SLF4J adapter but anyone could code one easily). If you need to use P6Spy in an application server, the configuration should be done on the application server itself, at the datasource level. In that case, every single use of this datasource will be traced, be it from Hibernate, TopLink, iBatis or plain old JDBC. In Tomcat, for example, put spy.properties in common/classes and update the datasource configuration to use P6Spy driver. The source code for this article can be found here. To go further: P6Spy official site Log4jdbc, a Google Code contender that aims to offer the same features From http://blog.frankel.ch/debugging-hibernate-generated-sql
April 13, 2010
by Nicolas Fränkel
· 30,817 Views
  • Previous
  • ...
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • ...
  • 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
×