Εκμηδενίστε το χρόνο υλοποίησης web εφαρμογών με το Spring Roo

Η υλοποίηση ενός Java project είναι μία δημιουργική διαδικασία που όμως όπως όλοι μας γνωρίζουμε αρκετές φορές εμπεριέχει κάποιες επαναλαμβανόμενες εργασίες  που μειώνουν τον ρυθμό ανάπτυξης και συνήθως τείνουν να είναι κουραστικές για τον προγραμματιστή. Αυτό ακριβώς το θέμα έρχεται να επιλύσει μία πολύ δυναμική τεχνολογία, το Roo από την Springsource.  Σκοπός του είναι να επιτρέψει στον developer να οικοδομήει υψηλής ποιότητας και υψηλής απόδοσης συστήματα σε λίγα μόνο λεπτά. Σε αυτό το άρθρο θα περιγράφεται αναλυτικά τι είναι αυτή η τεχνολογία και παράλληλα θα διαπιστώσουμε μαζί πώς μπορούμε να χτίσουμε μία πλήρως λειτουργική enterprise εφαρμογή σε λιγότερο απο ένα τέταρτο της ώρας.

1. ΕΙΣΑΓΩΓΗ

Η υλοποίηση ενός Java project είναι μία δημιουργική διαδικασία που όμως όπως όλοι μας γνωρίζουμε αρκετές φορές εμπεριέχει κάποιες επαναλαμβανόμενες εργασίες  που μειώνουν τον ρυθμό ανάπτυξης και συνήθως τείνουν να είναι κουραστικές για τον προγραμματιστή. Πόσες φορές για παράδειγμα δεν αγανακτούμε με το POJO που πρέπει να γράψουμε για να αντιστοιχήσουμε τις 100 στήλες ενός πίνακα σε Java πεδία, ή για την για την JSP που πρέπει να εμφανίζει σε φόρμα τα πεδία αυτά για input KAI με τα απαραίτητα validations. Για να μη μιλήσω για το plumbing που πρέπει να γίνει μεταξύ των components ενός τυπικού MVC. Όλα αυτά παίρνουν χρόνο και αποσπούν τη προσοχή από το core της εφαρμογής, δηλαδή το καθεαυτό business logic και μειώνουν, εν τέλει, την παραγωγικότητα.
Αυτό ακριβώς το θέμα έρχεται να επιλύσει μία πολύ δυναμική τεχνολογία, το Roo από την Springsource. Το Roo είναι ένα εύκολο στη χρήση εργαλείο παραγωγικότητας για την ταχεία ανάπτυξη επιχειρηματικών εφαρμογών βασισμένα σε Java. Σκοπός του είναι να επιτρέψει στον developer να οικοδομήει υψηλής ποιότητας και υψηλής απόδοσης συστήματα σε λίγα μόνο λεπτά !
Σε αυτό το άρθρο θα περιγράφεται αναλυτικά τι είναι αυτή η τεχνολογία και παράλληλα θα διαπιστώσουμε μαζί πώς μπορούμε να χτίσουμε μία πλήρως λειτουργική enterprise εφαρμογή σε λιγότερο απο ένα τέταρτο της ώρας.

2. ΤΙ (ΔΕΝ) ΕΙΝΑΙ ΤΟ ROO

Ας δούμε λοιπόν τι είναι το Roo. Πρόκειται για ένα εργαλείο το οποίο ανοίγει μέσα σε ένα command line shell εντελώς έξω και ανεξάρτητα από το περιβάλλον ανάπτυξης (πχ Eclipse) και το οποίο τρέχει παράλληλα καθώς προγραμματίζουμε. Καθώς κάνουμε τις αλλαγές μας, αυτό είναι αρκετά έξυπνο για να αντιλαμβάνεται τι προσπαθούμε να κάνουμε και το κάνει για εμάς αυτόματα δηλαδή αναλαμβάνει την διαχείριση του κώδικα  «για μας πριν από εμάς».

