Sunday, October 14, 2012

Looking at new front-end tech stack: bootstrap + backbone

Recently, I have been developing using a new front-end technology stack that includes bootstrap from Twitter and backbone.js (a subcomponent of DocumentCloud.org).

Here is a partial list



Bootstrap has had a lot of adoption in the last few months. It offers a great out of the box set of styles and behaviors that make sense, allowing the quick development of 'responsive web design' web designs that know the limits of the device at hand and respond by tailoring the layout appropriately. It requires jquery (of course) and builds on jquery.com by providing layout and default styles and a few basic components with great default behavior. Its CSS is managed nicely using less.js to provide your CSS with variables, mixins, functions etc.

Backbone is a javascript library supporting an MVC like framework to develop single page web apps (rendering a complete UI in one html page) where the only time to go to the server is to interact with REST resources for data. It organizes code into models, views and collections. It's 'controller' is implemented as a router that allows linking to behavior and routing as bookmark-able URLs for browser history. Views typically use client side template resolution implemented by underscore js and not implemented on the server. Models structure information passed to and from the server. Collections are collections of model objects that are associated with a REST resource on the server and support CRUD operations.  

What is obvious by analyzing technology innovation on the front end is how much we rely on good javascript skills to make it all happen. However javascript allows as much clumsy programming as it offers in elegance (read JavaScript The Good Parts by the Great Crockford). Larger scale javascript code can be quite strange to read when trying to leverage the good parts and organizing js into classes and modules to scale. So pre-compilers like CoffeeScript and Closure offer amazing lexical simplification and cleaner code organization and optimization. Neither of which we are using currently, but we possibly may. The elegance and readability of coffee-script for instance or the compression and performance enhancements with Closure are very impressive.

Further, writing large scale javascript application requires more than just MVC, it requires modular development. Wrapping the javascript into good modular design is accomplished following the AMD pattern (as explained well in this blog). Using require.js helps solve the problem of dependencies when javascript itself has no 'import' or 'module' commands, as well as allowing asynchronous loading and plugin architecture for the loading of different kinds of resources (like text)..

And what about testing? Our team is big on developer testing before tossing our project off to QA, and we like practicing TDD (or now BDD). There is QUnit from JQuery. But we are beginning to use jasmine. Jasmine, like QUnit runs tests and renders results on a nifty html page showing passes and fails. Integrating this will a build system for continuous integration (CI) is more of a challenge. That brings us to automated building, packaging, deploying, and continuous integration testing and analysis.

