<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4179812064174942414</id><updated>2011-11-27T16:32:43.431-08:00</updated><category term='Grails Portal WebFlow'/><category term='Architecture'/><category term='JAVA'/><category term='Maven'/><category term='Portal'/><category term='Spring Framework'/><category term='Grails'/><category term='IVY'/><category term='Build V.s Buy'/><category term='JBOSS'/><category term='Properties Integration'/><category term='Dependency Management'/><category term='Groovy'/><category term='Build Management'/><category term='Requirements'/><category term='Open Source'/><title type='text'>Java Architecture Rambings</title><subtitle type='html'>Java/Groovy/Grails Technical Architecture and development issues that are pertinent to the development that I am doing.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-5053395036246373608</id><published>2010-07-12T21:43:00.000-07:00</published><updated>2010-07-12T22:05:41.736-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Grails Portal WebFlow'/><title type='text'>Grails Portal Part II</title><content type='html'>This article is the second in a series of three that describes a simple way to build a working framework for a user portal. This framework is built upon some very popular features in Grails and provides many examples of Grails plug-in integration and use of some of the more complex features of Grails such as Grails Webflow. This post describes concepts that a novice Grails developer may find challenging.&lt;br /&gt;&lt;br /&gt;In this second post, a step-by-step approach will show how to construct a simple Grails-based workflow and integrate it with the Grails portal code created in the previous post. There are two parts to this post: the first one outlines the creation of the workflow; and the second shows how to use the results of the workflows in a business case.&lt;br /&gt;&lt;br /&gt;By the end of this post the reader will be familiar with the issues around creating Grails Webflows and should be able to implement the workflow features of a Grails portal application. I have not included all of the classes referenced in the code examples in the text of this post, but they are located at the Google Code project for the Grails Portal : &lt;a href="http://code.google.com/p/grailsportal/"&gt;http://code.google.com/p/grailsportal/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Why use a workflow engine such as Grails Webflow?&lt;br /&gt;&lt;br /&gt;Most web applications collect information in a stepwise fashion and then make business rule decisions based upon the data collected to accomplish some business functionality. This is a common requirement in any application, from a simple contact page to a commercial order management system. These types of requirements have been fulfilled in the past in many different ways.&lt;br /&gt;&lt;br /&gt;When these applications were written in a green-screen (mainframe) environment, it was easy to handle the interactions between the user and the application. In those days, the user could not switch or close the application window (if there was a window) without indicating what to do with the data that was recorded. The modern web user interface makes managing these kinds of applications much more challenging because of these complexities:&lt;br /&gt;&lt;br /&gt;· Workflow termination/re-entry:&lt;br /&gt;&lt;br /&gt;This is the process by which the user determines the state that they would like to terminate the workflow. At any time a user can do any number of things to exit the workflow including but not limited to:&lt;br /&gt;&lt;br /&gt;o Closing the Browser window&lt;br /&gt;o Selecting the “Cancel” button&lt;br /&gt;o Hitting the “Back” browser navigation button.&lt;br /&gt;o Hitting the “Refresh” browser button&lt;br /&gt;o Selecting the “Finish” button on the final state of the workflow.&lt;br /&gt;o Using re-entrant workflow processing&lt;br /&gt;&lt;br /&gt;· Workflow state:&lt;br /&gt;This issues centers around the persistence of the state of the workflow throughout the “life” of the workflow. As the user progresses through the workflow there should never be a perception that the data associated with the workflow will not be saved. If the user purposefully exits the workflow, the user should also be allowed the option to save the data.&lt;br /&gt;&lt;br /&gt;· Workflow implementation complexity:&lt;br /&gt;Typically, using workflow frameworks are tedious and counterintuitive. Implementing flows with other frameworks included a combination of XML configuration files, visual representations, and tools that center around code generation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Grails Webflow is a workflow based feature that gives the developer the tools to mitigate these issues:&lt;br /&gt;&lt;br /&gt;· It uses the well known Spring Web-Flow framework to manage the workflow.&lt;br /&gt;This framework handles the persistence of the workflow state and manages the issues when the refresh and back buttons are hit by the user during a workflow “session.” Combined with the Grails portal, it can also deliver targeted work flows based upon the user’s session state by recognizing specific values stored in the user’s web session.&lt;br /&gt;&lt;br /&gt;· Its convention-based paradigm of Groovy simplifies the development process to implement the flows in a concise, understandable manner.&lt;br /&gt;&lt;br /&gt;Flows are created in a manner consistent with other Grails development. No special tags are needed in the GSPs. Convention based development is used to connect the navigation on the workflow page to the workflow controller.&lt;br /&gt;&lt;br /&gt;· Its native Grails domain classes make it simple to save the result of the workflow.&lt;br /&gt;As in all other Grails development that accomplishes persistence of data, creating the code that saves and validates data is a chore but not as complex as in other Java-based frameworks.&lt;br /&gt;&lt;br /&gt;What does the workflow do for the Grails portal?&lt;br /&gt;&lt;br /&gt;Workflow for the Grails portal is one the fundamental user-based set of features that are used to write interactive web applications (apps that require users to log in and then provide individualized functionality). Workflow in a Grails portal is part of the launching pad for implementing functionality in a Grails portal. In Part I of this article, the setup of the project, domain objects, and security classes were created. In this article, the example will be further explained by demonstrating how to use Grails to manage appointments and create wizard pages to schedule appointments for the fictional wellness company “Wellness Unlimited.”&lt;br /&gt;&lt;br /&gt;Grails Webflow definition&lt;br /&gt;&lt;br /&gt;There are many types of workflow processes that exist, but it should be known that not all business flows lend themselves to being defined using Grails Webflow. There are three basic types of workflow:&lt;br /&gt;&lt;br /&gt;1. Human-based workflow&lt;br /&gt;This type of workflow is based upon the recording of activities strictly done by a human being where the intervals between recordings are extended and are not immediately ongoing. This can be, for example, the recording of a task such as a set of tests. Grails Webflow does not by default implement this type of workflow very well because it does not have the ability to re-constitute a workflow once the workflow session has been interrupted due to inactivity. It might be possible to implement this, but this is for future releases.&lt;br /&gt;&lt;br /&gt;2. Computer-based workflow&lt;br /&gt;This instance is where Grails Webflow shines. As in most web applications implemented using Grails Webflow, the intention is to collect data and guide the user between screens in one “flow session.” Typically, this works well for web applications where the workflow is completely computer based with no requirements to handle human based workflow.&lt;br /&gt;&lt;br /&gt;3. Mixed workflow (computer and human)&lt;br /&gt;A combination of the first two types, this hybrid workflow concept is a common reality when designing web applications. Grails Webflow can also implement this situation with a combination of traditional Grails web development and “linked” flows. In this case, the steps in the computer-based workflow steps are grouped together, and the human-based workflow is recorded separately from it.&lt;br /&gt;&lt;br /&gt;The Grails portal example outlined in this article is an example of mixed workflow.&lt;br /&gt;Planning is essential for success when defining a flow within a Grails application and all business processes can be distilled down to a basic set of steps. Whether you use a napkin or a formal diagram to document them, it is essential that you understand the required steps needed to implement the business process in your Grails application.&lt;br /&gt;&lt;br /&gt;In Grails Webflow, you take each of the steps and create a Groovy closure to capture the functionality. If you follow the normal process of GSP and Spring MVC web application development, you will find there are some slight adjustments required to enable webflows to work. Also, you will see that in this example I have not enabled any dynamic run-time functionality; perhaps in a future article I will show how to accomplish this. In the example of the registration controller, each of the steps for the business process of registration is implemented by using standard procedures described in the Grails documentation for this product.&lt;br /&gt;&lt;br /&gt;These procedures can be thought of as a roadmap for success. To start with here is a shortcut to understanding Grails Webflow development:&lt;br /&gt;&lt;br /&gt;1. The name of the flow is described by adding the “Flow” word to the end of a closure in your controller.&lt;br /&gt;&lt;br /&gt;2. When you create the views, you must use the same name as the webflow as a directory that contains the views for the webflow.&lt;br /&gt;&lt;br /&gt;3. The views are contained in the named directory from the previous item.&lt;br /&gt;&lt;br /&gt;4. Navigating between the webflows is pretty simple:&lt;br /&gt;&lt;br /&gt;a. The “name” property of the submit button for the pages in the flow indicates which closure to execute when the page is submitted.&lt;br /&gt;b. If the user navigates away from the flow, it is possible to re-establish the flow.&lt;br /&gt;c. Once the user ends the flow by hitting cancel, you have the ability to manage the data within the flow.&lt;br /&gt;&lt;br /&gt;5. Use the “flow” variable to store information for the span of a flow. This is a very important detail: without the flow variable you don’t have the ability to define the activity within a flow. I would recommend that you always use the flow variable when moving state within the flow.&lt;br /&gt;&lt;br /&gt;6. The default context in a view used for a webflow uses the “flow” variable. Unless you have worked extensively with Grails you might not understand the concept of a set of domain objects that are put into the context, but the flow variable is a default variable put into the session context.&lt;br /&gt;&lt;br /&gt;7. In your controller you should always have explicit entry points and exit points from the webflow. This can be implemented by creating a default closure that will be used by the webflow.&lt;br /&gt;8. When designing your flow, account for the ability to cancel the flow at any time. Placing a “cancel” button at each point in the process is a good idea.&lt;br /&gt;Implementing the flow in the Grails controller&lt;br /&gt;&lt;br /&gt;Saving the results of the flow at each step is important, at least in my example. The domain object validation utility methods and GORM methods within Grails are used to save the data for each step in the flow. When writing the code in the main controller for the flow, these are the steps that are always followed:&lt;br /&gt;&lt;br /&gt;1. Always use a service class when handling GORM objects. Either create a Grails service class or identify one that you will use to handle the saving of the data from the flow. For the example there are two service classes ContactUtilService and RegistrationService that are used explicitly for this purpose.&lt;br /&gt;&lt;br /&gt;2. Create a method to move the data from the posted web parameters to the domain objects. This process can vary widely in complexity. One of the easiest ways to do this is to have the names of the items on the view the same as the ones in your domain class. If you do this you can just instantiate the class using the parms variable–it can be that simple!&lt;br /&gt;&lt;br /&gt;3. Create a custom Java Exception class similar to ValidationException. Make sure that you have a try, catch block around the call to catch a validation error.&lt;br /&gt;&lt;br /&gt;4. Write a method in service class to validate the domain object. If there is an error, throw a custom validation error that will show to the user the field that needs to be changed.&lt;br /&gt;&lt;br /&gt;5. Handle the exception. If there is an exception, make sure the appropriate values are set in the view, and return the model.&lt;br /&gt;&lt;br /&gt;6. If there is no exception, create the model objects needed and move the flow to the next page.&lt;br /&gt;An Example of a flow in the Grails portal&lt;br /&gt;In the example for this article, we save the result of each stage of the webflow via calls to service classes. The objective is to employ as much of the default functionality provided by Grails as possible. In the example below from the RegistrationController, the flow definition for collecting the data for the Wellness Unlimited registration is shown.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;class RegistrationController{&lt;br /&gt;…&lt;br /&gt;…&lt;br /&gt;registrationFlow{&lt;br /&gt;def registrationService&lt;br /&gt;…&lt;br /&gt;…&lt;br /&gt;enterRegistrantInfo{&lt;br /&gt;on(GOTOPARENTINFO){&lt;br /&gt;try{&lt;br /&gt;flow.regEvent = this.registrationService.doRegistrationEvent(flow.regEvent,params)&lt;br /&gt;if (flow.regEvent.parent1==null){&lt;br /&gt;flow.regEvent.parent1=new RegistrationParent()&lt;br /&gt;}&lt;br /&gt;return success()&lt;br /&gt;}catch(ValidationException e){&lt;br /&gt;flash.message = "Please re-enter your information"&lt;br /&gt;flow.registerInstance = e.getExceptionVal()&lt;br /&gt;return error()&lt;br /&gt;}&lt;br /&gt;}.to ENTERPARENTINFO&lt;br /&gt;on(GOTOCANCEL){&lt;br /&gt;session.regEventId=null;&lt;br /&gt;flash.message="Cancelled"&lt;br /&gt;}.to CANCEL&lt;br /&gt;}&lt;br /&gt;…&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Listing 1: The enterRegistrantInfo flow step&lt;br /&gt;&lt;br /&gt;In this code snippet from the RegistrationController you see the call to the method registrationService.doRegistrationEvent() . There are some subtle but highly significant implementation details in this snippet of Groovy code:&lt;br /&gt;&lt;br /&gt;a. Note that the reference to the service always uses a “this” reference. The instance variables at the class level must be referenced this way since the flow is part of a closure.&lt;br /&gt;&lt;br /&gt;b. The custom exception ValidationException implements validation using the same patterns established by generated Grails scaffolding controllers and gsp files:&lt;br /&gt;&lt;br /&gt;i. Setting the flash.message which shows this message at the top of the page.&lt;br /&gt;&lt;br /&gt;ii. Setting the flash.registerInstance variable from exception, which is then used to generically&lt;br /&gt;show the specific fields that need to be changed by marking them red.&lt;br /&gt;Of course the visual representations of the error handling and validation can be replaced as they are accomplished using style sheets and images.&lt;br /&gt;&lt;br /&gt;c. Both successful and unsuccessful calls to doRegistrationEvent enable a model necessary to render a view.&lt;br /&gt;&lt;br /&gt;i. Make sure that when you return a view that you have the submitted values present in your flash scoped variable. This is important because there is nothing more unsettling for a user than an error where the page is returned–minus some of the originally submitted values.&lt;br /&gt;&lt;br /&gt;ii. The approach that I recommend is to have the same flow variable used in each of the flow steps. This will lower the complexity, and allow you to carry the data from previous steps forward without having to re-query that database at each step.&lt;br /&gt;&lt;br /&gt;Validation and persistence using Grails service classes&lt;br /&gt;&lt;br /&gt;As you see in Listing 2, which is a code snippet from the RegistrationService class, throwing and catching exceptions as part of a flow is one of the many ways to use the default functionality of Grails and Java. When the exception is thrown, it’s most likely because of a validation error on the data that is entered. As you can see in the code below, the validate()method is executed which tests against the constraints specified in the domain class. For example, if a field does not have a value when it should (null) it will put the value into an errors() method on the domain object (RegistrationEvent) which is processed by the default functionality present in a GSP page that has been generated.&lt;br /&gt;&lt;br /&gt;Grails service classes are somewhat unique in that they are the defined place within Grails development where database transactions through GORM are handled without much special work. Other methods in controller classes can do the same work, but in these classes much of the configuration for persistence is already done for you. In the doRegistrationEvent method you see an implementation of the instructions earlier in this article by:&lt;br /&gt;&lt;br /&gt;1. Using GORM Validation for the domain objects&lt;br /&gt;2. Keeping one single domain object (RegistrationEvent) that is used to return to the controller.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;Class RegistrationService{&lt;br /&gt;….&lt;br /&gt;…&lt;br /&gt;def RegistrationEvent doRegistrationEvent(RegistrationEvent regEvent,&lt;br /&gt;params)throws ValidationException{&lt;br /&gt;if (regEvent==null){&lt;br /&gt;regEvent=new RegistrationEvent()&lt;br /&gt;}&lt;br /&gt;try{&lt;br /&gt;regEvent.registrationAge=new Integer(params.registrantAge)&lt;br /&gt;}catch(Exception e){&lt;br /&gt;regEvent.registrationAge = 0&lt;br /&gt;}&lt;br /&gt;regEvent.registrationGrade=params.registrationGrade&lt;br /&gt;regEvent.registrationDate=new Date()&lt;br /&gt;def pt=PartyType.findByCd(CHILD)&lt;br /&gt;regEvent.registrationFor=doParty(pt,"",regEvent.registrationFor,params)&lt;br /&gt;SimpleDateFormat format=new SimpleDateFormat(DATEFORMAT)&lt;br /&gt;regEvent.registrationFor.birthDate = format.parse(params.birthDate_year+&lt;br /&gt;"-"+params.birthDate_month+&lt;br /&gt;"-"+params.birthDate_day)&lt;br /&gt;if (!regEvent.registrationFor.validate()){&lt;br /&gt;throw new ValidationException(regEvent.registrationFor)&lt;br /&gt;}&lt;br /&gt;regEvent.registrationFor.save()&lt;br /&gt;regEvent.registrationUser=this.securityService.getRegisteredUser()&lt;br /&gt;if(!regEvent.validate()){&lt;br /&gt;throw new ValidationException(regEvent)&lt;br /&gt;}&lt;br /&gt;regEvent.save()&lt;br /&gt;return regEvent&lt;br /&gt;}&lt;br /&gt;…&lt;br /&gt;…&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;Listing 2: doRegistrationEvent method in the registration service&lt;br /&gt;&lt;br /&gt;Grails portal and web browser navigation&lt;br /&gt;&lt;br /&gt;Another detail in this code snippet worth discussing is how the services class is controlling null objects which are a result of Web browser navigation. This is apparent consistently in the example above and all other service methods. Using a domain object to pass between the view, controller, and service layers creates situations where the flow will move back a step. If this happens, the user should see the data that they entered previously and when they submit an update, the service classes should seamlessly handle new objects as well as updates.&lt;br /&gt;&lt;br /&gt;The Grails service part of the solution is partially apparent in Listing 2, which employs a simple solution to the problem. In the Grails portal example, the domain object regEvent of type RegistrationEvent is the object stored in the flow scope for the life of the flow. To process a change in this domain object, the regEvent object is passed in, regardless of whether the object has been instantiated or not. If it is null then it comes from a situation where the user has not yet created a registration in that flow. If the object is not null then it implies that the object already exists and we use the existing object. This is crucial because in each of these cases the returned object is the one that is used in the controller and then passed back to the view as the model.&lt;br /&gt;&lt;br /&gt;Use of domain class configuration&lt;br /&gt;&lt;br /&gt;In the example of Listing 3–which shows the RegistrationEvent domain class–configuration heavily influences the behavior of the Grails Portal. This is because the way that the domain objects are configured implies that it’s also the way that the objects are validated. Since this is how all objects in the Grails portal are validated from each step in the flow, it is essential to understand the issues around Grails domain model constraints, relationships, and mappings.&lt;br /&gt;For conciseness, and the fact that all of the explanations for these options are available on the &lt;a href="http://www.grails.org/"&gt;Grails wiki&lt;/a&gt;, only the significant behaviors that affect the Grails portal and may be useful for anyone modifying the code are included for this article.&lt;br /&gt;&lt;br /&gt;· Grails constraints&lt;br /&gt;&lt;br /&gt;o nullable: A simple concept that can really be an issue if set incorrectly. This indicates to the validation routine and the database creation scripts that this column should have a value (false), or it is OK for it to be false (true). Validation will fail if the constraint is set to “false” and the instance variable of the domain object does not have a value.&lt;br /&gt;&lt;br /&gt;o inList: A restriction constraint that will check for these values when validation is run against this domain object.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;· Grails mappings&lt;br /&gt;&lt;br /&gt;o lazy: This is set to false for this domain class since this is the root object for the Wellness Unlimited registrations, and when a RegistrationEvent is retrieved from the database, it should return all referenced objects. By default, Grails sets this value to “true” for all GORM relationships.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;import java.sql.Timestamp&lt;br /&gt;class RegistrationEvent implements Serializable{&lt;br /&gt;Party registrationFor&lt;br /&gt;Date registrationDate&lt;br /&gt;String registrationGrade&lt;br /&gt;Integer registrationAge&lt;br /&gt;EmergencyContact emergencyContact1&lt;br /&gt;EmergencyContact emergencyContact2&lt;br /&gt;EmergencyContact emergencyContact3&lt;br /&gt;RegistrationParent parent1&lt;br /&gt;RegistrationParent parent2&lt;br /&gt;PickupContact pickupContact1&lt;br /&gt;PickupContact pickupContact2&lt;br /&gt;PickupContact pickupContact3&lt;br /&gt;OrderRecord orderRecord&lt;br /&gt;JsecUser registrationUser&lt;br /&gt;RegistrationDoctor registrationDoctor&lt;br /&gt;static constraints = {&lt;br /&gt;registrationFor(nullable:false)&lt;br /&gt;registrationUser(nullable:false)&lt;br /&gt;registrationDate(nullable:true)&lt;br /&gt;registrationGrade(inList:["Kindergarten",&lt;br /&gt;"First",&lt;br /&gt;"Second","Third",&lt;br /&gt;"Fourth",&lt;br /&gt;"Fifth","Sixth",&lt;br /&gt;"Seventh",&lt;br /&gt;"Eighth","Freshman",&lt;br /&gt;"Sophomore",&lt;br /&gt;"Junior","Senior"])&lt;br /&gt;registrationAge(range:5..19)&lt;br /&gt;emergencyContact1(nullable:true)&lt;br /&gt;emergencyContact2(nullable:true)&lt;br /&gt;emergencyContact3(nullable:true)&lt;br /&gt;parent1(nullable:true)&lt;br /&gt;parent2(nullable:true)&lt;br /&gt;pickupContact1(nullable:true)&lt;br /&gt;pickupContact2(nullable:true)&lt;br /&gt;pickupContact3(nullable:true)&lt;br /&gt;orderRecord(nullable:true)&lt;br /&gt;registrationDoctor(nullable:true)&lt;br /&gt;}&lt;br /&gt;static mapping={&lt;br /&gt;parent1 lazy:false&lt;br /&gt;parent2 lazy:false&lt;br /&gt;emergencyContact1 lazy:false&lt;br /&gt;emergencyContect2 lazy:false&lt;br /&gt;emergencyContact3 lazy:false&lt;br /&gt;pickupContact1 lazy:false&lt;br /&gt;pickupContact2 lazy:false&lt;br /&gt;pickupContact3 lazy:false&lt;br /&gt;orderRecord lazy:false&lt;br /&gt;}&lt;br /&gt;String toString() {&lt;br /&gt;return registrationFor.firstName+" "+registrationFor.lastName&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;Listing 3: The RegistrationEvent domain class&lt;br /&gt;&lt;br /&gt;Use of views in the Grails portal&lt;br /&gt;&lt;br /&gt;Views have four main facets that, when combined, create what the user sees on the page represented by the GSP.&lt;br /&gt;&lt;br /&gt;1. HTML notation&lt;br /&gt;2. Grails tags&lt;br /&gt;3. References to data available in different contexts&lt;br /&gt;4. The GSP page template (not shown in this example)&lt;br /&gt;&lt;br /&gt;The Grails portal employs a domain-based framework that takes advantage of the default scaffolding behavior of Grails. In Listing 4 the &lt;?xml:namespace prefix = g /&gt;&lt;g:if&gt;and &lt;g:else&gt;tags are used to handle the situation when the regEvent object does not have a value. This happens the first time that the form is rendered for that webflow. Also, this set of code will show the errors at the top and outline the field with red when the first name field is not filled in.&lt;br /&gt;&lt;br /&gt;In this post, each of the application layers of the Grails portal in respect to flow development has been detailed. From the view, controller, service layer and the domain, each contain a part of the puzzle to create an effective flow for a Grails portal. You should note that the files contain a full working and coded example of this functionality with these concepts fully employed.&lt;br /&gt;The next and last installation of the Grails portal series will take the working application and apply management and user interface features such as Ajax to the foundation that has already been built. In addition, the process of deploying the Grails portal application into an existing Tomcat server environment will be covered.&lt;br /&gt;&lt;/g:else&gt;&lt;/g:if&gt;&lt;g:if&gt;&lt;g:else&gt;&lt;br /&gt;&lt;br /&gt;&lt;/g:else&gt;&lt;/g:if&gt;&lt;g:if&gt;&lt;g:else&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/g:else&gt;&lt;/g:if&gt;&lt;g:if&gt;&lt;g:else&gt;&lt;/g:else&gt;&lt;/g:if&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-5053395036246373608?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/5053395036246373608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=5053395036246373608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5053395036246373608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5053395036246373608'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2010/07/grails-portal-part-ii.html' title='Grails Portal Part II'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-1930533076947190986</id><published>2010-03-08T09:34:00.000-08:00</published><updated>2010-03-08T09:41:32.652-08:00</updated><title type='text'>Grails Portal Part I</title><content type='html'>This article is the first in a series of three that describes a simple way to build a working framework for a user portal. This framework is built upon some very popular features in Grails and provides many examples of how to integrate popular plug-ins such as JSecurity.  This article describes concepts that a novice Grails developer may find challenging.&lt;br /&gt;&lt;br /&gt;In the first article, a step-by-step approach will show how to construct the architecture and creating a skeleton set of pages that will be used in articles two and three.  By the end of this article the reader will be familiar with using basic Grails concepts to form the basis of a Grails-based portal application.  Not all of the classes referenced in the code examples in the text of this article have been included.&lt;br /&gt;Why a Grails Portal?&lt;br /&gt;&lt;br /&gt;I have spent many years creating web applications that allow users to authenticate, and then be permitted access to specific features.  This does not imply that I have not used formal “portal” technologies, but most small web applications don’t merit being created within a jsr-168/286 portal environment.   Typically, most developers need a quick way to allow users to self-register and authenticate, and then manage the authorization of the user to specific functionality.&lt;br /&gt;&lt;br /&gt;Grails poses a very interesting choice for these kinds of applications, first because of its convention- based development model and second, its ability to incorporate new functionality quickly.  Basic features of Grails such as GSP templates, Grails Object Relational Mapping (GORM), and Web-Flow enable portal functionality to be quickly implemented.&lt;br /&gt;What can a Grails Portal do?&lt;br /&gt;&lt;br /&gt;A Grails portal is the fundamental user-based set of features that are used to write interactive web applications (apps that require users to log in and then provide individualized functionality.) A Grails portal can be a launching pad for implementing a web framework that creates and implementation that differs based on role and user. In this article, I will demonstrate how to use Grails to create a simple portal for the fictional wellness company “Wellness Unlimited.”  The portal will execute wizards to help users schedule appointments, report health issues, permit self-registration, receive specialized content through email, and allow them to sign up for web-based services.&lt;br /&gt;&lt;br /&gt;To accomplish this, our web application combines the user security features of JSecurity with a custom database schema that extends the simple database model provided by JSecurity. Our application also extends functionality to manage users.   These customizations are combined with default scaffolding enabled through Grails Web Flow and GORM.&lt;br /&gt;What you will need to do the examples for this article&lt;br /&gt;&lt;br /&gt;1.      A downloaded and working Grails environment&lt;br /&gt;&lt;br /&gt;2.      A database source such as MySQL&lt;br /&gt;Grails Portal Project definition&lt;br /&gt;&lt;br /&gt;The classes that are used to describe the Wellness Unlimited functionality are an example of a generic web application.  The abstractions used are applicable for most web applications that involve common business processes such as recording transactions, scheduling and purchasing.  They can also be used in other non-economic functions such as list and catalog management.  In these business domains, the organization presents website data to the user and then allows user interaction and records the selections made by the user.  Once the user has entered the information, an administrator or business user should be presented with the data for further processing.  In order to do this in Grails, domain classes, a framework like GORM, and a view technology like GSP are necessary.&lt;br /&gt;&lt;br /&gt;I have written many web applications that use the Spring and Hibernate frameworks and GORM is definitely superior from a usability perspective in getting database-backed web applications to work quickly and properly.  The only problem is that if these tools are not configured correctly, they will create bloated applications with inefficient database queries generated by the web application.  To prevent this from happening, I have adopted a few practices that facilitate the database and domain-class approach taken in this project.&lt;br /&gt;&lt;br /&gt;1.    Keep it simple&lt;br /&gt;&lt;br /&gt;2.    Don’t be afraid to “flatten” the database if it makes it easier; i.e. a generic database is not always best.&lt;br /&gt;&lt;br /&gt;3.    Use the options in GORM if possible before writing code.&lt;br /&gt;&lt;br /&gt;The primary domain objects used to define the application domain for the Wellness Unlimited portal are Party, Order, Product, and RegistrationEvent.  A brief description of each follows.&lt;br /&gt;Party&lt;br /&gt;&lt;br /&gt;A Party signifies a specific individual that takes part in the system, but a party is not necessarily only a person.  It could be a system, individual user, or anything that can be identified by the fields First Name and Last Name.  These fields are the mandatory fields on the equivalent domain class.  The Party class holds all of the information that composes an individual that participates in the functionality of the portal.&lt;br /&gt;Order&lt;br /&gt;&lt;br /&gt;The Order encapsulates the concept of orders and fulfillment.   This abstraction is important to the implementation of any selection for action from the website.  Orders are executed to establish that something needs to happen.  Order line items are created to track the specific products that are selected by the user.&lt;br /&gt;Product&lt;br /&gt;&lt;br /&gt;Products exemplify the concept of any item that can be selected by a user from Wellness Unlimited.  An example of a product would be something generic like a massage; a product could also be  an online user request for a specific type of acupuncture treatment.  Products have line items that enable bundling of products into a larger product.  An example of a bundled product would be to combine a facial with a pedicure into one item that a user schedules on the Wellness Unlimited website.&lt;br /&gt;Event&lt;br /&gt;&lt;br /&gt;Events describe the concept of an occurrence of a business “event.”  The recording of different types of business events enable business processes to be recorded along with all of the information associated with the process.  The implementation of this portal uses Grails WebFlow to initiate business events and track the progress of these events.  Typical events could be:&lt;br /&gt;&lt;br /&gt;1.    Scheduling of a service such as a massage&lt;br /&gt;&lt;br /&gt;2.    Purchasing  a product&lt;br /&gt;&lt;br /&gt;3.    Requesting a call back/email for help with a wellness issue&lt;br /&gt;How to create a Grails Portal&lt;br /&gt;&lt;br /&gt;The steps are as follow:&lt;br /&gt;&lt;br /&gt;1.      Create the Grails  project&lt;br /&gt;&lt;br /&gt;2.      Install and configure the JSecurity Plugin&lt;br /&gt;&lt;br /&gt;3.      Configure the domain classes and GORM&lt;br /&gt;&lt;br /&gt;4.      Configure the User Management Views&lt;br /&gt;Create the Grails project&lt;br /&gt;&lt;br /&gt;The first step in setting up this project is to create a Grails project using grails create-project grailsPortal.  This command creates the typical directory structure associated with all Grails projects.&lt;br /&gt;Install and configure the JSecurity Plugin&lt;br /&gt;&lt;br /&gt;The second step is to install the JSecurity plugin. The command is: “grails install-plugin jsecurity.”  In addition, JSecurity installs the quick-start script to generate the basic user screen, controllers, and domain classes for JSecurity. The next step installs the basic setup for JSecurity.   The command “grails quick-start” creates an authController, a view called login.gsp, and six domain classes:&lt;br /&gt;&lt;br /&gt;·         JsecPermission: holds the permissions and the descriptions of the possible actions that can be applied to the permission&lt;br /&gt;&lt;br /&gt;·         JsecRole: holds the name of the Role&lt;br /&gt;&lt;br /&gt;·          JsecRolePermissionRel: holds the relationship between the Role and Permission&lt;br /&gt;&lt;br /&gt;·         JsecUser: holds the user information (in the beginning only username and password)&lt;br /&gt;&lt;br /&gt;·         JsecUserPermissionRel: the relationship between the user and permission&lt;br /&gt;&lt;br /&gt;·         JsecUserRoleRel: the relationship between the JsecUser and the Role&lt;br /&gt;&lt;br /&gt;JSecurity is an excellent Grails plugin.  It is a generic framework for web application security that is easily extended.  At this point the application will work if you use “grails run-app.”  It gives you a great starting point but does not finish the work for a user-authenticated application such as a portal.&lt;br /&gt;&lt;br /&gt;JSecurity accomplishes user authentication by looking up the user in the JsecUser table and the relationships that the user has in JsecUserRolRel.  For this project we will create two role records: one that describes an administration role, and another that describes a user role.  In addition we will create two user records: one that describes an administration user (admin); and another that describes a user for the application (guest).&lt;br /&gt;&lt;br /&gt;The two user records are associated with the roles by using the JsecUserRoleRel table.  As shown in Figure 1, the relationship enables roles to be applied to users.&lt;br /&gt;&lt;br /&gt;Figure 1: Party and JSecurity tables ERD&lt;br /&gt;&lt;br /&gt;In Part I of this article we will detail how to augment the authorization controller (authController.groovy) to use the “Admin” and “User” role.  In the “Creating Default Data” section of this article (part II), I will show how automatically create default roles and users as well as the relationship table when the application is started.&lt;br /&gt;&lt;br /&gt;This project augments the default domain classes provided by JSecurity.  The default classes are not enough because there needs to be a relationship between these classes and the classes that describe the rest of the application. We accomplish this by adding a reference to the classes that describe the user from a “Wellness Unlimited” point of view.  This can be seen in  Figure 1  in the JSEC_USER table.&lt;br /&gt;Configure the domain classes and GORM&lt;br /&gt;&lt;br /&gt;The Party class is contained in Listing 1. The Party domain class references other domain classes by default such as ContactPhone, ContactEmail, ContactAddress and PartyType.  These references establish direct relationships in the database and make it much easier to use the classes at run time.  Also, you should notice that there is a one-to-many relationship with the OrderRecord domain class.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;class Party implements Serializable{&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    static mapping = {&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;         orderRecordList column:'partys_id',joinTable:'party_order_record'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;         partyType column:'party_type_id'&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    }&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String         firstName&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String         middleName&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String         lastName&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String         prefix&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String         suffix&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    Date           birthDate&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactAddress homeAddress&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactAddress workAddress&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactPhone   homePhone&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactPhone   workPhone&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactPhone   cellPhone&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactEmail   workEmail&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    ContactEmail   homeEmail&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    PartyType      partyType&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    static hasMany = [ orderRecordList : OrderRecord ]&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    static constraints = {&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        prefix(size:1..20, blank:true,nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        firstName(size: 1..100, blank: false,nullable:false)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        middleName(size:1..50, blank:true,nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        lastName(size: 1..100, blank: false,nullable:false)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        suffix(size:1..20, blank:true,nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        birthDate(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        partyType(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        homeAddress(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        workAddress(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        homePhone(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        workPhone(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        cellPhone(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        workEmail(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        homeEmail(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        orderRecordList(nullable:true)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    }&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    String toString() {&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;        return firstName+" "+lastName&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;    }&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Listing 1: Party Domain class&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Listing 1 shows that a Party can have many orders.  The syntax indicates to Grails GORM that an intermediate table will need to be created that will contain a reference to both the OrderRecord (Listing 2) class and to the Party class.  Grails has really improved support recently for many-to-many relationships and one-to-many relationships when generating scaffolding.  Our example application does not use many cases of many-to-many relationships, but as support improves it will make it even easier to create more generic systems.&lt;br /&gt;&lt;br /&gt;Figure 2: OrderRecord and Inventory Entity Relationship Diagram&lt;br /&gt;&lt;br /&gt;The OrderRecord class is contained in Listing 2.  This class is the main reference point for when an order is created; the OrderRecordLineItem class (which is in the zip file; see the “Learn more” section) has a reference to an OrderRecord (Listing 2).  The Entity Relationship Diagram that represents this data is shown in Figure 2.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;class OrderRecord implements Serializable{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   static mapping = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        table 'order_record'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        grossAmount       column:'gross_amount'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        orderComment      column:'order_comment'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        orderDate         column:'order_date'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        taxAmount         column:'tax_amount'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        totalAmount       column:'total_amount'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        orderStatus       column:'order_status'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        orderRecordType   column:'order_record_type_id'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   String          orderNumber&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Double          grossAmount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   String          orderComment&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Date            orderDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Double          taxAmount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Double          totalAmount&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   String          orderStatus&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   OrderRecordType orderRecordType&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Party           party&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   static constraints = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     orderNumber(nullable: false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       grossAmount(nullable: false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       orderRecordType(nullable:false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       party(nullable:false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       orderComment(size: 1..1000, blank: false, nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       orderDate(nullable: false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       taxAmount(nullable: false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       totalAmount(nullable: false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       orderStatus(size: 0..100)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   String toString() {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       return  orderNumber&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Listing 2: OrderRecord class&lt;br /&gt;&lt;br /&gt;The OrderRecordLineItem has a reference to the Product which is referenced in Listing 3.  This configuration is purposely done so Products can be bundled into an order. (The database design to accomplish this is shown in Figure 2.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;class Product implements Serializable{&lt;br /&gt;&lt;br /&gt;  static mapping = {&lt;br /&gt;&lt;br /&gt;       table 'product'&lt;br /&gt;&lt;br /&gt;       cd                  column:'cd',index: "product_cd_idx", unique: true&lt;br /&gt;&lt;br /&gt;       dsc                 column:'dsc'&lt;br /&gt;&lt;br /&gt;       ecommerceCode       column:'ecommerce_code'&lt;br /&gt;&lt;br /&gt;       name                column:'name'&lt;br /&gt;&lt;br /&gt;       netCostAmount       column:'net_cost_amount'&lt;br /&gt;&lt;br /&gt;       netSalesAmount      column:'net_sales_amount'&lt;br /&gt;&lt;br /&gt;       productImageuripath column:'product_imageuripath'&lt;br /&gt;&lt;br /&gt;       salesChannel        column:'sales_channel_id'&lt;br /&gt;&lt;br /&gt;       productType         column:'product_type_id'&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  String           cd&lt;br /&gt;&lt;br /&gt;  String           dsc&lt;br /&gt;&lt;br /&gt;  String           ecommerceCode&lt;br /&gt;&lt;br /&gt;  String           name&lt;br /&gt;&lt;br /&gt;  Double           netCostAmount&lt;br /&gt;&lt;br /&gt;  Double           netSalesAmount&lt;br /&gt;&lt;br /&gt;  String           productImageuripath&lt;br /&gt;&lt;br /&gt;  SalesChannel     salesChannel&lt;br /&gt;&lt;br /&gt;  ProductType      productType&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  static constraints = {&lt;br /&gt;&lt;br /&gt;      cd                 (size: 1..20, blank: false,nullable:false)&lt;br /&gt;&lt;br /&gt;      dsc                (size: 1..200, blank: true,nullable:true)&lt;br /&gt;&lt;br /&gt;      ecommerceCode      (size: 1..100, blank: false,nullable:false)&lt;br /&gt;&lt;br /&gt;      name               (size: 1..100, blank: false)&lt;br /&gt;&lt;br /&gt;      netCostAmount      (nullable: false)&lt;br /&gt;&lt;br /&gt;      netSalesAmount     (nullable: false)&lt;br /&gt;&lt;br /&gt;      productImageuripath(size: 1..255, blank: true,nullable:true)&lt;br /&gt;&lt;br /&gt;      salesChannel       (nullable:false)&lt;br /&gt;&lt;br /&gt;      productType        (nullable:false)&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  String toString() {&lt;br /&gt;&lt;br /&gt;      return name&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Listing 3: Product class&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The RegistrationEvent is a class (see Listing 4) where registration transactions happen in the portal.  One of the requirements is to be able to register patients for weekly Wellness Unlimited classes; this class enables that functionality. &lt;br /&gt;&lt;br /&gt;Another interesting point of the domain classes in this application is the toString() method that is implemented.  When classes are generated by Grails scaffolding, by default the classes use this method as a representation of the value of the row in the database.&lt;br /&gt;&lt;br /&gt;Constraints that are used in the domain classes will have a direct impact on how default scaffolding generates controllers and views.  In this application the blank:true and size:x…x+n are commonly used to control how the fields are generated when they are generated through scaffolding.&lt;br /&gt;&lt;br /&gt;Constraints also play a large role in the generation of the database classes.  The nullable constraint relates directly back to how the domain class is generated into a table in that it makes the column mandatory (not null).  The size constraint gives the indication of how large the field will be in the database.  The database design for this are of the database is shown in Figure 3.&lt;br /&gt;&lt;br /&gt;Figure 3: Registration Event ERD&lt;br /&gt;&lt;br /&gt;Another item to note about all of the domain classes is that they all implement the Serializable interface.  This is quite important.  One of the main features used in the Wellness Essentials portal are wizards that enable the users to schedule appointments, order products, and go through a web-based workflow; to enable this, Grails WebFlow is used.  It assumes that all domain classes have this interface implemented because it will attempt to store the state of the flow independent of the database.  If you are not familiar with Serializable, you should reference the Sun Java documentation around java.io.Serializable (see the “Learn More” section for details).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;import java.sql.Timestamp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;class RegistrationEvent implements Serializable{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Party              registrationFor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   Date               registrationDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   EmergencyContact   emergencyContact1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   EmergencyContact   emergencyContact2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   EmergencyContact   emergencyContact3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   OrderRecord        orderRecord&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   JsecUser           registrationUser&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   RegistrationDoctor registrationDoctor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   static constraints = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       registrationFor(nullable:false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       registrationUser(nullable:false)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       registrationDate(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       emergencyContact1(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       emergencyContact2(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       emergencyContact3(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       orderRecord(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       registrationDoctor(nullable:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     static mapping={&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           emergencyContact1 lazy:false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           emergencyContect2 lazy:false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           emergencyContact3 lazy:false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           orderRecord    lazy:false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   String toString() {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       return  registrationFor.firstName+" "+registrationFor.lastName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Listing 4: RegistrationEvent class&lt;br /&gt;Configure the User Management Views&lt;br /&gt;&lt;br /&gt;After the domain classes are created you can run the Grails application, but it won’t actually do much.  In this step we will configure the views and controllers for managing the user login into the Grails Portal.  To implement user management features, we must have the ability to separate users into roles.  Luckily, JSecurity enables this functionality.  In this application I assume that there are two roles, Admin and User (these roles are created by default in the bootstrap.groovy  that is available in the zip file; see the “Learn More” section).&lt;br /&gt;&lt;br /&gt;A default authController.groovy is created by the initial installation of the JSecurity plug-in.  You will need to replace the controller with the contents of Listing 5.  The main difference between the original controller and this one is that the original controller only has the code for logging in and logging out and does not provide any code for inserting a user into the database and assigning a role to them.&lt;br /&gt;&lt;br /&gt;The additional closures that I have created are register and registerUser.  They handle the registration of new users as well as modifying existing user profile information.  Another feature of this controller is that most database handling is done using Grails services (wellUnlSecurityService, contactUtilService) which enable the abstraction of database access and manipulation to these classes.&lt;br /&gt;&lt;br /&gt;The corresponding views for this controller handle the modification of the user and registration.  These are contained on the zip file.  In the next installation of this series I will go over how these were created as well as formulating the User Interface (UI).&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;import org.jsecurity.authc.AuthenticationException&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;import org.jsecurity.authc.UsernamePasswordToken&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;import org.jsecurity.SecurityUtils&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;import com.wellUnl.exception.ValidationException&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;class AuthController {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def jsecSecurityManager&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def wellUnlSecurityService&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def contactUtilService&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def index = { redirect(action: 'login', params: params) }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def login = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       return [ username: params.username, rememberMe: (params.rememberMe != null), targetUri: params.targetUri ]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def register={&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      JsecUser ju=new JsecUser()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      ju.party=new Party()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      String theAction="registerUser"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      try{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        ju=wellUnlSecurityService.getRegisteredUser()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        if (ju!=null){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;              theAction="updateUser"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      }catch(Exception e){}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      return [authInstance:ju,userAction:theAction]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def edit={&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           def ju=wellUnlSecurityService.getRegisteredUser()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           render (model:[authInstance:ju],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def registerUser={&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     JsecUser.withSession { session -&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     log.info("In registerUser")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Party userParty&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       JsecUser user&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       JsecUser ju&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       boolean isValidationError=false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       def userName=params.userName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     try{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         ju=wellUnlSecurityService.getRegisteredUser()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     }catch (Exception e){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       log.info("Registering a New User")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       ju=null;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       log.info("checking for mandatory fields")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           if (userName==null || userName=="" || params.firstName==null || params.firstName=="" || params.lastName==null || params.lastName=="" ||&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                       params.password==null || params.password=="" || params.passwordVerify==null || params.passwordVerify==""){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             log.info("no username, first name, last name, password, or password verify entered")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             flash.message="We are sorry, you have to enter a user name, First name, Last Name, Password and Verify Password"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             isValidationError=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     log.info("checking for existing user")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     def foundUser=null&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     if (ju==null){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         foundUser=JsecUser.findByUsername(userName)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         if (foundUser!=null){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         log.info("Trying to register duplicate user -"+userName)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         flash.message="We are sorry this user name is already taken, please pick another"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         isValidationError=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         session.clear()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       log.info("checking for password verification")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       if (params.password!=params.passwordVerify){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       log.info("Trying to register passwords do not match -"+userName)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       flash.message="We are sorry your passwords do not match, please try again"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       isValidationError=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 user=contactUtilService.doUser(ju,params)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               log.info("user="+user)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     log.info("validating data")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       try{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;          user.party=this.contactUtilService.doParty(user.party,params)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        }catch(ValidationException ex){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                flash.message = "ERROR-09:There was a problem validating the information, please try again"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                  log.error(ex.exceptionVal.errors)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                  render(model:[authInstance:user,authErrorInstance:ex.exceptionVal],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                  session.clear()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                  return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     if (!isValidationError){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         log.info("about to save the user")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             def userRole=JsecRole.findByName("User")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             try{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 user.party.save()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               user.save()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           new JsecUserRoleRel(user: user, role: userRole).save()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               user.save(flush:true)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               log.info("successfully saved the user")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             }catch(Exception e){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                   session.clear()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                   flash.message="ERROR-11: There was a problem saving the User, please try again"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         if (ju==null){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         flash.message="User Created You can log in now"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }else{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                 flash.message="User Profile Updated"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         if (user.party.id==null){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;         log.error("registerUser:can not create the user")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           flash.message = "ERROR-10:There was a problem saving the User, please try again"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           session.clear()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           return&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      }else{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           log.info("ValidationError-RegisterUser")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           session.clear()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           render(model:[authInstance:user],view:'register')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;     }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def signIn = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       def authToken = new UsernamePasswordToken(params.username, params.password)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       // Support for "remember me"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       if (params.rememberMe) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           authToken.rememberMe = true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       try{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // Perform the actual login. An AuthenticationException&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // will be thrown if the username is unrecognised or the&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // password is incorrect.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           this.jsecSecurityManager.login(authToken)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // If a controller redirected to this page, redirect back&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // to it. Otherwise redirect to the root URI.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           def targetUri = params.targetUri ?: "/"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           log.info "Redirecting to '${targetUri}'."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           redirect(uri: targetUri)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       catch (AuthenticationException ex){&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // Authentication failed, so display the appropriate message&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // on the login page.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           log.info "Authentication failure for user '${params.username}'."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           flash.message = message(code: "login.failed")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // Keep the username and "remember me" setting so that the&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // user doesn't have to enter them again.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           def m = [ username: params.username ]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           if (params.rememberMe) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               m['rememberMe'] = true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // Remember the target URI too.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           if (params.targetUri) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;               m['targetUri'] = params.targetUri&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           // Now redirect back to the login page.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;           redirect(action: 'login', params: m)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def signOut = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       // Log the user out of the application.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       SecurityUtils.subject?.logout()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       // For now, redirect back to the home page.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       redirect(uri: '/')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   def unauthorized = {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       render 'You do not have permission to access this page.'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Listing 5: authController.groovy&lt;br /&gt;&lt;br /&gt;The next installation of the Grails Portal series will show how to build Grails Service classes with GORM and implement the portal user interface.  It will also start to explain how to use the Grails WebFlow feature to orchestrate web-based wizards.&lt;br /&gt;Learn More&lt;br /&gt;&lt;br /&gt;The files for this article are contained on my website at http://www.webtech20.com/articlel.zip.&lt;br /&gt;&lt;br /&gt;JSecurity plugin - http://grails.org/JSecurity+Plugin&lt;br /&gt;&lt;br /&gt;Grails Framework Reference Guide - http://grails.org/doc/1.1.x/&lt;br /&gt;&lt;br /&gt;Java Serialization - http://java.sun.com/developer/technicalArticles/Programming/serialization/&lt;br /&gt;&lt;br /&gt;JSecurity web site - http://cwiki.apache.org/confluence/display/SHIRO/IndexThe Definitive Guide to Grails (second edition) by Graeme Rocher and Jeff Brown ISBN:9781590599952&lt;br /&gt;&lt;br /&gt;Enterprise Patterns and MDA: Building Better Software with Achetype Patterns and UML by Jim Arlow, Ila Neustadt Addison Wesley Press ISBN-13: 978-0321112309&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-1930533076947190986?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/1930533076947190986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=1930533076947190986' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1930533076947190986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1930533076947190986'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2010/03/grails-portal-part-i.html' title='Grails Portal Part I'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-8426865893590904939</id><published>2009-08-19T14:55:00.000-07:00</published><updated>2009-08-19T14:59:45.450-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails and Groovy Blog</title><content type='html'>&lt;p&gt;I have found a great Groovy/Grails Blog &lt;a href="http://fbflex.wordpress.com/"&gt;here&lt;/a&gt; since I am meddling in using Grails on the Google App Engine.  It seems very interesting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-8426865893590904939?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/8426865893590904939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=8426865893590904939' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8426865893590904939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8426865893590904939'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2009/08/grails-and-groovy-blog.html' title='Grails and Groovy Blog'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-5210140733046780953</id><published>2009-08-04T21:31:00.000-07:00</published><updated>2009-08-10T14:54:06.353-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Portal'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Grails Portal</title><content type='html'>I have been working on a project that will enable Grails to function as a Portal environment.  The article for this is on &lt;a href="http://www.groovymag.com/"&gt;GroovyMag&lt;/a&gt; which is a magazine for Groovy/Grails developers.  Here is an excerpt from the Abstract:&lt;br /&gt;&lt;br /&gt;&lt;p class="Introduction"&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p class="Introduction"&gt;&lt;span style="font-style: italic;"&gt;This article is the first in a series of three that describes a simple way to build a working framework for a user portal. This framework is built upon some very popular features in Grails and provides many examples of how to integrate popular plug-ins such as JSecurity.&lt;/span&gt;&lt;span style="font-style: italic;"&gt;  &lt;/span&gt;&lt;span style="font-style: italic;"&gt;This article describes concepts that a novice Grails developer may find challenging. &lt;/span&gt;&lt;/p&gt;&lt;p class="Introduction"&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;In the first article, a step-by-step approach will show how to construct the architecture and creating a skeleton set of pages that will be used in articles two and three.&lt;/span&gt;&lt;span style="font-style: italic;"&gt;  &lt;/span&gt;&lt;span style="font-style: italic;"&gt;By the end of this article the reader will be familiar with using basic Grails concepts to form the basis of a Grails-based portal application.&lt;/span&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-5210140733046780953?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/5210140733046780953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=5210140733046780953' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5210140733046780953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5210140733046780953'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2009/08/grails-portal.html' title='Grails Portal'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-1309999158804648474</id><published>2009-05-13T07:37:00.000-07:00</published><updated>2009-08-10T14:47:18.577-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Portal'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Requirements'/><category scheme='http://www.blogger.com/atom/ns#' term='Grails'/><title type='text'>Case Study: Using Grails as a Platform</title><content type='html'>&lt;div&gt;A few months ago I started on a new project for a not-for-profit that asked me to create a Portal and registration site for their business.  I knew that it was going to be a challenge because Grails is a new web development environment for me, and it is only in it's first release.  To my pleasant surprise Grails is now my web development environment of choice.&lt;br /&gt;&lt;br /&gt;To implement the portal, I created a set of basic requirements that would follow me through the development process:&lt;br /&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Enable users to register for the site &lt;/li&gt;&lt;li&gt;Collect Information from the user&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Manage the information and continue a business process as the result&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-1309999158804648474?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/1309999158804648474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=1309999158804648474' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1309999158804648474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1309999158804648474'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2009/05/case-study-using-grails-as-platform.html' title='Case Study: Using Grails as a Platform'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-6972192391678364575</id><published>2008-12-21T09:28:00.000-08:00</published><updated>2008-12-23T10:27:46.285-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><category scheme='http://www.blogger.com/atom/ns#' term='Build Management'/><title type='text'>Maven and IVY Dependency Management IV</title><content type='html'>&lt;h2&gt;What is Maven&lt;/h2&gt;&lt;p&gt;In this post I am not explaining how Maven is used, or the artifacts within Maven. These are very well explained in the existing documentation. In this post I will be sharing the experience of using Maven heavily over the past 2 years and comparing it to other tools that are out in the marketplace. This post is valuable to Software developers and Techical Management. It is assumed that the individual reading this post has used Maven previously and knows terminology such as &amp;quot;POM File&amp;quot; and &amp;quot;build.&amp;quot;&lt;/p&gt;&lt;p&gt;Maven can be considered to fulfill any or all of these types of products:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Project Management Tool&lt;p&gt;Maven integrates with a few good project management tools, but one of it&amp;#39;s first uses was the ability to generate a set of web pages defining the project. This was very useful when it was used by individuals on Open Source projects because at the time there was no open-source project management tools around that would build these pages by default.&lt;/p&gt;&lt;p&gt;Personally when I first reviewed the first release of Maven I found that it made the use of Maven a tad complex and decided not to use this feature. As it turns out this feature was eclipsed by many of the products that people use today like Blogs and Wikis. The really nice thing about Maven in this area is that it does automatically produce a very nice product page without work beyond putting in the name and purpose of the project.&lt;/p&gt;&lt;p&gt;Project management is key when developing large projects that have many components and many individuals working on it. There are a few project management tools that are available for no cost. Usually you can find these products inside of others such as Trac or Alfresco (which has a content type for programmers), Google Code, and Windows live services. These are all, in my opinion among others a better and more complete alternative to using Maven 2 alone for project management. I have not attempted this but I have heard of teams using configuration management tools to generate the POM files&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Build tool for software development.&lt;p&gt;This is where Maven really shines, and also has some room for improvement.&lt;/p&gt;&lt;p&gt;Maven Shines...&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Maven provides &amp;quot;structure&amp;quot; for Java programmers.&lt;p&gt;It gives developers and development groups a standard directory structure that every POM file will understand. This is very powerful because when you go from one Java project to another it can have a completely different set of directory structures and can add a layer of complexity. If you violate these rules, the build system will not work effectively by default from Maven and the programmers will have to understand the details of the build, which should not be a part of their world.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Maven has been designed to use the &amp;quot;Convention over Configuration&amp;quot; principle.&lt;p&gt;This implies that by convention Maven assumes that your projects are setup a certain way and that as software developers add different &amp;quot;Conventions&amp;quot; they will not violate previous ones that have been used. This creates a standard build system that out of the box will build a project from scratch and place it into the Maven repository to be used by other projects.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Maven is built around the concept of component development and usage.&lt;p&gt;Most build systems that are built in Ant rarely allow for the complexity of building 20-30 projects with hundreds of dependencies. Maven allows for this and definitely has the capability to resolve these issues. If you haven&amp;#39;t spent many hours trying to figure out why your web application says &amp;quot;cant find method xxxx&amp;quot; then count yourself lucky. This is typically caused when you have two different versions of the same jar file in your Java classpath. This can get ugly when you have 20-30 jar files that you have added to your Java classpath for a project. These issues are not completely resolved by using Maven, but generally they are reduced by the way that Maven tells you that there is a conflict and then gives you the tools to solve the conflict.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Maven has the ability to look inside of a products&amp;#39; dependencies and if they conflict with another jar file that is already loaded.&lt;p&gt;It shows up as conflict within Maven (when you run mvn-install, build, or package). This is important because this solves one of the major &amp;quot;time eaters&amp;quot; in a Java developers work day. These issues are pertinent to many Java architects and senior developers where their main goal is to enable other individuals to work without having to understand or have to think about the details of how the larger project is built.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Maven, of course is not the holy grail when it comes to build systems and has it&amp;#39;s problems. These problems are not issues with the design or architecture of Maven, but with the ecosystem that developed around this project:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Repository issues&lt;p&gt;There are too many Maven repositories with the same products, i.e. there are too many places that have differing versions of the same products. It doesn&amp;#39;t happen very often but I have found different public repositories that have different versions of the same open source projects. It can be very confusing to find the &amp;quot;latest&amp;quot; out on the public repositories if you don&amp;#39;t know the project well.&lt;/p&gt;&lt;p&gt;Maven repositories are everywhere, and there is one for every product.&amp;nbsp; It seems to me over the past year that the number of repositories with projects have been exploding.&amp;nbsp; In some ways that is a good thing, but when you are trying to find a product that you expect to be out on a common repository, and it isn&amp;#39;t there it can be very frustrating.&amp;nbsp; As the Internet is not run by one person or one organization these decisions can&amp;#39;t be made anywhere but the community of users.&amp;nbsp; There must be a process by which current versions of projects and new projects are placed onto a common repository.&amp;nbsp; As this is not my area of expertise I will say that it&amp;#39;s confusing for the experienced user of Maven and I know people who have stopped using Maven for precisely this reason.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Confusing documentation&lt;p&gt;Although the documentation is great for Maven in comparison to other open source projects, it still doesn&amp;#39;t really make it easy to use Maven.&amp;nbsp; The documentation for the most part is written from a completely Java technical perspective, which is fine but now that Maven is maturing and is more heavily used in corporate development better documentation will ease it&amp;#39;s integration.&amp;nbsp;&amp;nbsp; Although it is a better product than most of the build managers out there commercial or not, it loses some of it&amp;#39;s punch when higher level individuals attempt to read the documentation from the website.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;p&gt;Next Time....&lt;/p&gt;&lt;li&gt;Configuration Management Tool&lt;/li&gt;&lt;li&gt;Interoperability tool for software development&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-6972192391678364575?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/6972192391678364575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=6972192391678364575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6972192391678364575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6972192391678364575'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/maven-and-ivy-dependency-management-iv.html' title='Maven and IVY Dependency Management IV'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-6630095156016534003</id><published>2008-12-19T04:52:00.000-08:00</published><updated>2008-12-19T05:44:14.320-08:00</updated><title type='text'>Maven and IVY Dependency Management III</title><content type='html'>&lt;h2&gt;What is IVY?&lt;/h2&gt;&lt;h3&gt;Quick Introduction&lt;/h3&gt;&lt;p&gt;Ivy is a dependency management system that works within Ant.  It uses the same principles as Maven, but it's purposes are much more specialized.  It can be used to handle the downloading of resources for development, production, etc. from different repositories that are setup.  I have used it previously because I was not familiar with Maven and Ant was an easier option at the time&lt;/p&gt;&lt;h3&gt;Why was it created?&lt;/h3&gt;&lt;p&gt;As far as I can tell a few years ago there was an awareness that the issues around dependency management and build management in the open source eco-system became known.  Many developers who used open-source frameworks were going through a very painful problem when adding a new product to their internal projects.  This created a barrier to use open source.&lt;/p&gt;&lt;p&gt;IVY is one of the open-source projects that have the concept of dependency management at it's core.  As far as I know, IVY is the only one that worked pretty well with Ant and had examples that were easy to understand.  As IVY evolved, it became closer tied to Ant and now it is part of the Apache Ant project.&lt;/p&gt;&lt;h3&gt;How is it relevant today?&lt;/h3&gt;&lt;p&gt;IVY is very relevant today.  Many open source projects don't use Maven and probably won't. Ivy can be bootstrapped into any build system that is using Ant, and developers can reap the benefits of dependency management without having to change their build environment to use Maven.  Also, some environments have custom build/configuration management tools that may not be compatible with they way that Maven runs commands, IVY can solve that as well.&lt;/p&gt;&lt;h3&gt;Would I recommend IVY&lt;/h3&gt;&lt;p&gt;Here are the situations that IVY seems to be better suited for than Maven:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Using a commercial build system that is not compatible with Maven&lt;/li&gt;&lt;li&gt;Only want to use dependency management, and not complexity of Maven&lt;/li&gt;&lt;li&gt;A decision is made that changing all of the configuration management to use Maven would be too costly but still need dependency management.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-6630095156016534003?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/6630095156016534003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=6630095156016534003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6630095156016534003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6630095156016534003'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/maven-and-ivy-dependency-management-iii.html' title='Maven and IVY Dependency Management III'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-5018365452869152844</id><published>2008-12-18T05:21:00.001-08:00</published><updated>2008-12-18T05:43:49.761-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Build V.s Buy'/><title type='text'>Build Vs. Buy III - Steps to Analysis</title><content type='html'>One of the main reasons why you are doing this analysis is to map the business and/or technical requirements against the product(s) that you are trying to evaluate. The evaluation should be objective, but that is not always possible in every organization. As I have stated previously a good way of handling this is to use 3rd party analysis and compare the products based upon the functionality needed.&lt;br /&gt;&lt;br /&gt;Here are the steps that are typically taken during the process of doing a Build Versus Buy analysis:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Do a detailed functional requirements analysis of the needs associated with the product. These are the business drivers for using this product. Make sure that these requirements can be related back directly to a group/individual that is responsible for the outlay of budget for the outcome of the decision.&lt;/li&gt;&lt;li&gt;Do a detailed non-functional requirements analysis of the needs associated with the product. These are sometimes called system requirements or technical requirements. These will need to incorporate issues such as technical &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;infrastructure&lt;/span&gt;, support, and personnel.&lt;/li&gt;&lt;li&gt;Create a set of criteria in a spreadsheet that specifies the criteria for each of the vendors that you will be evaluating. &lt;/li&gt;&lt;li&gt;Create a set of weights that will be used for each criteria. &lt;/li&gt;&lt;li&gt;Have the weights and criteria approved by management and if possible publish internally within the organization so that everyone involved will feel empowered by understanding the criteria by which the evaluation will be performed.&lt;/li&gt;&lt;li&gt;Work with each Vendor to get the questions answered.&lt;/li&gt;&lt;li&gt;If questions can't be answered directly by Vendors, you may need to evaluate the product directly to get the questions answered.&lt;/li&gt;&lt;li&gt;As the person administering the build vs. buy &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;exercise&lt;/span&gt; you should rate the product(s) and compute a score.&lt;/li&gt;&lt;li&gt;Deliver the answered questions (without your rating) to any other individuals who will have to rate the product.&lt;/li&gt;&lt;li&gt;Collate the ratings and deliver:&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;li&gt;A spreadsheet with all of the questions, weights, and ratings.&lt;/li&gt;&lt;li&gt;A powerpoint presentation with explanation of the process and ratings.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Next time: Examples of a build vs. buy&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-5018365452869152844?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/5018365452869152844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=5018365452869152844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5018365452869152844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/5018365452869152844'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/build-vs-buy-iii-steps-to-analysis.html' title='Build Vs. Buy III - Steps to Analysis'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-8838638203933087975</id><published>2008-12-16T20:59:00.001-08:00</published><updated>2008-12-16T20:59:59.634-08:00</updated><title type='text'>Build Vs. Buy II</title><content type='html'>&lt;div&gt;One of the first things that I have always had trouble with during the analysis of  any of the build versus buy scenarios is finding free research that can be used, that is not bias to a specific vendor.  It is easier now with the Blogs that are out there on the Internet, but you have to be careful anyway.  Just because some guy with a professional looking blog has said that this or that application "kicks xxx" it doesn't mean that they aren't being paid by this vendor to do this, or have some other kind of bias that permeates through the IT industry.  &lt;/div&gt;&lt;br /&gt;&lt;div&gt;To avoid that, sometimes it is best to actually get research directly from the Vendor, and compare what they say.  I know that sounds kind of funny but if you look closely to some of these reports you find out what they think their product competes against.  Then, typically I will investigate those products to see if they match what I am looking for.  &lt;/div&gt;&lt;br /&gt;&lt;div&gt;The concept of it is that by looking at what their competitors are you can get a feel for what areas the product is really good in and what it is not good in.  An example is Biztalk which I am very familiar with.  In the research for Biztalk 6 (in 2006) Microsoft positioned this product as a tool for Mapping and handling XML.  When it came to SOA it was not a big player (although it could have been).  In all of the research that I did at the time it put itself in competition with other tools that mapped using XSLT instead of a full fledged SOA. The point is that by looking at their research I knew ahead of time not to expect great scores in SOA Governance, rules engine and other SOA based requirements.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;There are a few sites that you can goto for pretty good objective reporting on different products.  My favorites are listed below:&lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.infoq.com/"&gt;InfoQ&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.javalobby.org/"&gt;Java Lobby&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.theserverside.com/"&gt;The Server Side&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;br /&gt;&lt;div&gt;Next Time, Purchased Research....&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-8838638203933087975?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/8838638203933087975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=8838638203933087975' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8838638203933087975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8838638203933087975'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/build-vs-buy-ii.html' title='Build Vs. Buy II'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-4244336448288392486</id><published>2008-12-16T20:58:00.000-08:00</published><updated>2008-12-16T20:59:12.537-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Build V.s Buy'/><title type='text'>Build Vs. Buy I</title><content type='html'>&lt;div style="margin: 0px; padding: 0px; display: inline;"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/Java" rel="tag"&gt;Java&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Build%20Vs.%20Buy" rel="tag"&gt;Build Vs. Buy&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Work%20Experience" rel="tag"&gt;Work Experience&lt;/a&gt;&lt;/div&gt; &lt;p&gt;What is "Build Vs. Buy"?&amp;nbsp; This is the process that we go through as software architects, developers, technical managers to decide whether it makes sense to build the software in-house or purchase the software off the shelf and integrate it.&amp;nbsp; Here are a few examples of some experiences I have had in this area: &lt;/p&gt;&lt;ol&gt; &lt;li&gt;Central Florida Investments, Orlando FL (1992 to 1998)&lt;br&gt;&lt;br&gt; &lt;div&gt;Over the past 13 years build vs.buy recommendations have been one of the main activities that I have been involved with.&amp;nbsp; The experience that I have originates with my experiences as a lead engineer and Oracle Database Administrator at Central Florida Investments in Orlando, FL.&amp;nbsp; The environment was an Oracle Forms V3 data entry system to maintain customers and enter financial transactions.&amp;nbsp; We evaluated many products to handle pieces of the business, but in the end because of our proprietary systems it was difficult to implement any "out of the box" solutions.&amp;nbsp; These products included many report writing solutions, phone solutions and accounting packages.&lt;br&gt;&lt;br&gt;The logical solution in today's world would have been an ERP system. At the time they were evaluated and found to not be flexible enough to handle the unique business situations.&amp;nbsp; They were also too expensive&amp;nbsp; for the size of the company.&amp;nbsp; Later on, they did implement Oracle Financials successfully and it made a big impact on their business.&amp;nbsp; They were able to move from 2 resorts to 20 resorts.&amp;nbsp; I have seen this kind of investment pay off big time in many companies over the years. &lt;br&gt;&lt;br&gt;&lt;/div&gt; &lt;/li&gt;&lt;li&gt;Sunterra Resorts 1998-2000&lt;br&gt;&lt;br&gt;The next major build/buy decision I was involved with was when I worked for Sunterra Resorts in Orlando, FL.&amp;nbsp; The package we evaluated at this time was a comprehensive Resort Management System from RCI.&amp;nbsp; This system was evaluated before I came on board, and we started to use it as a basis for a large development project called "Sword."&amp;nbsp; My involvement was analyzing the Technical architecture and guessing how many hours it would take to customize the software for use by Sunterra Resorts.&lt;br&gt;&lt;br&gt;Many build versus buy decisions were made as part of this situation because of the availability of modules from RCI as well as the availability at the time of off the shelf software that could solve pieces of the business problem.&amp;nbsp; At the time I also headed a small group of software developers responsible for augmenting the system to make it scale. &lt;br&gt;&lt;br&gt;In this case my evaluation was extensive as we realized that it would take quite a bit work to scale the system because of it's architecture.&amp;nbsp; Many skilled Oracle developers were on our team including many who had worked for Oracle for a period of time.&amp;nbsp; The package was purchased, but as far as I know was never actually deployed to the extent necessary to recoup the cost of development. &lt;br&gt;&lt;br&gt; &lt;/li&gt;&lt;li&gt;Walt Disney Internet Group (2000-2005)&lt;br&gt;&lt;br&gt;At Walt Disney Internet Group (2000-2004) I was involved with a very large project called "Destination Disney." It was an 8 year project to implement CRM philosophies across Walt Disney World.&amp;nbsp; The World Wide Web really took off in importance for the latter part of this project and because there were no easy ways to get marketing information from &lt;a href="http://disneyworld.com/"&gt;disneyworld.com&lt;/a&gt; to the back-end systems of Walt Disney World a solution needed to be created that would map from the "Web" world to WDW's back end systems.&amp;nbsp; &lt;br&gt;&lt;br&gt;We evaluated a few different ETL solutions at the time using Gartner research as a guide.&amp;nbsp; We also looked at the time it would take to write it ourselves.&amp;nbsp; We did an extensive evaluation and eventually selected Informatica.&amp;nbsp; In this process I participated in creating the RFI and RFP as well as attending all evaluations.&amp;nbsp; One other task was creating a scorecard.&amp;nbsp; This scorecard was used to objectively evaluate all of the vendors as they created proof of concepts. &lt;br&gt;&lt;br&gt;In the next phase of the same project as above we needed to select a J2EE application server.&amp;nbsp; As the architect for this project I created the RFP and RFI as well as creating the scorecards.&amp;nbsp; The evaluation was done on a purely technical basis.&amp;nbsp; This was a difficult selection because the budget was very limited and our requirements very high.&lt;br&gt;&lt;br&gt; &lt;/li&gt;&lt;li&gt;Gentiva Health Services (2005-2007)&lt;br&gt;&lt;br&gt;At Gentiva Health Services (2006) as the Application Architect for the Application Development Group developing a 35 million dollar project I was responsible for designing all of the Enterprise Services.&amp;nbsp; The build/buy recommendation was for a product that could handle the HIPAA X11 messages over EDI that were coming from our business partners.&amp;nbsp; This product would also need to be part of a general SOA approach.&amp;nbsp; Gartner and Forrester research was used to select the Vendors and establish a basic set of functionality needed in the evaluation.&amp;nbsp; After meeting with the business to match the basic features from the research, I then created the RFP and RFI.&amp;nbsp; I then evaluated all of the responses according to a scorecard that was approved by upper management.&lt;br&gt;&lt;br&gt;After the results of the scorecard were published I created a presentation to the Director and Vice President who were in charge of Software Development and Infrastructure.&amp;nbsp; This was an invaluable experience because presenting to the Director of Software development and V.P. gave me experience in using the scorecard and instead of being an argument based upon opinion, the scorecard represents an objective view of the product selection.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Next Time ... What are the steps you should take ...&lt;/p&gt; &lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-4244336448288392486?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/4244336448288392486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=4244336448288392486' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/4244336448288392486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/4244336448288392486'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/build-vs-buy-i.html' title='Build Vs. Buy I'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-1148815838687229173</id><published>2008-12-16T20:50:00.000-08:00</published><updated>2008-12-16T20:56:33.172-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JBOSS'/><category scheme='http://www.blogger.com/atom/ns#' term='Spring Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='Properties Integration'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><title type='text'>Spring - JBoss Application Properties Integration - 1</title><content type='html'>&lt;div style="margin: 0px; padding: 0px; display: inline;"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/Spring%20Framework" rel="tag"&gt;Spring Framework&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/JBoss" rel="tag"&gt;JBoss&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Java" rel="tag"&gt;Java&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Properties%20Integration" rel="tag"&gt;Properties Integration&lt;/a&gt;&lt;/div&gt; &lt;p&gt;Even though there have been so many things written about Spring and JBoss it seems that there really isn't a good discussion around properties.  I have been doing web development with JBoss since 2003 and have found that the properties service is invaluable to work with since it really makes it easy to deal with Server based properties that are bound to the system that it is running on. &lt;/p&gt;&lt;table border="1" cellpadding="2" cellspacing="0" width="400"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="400"&gt; &lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;server&gt;  &lt;/server&gt;&lt;/p&gt;&lt;p&gt; &lt;mbean code="org.jboss.varia.property.PropertyEditorManagerService" name="jboss:type=Service,name=PropertyEditorManager"&gt;  &lt;/mbean&gt;&lt;/p&gt;&lt;p&gt;    &lt;/p&gt;&lt;p&gt;  &lt;!-- ==================================================================== --&gt;&lt;br /&gt;&lt;!-- System Properties Service                                            --&gt;&lt;br /&gt;&lt;!-- ==================================================================== --&gt;  &lt;/p&gt;&lt;p&gt;  &lt;!--     | Allows rich access to system properties.   --&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;  &amp;lt;mbean code="org.jboss.varia.property.SystemPropertiesService"&lt;br /&gt;  name="jboss:type=Service,name=SystemProperties"&amp;gt;  &lt;/p&gt;&lt;p&gt;    &amp;lt;attribute name="Properties"&amp;gt;&lt;br /&gt;   project.filepath=../soap/project.xml&lt;br /&gt;   project.service=service&lt;br /&gt;   project.portNumber=8888&lt;br /&gt; &amp;lt;/attribute&amp;gt;  &lt;/p&gt;&lt;p&gt;  &amp;lt;/mbean&amp;gt;  &lt;/p&gt;&lt;p&gt;&amp;lt;/server&amp;gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;If you are curious about the Properties service, there is a properties-service.xml in each deploy directory of your JBoss implementation.  This file, if not changed by the user does not contain any properties.  When there are properties added to the file they become "Java System properties."  The properties are then available to Springs' PropertyPlaceholderConfigurer. &lt;/p&gt;&lt;table border="1" cellpadding="2" cellspacing="0" width="481"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="479"&gt; &lt;p&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;beans xmlns="&lt;a href="http://www.springframework.org/schema/beans%22"&gt;http://www.springframework.org/schema/beans"&lt;/a&gt;&lt;br /&gt; xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance%22"&gt;http://www.w3.org/2001/XMLSchema-instance"&lt;/a&gt;&lt;br /&gt; xsi:schemaLocation="&lt;a href="http://www.springframework.org/schema/beans"&gt;http://www.springframework.org/schema/beans&lt;/a&gt; &lt;a href="http://www.springframework.org/schema/beans/spring-beans.xsd%22"&gt;http://www.springframework.org/schema/beans/spring-beans.xsd"&lt;/a&gt;&amp;gt;&lt;br /&gt;&amp;lt;bean id="propertyConfigurer"&lt;br /&gt;class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&amp;gt;&lt;br /&gt;&amp;lt;property name="systemPropertiesMode" value="2"&amp;gt;&amp;lt;/property&amp;gt;&lt;br /&gt;&amp;lt;property name="location" value="WEB-INF/test.properties"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&amp;lt;bean id="soapUi" class="com.test.utility.SpringMockServiceRunner" lazy-init="false"&amp;gt;&lt;br /&gt;&amp;lt;constructor-arg index="0" value="${project.filepath}" /&amp;gt;&lt;br /&gt;&amp;lt;constructor-arg index="2" value="${project.portNumber}"/&amp;gt;&lt;br /&gt;&amp;lt;constructor-arg index="1" value="${project.service}"/&amp;gt;&lt;br /&gt;&amp;lt;/bean&amp;gt;&lt;br /&gt;&amp;lt;/beans&amp;gt;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;  &lt;/p&gt;&lt;p&gt;More on different options available next time..&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-1148815838687229173?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/1148815838687229173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=1148815838687229173' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1148815838687229173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/1148815838687229173'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/12/spring-jboss-application-properties.html' title='Spring - JBoss Application Properties Integration - 1'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-6581761299637414706</id><published>2008-10-21T19:50:00.000-07:00</published><updated>2008-12-16T20:56:56.496-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><title type='text'>Maven and IVY Dependency Management II</title><content type='html'>&lt;h2&gt;Maven Dependency Management&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;There have been many blogs written about Maven, and how it can be used.  What I really haven't seen is an explanation for how it should be used.  I have done quite a bit of reading through many blogs, and found answers to some of my questions.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Most of those questions were answered by reading the documentation provided by Apache.  The problem really is knowing how to read the Apache documentation so that it makes sense.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Enables me to find compatibilities/incompatibilities in libraries without having to sweat the details.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integrates ok with Eclipse Ganymede&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Creates an out of the box build system that can compete with anything I can write&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Integrates via plugin with any open source build tool imaginable&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-6581761299637414706?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/6581761299637414706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=6581761299637414706' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6581761299637414706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/6581761299637414706'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/10/maven-and-ivy-dependency-management-ii.html' title='Maven and IVY Dependency Management II'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-7896077449847371364</id><published>2008-10-05T10:19:00.000-07:00</published><updated>2008-12-16T20:57:28.801-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Open Source'/><category scheme='http://www.blogger.com/atom/ns#' term='Maven'/><category scheme='http://www.blogger.com/atom/ns#' term='JAVA'/><category scheme='http://www.blogger.com/atom/ns#' term='IVY'/><title type='text'>Maven, IVY and Dependency Management  Part 1</title><content type='html'>&lt;div style="margin: 0px; padding: 0px; display: inline;"&gt;del.icio.us Tags: &lt;a href="http://del.icio.us/popular/Maven" rel="tag"&gt;Maven&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Java" rel="tag"&gt;Java&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Ivy" rel="tag"&gt;Ivy&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Dependency%20Management" rel="tag"&gt;Dependency Management&lt;/a&gt;,&lt;a href="http://del.icio.us/popular/Open%20Source" rel="tag"&gt;Open Source&lt;/a&gt;&lt;/div&gt; &lt;h2&gt;Introduction&lt;/h2&gt; &lt;p&gt;After working with many open source technologies, dependency management has been a tough issue.  There are so many frameworks these days that have overlapping functionality so it is very common that the dependencies for these projects are actually very similar, but they do not always work together very well.  This problem is especially evident when you are taking two different frameworks that do any sort of Java Byte manipulation (cglib for example).   &lt;/p&gt;&lt;p&gt;To solve this very complex problem, among others two Apache projects have been maturing over the past two years that have different approaches but from a dependency management standpoint, similar outcomes.  In addition, the maturity of these projects have risen to a point where there is adequate IDE integration. &lt;/p&gt;&lt;p&gt;&lt;a href="http://maven.apache.org/"&gt;Apache Maven 2 project&lt;/a&gt;&lt;br /&gt;&lt;a href="http://ant.apache.org/ivy/"&gt;Apache Ant IVY&lt;/a&gt; &lt;/p&gt;&lt;h2&gt;&lt;/h2&gt; &lt;h2&gt;What is Dependency Management&lt;/h2&gt; &lt;p&gt;Dependency Management creates rules by which different frameworks and different projects can be integrated with as little impact as possible.  There are many situations where you would like to use a specific feature of a new version of an open source project. You can't just use the project without having to figure out which other open source packages it uses, and what versions.  This has been solved by most open source projects by including a "pom" file.  This pom file is a set of dependencies that are specified in the file and then relate to other files that are needed.  These files have their dependencies, and so on. &lt;/p&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:180%;"&gt;Why use Dependency Management?&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;p&gt;There are many reasons to use dependency management, as I see it there a few factors:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Large teams have trouble integrating components that are developed separately.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;There are many open-source frameworks that when used together have conflicting Java libraries.&lt;/li&gt;&lt;li&gt;It is slowly becoming a standard on open source projects to have a dependency manager download the correct libraries at build time either through IVY or Maven 2.&lt;/li&gt;&lt;li&gt;Dependency management instills a software engineering discipline missing in many projects in the past by specifying what other projects the piece of software is dependent upon.&lt;/li&gt;&lt;/ul&gt;In this new age of having very short time-lines we as developers try to create software designs that are based upon components that we can bring from either a commercial vendor or an open source project.  We then plan on combining those libraries and frameworks with code that we quickly develop in-house to solve the business problem.  Part of the issue as a result of this is that we need to know that each off the shelf framework/component that we use will be compatible with other components that are developed in-house.&lt;br /&gt;&lt;br /&gt;In the past, small teams were able to create the whole project from the bare-bones including the application server components such as servlet engines.  In the past few years each of the pieces that we are responsible to actually write code for as been reduced.  For instance just a few years ago I was asked to develop a whole architecture for persisting data to a database so that it would be easy for programmers to request the data from the database.  This was before Hibernate and Toplink during the formative years of EJB 1.x and 2.x.&lt;br /&gt;&lt;br /&gt;Now, as Java developers we don't have the responsiblity of building these layers as they are provided either by the software Vendor we are using, or using an open source framework such as Hibernate, IBatis, etc. The casualty of building some of these layers yourself is that you have to adapt to the fact that these frameworks have their own dependencies that may conflict with either your own frameworks, the JDK you are using, or even the application server you are deploying to.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-7896077449847371364?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/7896077449847371364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=7896077449847371364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/7896077449847371364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/7896077449847371364'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/10/maven-ivy-and-dependency-management.html' title='Maven, IVY and Dependency Management  Part 1'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-3842193240465290653</id><published>2008-10-05T10:08:00.000-07:00</published><updated>2008-10-05T10:10:56.655-07:00</updated><title type='text'>Useful Maven Update Sites for common Apps</title><content type='html'>After working with Maven for my second project I have definitely found it to be a real asset to a Java project.  Combined with the M2 eclipse plugin you really have an environment that can make it easy to develop software.  Here are some of the essential plug-ins that I recommend for Eclipse and Maven:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://m2eclipse.sonatype.org/update/"&gt;Maven Integration for Eclipse Update Site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://dist.springframework.org/release/IDE"&gt;Spring IDE Update Site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://subclipse.tigris.org/update_1.2.x"&gt;Subclipse Update Site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I would recommend the JBOSS IDE but I have not found it to be very stable lately and I'm patiently waiting for the 3.0 release.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-3842193240465290653?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/3842193240465290653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=3842193240465290653' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/3842193240465290653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/3842193240465290653'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/10/useful-maven-update-sites-for-common.html' title='Useful Maven Update Sites for common Apps'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4179812064174942414.post-8377603246646793163</id><published>2008-10-05T10:02:00.000-07:00</published><updated>2008-10-05T10:08:49.509-07:00</updated><title type='text'>Common Maven Commands</title><content type='html'>Here are some important Maven commands that I always seem to forget but are needed on many projects that I work on.&lt;br /&gt; &lt;br /&gt;I am using this command to create an Eclipse project from a Maven project&lt;br /&gt; &lt;br /&gt;mvn eclipse:eclipse&lt;br /&gt; &lt;br /&gt;This will download all of the libraries required in your pom.xml and create a default repository for you.&lt;br /&gt; &lt;br /&gt;mvn install&lt;br /&gt;&lt;br /&gt;This will clean the "target" directory of all files, note that this does not compile your code.&lt;br /&gt;&lt;br /&gt;mvn clean&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4179812064174942414-8377603246646793163?l=javaarchramble.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javaarchramble.blogspot.com/feeds/8377603246646793163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4179812064174942414&amp;postID=8377603246646793163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8377603246646793163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4179812064174942414/posts/default/8377603246646793163'/><link rel='alternate' type='text/html' href='http://javaarchramble.blogspot.com/2008/10/common-maven-commands.html' title='Common Maven Commands'/><author><name>Joshua Davis</name><uri>http://www.blogger.com/profile/10630084168049860089</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='23' height='32' src='http://4.bp.blogspot.com/_W26P9F1sE2o/SOj2jcm00gI/AAAAAAAABDU/nQ8ptC7xeQg/S220/JoshHeadShot.jpg'/></author><thr:total>0</thr:total></entry></feed>