Όλα αυτά θα τα δούμε αναλυτικά αλλά πριν προχωρήσουμε ας ξεκαθαρίσουμε ότι δεν πρόκειται για κάποιο runtime ούτε για κάποιο plugin του αγαπημένου μας IDE. Δεν υπάρχουν κάποια jars που βάζουμε στον κώδικα και επομένως αν χρειαστεί να το αφαιρέσουμε δεν αλλάζει τίποτα ουσιαστικό στον κώδικά μας και εξαφανίζεται σαν να μην υπήρχε ποτέ ! Τέλος δεν καθυστερεί την εκτέλεση του υπό υλοποίηση λογισμικού και δεν επιβάλει οποιαδήποτε αλλαγή στην αρχιτεκτονική προκειμένου να χρησιμοποιηθεί.

Αντίθετα, με τη χρήση του Roo επιτυγχάνονται μια σειρά από πολύ σημαντικούς στόχους.

  1. Αυξάνει τη παραγωγικότητα: Γίνεται εφικτή η ταχύτατη υλοποίηση ενός ολοκληρωμένου και λειτουργικού Java έργου ακόμη και σε ελάχιστα λεπτά
  2. Ενσωμάτωση των καλύτερων τεχνολογιών: Η νέα εφαρμογή σας θα στηρίζεται σε καταξιωμένες και ευρέως διαδεδομένες τεχνολογίες  (Spring, Maven, JSP, Hibernate κτλ.)
  3. Πανεύκολη εκμάθηση και χρήση: Τρέχει από ένα εξαιρετικά εύχρηστο command line περιβάλλον με τεχνολογίες που πιθανώς γνωρίζεται ήδη παρέχοντας ταυτόχρονα hints σε κάθε βήμα.
  4. Απλότητα στην αρχιτεκτονική:  Εύκαμπτος κώδικας που είναι εύκολο να τροποποιηθεί . Το τελικό αποτέλεσμα χρησιμοποιεί λιγότερη υπολογιστική δύναμη και μνήμη
  5. Ταχύτατη απεγκατάσταση: Με λίγα απλά βήματα ο προγραμματιστής μπορεί να αφαιρέσει το Roo χωρίς ρίσκο και χωρίς αλλαγή του βασικού κώδικα (το πολύ κάποια @Roo annotations).

3. Το ROO στην πράξη

Πάμε να δούμε λοιπόν πώς το ROO χρησιμοποιείται μέσα από ένα συγκεκριμένο παράδειγμα. Πριν από αυτό όμως ας δούμε τα βήματα που πρέπει να ακολουθήσουμε για την εγκατάστασή του.

  1. Προ-εγκατεστημένο λογισμικό
    1. Κλασικά έχουμε, Windows, Mac ή Linux και οπουδήποτε αλλού «παίζει» η Java
    2. Ένα οποιοδήποτε JVM (Sun, JRockit, IBM, OpenJDK κτλ.) αλλά με την environment variable JAVA_HOME σεταρισμένη.
    3. Το Apache Maven
  2. Κατεβάστε το Roo από εδώ:
  3. Κάνουμε Unzip στο φάκελο που θέλουμε να εγκατασταθεί. Αυτό θα είναι και το ROO_HOME μας
  4. Σετάρουμε το ROO_HOME
    • Windows:
      • SET ROO_HOME=C:\roohome (για παράδειγμα)
      • SET PATH=%PATH%;%ROO_HOME%\bin
    • Linux (και παρόμοια σε Mac)
      • ROO_HOME=/app/Software/roohome (για παράδειγμα)
      • sudo ln –s $ROO_HOME/bin/roo.sh /usr/bin/roo

5. Για να επιβεβαιώσετε τη σωστή εγκατάσταση κάνουμε:

[diff]
$ roo
____ ____ ____
/ __ \/ __ \/ __ \
/ /_/ / / / / / / /
/ _, _/ /_/ / /_/ /
/_/ |_|\____/\____/ 1.0.2.RELEASE [rev 638]

Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
roo> quit
$
[/diff]