Our back end is traditional J2EE. We expose REST resources via Jersey and interact with business services and information via EJB3 and JPA (and also the great SOA Suite layer from Oracle with BPEL, a Service Bus and traditional SOAP based service integration.  We build using maven, continuously integrate with Hudson, run JUnit tests and generate reports on code coverage via JaCoCo or Coberatura. On the back end, we are used to automating this build and deploy cycle and assuring no breakage after each check in. But these tools and techniques are new to us on the front end side..

We need solutions for automated and scripted builds, running and analyzing tests, code coverage and other static analysis using continuous integration techniques. At least that is what we are used to and expect. This process must/should integrate with our existing continuous integration and code analysis tools if possible. Tools offered as part of Node.js are possible solutions. Also maven has a javascript plugin. Many others exist as well. Further analysis is required on this. I will update progress on this blog.

Friday, October 5, 2012

The front-end Moves to the Front Seat

Sometimes the new is old. Back in the 'client-server' days (yes, I'm that old) the main development cost was on the client side. Using the likes of Powerbuilder, Visual Basic or other tools, developers would spend fantastic amounts of time on the front end connecting directly to a database, embedding sql (or proprietary data access api) and creating interactive screens and windows to present and manage data. A three tiered architecture would enhance the database operations with procedures or tirggers to enable server side processing. A brave few created purpose built server API's in C to support a true middle tier between the client and the database. And transaction managers and message oriented middleware were engaged to connect everything together. But even then, the main application logic would fall on the front end.

The web moved us back to a more 'time share' IBM 360/CICS/3270 kind of model (no, I'm not that old) where the client took a back seat and the application logic was all rendered on the server. The browser was the new 'terminal' displaying html pages with form fields and submitting requests to the almighty server to dice up a screen for the response. Though the back end divided into multiple tiers separating application front-end logic (typically a markup language) from business logic (e.g. EJB) from the database and other resources (n-tier), the client (browser) was still basically a dumb terminal. There were some spikes to make the client smarter: applets, flash, etc. and some javascript to enhance the experience with more sophisticated controls. But the browser was still a speed bump to drive processing to the front end.

Today the client is taking the front seat again. JavaScript, HTML5 and powerful and fast browsers have allowed much more sophisticated processing running on the client. New frameworks such as backbone js are allowing developers to build entire applications with a single page html dynamically rendered by javascript where the only interactions to the back end are to manipulate the data not render the screen. The client development is reminiscent of small talk, relying on Model View Controller (MVC) architecture to separate the display from the data and the control. The back end remains basically stateless providing a thin logical access to CRUD operations on data, and implementing business logic to shape, compute or aggregate data and coordinate functionality with other resources and tiers.

Sunday, March 18, 2012

Getting started with Spring Roo, STS and GWT - Part 2

In part one of this multipart blog/article, we followed along with the Spring  Roo Tutorial creating a Pizza shop. But we stopped at the back end. Now its time to create front end. For this blog we will complete the tutorial and show the front end using Spring MVC and JSP pages. Next article we will do this with GWT.





Part 2 - Adding a front end with Spring MVC and JSP

To summarize the previous blog,

  1. installed Spring StS
  2. created a spring project named 'pizza' to package 'com.springsource.pizzashop'
  3. executed the following in spring roo's shell:

// Spring Roo 1.1.4.RELEASE [rev f787ce7] log opened at 2012-03-17 10:38:04
project --topLevelPackage com.springsource.roo.pizzashop --projectName pizza --java 6
// Spring Roo 1.1.4.RELEASE [rev f787ce7] log closed at 2012-03-17 10:38:15
// Spring Roo 1.1.4.RELEASE [rev f787ce7] log opened at 2012-03-17 10:38:19
hint
hint
persistence setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE 
hint
entity --class ~.domain.Topping --testAutomatically 
field string --fieldName name --notnull --sizeMin 2
entity --class ~.domain.Base --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float
 
field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
 
field set --fieldName pizzas --type ~.domain.Pizza
perform tests

No we will add a user interface.

Step 1 - setup Spring MVC

In Roo shell type:
  1. web mvc setup
The web mvc setup does a lot. We really need to drill down here if we hope to understand the science behind the magic. But you can skip to Step 2 if you are impatient. After the code is generated it may work in a basic way, but you always have to muck with the details to make it work the way you want it to.

 Here is the output from Spring Roo shell:

Created SRC_MAIN_WEBAPP\WEB-INF\spring
Created SRC_MAIN_WEBAPP\WEB-INF\spring\webmvc-config.xml
Created SRC_MAIN_WEBAPP\WEB-INF\web.xml
Created SRC_MAIN_WEBAPP\images
Created SRC_MAIN_WEBAPP\images\create.png
Created SRC_MAIN_WEBAPP\images\list.png
Created SRC_MAIN_WEBAPP\images\resultset_previous.png
Created SRC_MAIN_WEBAPP\images\resultset_next.png
Created SRC_MAIN_WEBAPP\images\show.png
Created SRC_MAIN_WEBAPP\images\favicon.ico
Created SRC_MAIN_WEBAPP\images\delete.png
Created SRC_MAIN_WEBAPP\images\resultset_first.png
Created SRC_MAIN_WEBAPP\images\springsource-logo.png
Created SRC_MAIN_WEBAPP\images\resultset_last.png
Created SRC_MAIN_WEBAPP\images\add.png
Created SRC_MAIN_WEBAPP\images\banner-graphic.png
Created SRC_MAIN_WEBAPP\images\update.png
Created SRC_MAIN_WEBAPP\styles
Created SRC_MAIN_WEBAPP\styles\alt.css
Created SRC_MAIN_WEBAPP\styles\standard.css
Created SRC_MAIN_WEBAPP\WEB-INF\classes
Created SRC_MAIN_WEBAPP\WEB-INF\classes\standard.properties
Created SRC_MAIN_WEBAPP\WEB-INF\classes\alt.properties
Created SRC_MAIN_WEBAPP\WEB-INF\layouts
Created SRC_MAIN_WEBAPP\WEB-INF\layouts\default.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\layouts\layouts.xml
Created SRC_MAIN_WEBAPP\WEB-INF\views
Created SRC_MAIN_WEBAPP\WEB-INF\views\header.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\footer.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\views.xml
Created SRC_MAIN_WEBAPP\WEB-INF\views\index.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\index-template.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\uncaughtException.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\resourceNotFound.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\dataAccessFailure.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\update.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\create.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\dependency.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\show.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\list.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\find.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\select.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\display.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\column.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\editor.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\checkbox.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\simple.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\input.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\textarea.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\datetime.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\table.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\form\fields\reference.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\menu
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\pagination.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\theme.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\placeholder.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\panel.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\language.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\util\load-scripts.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\i18n
Created SRC_MAIN_WEBAPP\WEB-INF\i18n\messages.properties
Created SRC_MAIN_WEBAPP\images\en.png
Updated SRC_MAIN_WEBAPP\WEB-INF\i18n\application.properties
Updated SRC_MAIN_WEBAPP\WEB-INF\web.xml
Updated ROOT\pom.xml [added dependencies org.springframework:spring-web:${spring.version}, org.springframework:spring-webmvc:${spring.version}, org.springframework.webflow:spring-js-resources:2.2.1.RELEASE, commons-digester:commons-digester:2.0, commons-fileupload:commons-fileupload:1.2.1, javax.servlet:jstl:1.2, javax.el:el-api:1.0, joda-time:joda-time:1.6, javax.servlet.jsp:jsp-api:2.1, commons-codec:commons-codec:1.4; updated project type to war; added dependencies org.apache.tiles:tiles-core:2.2.1, org.apache.tiles:tiles-jsp:2.2.1]
Updated SRC_MAIN_WEBAPP\WEB-INF\spring\webmvc-config.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\footer.jspx

Let's look at a couple of things here to understand what happened. This is just the 'framework' of supporting configurations and code of a fully functional web application based on Spring MVC with JSP pages and Apache Tiles with layout. In spring MVC, one place to look in Spring MVC is the spring config file so see how your application is configured, here it is found in SRC_MAIN_WEBAPP\WEB-INF\spring\webmvc-config.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
 <!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
 <context:component-scan base-package="com.springsource.roo.pizzashop" use-default-filters="false">
  <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
 </context:component-scan>
 
 <!-- Turns on support for mapping requests to Spring MVC @Controller methods
      Also registers default Formatters and Validators for use across all @Controllers -->
 <mvc:annotation-driven/>
 
 <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources -->
 <mvc:resources location="/, classpath:/META-INF/web-resources/" mapping="/resources/**"/>
 
 <!-- Allows for mapping the DispatcherServlet to "/" by forwarding static resource requests to the container's default Servlet -->
 <mvc:default-servlet-handler/>
 
 <!-- register "global" interceptor beans to apply to all registered HandlerMappings -->
 <mvc:interceptors>
  <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
  <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
 </mvc:interceptors>
 
 <!-- selects a static view for rendering without the need for an explicit controller -->
 <mvc:view-controller path="/" view-name="index"/>
 <mvc:view-controller path="/uncaughtException"/>
 <mvc:view-controller path="/resourceNotFound"/>
 <mvc:view-controller path="/dataAccessFailure"/>

 <!-- Resolves localized messages*.properties and application.properties files in the application to allow for internationalization. 
  The messages*.properties files translate Roo generated messages which are part of the admin interface, the application.properties
  resource bundle localizes all application specific messages such as entity names and menu items. -->
 <bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource" p:basenames="WEB-INF/i18n/messages,WEB-INF/i18n/application" p:fallbackToSystemLocale="false"/>
 
 <!-- store preferred language configuration in a cookie -->
 <bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver" id="localeResolver" p:cookieName="locale"/> 
 
 <!-- resolves localized <theme_name>.properties files in the classpath to allow for theme support -->
 <bean class="org.springframework.ui.context.support.ResourceBundleThemeSource" id="themeSource"/>
 
 <!-- store preferred theme configuration in a cookie -->
 <bean class="org.springframework.web.servlet.theme.CookieThemeResolver" id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard"/>

 <!-- This bean resolves specific types of exceptions to corresponding logical - view names for error views. 
      The default behaviour of DispatcherServlet - is to propagate all exceptions to the servlet container: 
      this will happen - here with all other types of exceptions. -->
 <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="uncaughtException">
  <property name="exceptionMappings">
   <props>
    <prop key=".DataAccessException">dataAccessFailure</prop>
    <prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
    <prop key=".TypeMismatchException">resourceNotFound</prop>
    <prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
   </props>
  </property>
 </bean>
 
 <!-- allows for integration of file upload functionality -->
 <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
  </bean>
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
    <property name="definitions">
      <list>
        <value>/WEB-INF/layouts/layouts.xml</value>
        <!-- Scan views directory for Tiles configurations -->
        <value>/WEB-INF/views/**/views.xml</value>
      </list>
    </property>
  </bean>
</beans>

Most of this is well documented and standard. But I would point out a couple of things. The top of this configuration defines how controllers are found. In spring MVC, rather than a monolythic servlet, the url requests are dispatched to controllers. Controllers are java classes annotated with @Controller that handle the requests and generate responses (typically by delegating to a view resolver that can render a jspx page or a tiles definition (or other technology)).
The below snippet shows that we are using spring MVCs component scan ccapability to find controllers by looking for the Controller stereotype (@Controller marker) in the com.springsource.roo.pizzashop base package. The next command will generate these contollers for each domain class we have created.

<!-- The controllers are autodetected POJOs labeled with the @Controller annotation. -->
 <context:component-scan base-package="com.springsource.roo.pizzashop" use-default-filters="false">
  <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
 </context:component-scan>
 
 <!-- Turns on support for mapping requests to Spring MVC @Controller methods
      Also registers default Formatters and Validators for use across all @Controllers -->
 <mvc:annotation-driven/>


The last part, usage of Titles. this bean configuration shows where the layouts.xml and views.xml files are. You will need to understand Tiles

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>
    <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
      <property name="definitions">
        <list>
          <value>/WEB-INF/layouts/layouts.xml</value>
          <!-- Scan views directory for Tiles configurations -->
          <value>/WEB-INF/views/**/views.xml</value>
        </list>
      </property>
    </bean>

The layout.xml class defines some basic arrangements of the pages that we can reuse. Tiles 'composes' pages from smaller parts based on these definition files.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

  <definition name="default" template="/WEB-INF/layouts/default.jspx">
    <put-attribute name="header" value="/WEB-INF/views/header.jspx" />
    <put-attribute name="menu" value="/WEB-INF/views/menu.jspx" />
    <put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
  </definition>

  <definition name="public" template="/WEB-INF/layouts/default.jspx">
    <put-attribute name="header" value="/WEB-INF/views/header.jspx" />
    <put-attribute name="footer" value="/WEB-INF/views/footer.jspx" />
  </definition>

</tiles-definitions>


And the views.xml file contains configurations of specific pages. when spring navigates to a page, the view resolver translates the view names found here into tiles configurations, which then allow tiles to render the final page by assembling the pieces together. Notice the view definitions 'extend' the definitions in layouts.xml. Layouts.xml reference the exact layout jspx pages and standard parts (header, menu, footer) that are reusable. The view definition supplies the body that is unique to the view. Initially only standard 'error' pages are configured. The next command will add specific pages generated based on analyzing the domain classes we have created in Roo.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
 "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
 "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

  <definition name="index" extends="default">
    <put-attribute name="body" value="/WEB-INF/views/index.jspx" />
  </definition>

  <definition name="dataAccessFailure" extends="public">
    <put-attribute name="body" value="/WEB-INF/views/dataAccessFailure.jspx" />
  </definition>

  <definition name="resourceNotFound" extends="public">
    <put-attribute name="body" value="/WEB-INF/views/resourceNotFound.jspx" />
  </definition>

  <definition name="uncaughtException" extends="public">
    <put-attribute name="body" value="/WEB-INF/views/uncaughtException.jspx" />
  </definition>

</tiles-definitions>


Step 2 - create the scaffold pages for our classes
  1. web mvc all --package ~.web 
This also does a lot of code generation.

Here is what Roo responded with:

Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\BaseController.java
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\PizzaOrderController.java
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\ToppingController.java
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\PizzaController.java
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\ApplicationConversionServiceFactoryBean.java
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\toppings\views.xml
Created SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\menu\menu.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\menu\item.tagx
Created SRC_MAIN_WEBAPP\WEB-INF\tags\menu\category.tagx
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\views\toppings\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\i18n\application.properties
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\bases\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\views\bases\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\i18n\application.properties
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\i18n\application.properties
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\views.xml
Updated SRC_MAIN_WEBAPP\WEB-INF\views\menu.jspx
Updated SRC_MAIN_WEBAPP\WEB-INF\i18n\application.properties
Updated SRC_MAIN_WEBAPP\WEB-INF\spring\webmvc-config.xml
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\ApplicationConversionServiceFactoryBean_Roo_ConversionService.aj
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\ToppingController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings\list.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings\show.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings\create.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\toppings\update.jspx
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\BaseController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases\list.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases\show.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases\create.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\bases\update.jspx
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\PizzaController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\list.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\show.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\create.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzas\update.jspx
Created SRC_MAIN_JAVA\com\springsource\roo\pizzashop\web\PizzaOrderController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\list.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\show.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\create.jspx
Created SRC_MAIN_WEBAPP\WEB-INF\views\pizzaorders\update.jspx

Looking at this output we can see that there is some repition. For each main domain class (Toppping, Bse, Pizza and PizzaOrder) we generate a controller and four jspx pages (views) list.jspx, show.jspx, create.jspx and update.jspx tied together in a menu system (menu.jspx). For tiles, each has its own views.xml file to show what layout is used.

Lets look at a couple of parts. Here is the controllers it created for Pizza:

File: ~.web.PizzaController.java

package com.springsource.roo.pizzashop.web;

import com.springsource.roo.pizzashop.domain.Pizza;
import org.springframework.roo.addon.web.mvc.controller.RooWebScaffold;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@RooWebScaffold(path = "pizzas", formBackingObject = Pizza.class)
@RequestMapping("/pizzas")
@Controller
public class PizzaController {
}



This looks pretty simple. From spring mvc the @Controller annoation marks this as a controller for the dispatcher to find. The @RequestMapping annotation indicates how to find this controller based on the request uri. The @RooWebScaffold annotation is the secret sauce that supports the Roo generated scaffold application, allowing for CRUD based functionality with List and Form views.

In fact, the annotations leverage several aspects that inject a lot of behavior here. STS can show you these using the Cross references panel to the right of the code (typically)


We can see here, that the aspects inject methods like:

  • create
  • createForm
  • delete
  • encode
  • list
  • populateBases (many-one relationship)
  • populatePizzas (for lists)
  • populateToppings (many-many relationship)

Each one of these methods is very useful and relatively generic. Because roo generates this aspect j inter type generation ITD file (see spring roo architecture page) which will  add these neumerous methods to your controller separating the maintenance of your customization of you particular controller class from this standardized template like methods.

For real applications, to customize behavior, we need to understand what is injected in the ITD.

Generated PizzaController_Roo_Controller.aj
// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).

package com.springsource.roo.pizzashop.web;

import com.springsource.roo.pizzashop.domain.Base;
import com.springsource.roo.pizzashop.domain.Pizza;
import com.springsource.roo.pizzashop.domain.Topping;
import java.io.UnsupportedEncodingException;
import java.lang.Integer;
import java.lang.Long;
import java.lang.String;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

privileged aspect PizzaController_Roo_Controller {
    
    @RequestMapping(method = RequestMethod.POST)
    public String PizzaController.create(@Valid Pizza pizza, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            uiModel.addAttribute("pizza", pizza);
            return "pizzas/create";
        }
        uiModel.asMap().clear();
        pizza.persist();
        return "redirect:/pizzas/" + encodeUrlPathSegment(pizza.getId().toString(), httpServletRequest);
    }
    
    @RequestMapping(params = "form", method = RequestMethod.GET)
    public String PizzaController.createForm(Model uiModel) {
        uiModel.addAttribute("pizza", new Pizza());
        return "pizzas/create";
    }
    
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String PizzaController.show(@PathVariable("id") Long id, Model uiModel) {
        uiModel.addAttribute("pizza", Pizza.findPizza(id));
        uiModel.addAttribute("itemId", id);
        return "pizzas/show";
    }
    
    @RequestMapping(method = RequestMethod.GET)
    public String PizzaController.list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            uiModel.addAttribute("pizzas", Pizza.findPizzaEntries(page == null ? 0 : (page.intValue() - 1) * sizeNo, sizeNo));
            float nrOfPages = (float) Pizza.countPizzas() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
        } else {
            uiModel.addAttribute("pizzas", Pizza.findAllPizzas());
        }
        return "pizzas/list";
    }
    
    @RequestMapping(method = RequestMethod.PUT)
    public String PizzaController.update(@Valid Pizza pizza, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            uiModel.addAttribute("pizza", pizza);
            return "pizzas/update";
        }
        uiModel.asMap().clear();
        pizza.merge();
        return "redirect:/pizzas/" + encodeUrlPathSegment(pizza.getId().toString(), httpServletRequest);
    }
    
    @RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
    public String PizzaController.updateForm(@PathVariable("id") Long id, Model uiModel) {
        uiModel.addAttribute("pizza", Pizza.findPizza(id));
        return "pizzas/update";
    }
    
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public String PizzaController.delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        Pizza.findPizza(id).remove();
        uiModel.asMap().clear();
        uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
        uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
        return "redirect:/pizzas";
    }
    
    @ModelAttribute("bases")
    public Collection PizzaController.populateBases() {
        return Base.findAllBases();
    }
    
    @ModelAttribute("pizzas")
    public Collection PizzaController.populatePizzas() {
        return Pizza.findAllPizzas();
    }
    
    @ModelAttribute("toppings")
    public Collection PizzaController.populateToppings() {
        return Topping.findAllToppings();
    }
    
    String PizzaController.encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
        String enc = httpServletRequest.getCharacterEncoding();
        if (enc == null) {
            enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
        }
        try {
            pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
        }
        catch (UnsupportedEncodingException uee) {}
        return pathSegment;
    }
    
}




