Chicago, October 19 - 22, 2010 Hello, RooBot: Writing and Distributing Your Own Spring Roo Add-Ons Stefan Schmidt
May 28, 2015
Chicago, October 19 - 22, 2010
Hello, RooBot: Writing and Distributing Your Own Spring Roo Add-Ons Stefan Schmidt
Agenda
• Architectural Journey • Getting Started with a new Add-on • Implementation • Roo Shell & OSGi • Pointers for Starters
Architectural Journey
Design Goals
• High productivity for Java developers – Reuse their existing knowledge, skills and experience
• Eliminate barriers to adoption – Lock-in, runtime, size, development experience
• Embrace the strengths of Java – Dev-time: tooling, popularity, API quality, static typing – Deploy-time: performance, memory use, footprint
High-Impact Decisions
• Use Java – This is a tool for Java developers – It defeats the purpose if we insist on a new language
• Don't create a runtime – This avoids bugs, lock-in, adoption barriers, approvals – This avoids CPU cost, RAM cost and footprint cost
• This easily led to some sort of generation model
Prototyped Approaches
• Pluggable Annotation Processing API (JSR 269) • Generate source at build time (XDoclet-style) • Generate bytecode at build time (ASM) • Generate bytecode at runtime (ASM) • Advanced proxy-based approaches (Spring AOP) • IDE plugins
• None of them satisfied all of the design goals
Decision 1: Use AspectJ
• AspectJ ITDs for “active” generation – Active generation automatically maintains output
• Delivers compilation unit separation of concern – Easier for users, and easier for us as developers
• Instant IDE support – Reduce time to market and adoption barriers
• Other good reasons – Mature, “push in” refactor, compile-time is welcome
ITD Model
• Roo owns *_Roo_*.aj files – Will delete them if necessary
• Every ITD provider registers a “suffix” it uses – Eg “Entity” becomes *_Roo_Entity.aj – A missing ITD provider causes AJ file removal
• ITDs have proper import management – So they look and feel normal to developers – So they “push in refactor” in a natural form
Decision 2: Create A Shell
• Need something to host the “active” generation
• Need something to receive user commands
• Usability issues were of extremely high priority
• We chose an interactive shell – Highest usability (tab, context awareness, hiding, hints...) – Background monitoring of externally-made changes – Background monitoring avoided crude “generate” steps
Shell Model
• Shell will perform a “startup” scan – To handle changes made while it wasn't running
• Shell will monitor file system once started – To handle changes made while it is running
• Shell will have a set of commands registered – To handle explicit directives from the user
• Roo will never modify a *.java file except at the explicit request of a user via a shell command
That Leaves One Key Question…
Control Information
Getting Started with a new Add-on
Add-on Creator
• ‘Add-on Creator’ itself is a Roo add-on • Quick start for Roo add-on development • Currently supports three types of add-ons:
– Simple Add-on • ideal for small additions to project dependencies and/or
configuration – Advanced Add-on
• ideal for starting fully-fledged Spring Roo add-ons – Internationalization Extension for MVC scaffolding
• ideal for offering new language translations for Roo’s scaffolded Spring MVC admin UI
Add-on Creator
• Project Maven pom.xml is configured for – hosting in SVN repository – easy creation of Maven repository – automatic generation of PgP signed artifacts
• Optimized for hosting as Google Code projects • Add-ons are compliant with RooBot
– PgP signed artifacts with public keys – Generation of OSGi compliant bundles – use of httppgp protocol
New Add-on command (Simple)
• Three new commands in version 1.1.x of Roo – ‘addon create simple’
• What: Command & Operations support • When: Simple add-ons which want to add dependencies and/
or configuration artifacts to project • Example:
– addon create simple --topLevelPackage com.foo.batch – optional attributes
» projectName (can use this to map to Google code project names) » description (Meaningful description of add-on)
New Add-on Commands (Advanced)
– ‘addon create advanced’ • What: Command, Operations & ITD support • When: Full-fledged add-ons which offer new functionality to
project – enhancements to existing Java types in project – introduction of new Java types (+ ITDs)
• Example: – addon create advanced --topLevelPackage com.foo.batch – optional attributes
» projectName (can use this to map to Google code project names) » description (Meaningful description of add-on)
New Add-on command (i18n)
– ‘addon create i18n’ • What: extension to the existing ‘web mvc install language’
command • Example:
– addon create i18n --topLevelPackage com.foo.ru --locale ru --messageBundle <path-to>/messages_ru.properties
– optional attributes » projectName (can use this to map to Google code project names) » description (Meaningful description of add-on) » flagGraphic* (provide a custom flag icon for UI use) » language** (provide a meaningful language name)
* based on the ISO 3166 country code Roo will attempt to download the graphic automatically ** based on the ISO 3166 country code Roo will attempt to determine the language name
automatically
DEMO i18n add-on
RooBot
• RooBot is a Vmware hosted service for Roo add-on registration
• Register new add-on repository by Email – send email to [email protected] – subject line: MUST be URL to OSGi repository definition
• ie: http://spring-roo-simple-addon.googlecode.com/svn/repo/repository.xml
– body: currently not used (but you can send greetings to the Roo team ;-)
– other interaction forms planned • Web front-end, • Roo shell command
RooBot requirements
RooBot verifies: – the provided repository.xml is a OSGi Repository – the resource URI must use the httppgp prefix
• ie: <resource uri="httppgp://fr-test.googlecode.com/svn/…/> – the referenced bundle in the repository has a
corresponding .asc file containing the PgP public key – RooBot will retrieve publicly accessible key information (key
owner name, email) from public key server – the referenced bundle contains a OSGi compliant
manifest.mf file
RooBot
• RooBot compliant add-on bundles – are registered in a publicly accessible roobot.xml file
• http://spring-roo-repository.springsource.org/roobot.xml – popularity of bundles registered (soon)
• RooBot Roo Shell client – addon list (lists all known add-ons)
• optional ’--refresh’ attribute – addon info --bundleSymbolicName <TAB> – addon install --bundleSymbolicName <TAB> – PgP trust model integrated – addon suggestions for unknown commands
Implementation
Metadata
• Project details – Project name, dependencies, build system...
• Java type details – Fields, methods, constructors, inheritance...
• Higher-level concepts – Entity properties, controller paths, validation rules...
• Must be automatically determined from project – With @Roo* (source level retention) where infeasible
Metadata Model
• Immutable – String-based keys (start with “MID:”) – Built on demand only (never persisted)
• Metadata can depend on other metadata – If “upsteam” metadata changes, “downstream” is told – Some metadata will want to monitor the file system
• Central metadata service and cache required
Conventions we follow
• Ensure usability is first-class • Minimize the JAR footprint that Roo requires • Relocate runtime needs to sister Spring projects • Embrace immutability as much as possible • Maximize performance in generated code • Minimize memory consumption in generated code • Use long artifact IDs to facilitate identification • Don't put into @Roo* what you could calculate • Don't violate generator predictability conventions
Role of Third Party Add-Ons
• 3rd party add-ons have a long-term role in Roo
• Minimize download size of Roo distribution • Avoid licensing issues with Roo distribution • Facilitate features of more niche interest • Separate project management and maintenance • Enable end user customization • Provide a sandbox for easy experimentation
Core Components
File Monitor API
• Mostly used by project and classpath modules – Rare for an add-on to directly use file monitor
• Publishes startup and “on change” events
• Events – Create – Update – Delete – Rename (if implementation supported) – Monitoring start (for each file when first found)
File Monitor Implementation
• Polling-based implementation
• Auto-scales to reduce CPU overhead
• Shell commands – “poll status” → indicates scan frequency and duration – “poll speed” → allows specification of frequency – “poll now” → forces an immediate poll
Common Services
• Services – o.s.roo.process.manager.FileManager
• use file manager for all file system operations in project (offers automatic undo on exception)
– o.s.roo.project.PathResolver • offers abstraction over common project paths
– o.s.roo.metadata.MetadataService • offers access to Roo metadata
– bean info metadata for mutators/accessors of target type – o.s.roo.project.ProjectMetadata
• project name, top level package • read access to project dependencies, repositories, etc
Common Utils
• o.s.roo.support.util.Assert – similar to Spring’s Assert
• o.s.roo.support.util.FileCopyUtils – useful for copying resources from add-on into project
• o.s.roo.support.util.TemplateUtils – useful for obtaining InputStream of resources in bundle
• o.s.roo.support.util.XmlUtils – hides XML ugliness
• writeXml methods • Xpath abstraction
Source Code Metadata Abstraction
• o.s.roo.classpath.details.*MetadataBuilder types
– FieldMetadataBuilder
– MethodMetadataBuilder • most commonly used builder during add-on development
– ConstructorMedataBuilder
– AnnotationMetadataBuilder
Roo Shell & OSGi
Roo Shell
• Implementations for STS and JLine
• Add-ons should – Make a “Command” class and implement CommandMaker – Delegate methods through to an “Operations” object – Annotate methods with @CliCommand – Annotate method parameters with @CliOption – Optionally use @CliAvailabilityIndicator if desired – Throw any exceptions to abort and rollback changes – Use JDK logging or return objects for console output
Development mode
• Enable via – Loading Roo via roo-dev shell script – JVM property developmentMode = true – Typing “development mode” at the roo> shell prompt
• Outputs full exception traces within Roo – Ugly for normal usage (exceptions are the normal way that
an add-ons abort from unexpected conditions)
• First line of troubleshooting add-on bugs is to ask for “development mode” exception data
OSGi
• Roo runs in an OSGi container since version 1.1 – ideal for Roo’s add-on model – developers can install, uninstall, start, and stop different
add-ons dynamically without restarting the Roo shell – automatic provisioning of external add-on repositories – OSGi provides very good infrastructure for developing
modular, as well as embedded, and service-oriented applications
– Roo uses Apache Felix OSGi implementation
OSGi Container & Roo Shell
• ‘osgi’ commands – osgi ps displays OSGi bundle information & status – osgi log access OSGi container logs – osgi scr info info about a specific component – help osgi help to ~20 osgi commands
• ‘addon install’ command – addon install high level abstraction for
‘felix shell start httppgp://…’
Development with OSGi
• Technical implications minimal: – use Apache Felix Annotations
• @Service offer functionality to other add-ons; must use interfaces
• @Component (required) for OSGi container • @Reference allows injection of services by other bundles
– Manifests are (auto-)generated by Maven bundle plugin • Reference other Roo bundles or OSGi compliant
dependencies in the add-on pom.xml
Development with OSGi
• Use activate method for – inititalization tasks performed at bundle startup – metadata dependency registration
• Don’t forget deactivate method
// example from JsonMetadataProviderImpl"protected void activate(ComponentContext context) {" metadataDependencyRegistry.registerDependency (…);" addMetadataTrigger(new JavaType(RooJson.class.getName()));" addMetadataTrigger(new JavaType(”org.springf.roo.addon.entity.RooIdentifier"));"}"
protected void deactivate(ComponentContext context) {" metadataDependencyRegistry.deregisterDependency(..);" removeMetadataTrigger(new JavaType(RooJson.class.getName()));"}"
DEMO advanced add-on
Pointers for Starters
Add-on Development Examples
• Roo 30+ core add-ons provide plenty of examples
addon-create a typical simple add-on with commands and operations
addon-toString a simple ITD-providing add-on with trigger annotation
addon-json a ‘classic’ add-on with commands, operations, ITD & trigger annotation
Spring Roo Sources
• We develop against a public Git repository – You can anonymously checkout the code – git clone git://git.springsource.org/roo/roo.git spring-roo
• Review source code without Git – http://git.springsource.org/roo/roo/trees/master – https://fisheye.springsource.org/changelog/spring-roo
• Roo itself uses Maven, so it's very easy to build – Standard package, install, assembly and site goal – PgP should be installed – see readme.txt in Roo master root for details
Other Project Resources
• Project Bug Tracker (Jira) – Contains lots of tips and tricks – https://jira.springframework.org/browse/ROO
• Project Forums – http://forum.springsource.org/forumdisplay.php?f=67
• Roo Documentation – http://static.springsource.org/spring-roo/reference/html-
single/index.html – Architecture details – Usage & conventions
Q&A