Ας υποθέσουμε, λοιπόν ότι μας έχει ανατεθεί η υλοποίηση του μηχανογραφικού συστήματος μίας δημοτικής βιβλιοθήκης. Πρόκειται για μία intranet εφαρμογή όπου οι υπάλληλοι θα μπορούν να καταχωρούν στο σύστημα βιβλία και στη συνέχεια, πάλι μέσα από την εφαρμογή, θα καταγράφουν που έχουν δανειστεί τα βιβλία. Το project πρέπει να είναι έτοιμο χτες !
Με το ROO θα φτιάξουμε την εφαρμογή το πολύ σε 15 λεπτά. Έτοιμοι; Το χρονόμετρο ξεκινάει τώρα.

  1. Δημιουργία του project

Φτιάχνουμε ένα φάκελο μέσα στο οποίο θα δημιουργηθεί το project και ξεκινάμε το Roo

[diff]
$ mkdir librarymanager
$ cd librarymanager
$ roo
____ ____ ____
/ __ \/ __ \/ __ \
/ /_/ / / / / / / /
/ _, _/ /_/ / /_/ /
/_/ |_|\____/\____/ 1.0.2.RELEASE [rev 638]

Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.

[/diff]

Όπως ανέφερα και πριν, το Roo διευκολύνει τον χρήστη με την εντολή hint. Θα τη χρησιμοποιήσουμε κατά κόρον στη συνέχεια. Πάμε να δούμε πώς:

[diff]
roo> hint
Welcome to Roo! We hope you enjoy your stay!

Before you can use many features of Roo, you need to start a new project.

To do this, type ‘project’ (without the quotes) and then hit TAB.

Enter a –topLevelPackage like ‘com.mycompany.projectname’ (no quotes).
When you’ve finished completing your –topLevelPackage, press ENTER.
Your new project will then be created in the current working directory.

Note that Roo frequently allows the use of TAB, so press TAB regularly.
Once your project is created, type ‘hint’ and ENTER for the next suggestion.
You’re also welcome to visit http://forum.springframework.org for Roo help.
roo> project –topLevelPackage gr.zenika.librarymanager
Created /app/Development/librarymanager/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/log4j.properties
[/diff]

Το project μας δημιουργήθηκε και είναι ένα πολύ απλό κέλυφος μίας spring εφαρμογής.

2.  Βάση δεδομένων

Πάμε τώρα να φτιάξουμε τη βάση δεδομένων. Ξαναπατώντας hint μας ενημερώνει το ίδιο το Roo σχετικά με αυτό το βήμα.. Δημιουργούμε μία in-memory βάση αλλά σαφώς θα μπορούσε να είναι μία οποιαδήποτε βάση (πχ. PostgreSQL).

[diff]
gr.zenika.librarymanager roo> hint
Roo requires the installation of a JPA provider and associated database.

Type ‘persistence setup’ and then hit TAB three times.
We suggest you type ‘H’ then TAB to complete "HIBERNATE".
After the –provider, press TAB twice for database choices.
For testing purposes, type (or TAB) HYPERSONIC_IN_MEMORY.
If you press TAB 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.
gr.zenika.librarymanager roo> persistence setup –provider HIBERNATE –database HYPERSONIC_IN_MEMORY
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed ROOT/pom.xml
[/diff]

3.   Δημιουργία του 2 entities

Το επόμενα βήμα είναι να φτιάξουμε ένα persistence Entity για τα βιβλία και το οποίο θα ονομάζεται Books και ένα για τους εγγεγραμμένους χρήστες RegisteredUsers. Και στα δύο θα προστεθούν τα απαραίτητα πεδία. Θα έχουμε:
BOOK

Title String not null
Authors String not null
ISBN String
Max Loan Days String
Copy ID Integer not null
LoanedTo Integer
ReturnDate Date

RegisteredUser

Name String not null
Surname String not null
DOB Date
Registration Date Date
Activated Boolean not null