Step 3 - Run the Application on the Web Server

Right click the application 'pizza' and choose Run... > Run on server. This will open the run on server dialog.




Select the default app server. STS already configures the VMWare vFabric server which will work for us for the spring mvc. For GWT eventually we will choose other options (see next articles).

Press Next and make sure the pizza application is deployed (moved from Available to Configured)
And press 'Finish'

Now the application is deployed and stared. STS will try and start this in its own default browser, which wont really run it well (unless configured otherwise). So mke sure to open your favorite browser (aka Chrome) and see the results from the url

http://localhost:8080/pizza/

When started you should see:


Notice that tiles has assembled this page by bringing together a standard header, and a menu. The content area changes depending on what is selected.

The menu shows each domain class with two actions: Create new and List all . You can experiment with this scaffold application, create stuff etc. Notice how it handles the relationships from Pizza to Topping, or Pizza to Base. Or how PizzaOrders works.

This is not a deliverable application by far, but it will demonstrate your model. The technology configuration that it uses has a lot of assumptions on the tag @RooWebScaffold annotation to make it all work for actions like:

  • List
  • Create
  • View
  • Edit
  • Remove


The scaffold also uses custom tags to handle these forms and expose this functionality.

You can customize what it generates incrementally to move closer to your application.


  • You can modify messages
  • you can modify csss
  • you can play with layout (remember tiles)
  • And parts of the JSP


