210 likes | 485 Views
Jazz Ajax Framework. Design and Programming Model. Bill Higgins. 22 October 2007. Overview. Jazz Ajax Framework (JAF). Layered infrastructure to assist in building Ajax-style web UIs Independent of Jazz Platform The “Jazz” in “Jazz Ajax Framework” only reflects its origin
E N D
Jazz Ajax Framework Design and Programming Model Bill Higgins 22 October 2007
Overview Jazz Ajax Framework (JAF) • Layered infrastructure to assist in building Ajax-style web UIs • Independent of Jazz Platform • The “Jazz” in “Jazz Ajax Framework” only reflects its origin • Brings the OSGi plug-in and extension-point extensibility model to Ajax • Can run standalone or within a JEE web app container • Available on Jazz.net as an incubator download (registration required)
Overview A word about frameworks… • Frameworks often seem to do more harm than good • Joel Spolsky: “Why I Hate Frameworks” • Two paths to a framework: • “If you build it, they will come” • Extract the framework from real running apps • With the JAF, we followed path #2 • Every JAF feature is the result of at least two extenders needing it • In many cases JAF features have been directly pushed down from an extender’s pre-existing implementation
Overview Design Goals • Early (2006) • Extensible: Ability to contribute UI ‘pages’ and code into a pre-defined UI shell • Responsive: Both initial load and user interactions • Easy to Debug: Make it easy to diagnose and fix problems in various parts of the system (browser, wire, server) • Cool • Later (mid-2007) • Customizable: Ability to define completely new applications • Small Footprint: Make it easy for non-Jazz products to consume
Overview Key Dependency JAF Structural Elements Extension net.jazz.ajax Dojo (0.9) Mozilla Rhino Jazz JSON Marshaling Equinox Server-side
Key Iteration Plans Dependency Extension Dashboard Work Items Reports SCM Jazz Kernel (Repository + Process) Jazz Ajax Framework net.jazz.ajax Dojo 0.9 Mozilla Rhino Jazz JSON Equinox Server-side Example JAF Application – Rational Team Concert
Extension Points Extension-point: net.jazz.ajax.webBundles • Marker extension that the JAF uses to discover the subset of server bundles containing JAF-targeted code • As opposed to bundles containing servlets, web services, etc. • Required for JAF extenders <extension point=“net.jazz.ajax.webBundles”/>
Extension Points Extension-point: net.jazz.ajax.applications • Reserves a URI (or URI pattern) • Total control over UI • Provides a scoping mechanism for other UI elements (e.g. pages) • Examples: Jazz Project UI, Jazz Server Admin UI <extension id=“projectArea” point=“net.jazz.ajax.applications”> <application alias=“/web/projects” jsclass=“com.ibm.team.process.ProjectApp”/> </extension>
Extension Points Extension-point: net.jazz.ajax.applications • Reserves a URI (or URI pattern) • Total control over UI • Provides a scoping mechanism for other UI elements (e.g. pages) • Examples: Jazz Project UI, Jazz Server Admin UI Used by pages for ‘applicationScope’ (see ‘pages’ ext pt) URI (under context root) to access application Fully-qualified name of ‘class’ implementation <extension id=“projectArea” point=“net.jazz.ajax.applications”> <application alias=“/web/projects” jsclass=“com.ibm.team.process.ProjectApp”/> </extension>
Extension Points Extension-point: net.jazz.ajax.pages • Coarse-grained chunk of UI • Run within one or more applications • Contains a set of one or more bookmarkable “actions” • Examples: “Work Items”, “Iteration Plans”, “Reports” within Jazz Project Area application
Extension Points Extension-point: net.jazz.ajax.pages (con’t) <extension point=“net.jazz.ajax.pages”> <page id=“com.ibm.team.workitem” widget=“com.ibm.team.workitem.Page” name=“Work Items” defaultAction= “com.ibm.team.workitem.runDefaultQuery”/> <!-- action declarations --> <action id=“com.ibm.team.workitem.runDefaultQuery”/> <action id=“com.ibm.team.workitem.viewWorkItem”/> <action id=“com.ibm.team.workitem.runQuery”/> <action id=“com.ibm.team.workitem.editQuery”/> <applicationScope id=“com.ibm.team.process.web.projectArea”/> </extension>
Extension Points Extension-point: net.jazz.ajax.pages (con’t) Parameter to built-in jazz.viewPage action <extension point=“net.jazz.ajax.pages”> <page id=“com.ibm.team.workitem” widget=“com.ibm.team.workitem.Page” name=“Work Items” defaultAction= “com.ibm.team.workitem.runDefaultQuery”/> <!-- action declarations --> <action id=“com.ibm.team.workitem.runDefaultQuery”/> <action id=“com.ibm.team.workitem.viewWorkItem”/> <action id=“com.ibm.team.workitem.runQuery”/> <action id=“com.ibm.team.workitem.editQuery”/> <applicationScope id=“com.ibm.team.process.web.projectArea”/> </extension> Initial action that runs if a user clicks on a page link The set of all (bookmarkable) actions defined for the page (more on this later) Displayed in the user interface Fully-qualified path to widget implementation Determines in which application(s) this page will show up
Putting it all together Creating a Custom JAF-based Application • Create a new Equinox bundle • Extend the webBundles and applications extension-points • Create a new JavaScript module with a ‘class’ definition (using dojo.declare) that extends the net.jazz.ajax.ui._Application class • In your class definition, place top-level UI elements in the page • This usually includes reusable JAF widgets (e.g. PageList, ProgressIndicator) that provide UI access to JAF internals (like page loading) • Call the _Application superclass’s start() method to tell the JAF to start processing URI changes • Define one or more pages, each with one or more actions
Capabilities Client-side Stack Plugs a large chunk of UI into an existing application Example: Jazz Work Items ‘Page’ Extension ‘Application’ Extension Defines a common look and feel and user experience and a container for pages Examples: Rational Team Concert Project, Rational Team Concert Admin UI Makes browser controls (back, forward, bookmarking, history) work in the Ajax-y page Provides APIs for layouts, page list, progress feedback, error-handling Browser Runtime Server-side Stack Helps JAF-based applications load fast by automatically optimizing (compression, concatenation, caching) Ajax resources based on dependency structure and UI entry point (i.e. which top-level UI module do you need to show and what does it transitively depend on?) Dynamic Optimization OSGi plug-in / extensibility model for Ajax code Mechanism to structure Ajax code as server-side OSGi bundles to enable component-based Ajax development Allows JAF to discover extensions and call into contributed code Allows extensions to define their own extension-points (open-ended extensibility)
Inside the JAF Dynamic Optimization • In non-JAF Ajax applications, in order to reduce initial page load times, teams use a build-time step to create a single compressed JavaScript file containing all of their Ajax code • In an extensible, plug-in-based server (like Jazz), independent teams build plug-ins at different times, so it’s not possible to create a single optimized file at build-time • The JAF uses a run-time process called ‘dynamic optimization’ in which the JAF… • Discovers all of the bundles with JAF-targeted code (via the webBundles extension point) • Analyzes the dependencies between JavaScript modules and builds an in-memory dependency graph • Builds up a single monolithic in-memory string of all CSS • Stores an optimized form of each JavaScript module in-memory
Inside the JAF JAF Application Startup • A JAF-based application has a sophisticated bootstrapping sequence optimized for a fast, responsive load • Note: This process is invisible to extenders • User browses to a JAF-based application (e.g. /web/myJAFApp) • Equinox server-side passes request to a JAF servlet • The JAF servlet responds with an HTML page (which uses validation-based caching) with: • Inlined CSS • A <script> tag (using expiration-based caching) pointing to a URI that contains the compressed, concatenated “JAF runtime” (basically Dojo + core JAF functionality) and the relevant application code • The extension registry data from all webBundles • A dojo.addOnLoad function that starts the targeted application • The contributed application builds up the basic UI and tells the JAF when it’s done • The JAF runs the initial action which, as a side-effect, loads the code for the initial page (based on the URI) • The JAF monitors the URI for changes to the URI’s hash value
Inside the JAF URI-Action Framework • The URI-action framework provides a mechanism to make browser controls like Back, Forward, History, and bookmarking work within a JAF-based Ajax application • This mechanism uses the hash value at the end of the page’s URI to denote unique UI states within the application • Example: #action=com.ibm.workitem.viewWorkItem&id=1234 • When the JAF notices a change to the hash value, it… • Looks up the action in the extension registry and its enclosing ‘page’ • If the page isn’t loaded, lazily loads the page code (XHR + eval) • Calls the corresponding JavaScript implementation code, which typically updates the view and sets the page title • All of this is invisible to extenders; they simply declare action IDs in their page extension and write action-handling JavaScript • Upcoming exploration: resource-centric URIs
Inside the JAF Debug Mode • Dynamic optimization makes debugging hard because the JAF lazily loads code via XHR calls and eval statements which makes the code invisible to debuggers • By appending ?debug=true to a URI, your application loads in ‘debug mode’ • Debug mode follows the same basic bootstrapping sequence, with the following differences: • JavaScript modules loaded as dynamically-appended <script> tags rather than XHR+eval (so debuggers can ‘see’ them) • The JAF servlet reads all files from disk rather than from memory • [Firefox only] Displays stack trace information for any uncaught error • Debug mode + disabled browser caching = rapid Ajax development
Inside the JAF Reusable JAF Widgets • The JAF provides a set of reusable widgets to simplify building JAF-based applications • Examples: • PageList: Displays a list of available pages for the application with links that load the page’s code and display the pages • PageContainer: Displays page content • ProgressIndicator: Displays progress messages • These widgets are driven by internal JAF events, so all you have to do is instantiate them and place them in the DOM; the JAF does the rest • OOTB, these widgets have no styles, so you style them with CSS to match your application’s L&F
Looking Forward… In-Progress but Unreleased Work • JAF-aware automated unit test infrastructure based on DOH • “Dashboard” infrastructure for finer-grained UI contributions
Looking Forward… Longer-term Ideas • More dynamic installation model, perhaps using Jazz repository (rather than Equinox bundles) to store JAF-extensions • Support for more traditional web apps (i.e. with page refresh) with Ajax-y adornments