[diff]
gr.zenika.librarymanager roo> hint
You can create entities either via Roo or your IDE.
Using the Roo shell is fast and easy, especially thanks to the TAB completion.

Start by typing ‘ent’ and then hitting TAB twice.
Enter the –class in the form ‘~.domain.MyEntityClassName’
In Roo, ‘~’ means the –topLevelPackage you specified via ‘create project’.

After specify a –class argument, press SPACE then TAB. Note nothing appears.
Because nothing appears, it means you’ve entered all mandatory arguments.
However, optional arguments do exist for this command (and most others in Roo).
To see the optional arguments, type ‘–‘ and then hit TAB. Mostly you won’t
need any optional arguments, but let’s select the –testAutomatically option
and hit ENTER. You can always use this approach to view optional arguments.

After creating an entity, use ‘hint’ for the next suggestion.
gr.zenika.librarymanager roo> entity –class ~.domain.Books –testAutomatically
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books.java
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksDataOnDemand.java
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksIntegrationTest.java
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_Entity.aj
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_ToString.aj
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_Configurable.aj
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksIntegrationTest_Roo_Configurable.aj
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksDataOnDemand_Roo_DataOnDemand.aj
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksIntegrationTest_Roo_IntegrationTest.aj
Created SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksDataOnDemand_Roo_Configurable.aj
~.domain.Books roo> hint
You can add fields to your entities using either Roo or your IDE.

To add a new field, type ‘field’ and then hit TAB. Be sure to select
your entity and provide a legal Java field name. Use TAB to find an entity
name, and ‘~’ to refer to the top level package. Also remember to use TAB
to access each mandatory argument for the command.

After completing the mandatory arguments, press SPACE, type ‘–‘ and then TAB.
The optional arguments shown reflect official JSR 303 Validation constraints.
Feel free to use an optional argument, or delete ‘–‘ and hit ENTER.

If creating multiple fields, use the UP arrow to access command history.

After adding your fields, type ‘hint’ for the next suggestion.
To learn about setting up many-to-one fields, type ‘hint relationships’.
~.domain.Books roo> field string –fieldName title
field string –fieldName title
required –fieldName: The name of the field to add; no default value
~.domain.Books roo> field string –fieldName title –notNull
Managed SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books.java
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_JavaBean.aj
Managed SRC_TEST_JAVA/gr/zenika/librarymanager/domain/BooksDataOnDemand_Roo_DataOnDemand.aj
Managed SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_ToString.aj

[/diff]

Κάνουμε το ίδιο και για τα υπόλοιπα πεδία (δεν περιλαμβάνω όλο το output μόνο τις εντολές).

[diff]

~.domain.Books roo> field string –fieldName author –notNull
….
~.domain.Books roo> field string –fieldName isbn –notNull
….
~.domain.Books roo> field number –fieldName maxLoanDays —
notNull –type java.lang.Integer
….
~.domain.Books roo> field number –fieldName copyid –type java.lang.Integer
….
~.domain.Books roo> field date –fieldName returnDate –type java.util.Calendar
….

[/diff]

Προσθέτουμε τώρα το RegisteredUser

[diff]
~.domain.Books roo> entity –class ~.domain.RegisteredUser –testAutomatically
….
[/diff]

… και τα πεδία του

[diff]
~.domain.RegisteredUser roo> field string –fieldName name –notNull
….
~.domain.RegisteredUser roo> field string –fieldName surname –notNull
….
~.domain.RegisteredUser roo> field date –fieldName dob –type java.util.Calendar –dateFormat SHORT –notNull
….
~.domain.RegisteredUser roo> field date –fieldName regdate –type java.util.Calendar –dateFormat SHORT
….
~.domain.Books roo> field boolean –fieldName activated –notNull
….

[/diff]