Opinion

But real customization to the desired application design is hard if you start with a web site design in mind and try to map it to the scaffold UI. For the controller, the ITD (intertype files) created add very useful standard form based behavior to your applicaitons which can be leveraged by a variety of UI approaches.  But for the JSP generated, if you don't care as much and are doing an administrative application, this approach may suit you. You can compromise the UI design to best fit what has been generated and make customization's where needed. My experience is that this is rare. You can look at what is generated, but day 2 you are on your own. The basic configuration of spring mvc with tiles is good. The scaffold tags and jsps may not be what you need. You will need to really understand the annotated controllers and be able to write your own front end.

Next Steps

Next we will configure to use with GWT and see how this looks








Saturday, March 10, 2012

Another MVC Framework - Play

Recently, I have found a little down time and thought I would investigate some other frameworks. I have been working mostly with Spring MVC this last year. I stumbled upon  Play Framework recently. It reminded me of a promotion of Ruby on Rails a few years ago comparing a several feet high stack of books on J2EE with the one simple single Rails book. Play framework is taking the same approach. Simplicity and immediacy.

It uses a command line similar to Rails (and Spring Roo by the way) to create initial constructs based on archetypes/patterns. It incorporates the web server so every change is instantly view-able on the web page and it will immediately display errors right in the web being developed. Further, it includes a simple template engine integrating the framework for creating pages to deliver to the client.