Παρατηρήστε πόσο απλό είναι να προστεθούν entities και πεδία. Επίσης βλέπουμε ότι κάθε στιγμή το Roo μας δίνει τη δυνατότητα να δούμε ποιο είναι το context (πχ. ~.domain.RegisteredUser), οπότε ξέρουμε που θα προστεθούνε τα πεδία.

4.   Δημιουργία σχέσης πινάκων

Στον πίνακα Book δεν έχουμε δηλώσει ακόμη το πεδίο LoanedTo. Ξέρουμε ότι το κάθε copy βιβλίου μπορεί να δανειστεί από ένα και μόνο χρήστη. Άρα έχουμε μία σχέση 1:1. Αυτό το πεδίο το δηλώνουμε λοιπόν ως εξής:

[diff]
~.domain.RegisteredUser roo> field reference –fieldName loanTo –type ~.domain.RegisteredUser –class ~.domain.Books
Managed SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books.java
Managed SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/gr/zenika/librarymanager/domain/Books_Roo_ToString.aj

[/diff]

Παρατηρήστε ότι έβαλα το –class ~.domain.Books για να δηλώσω ότι αυτό το πεδίο ανήκει στο Books. Το Roo το βάζει σε αυτή την class και αλλάζει το context στο command prompt.

5.   Web front end

Με ολοκληρωμένο το back-end της εφαρμογής πάμε να φτιάξουμε το web layer. Αρκεί μία και μόνο εντολή:

[diff]
roo> controller all –package ~.web
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/web
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/web/RegisteredUserController.java
Created SRC_MAIN_WEBAPP/WEB-INF/spring
Created SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/web/RegisteredUserController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/images
Created SRC_MAIN_WEBAPP/images/nl.png
Created SRC_MAIN_WEBAPP/images/update.png
Created SRC_MAIN_WEBAPP/images/es.png
Created SRC_MAIN_WEBAPP/images/delete.png
Created SRC_MAIN_WEBAPP/images/add.png
Created SRC_MAIN_WEBAPP/images/resultset_previous.png
Created SRC_MAIN_WEBAPP/images/resultset_next.png
Created SRC_MAIN_WEBAPP/images/favicon.ico
Created SRC_MAIN_WEBAPP/images/banner-graphic.png
Created SRC_MAIN_WEBAPP/images/resultset_last.png
Created SRC_MAIN_WEBAPP/images/gb.png
Created SRC_MAIN_WEBAPP/images/springsource-logo.png
Created SRC_MAIN_WEBAPP/images/it.png
Created SRC_MAIN_WEBAPP/images/show.png
Created SRC_MAIN_WEBAPP/images/sv.png
Created SRC_MAIN_WEBAPP/images/list.png
Created SRC_MAIN_WEBAPP/images/resultset_first.png
Created SRC_MAIN_WEBAPP/images/de.png
Created SRC_MAIN_WEBAPP/styles
Created SRC_MAIN_WEBAPP/styles/standard.css
Created SRC_MAIN_WEBAPP/styles/alt.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/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/resourceNotFound.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/uncaughtException.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/dataAccessFailure.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/controller-index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/tags
Created SRC_MAIN_WEBAPP/WEB-INF/tags/language.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/theme.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/pagination.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/i18n
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_sv.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_nl.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_it.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_es.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages_de.properties
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser/create.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser/update.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/registereduser/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/urlrewrite.xml
Created SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed ROOT/pom.xml
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/web/BooksController.java
Managed SRC_MAIN_WEBAPP/WEB-INF/web.xml
Managed ROOT/pom.xml
Created SRC_MAIN_JAVA/gr/zenika/librarymanager/web/BooksController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/WEB-INF/views/books
Created SRC_MAIN_WEBAPP/WEB-INF/views/books/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/books/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/books/create.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/books/update.jspx
Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/books/views.xml
gr.zenika.librarymanager.web roo>

[/diff]

Η εντολή αυτή σαρώνει το project για entities και δημιουργεί αντίστοιχους controllers και views (jsp).
Το project μας τώρα είναι ένα web Java project και βασίζεται στο Spring MVC (βλέπε το προηγούμενο άρθρο μου) και οι Controllers ακολουθούν το REST (βλέπε άρθρου του καλού συναδέλφου Αλέξιου).

6.  Φόρτωμα σε IDE


Το project μας έχει ολοκληρωθεί. Πριν προχωρήσουμε, ας το φορτώσουμε σε ένα IDE. Μιας και το project δεν περιέχει οποιαδήποτε αρχεία παραμέτρων για IDE μπορούμε να τα δημιουργήσουμε με την εντολή:

[diff]
gr.zenika.librarymanager.web roo> perform eclipse
[INFO] Scanning for projects…
[INFO] ————————————————————————
[INFO] Building librarymanager
[INFO] task-segment: [eclipse:clean, eclipse:eclipse]
[INFO] ————————————————————————
[INFO] [eclipse:clean {execution: default-cli}]
[INFO] Deleting file: .project
[INFO] Deleting file: .classpath
[INFO] Deleting file: .wtpmodules
[INFO] Deleting file: .component
[INFO] Deleting file: org.eclipse.wst.common.component
[INFO] Deleting file: org.eclipse.wst.common.project.facet.core.xml
[INFO] Deleting file: org.eclipse.jdt.core.prefs
[INFO] Deleting file: org.eclipse.ajdt.ui.prefs
[INFO] Preparing eclipse:eclipse
[INFO] [aspectj:compile {execution: default}]
[WARNING] advice defined in org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.springframework.mock.staticmock.AbstractMethodMockingControl has not been applied [Xlint:adviceDidNotMatch]
[INFO] [eclipse:eclipse {execution: default-cli}]
[INFO] Adding support for WTP version 2.0.
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] Wrote settings to /app/Development/librarymanager/.settings/org.eclipse.jdt.core.prefs
[INFO] Wrote Eclipse project for "librarymanager" to /app/Development/librarymanager.
[INFO]
Javadoc for some artifacts is not available.
Please run the same goal with the -DdownloadJavadocs=true parameter in order to check remote repositories for javadoc.
List of artifacts without a javadoc archive:
o edu.emory.mathcs.backport:com.springsource.edu.emory.mathcs.backport:3.1.0
o javax.persistence:com.springsource.javax.persistence:1.0.0
o javax.servlet:com.springsource.javax.servlet:2.5.0
o javax.servlet:com.springsource.javax.servlet.jsp.jstl:1.2.0
o org.apache.taglibs:com.springsource.org.apache.taglibs.standard:1.1.2
o javax.transaction:com.springsource.javax.transaction:1.1.0
o javax.validation:com.springsource.javax.validation:1.0.0.GA
o net.sourceforge.ehcache:com.springsource.net.sf.ehcache:1.4.1
o net.sourceforge.jsr107cache:com.springsource.net.sf.jsr107cache:1.0.0
o org.apache.commons:com.springsource.org.apache.commons.collections:3.2.0
o org.apache.commons:com.springsource.org.apache.commons.logging:1.1.1
o org.apache.commons:com.springsource.org.apache.commons.dbcp:1.2.2.osgi
o org.apache.commons:com.springsource.org.apache.commons.pool:1.3.0
o org.apache.commons:com.springsource.org.apache.commons.fileupload:1.2.0
o org.apache.commons:com.springsource.org.apache.commons.io:1.4.0
o org.apache.el:com.springsource.org.apache.el:6.0.20
o org.apache.log4j:com.springsource.org.apache.log4j:1.2.15
o org.apache.tiles:com.springsource.org.apache.tiles:2.1.3
o org.apache.tiles:com.springsource.org.apache.tiles.core:2.1.3
o org.apache.commons:com.springsource.org.apache.commons.digester:1.8.1
o org.apache.commons:com.springsource.org.apache.commons.beanutils:1.8.0
o org.apache.tiles:com.springsource.org.apache.tiles.jsp:2.1.3
o org.apache.tiles:com.springsource.org.apache.tiles.servlet:2.1.3
o org.aspectj:com.springsource.org.aspectj.runtime:1.6.6.RELEASE
o org.hibernate:com.springsource.org.hibernate.annotations:3.3.1.ga
o org.dom4j:com.springsource.org.dom4j:1.6.1
o org.hibernate:com.springsource.org.hibernate.annotations.common:3.3.0.ga
o org.hibernate:com.springsource.org.hibernate:3.2.6.ga
o org.antlr:com.springsource.antlr:2.7.6
o org.jboss.javassist:com.springsource.javassist:3.3.0.ga
o net.sourceforge.cglib:com.springsource.net.sf.cglib:2.1.3
o org.objectweb.asm:com.springsource.org.objectweb.asm:1.5.3
o org.objectweb.asm:com.springsource.org.objectweb.asm.attrs:1.5.3
o org.hibernate:com.springsource.org.hibernate.ejb:3.3.2.GA
o org.jboss.util:com.springsource.org.jboss.util:2.0.4.GA
o edu.oswego.cs.concurrent:com.springsource.edu.oswego.cs.dl.util.concurrent:1.3.4
o org.hibernate:com.springsource.org.hibernate.validator:4.0.0.GA
o org.slf4j:com.springsource.slf4j.api:1.5.6
o org.hsqldb:com.springsource.org.hsqldb:1.8.0.9
o org.joda:com.springsource.org.joda.time:1.6.0
o org.junit:com.springsource.org.junit:4.7.0
o org.slf4j:com.springsource.slf4j.log4j:1.5.6
o org.springframework:org.springframework.aop:3.0.0.RELEASE
o org.aopalliance:com.springsource.org.aopalliance:1.0.0
o org.springframework:org.springframework.beans:3.0.0.RELEASE
o org.springframework:org.springframework.core:3.0.0.RELEASE
o org.springframework:org.springframework.asm:3.0.0.RELEASE
o org.springframework:org.springframework.aspects:3.0.0.RELEASE
o org.springframework:org.springframework.context:3.0.0.RELEASE
o org.springframework:org.springframework.expression:3.0.0.RELEASE
o org.springframework:org.springframework.jdbc:3.0.0.RELEASE
o org.springframework:org.springframework.transaction:3.0.0.RELEASE
o org.springframework:org.springframework.orm:3.0.0.RELEASE
o org.springframework:org.springframework.test:3.0.0.RELEASE
o org.springframework:org.springframework.web:3.0.0.RELEASE
o org.springframework:org.springframework.web.servlet:3.0.0.RELEASE
o org.springframework.roo:org.springframework.roo.annotations:1.0.2.RELEASE
o org.springframework.webflow:org.springframework.js:2.0.8.RELEASE
o org.tuckey:com.springsource.org.tuckey.web.filters.urlrewrite:3.1.0