Watch a a nice tutorial posted on YouTube.

One premise play is based on is of more interest than its Rails like simplicity, that is its assumption of a stateless "share nothing'' REST first approach. Keeping state synchronized on the client, in the session and on persistent store can be annoying and difficult. It makes clustering more difficult and tends to produce complexity and as a result bug potential.


Friday, March 9, 2012

Looking at Google Plus API

I'm jumping around technologies right now but I am playing around with the new google plus restful APIs.

After watching an interesting youtube video of the API by jenny murphy, I explored the API interactively using the google plus api developers site.

Clicking on REST API, you can go to each api resource (people, activities, comments, oauth) and explore the API including running an example request and seeing the results. I have a google plus identity (+Ed)  so I posted a couple of public messages to play with.

I was able to download the google plus java client api and google plus java starter project.

I followed these steps to get started

Copy the google java starter project web app example (./google-plus-java-starter/web-app) to a new directory to begin playing. The instructions are in the readme.txt to get started.

In order to access the API, you first have to register your application using the google api console and get a token for oauth and access to the specific api. The steps

  1. go to  https://code.google.com/apis/console/b/0/?api=plus 
  2. click on 'create project'
  3. agree to the terms of service (and read :)) (two of them)
  4. Select the google+API (if not already selected (note the url I supplied should select this)
  5. CLick on API access (left side menu)
  6. Click on Create an OAuth 2.0 client ID
  7. describe your project (and upload logo if you have it) and press next
  8. select application type=web app, and site host name to run locally, select http: and enter localhost
  9. click 'create client ID'
  10. there are 4 pieces of info that you'll need to copy to your project: client id, client secret, redirect URI and API key (from the Simple API access)
in your new project (copied from starter) open src/main/resources/config.properties

paste in the 4 bits of information from the registration process (the redirect URI may already be correct)

now from the project root, use maven to launch the project using the built in jetty:

mvn compile jetty:run

go to your browser (chrome naturally) to check out 

http://localhost:8080/

This may fail (the version I had downloaded _v5 did fail) 

If you get an exception thrown when first accessing with error: 

Exception initializing page context java.lang.VerifyError: (class: org/apache/jasper/runtime/PageContextImpl, method: getELResolver signature: ()Ljavax/el/ELResolver;) Incompatible argument to function
Then you may need to fix the pom.xml. Open pom.xml and add scope provided element for the jsp 2.1 dependency:

<dependency>
     <groupid>org.mortbay.jetty</groupid>
     <artifactid>jsp-2.1</artifactid>
     <version>6.1.14</version>
     <scope>provided</scope>
</dependency>

Then restart and access again. Then it works!

You should see 'connect me' button.

This will require you to authorize access to your account from this program. Once authorized, it presents your profile information and a list of public activities.

Now you can play with the API

Tuesday, January 17, 2012

Sencha Touch

This blog is outlining my experiences developing a mobile web based application developed with Sencha Touch and packaged with PhoneGap.

I have been developing a quick app for my iphone using Sencha Touch API (currenty 1.1). I have found it quite intuitive and the outcome is that I get a web based app that can be run nicely on Android as well as iOS devices. And I get to develop on my Win based machine in Java. Easy to test without emulator using normal browser too.

The idea is to write code via HTML5 that can be useful on touch based devices such as iPhone, iPad and Android based phones and tabs. Rather than learning languages and frameworks specific to these technologies it is possible to stick to common HTML5 skills that still support touch device like gestures and form factors.

In addition to deploying as a device capable web site, I intend to wrap it up with PhoneGap to deploy it as native binaries onto multiple devices (Android, iOS, BB) with access to native APIs.

The technology I am starting with

I'm not cool enough to develop on a Mac Book, so I'm building on Win 7 Laptop. For my editor, I've been trying out Sublime Text 2. Nice that it opens a folder tree and has smart syntax highlighting for JavaScript, and knows about all the HTML5 stuff (CSS, JSON, HTML, JavaScript) but a full fledged IDE would have things like code complete and syntax checking right in the IDE, so I am also old schooling it and using Eclipse IDE.

I have setup Eclipse IDE (Classic edition) augmented with Android SDK and the emulators, with the ADT Android Developer Tools eclipse plugin. However, for just Sencha touch the android stuff is not needed. But soon i will be looking at PhoneGap to create binaries ready to deploy to devices. And I'm also developing with Android SDK specifically.

I am also building the server side. I have been looking at node.js as a possibility. But I am also looking at Java based solutions as well (I'm showing my age I guess). For the Java based solutions, I am looking at deploying a J2EE (war) app and using Spring MVC as a core framework on the server side.

To deploy as a server based web app (and I also intend to have server side components as well), I have constructed a maven driven web app from a maven archetype (see this great blog article), and assuring it has the web app nature for using eclipse with help and great gratitude from this blog. This process of getting Eclipse to work with Maven for a web app based project was more complex and error prone than I'd like. My desire was to use the IDE to code and build, and see the results immediately synchronized on the integrated web server. But Eclipse doesn't build natively with Maven goals like NetBeans does, and the integrated web server plugins aren't as smart as they should on when to sync, deploy and run. I may rethink this choice as I go along.

To help provide the server stuff I need (remember Im on a Windows platform) I downloaded XAMPP and am running separate a Tomcat instance as an independent deployment target different from the Eclipse integrated tomcat server where I can test changes during development.

For the hosted solution and since I'm deploying to a java based app server (tomcat), I am deploying to jelastic I can test  it on my real devices. I also have Android emulators integrated into Eclipse and also iPadian emulating an ipad but I haven't tried that avenue yet.

The real devices I have to test on incude:
  • galaxy 10.1 tab
  • iphone 3GS (old I know)
For basic application architecture I have two MVC frameworks!

  • One MVC on the client (Sencha Touch with MVC pattern) and 
  • One MVC on the server (Spring MVC). 
Overkill? we shall see. We will get into the MVC model client and server side in another blog.

For Sencha Touch I am following the MVC pattern as described by the sencha forms tutorial.  Also, I have followed a great talk and tutorial from this German developer Nils Dehl where he creates a shopping list app.

For persistence, I have two choices: old school main stream relational (MySQL) or NoSQL approach with MondoDB. I will start out with mondo db and see what happens. The idea is that the data model is going to be json based and object oriented. Structured, hierarchic data can be managed using objects and indexes. For the app I want to build, it may work well. But it seems heretical (not necessarily a bad thing)..

Next article I will get into the app design...

Friday, July 29, 2011

Getting started with Spring Roo, GWT and STS - Part 1


This is a multi-part article. This article walks through my experiences getting started with spring's Roo framework using the Spring Tools Suite (STS). The next articles will walk through different aspects of building an application from scratch.
Also see

  • Part 1 - Install and create - back end (this blog)
  • Part 2 - Web MVC
  • Part 3 - GWT
  • Part 4 - Custom app from scratch



Part One - Getting started with Roo using STS - The Roo tutorial 

Time to get started. I'm going to run through the introductory materials on building a Spring Roo application using the Roo tutorial. In the next articles I will build a custom example using Spring Roo with the Google Web Toolkit front end. I will be using the Spring Tools Suite as the IDE (based on Eclipse).

I will start by following some initial advice:
Installation

What I have
  • Java 6 SDK r26 from here
  • Running on a Windows 7 Laptop (64 bit)
Step 1 - Install STS  
Download from here and follow the simple instructions.
I installed SpringSource Tool Suite: Version: 2.9.0.RELEASE Build Id: 201203011000

Step 2 - Configure to use Google Web Toolkit and Google App Engine
After running STS, go to the dashboard and select the 'extensions' tab (bottom). Find and Check Google Plugin for Eclipse and press 'Install' (bottom left)

Restart STS and thats it (for now)

Running through the Spring Roo Tutorial

Overview of Spring Pizza Shop Demo
Lets use the Spring Framework Roo tutorial to get started.This tutorial walks us through creating a Roo project including entities controllers and the UI/scaffold. I will try to emphasise use of the STS tool as well as focusinging on using GWT as the front end. To begin with, we will follow the tutorial fairly closely.

Here is the project UML from the spring tutorial that we will create



This is the Roo Pizza Shop demo













First Step Basic Roo Configuration

Spring Roo builds upon Spring framework 3.0 with JPA 2.0. It uses a command line tool to create basic elements of a project, from persistence setup, to creating entities, to creating Spring MVC controllers, to generating Scaffold ui (later we will be using GWT).


We can use spring STS to create a new spring Roo project project


  1. From the Dashboard, select Create a Spring Roo Project
  2. Fill out dialog: Project Name: pizza, top level package: com.springsource.roo.pizzashop
  3. Accept all other defaults and press Next (and then Finish). This will create the Roo project and open the roo shell. Actually, STS is executing the roo shell to create the project directory and the roo command:
    roo> project --topLevelPackage com.springsource.roo.pizzashop
We see the ROO command shell at the bottom with a command promt inviting us to execute roo commands.

Note: Using the Roo shell in StS 

Roo uses a shell similar to Rails to invoke commands that create essential structures and configurations around the Roo project. It saves a lot of time writing repetitive code or digging around to configure stuff. the shell is a bit smart in that it knows what you have done in your project and what steps can be next.




The window has a top part showing a console with roo commands as well as a prompt, but don't be fooled. The roo prompt we use in StS is below (a single line edit).
The spring ROO project leverages Maven2 and its unique project structure.

One cool roo command you will use right away is hint. This will give you possible options to do from the point in your project.

After creating a roo project, you can type HINT in the Roo shell. It will respond with:

Roo requires the installation of a JPA provider and associated database.

Type 'persistence setup' and then hit CTRL+SPACE three times.
We suggest you type 'H' then CTRL+SPACE to complete "HIBERNATE".
After the --provider, press CTRL+SPACE twice for database choices.
For testing purposes, type (or CTRL+SPACE) HYPERSONIC_IN_MEMORY.
If you press CTRL+SPACE again, you'll see there are no more options.
As such, you're ready to press ENTER to execute the command.

Once JPA is installed, type 'hint' and ENTER for the next suggestion.
It knows what you have done before so it can provide hints for the next steps. Very smart!

Next: Setup project with persistence library

As mentioned before, Spring Roo requires the configuration of a JPA provider such as Eclipselink,, OpenJPA or Hibernate.

configure persistence for this project: in Roo shell,
  1. As explained above, type hint and roo will prompt you to setup persistence for your project
  2. type' persitence setup' and press ctrl+space. In StS, this will use code assist to allow you to select possible next options for the command (the command line, you press the TAB key). In this case we will select --provider HIBERNATE and --database HYPERSONIC_IN_MEMORY
  3. The complete roo command is:
    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
    
  4. Roo will generate the JPA configuration files and initial spring context

Note: the roo log file

Spring keeps a log of your commands in the root project: log.roo. This may be handy to track what you have done, and in fact can be re-executed line by line to repeat your steps.

Next: Create your first Entity

In JPA, classes annotated as Entity are persistable, and generally map one-to-one to a table. Class properties generally map to columns in that table. The first class we will create will be Topping (see above UML model).

Using Roo shell:
  1. Type Hint again, and Roo will advise you to type ent and press TAB to get the next option (from STS, ctrl+space). This will allow us to create an entity with a specific class name: Topping
  2. Type entity then press (ctrl+space) . This will produce --class
  3. Type ~.domain.Topping for the class name (the tilda will indicate the project's package root (remember we specified com.springsource.roo.pizzashop)
  4. Now ctrl+space doesn't give us more hints since all required options are satisfied, but type double dash (--) and then ctrl+space will give us a bunch more options.
  5. type or select --testAutomatically to generate test classes for the new entity and press enter
 (the complete roo command: entity --class ~.domain.Topping --testAutomatically)

Roo creates a whole bunch of files and aspects. Notice the actual entity "SRC_MAIN_JAVA\com\springsource\roo\pizzashop\domain\Topping.java" is created. You can see it in the packag tree. However, STS starts with an inital filter in the package tree to 'Focus on Active Task'.

Click the filter icon in the top toolbar of the Package view to reveal the entire project. Now navigate to src/main/java. See the com.springsource.roo.pizzashop.domain package and the created Topping.java class just created.

Next: Create Fields for Our Entity

Now lets add a field.
Use the roo command to type:


  1.  field string --fieldName name --notnull --sizeMin 2

This will add a field, and update/add to the generated aspects based on the annotaitions.

Opening this class, all you see is

File: Topping.java
package com.springsource.roo.pizzashop.domain;  
import org.springframework.roo.addon.entity.RooEntity; 
import org.springframework.roo.addon.javabean.RooJavaBean; 
import org.springframework.roo.addon.tostring.RooToString; 
import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Size;  
@RooJavaBean 
@RooToString 
@RooEntity 
public class Topping { 
     @NotNull
     @Size(min = 2)
     private String name; 
} 


Notice the classs annotations that roo adds @RooJavaBean, @RooToString and @RooEntity. These annotations generate aspects with extensions .aj for inter type definitions. Spring also adds JSR 303 bean validation annotations on the field based on the options we specified: @NotNull and @Size(min = 2).

The principle that Roo introduces here is the heavy leveraging of AspectJ's Inter-Type Declaration (ITD). The ITD code generates as a separately complied file, but is encorporated into the class byte code of the advised class. Generally we don't need to bother about what is generated here. But lets look anyway. For instance, the @RooJavaBean annotaion creates the class Topping_Roo_JavaBean.aj. Peeking at it, we see:
File: Topping_Roo_Entity.aj
// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO. 
// You may push code into the target .java compilation unit if you wish to edit any member(s).  
package com.springsource.roo.pizzashop.domain; 

import java.lang.String; 

privileged aspect Topping_Roo_JavaBean { 
    public String Topping.getName() { 
        return this.name; 
    }     

    public void Topping.setName(String name) { 
        this.name = name; 
    }      
}  


We see that the name field produced a getter and a setter for the field. As we add new fields, this aspect will be updated. Using aspects this way allows the domain class to remain particularly pure.

As another example, lets look at what was generated for the @RooToString annotation:

File: Topping_Roo_ToString.aj

package com.springsource.roo.pizzashop.domain;  
import java.lang.String;  
privileged aspect Topping_Roo_ToString {      
    public String Topping.toString() { 
        StringBuilder sb = new StringBuilder(); 
        sb.append("Id: ").append(getId()).append(", "); 
        sb.append("Name: ").append(getName()).append(", "); 
        sb.append("Version: ").append(getVersion()); 
        return sb.toString(); 
    } 
}



Pretty nifty, huh! this is the Secret Sauce of Roo as described in Ben Alex' Blog on Roo's Architecture

Finally, lets' look at what Roo does with the @RooEntity declairation
File: Topping_Roo_Entity.aj

// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).

package com.springsource.roo.pizzashop.domain;

import com.springsource.roo.pizzashop.domain.Topping;
import java.lang.Integer;
import java.lang.Long;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PersistenceContext;
import javax.persistence.Version;
import org.springframework.transaction.annotation.Transactional;

privileged aspect Topping_Roo_Entity {
    
    declare @type: Topping: @Entity;
    
    @PersistenceContext
    transient EntityManager Topping.entityManager;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long Topping.id;
    
    @Version
    @Column(name = "version")
    private Integer Topping.version;
    
    public Long Topping.getId() {
        return this.id;
    }
    
    public void Topping.setId(Long id) {
        this.id = id;
    }
    
    public Integer Topping.getVersion() {
        return this.version;
    }
    
    public void Topping.setVersion(Integer version) {
        this.version = version;
    }
    
    @Transactional
    public void Topping.persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }
    
    @Transactional
    public void Topping.remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Topping attached = Topping.findTopping(this.id);
            this.entityManager.remove(attached);
        }
    }
    
    @Transactional
    public void Topping.flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }
    
    @Transactional
    public void Topping.clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }
    
    @Transactional
    public Topping Topping.merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        Topping merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }
    
    public static final EntityManager Topping.entityManager() {
        EntityManager em = new Topping().entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }
    
    public static long Topping.countToppings() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Topping o", Long.class).getSingleResult();
    }
    
    public static List Topping.findAllToppings() {
        return entityManager().createQuery("SELECT o FROM Topping o", Topping.class).getResultList();
    }
    
    public static Topping Topping.findTopping(Long id) {
        if (id == null) return null;
        return entityManager().find(Topping.class, id);
    }
    
    public static List Topping.findToppingEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Topping o", Topping.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }
    
}

}