[INFO] ————————————————————————
[INFO] BUILD SUCCESSFUL
[INFO] ————————————————————————
[INFO] Total time: 26 seconds
[INFO] Finished at: Sun Sep 19 08:58:05 EEST 2010
[INFO] Final Memory: 28M/77M
[INFO] ————————————————————————
gr.zenika.librarymanager.web roo>

[/diff]

Το project μας είναι έτοιμο για φόρτωμα στο Eclipse. Κάνουμε:
File => Import => Import existing Project into Workspace και πηγαίνουμε στο φάκελο librarymanager.
Ρίχνοντας μια γρήγορη ματιά στη δομή του project βλέπουμε ότι έχει τη γνωστη δομή ενός Spring MVC Template που χρησιμοποιεί το STS (βλέπε το σχετικό άρθρο μου).
Roo on IDE

7.   Φόρτωμα σε server


Έφτασε η στιγμή να δούμε τους κόπους της δουλείας μας. Φορτώνουμε το Project στον Tomcat (για παράδειγμα) μέσα (ή έξω) από το IDE μας et voila… μία έτοιμη εφαρμογή σε ελάχιστη ώρα.
Roo on IDE

8.  Χρήση της εφαρμογής


Βάλτε μερικά δεδομένα τώρα. Ξεκινήστε από τα βιβλία χρησιμοποιώντας το Create New Book. Όπως βλέπουμε το Roo έφτιαξε την εφαρμογή πλήρης με validation, tips και ακόμη με calendar για πεδία με ημερομηνίες.
Roo on IDE
Βάλτε τώρα ένα χρήστη από Create new Registered User. Τα βιβλία που έχουμε βάλει εμφανίζονται σαν multi choice λίστα. Επίσης υπάρχει αυτόματο paging για τις καταχωρήσεις
Παρατηρήστε επίσης ότι το site μας είναι και Multilingual ! Δοκιμάστε μερικές από τις σημαιούλες. Επίσης έχουμε τη δυνατότητα εναλλαγής του theme.
Συνοψίζοντας λοιπόν τις βασικές λειτουργίες που έχει η εφαρμογή έχουμε:

  1. Καταχώρηση / επεξεργασία εγγραφών
    1. Validation
    2. Tips
    3. Popup Calendar
  2. Λίστα εγγραφών
    1. Σύνοψη πεδίων
    2. Σελιδοποίηση
    3. Κουμπάκια για επεξεργασία / διαγραφή
  3. Πόλυ-γλωσσικότητα
  4. Themes
  5. Έτοιμο σχήμα στη βάση δεδομένων