Rather than creating a data access object (DAO) or service, Roo assumes that each entity created has its own implementation of persistence. The @RooEntity annotation generates a ITD (Inter-type Declairation) for the entity advising it to add many methods to support persistence, inclding id generation, versioning, access to the entity manager, various transactional methods:

  • persist,
  • remove,
  • flush,
  • merge,
  • clear
and various finder methods

  • count
  • find by id
  • findAll
  • and pagable findAll



Next: Some More entitles and fields

As Roo creates objects, it keeps track of the last object you created. The next command defaults to this target, so there is no need to specify it explicitly. For example, when we created the field, we didn't need to specify what class to create the field for. It assumed we meant the last entity we worked with.. The spring Roo console shows what entity we last worked with in its prompt, much like a command shell might with a prompt showing the current directory path.

Using roo shell:

Now lets create another entity and some fields similar to the ones we created before. Here are the Roo commands:

entity --class ~.domain.Base --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Pizza --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float




That's it. As long as we follow the defaults, things are easy. This is the approach taken by Ruby on Rails: convention over configuration. The command line invokes templated commands to create objects quickly.

Our project should look basically like this (as seen from the project view)


Next: Some Relationships for our Entities


We are still in JPA land. JPA allows us to create relationships as well as if POJO java classes using well known collections. Roo supports a one-to-one or many-to-one reference, a one-to-many 'set' (and also ways to create many-many). In the above, we have a one-many relationship from Pizza to Topping (a pizza has many toppings) and a one-one relationship (reference) to a base. We'll use the Roo command shell to create these too. The tutorial shows there are two relationships from Pizza, a 'reference' to a base (m:1) where a Pizza has one base, and a set of toppings (m:m relationship to toppings), where a pizza has a set of toppings.