4. ΣΥΜΠΕΡΑΣΜΑ

Σε αυτό το άρθρο είδαμε πως κατασκευάζεται μία εφαρμογή με το Roo χωρίς να γράψουμε ούτε γραμμή κώδικα, μέσα σε λίγα λεπτά. Στην πράξη, για να είναι ολοκληρωμένη η εφαρμογή θα βάλουμε τα δικά μας stylesheet, θα αλλάξουμε τα λεκτικά (θα γίνουν ελληνικά ίσως) και θα κάνουμε κάποιες τελευταίες τελειοποιήσεις. Ο βασικός κορμός της εφαρμογής (και αυτός που συνήθως παίρνει 90% της υλοποίησης) είναι έτοιμος.
Από την άλλη, έχοντας πλέον χρησιμοποιήσει το Roo σε διάφορα project σίγουρα δεν αποτελεί πανάκεια. Αν η εφαρμογή έχει πολύ business logic και πρόκειται να κάνετε πολλές επεμβάσεις στο front-end για να τελειοποιηθεί ίσως να μην ενδείκνυται (αλλά πάλι εξαρτάται).
Συμπερασματικά, θα έλεγα ότι το Roo αποτελεί ένα πολύ δυνατό εργαλείο για τη γρήγορη δόμηση εφαρμογών ιδιαίτερα σε εφαρμογές με μεγάλο πλήθος πεδίων όπου καταναλώνεται μεγάλος χρόνος για την κατασκευή αντίστοιχων φορμών, διαχείρισης entities και το validation.
Περιμένω τα σχόλιά σας αφού το χρησιμοποιήσετε.

5. REFERENCES

  • Η homepage του Spring Roo
  • Το επίσημο (και εξαιρετικά περιεκτικό) documentation με 2 πολύ καλά tutorials
  • Ένα ακόμη καλό tutorial

Passionate Archer, Runner, Linux lover and JAVA Geek! That's about everything! Alexius Dionysius Diakogiannis is a Senior Java Solutions Architect and Squad Lead at the European Investment Bank. He has over 20 years of experience in Java/JEE development, with a strong focus on enterprise architecture, security and performance optimization. He is proficient in a wide range of technologies, including Spring, Hibernate and JakartaEE. Alexius is a certified Scrum Master and is passionate about agile development. He is also an experienced trainer and speaker, and has given presentations at a number of conferences and meetups. In his current role, Alexius is responsible for leading a team of developers in the development of mission-critical applications. He is also responsible for designing and implementing the architecture for these applications, focusing on performance optimization and security.