In roo shell, type the following:

field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base


The above commands assume you are creating the relationship fields to the last entity you created: Pizza as it would show you in a command prompt. If not, make sure to append --class ~.domain.Pizza to the above commands (at least the first one) to assure the relationships are created for the Pizza class.


And we can finish up with PizzaOrder, in roo shell:


entity --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --type ~.domain.Pizza

Note: if you make a mistake, you cn press the up arrow from the Roo shell prompt in STS and previous commands can be edited and re executed.

Notice the last command creates another relationship, this time an PizzaOrder has a set of Pizzas ordered, which Roo will create a m:m relationship for of type Set pizzas. As you can see, creating entities, fields and relationships with Roo comes down to running a set of commands to generate the appropriate Java code and Aspects according to Roo convention. In fact, you can save these commands as a 'seed' text file that will create a project for you, generating the project structure, configruation, classes and aspects required.


Next: Lets Test


We can now run the integration tests using the roo command perform tests.
perform tests


Here is a summary of the roo commands executed
// Spring Roo 1.1.4.RELEASE [rev f787ce7] log opened at 2012-03-17 10:38:04
project --topLevelPackage com.springsource.roo.pizzashop --projectName pizza --java 6
// Spring Roo 1.1.4.RELEASE [rev f787ce7] log closed at 2012-03-17 10:38:15
// Spring Roo 1.1.4.RELEASE [rev f787ce7] log opened at 2012-03-17 10:38:19
hint
hint
persistence setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE 
hint
entity --class ~.domain.Topping --testAutomatically 
field string --fieldName name --notnull --sizeMin 2
entity --class ~.domain.Base --testAutomatically 
field string --fieldName name --notNull --sizeMin 2
entity --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float

field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date

field set --fieldName pizzas --type ~.domain.Pizza
perform tests



Finally: Look at the test classes generated


The main class 'Pizza' has a name (required min size 2) and a price, but also two relationships: one a many-many relationship to Toppings class and a reference (many-one) relationship to Base class.


File: Pizza.java
package com.springsource.roo.pizzashop.domain;

import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Set;
import java.util.HashSet;
import javax.persistence.ManyToMany;
import javax.persistence.CascadeType;
import com.springsource.roo.pizzashop.domain.Topping;
import com.springsource.roo.pizzashop.domain.Base;
import javax.persistence.ManyToOne;

@RooJavaBean
@RooToString
@RooEntity
public class Pizza {

    @NotNull
    @Size(min = 2)
    private String name;

    private Float price;

    @ManyToMany(cascade = CascadeType.ALL)
    private Set toppings = new HashSet();

    @ManyToOne
    private Base base;
}


The class 'Base' has a single field 'name' but annotated with @NotNull and @Size min 2.

File: Base.java
package com.springsource.roo.pizzashop.domain;

import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@RooJavaBean
@RooToString
@RooEntity
public class Base {

    @NotNull
    @Size(min = 2)
    private String name;
}

Topping is also a simple class, with one field 'name' declaired as Min 2 (but not NotNull ?) probably should be NotNull, dont you think?

File: Topping.java
package com.springsource.roo.pizzashop.domain;

import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.Size;

@RooJavaBean
@RooToString
@RooEntity
public class Topping {

    @Size(min = 2)
    private String name;
}

Finally, PizzaOrder is the workhorse of the project. It relates the person ordering (this could be another class 'Customer' but isn't for simplicity sake (we may not need to track people or order pizza but it may help down the road)

File: PizzaOrder.java
package com.springsource.roo.pizzashop.domain;

import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Set;
import com.springsource.roo.pizzashop.domain.Pizza;
import java.util.HashSet;
import javax.persistence.ManyToMany;
import javax.persistence.CascadeType;

@RooJavaBean
@RooToString
@RooEntity
public class PizzaOrder {

    @NotNull
    @Size(min = 2)
    private String name;

    @Size(max = 30)
    private String address;

    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "S-")
    private Date deliveryDate;

    private Float total;

    @ManyToMany(cascade = CascadeType.ALL)
    private Set pizzas = new HashSet();
}

Fixing a problem
In the above example, i noted that Toppings 'name' field doesn't have a @NotNull annotation and it probably should. How do you fix it? Using the Roo shell is good for adding stuff, but not changing or removing stuff. To do this, just go to the java code itself.


  1. Open the Toppings class
  2. Add the @NotNull annotation
  3. Add the import for the annotation (I like to use CTRL+SHIFT+O for 'Organize Imports' in the Source menu)
And that's it!


Next steps

On next blog article we will add a user interface to this to complete the tutorial, still no GWT yet. That will be following.