It was 1997 and I hadn’t really embraced the web yet as a programmer. While I had played with HTML, I was convinced that real developers wrote in C/C++ and PL-SQL. HTML was for sissies. One of my co-workers was building an online search engine for an e-commerce company and he introduced me to CGI programming. The idea of redirecting the incoming HTTP request to a script that generated HTML on the fly instead of regurgitating the contents of a file seemed immensely cool to me at the time. Technology advanced and I followed with SSI, then servlets, then ASP, then JSP, then taglibs, then struts, then JSF, etc.
However, I never really questioned the basic premise that web applications are essentially a simple collection of scripts which dynamically generate HTML documents and share a server-side context (http session). Afterall, all of the server-side web technologies I had used were based on the same fundamental concept that CGI had introduced back in 1995. Most innovations in this area were just further abstractions built on top of this concept (e.g. JSP custom taglibs). But abstraction is a double-edged sword. It eliminates the need to understand everything going on under the covers. However, each abstraction layer typically includes its own configuration (struts XML hell), quirks, and conventions. Which results in the need for someone to define “best practices” based on their personal pain of figuring out where the friction points are between the layers of abstraction that live just above and just below it (e.g. ValueObjects/DataTransferObjects).
Building web applications has become much more complex than necessary and the the development community has responded with simplification efforts (think Ruby on Rails, annotations, configuration by exception, etc.). Each of these efforts were a significant evolution of web application development, but none were revolutionary. While undeniably valuable, they were still just lipstick on CGI.
True Web Clients
There is an opportunity today that really hasn’t existed until recently (outside of building GUIs completely inside a proprietary player like Flash). Stop generating HTML on the server-side. Write rich web applications as standalone clients based on open standards such as HTML, CSS, and JavaScript. Call it Client-Server 2.0 if you like, but without the baggage of software distribution, version management, and platform dependencies. While JavaScript was the foundation of this revolution it was the introduction of CSS, DOM manipulation, and finally AJAX that allowed us to build truly standalone web clients.
So how do you go about building true web clients? Until recently it was actually rather painful to do so. You had to be a JavaScript guru and even then you typically were weaving together multiple 3rd party JavaScript libraries and frameworks to provide the necessary event handling, DOM manipulation, parsing, etc. Appcelerator was designed specifically to simplify the development of web clients so that mere mortals can develop them (not just the PhDs @ Google). Yes, you can use all of the Appcelerator widgets and even leverage the client messaging bus without giving up your HTML generation scripts (and many people do). But once you’ve experienced the elegant simplicity of developing true standalone web clients that invoke services for business logic & data access, you will never go back.
The shift is already underway. The client operating system IS the browser. See the rise of offline, single-site-browsers, and desktop web integration. The clients call services and re-render themselves accordingly. The only question remaining is… how long before you starting writing webapps as standalone web clients?
upcoming blogpost teaser : HTTP sessions are so 1998
Popularity: 14% [?]
The world of web development is moving away from MVC-based web architectures and towards a client/server model that is probably best described as RIA + SOA, where RIA represents the rich user interface and SOA represents the services that it consumes. There has been a lot of buzz around rich Web 2.0 applications, but they will not become mainstream until the next generation of web platforms emerge - fully integrated platforms that enable RIA + SOA.
State of the Union
Currently, in the standards-based world of HTML, CSS and Javascript, RIA developers have to assemble multiple third-party libraries and frameworks in order to build a rich user interface. This “a la carte” approach to building RIAs places an unnecessary burden on the developer. Instead of focusing on building applications, the developer must spend time finding, integrating, and versioning the various pieces of their RIA development platform. The same holds true on the SOA side; developers are left to figure out how to create services and how to integrate them with their RIA front-ends. Developers need a platform that addresses every aspect of building an application, so that they can focus on doing what they do best – build applications. The question is: what should a next-generation RIA + SOA platform look like? The best place to start is with the activities that are required to build an RIA + SOA-based application. At a high-level these activities include:
1. Design the “look” of the application
This is the general appearance of an application. It includes things like: color, fonts, graphics, and a general page layout.
Common toolsets: HTML, CSS and images
2. Integrate widgets
Widgets encapsulate a set of common capabilities within a single component. They typically contain both “look and feel” as well as a set of pre-defined dynamic behaviors. They are a fundamental building block of an RIA.
Common toolsets: ExtJS, Dojo, Yahoo YUI and several other small widget projects
3. Add dynamic behavior to the user interface
Creating dynamic behavior in the user interface involves two things:
- Event handling
- Document Object Model (DOM) Manipulation
Event handling is the ability to know when a particular event occurs (e.g., a user clicks a button or a service response is received). DOM Manipulation allows you to dynamically change the user interface based on the receipt of an event.
Common toolsets: Javascript libraries like JQuery, Prototype, and Scriptaculous
4. Consume services
Consuming backend services is a key capability of an RIA. It enables the creation of single page user interfaces that exchange application data with services. It also enables a clean separation between the user interface and the service tier. The most common method for interacting with services is Ajax.
Common toolsets: Javascript libraries like JQuery and Prototype
5. Create services
Services provide an interface to data and application business logic.
Common toolsets: There are several frameworks available for creating services in your programming language of choice
Now that we have a sense of what is required to build RIA + SOA-based applications, we can take a look at how these activities should be integrated in order to provide the most value to developers. The following sections outline the defining characteristics of a next-generation RIA + SOA platform.
Support for HTML and CSS
These two languages are perfectly suited for implementing the “look” of an application, plus they are familiar to most developers of web-based user interfaces. There is no reason to recreate the wheel.
Provide an Open Widget Framework
As stated earlier, widgets are a fundamental building block of RIAs. There are several widget toolkits available from the likes of Yahoo, Dojo, and ExtJS. There are also several standalone widgets that have been created by smaller projects and individuals. You can build RIAs using these widgets, but there are some catches:
- It’s unlikely that one widget offering is going to meet all of your needs
- Integrating different third-party widgets may require custom code as well as an in depth understanding of how each widget works
- Writing new widgets is challenging because you either have to write to the low-level API of your preferred widget toolkit, or you have to write your own from scratch
- Some widget frameworks require developers to write a significant amount of Javascript just to use their widgets, which is problematic for those with little to no Javascript experience.
In order to address the problems above, an RIA + SOA platform should provide an Open Widget Framework that has the following capabilities:
- Support integration of existing third-party widgets
- Provide a simple API for creating new widgets
- Enable widgets to be used via simple markup (no Javascript required)
- Support a distribution model that makes it easy to submit, find and use new widgets.
An Open Widget Framework will provide developers with one source for obtaining widgets and one simple way to integrate these widgets into their application. If a particular widget is not available, it can be easily created using the Open Widget Framework API.
Given the importance of widgets within RIA development and the fragmented nature of widgets today, an Open Widget Framework should be considered an essential part of any RIA + SOA platform.
Provide an Integrated RIA Programming Model
Developing RIAs requires significantly more user interface code than traditional web-based applications. As a result, a next generation platform needs to provide an integrated RIA programming model that facilitates and simplifies the key user interface programming tasks. These tasks include:
- Event handling
- DOM manipulation
- Service consumption (Ajax).
Event handling, DOM manipulation and Ajax enable the “rich” in rich Internet application. It doesn’t take much investigation to see that they are closely related. To illustrate this point, let’s look at the typical steps involved with an RIA login form submission:
- Login button is clicked (event handling)
- Service request is sent (Ajax)
- Some type of activity indicator is displayed (DOM Manipulation)
- Service returns (Ajax)
- Activity indicator is hidden (DOM Manipulation)
- A Login “success” message is displayed (DOM Manipulation).
Despite their close relationship, most frameworks and libraries provide only light integration between the three, leaving the developer to bridge the gap. To illustrate this point, let’s look at some code. In the example below, we will set the contents of one combo box when the value of a second combo box changes. This example is written using JQuery:
1
2
3
4
5
6
7
8
9
10
11
| $(function(){
$("select#comboOne").change(function(){
$.getJSON("/combo.php",{id: $(this).val(), ajax: 'true'}, function(j){
var options = '';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
}
$("select#comboTwo").html(options);
})
})
}) |
Now, let’s look at how this could be accomplished using a fully integrated approach to event handling, DOM manipulation and Ajax.
1
2
3
4
5
6
| <select id=”comboOne”
on=”change then r:load.combo2.request”>
</select>
<select id=”comboTwo”
on=”r:load.combo2.response then value[property=rows,text=text,value=value]”>
</select> |
These two examples accomplish the same thing, but in very different ways. The first example requires more code and it’s all in Javascript. The second example uses a simple expression language to do the same thing. Let’s take a closer look at the syntax.
1
| on=”change then r:load.combo2.request” |
In this expression, the Ajax request message r:load.combo2.request will be sent when the <select> gets a “change” event – pretty simple. Now, let’s look at the second expression:
1
| on=”r:load.combo2.response then value[property=rows,text=text,value=value]” |
When the Ajax response message r:load.combo2.response is received, the contents of the second combo box are set based on data in the response message.
Let’s take this example one step further by adding a visual queue when the response message is received.
1
2
3
4
| <select id=”comboTwo”
on=”r:load.combo2.response then value[property=rows,text=text,value=value]
and effect[Highlight]”>
</select> |
By adding and effect[Highlight] to our expression, we are able to incorporate a subtle effect that lets the user know that the combo box values have changed.
These code examples demonstrate the power and simplicity of a fully integrated approach to event handling, DOM manipulation and Ajax. Developers that have little to no Javascript experience will find it easy to learn an expression language like the one above. It will enable them to get productive quickly, since they don’t have to climb a steep learning curve. Of course, there are developers that are comfortable with Javascript and would prefer to use it. As a result, an integrated RIA programming model should also support the use of Javascript, specifically in a way the supports the separation of behavior from markup. This is commonly referred to as unobtrusive Javascript. Let’s look at an example:
1
2
| <img id=”progress_image” src=”images/indicator.gif”/>
$(“progress_images”).on(“r:login.request then show”).on(“r:login.response then hide”); |
In this example, the <img> markup is separate from the Javascript code that defines its behavior – i.e., “show” when the login request message is received and “hide” when the login response is received. This type of programming model is good for developers that prefer to do their RIA programming in Javascript.
An Integrated RIA Programming model is a fundamental component of an RIA + SOA platform. It provides developers with a single integrated mechanism for handling the major RIA programming activities. The net result is that developers can build rich user interfaces faster and with significantly less code than is required today.
Provide an Integrated Services Platform
RIA only gets us halfway to our goal of building a rich application. We still need to provide an answer for the SOA piece of RIA + SOA. Unfortunately, the current crop of Web 2.0 toolkits and frameworks primarily focus on RIA; they provide little to no support for building services. This is problematic because developers are, once again, left to bridge the gap, which makes application development and maintenance unnecessarily more time consuming and difficult than it should be.
A next generation RIA + SOA platform must address this gap by providing an integrated services platform that provides the following:
- Support for creating services in any programming language
- Seamless interoperability between the RIA and SOA tiers
- Ability to consume local mock services .
Historically, web-based frameworks have been built around a particular programming language, but in the world of RIA + SOA this practice seems outdated and unnecessary. RIAs only need to exchange application data with services, so they should be programming language agnostic. The only required link between an RIA and its SOA-based services should be a lightweight message-based contract. This loose coupling between the RIA and SOA tiers opens the door to a integrated services platform that enables developers to use any programming language for service creation without impacting the RIA tier of the application.
An integrated services platform should also provide seamless interoperability between the RIA and SOA tiers. Specifically, it should handle service routing and data marshalling on behalf of the developer. Here’s an example of a simple integrated approach to building a service. This particular example uses Java.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| @Service (request = ‘login.request’, response =’login.response’)
protected void loginRequest (Message req, Message resp)
throws Exception
{
String username = req.getData().getString(“username”);
String password = req.getData().getString(“password”);
User user = UserDAO.login(username,password);
if (user !=null)
{
response.getData().put(“success”,true);
response.getData().put(“user”,user);
return;
}
response.getData().put(“success”,false);
} |
In the example above, there are two things to notice. First, a plain Java object is turned into a service by simply adding a “Service” annotation to a Java method. This annotation contains both the service request and service response message that this method handles, which makes routing configuration easy. Second, working with service request and response data is simple and straightforward. In the example, the entire User object is placed into the response message. The service platform handles the data marshalling. The result is that developer can focus on writing service logic instead of writing glue code, which ultimately results in faster development with less code.
Finally, if the contract between the RIA and its services is message-based, then it becomes possible to create local mock services. Local mock services respond to remote requests but they exist locally within the RIA. This is a powerful capability because it opens the door to creating fully functional RIA prototypes without writing a single line of service code. These local mock services can be placed in a single file and removed once user interface development is complete. Let’s look at an example.
1
2
3
4
5
6
7
8
9
| <!-- Progress indicator -->
<img src=”images/indicator.gif” style=”display:none
on=”r:login.request then show or r:login.response then hide”/>
<!-- Login form -->
Username: <input type=text” fieldset=”login” id=”username”/>
Password: <input type=”password” fieldset=”login” id=”password”/>
<input type=”button” value=”Login”
on=”click then r:login.request”/> |
Login Form
1
2
3
| <app:script on=”r:login.request then execute after 1s”>
$MQ(‘r:login.response’,{‘success’:true,’username’:’foo’});
</app:script> |
Mock Service
In the example above, we have a login form that generates the service request r:login.request. We also have an image that will show when r:login.request is received and hide when r:login.response is received. The second part of the example is the mock service. The mock service listens for the r:login.request service request and responds with a r:login.response message after one second in order to simulate service latency. The login form has no knowledge of the service location; it simply responds to messages. This simple example demonstrates how an entire RIA prototype can be built without writing any service code. This prototype would be 100% reusable, and it has the added benefit of enabling developers to define the service contracts in advance of service creation. The result is that service creation is greatly simplified because service developers not only have a fully functional prototype as a reference; they have a complete set of service interfaces.
Conclusion
Developers are currently caught in the middle of a fundamental shift in web application development. We are moving away from the server-side MVC frameworks of Web 1.0 and towards a client/server architecture for the web, or more specifically RIA + SOA. As a result of this shift, developers have been left to piece together their web development platform for rich web applications. Of course, change creates opportunity. The opportunity in this case is to build a next generation web platform that provides end-to-end support for building Web 2.0 applications. At Appcelerator, we saw this shift coming well over a year ago. Our response was to build the Appcelerator Platform; a platform built from the ground up to support RIA + SOA. The examples used in this article are based on Appcelerator. Of course, many different approaches will be taken to create the next generation of web platforms, but while the specific implementations may differ the general characteristics should remain the same.
Popularity: 15% [?]
Purpose
The Appcelerator framework allows for the extension of the build and deployment process so that you can add components and modify the behavior of your service implementations. It is quite powerful and not only restricted to services, plugins for example could span across to the modification of applications and the entire build and deployment process for that matter. For simplicity, this article will identify how to create a new component added to our java service for monitoring performance.
Install Appcelerator
I’ve assumed that you’ve successfully downloaded and installed Appcelerator from http://www.appcelerator.org/products. Once you’ve gone through the installer you can get the java service
1
| app install:service java |
You may want to get an existing plugin (I needed the java:spring plugin to implement my plugin):
1
| app install:plugin java:spring |
Plugin Creation
Lets assume that our plugin is going to be called java:perf, to create the plugin project:
1
2
| cd $HOME/workspace
app create:plugin . java:perf |
This will create a sub directory named java_perf, now you will want to create a proper license entry in your build.yml for example check out build.yml. You now have the opportunity to modify the entry points in your java_perf.rb. I personally wanted to setup my install script so that:
- it dynamically builds the jar when we add the plugin to a project
- modifies the spring.xml to include the bean entries for my component
All of this is in before_add_plugin(event) callback. If you want to see where this is called, check out add_plugin.rb. Once my coding is complete (added my source files to java_perf/src), I created the plugin distribution:
Install the plugin
As you noticed, I haven’t covered debugging the plugin just yet, this is because I want to first set up the plugin for installation and then work with it in my install directory. Lets install it to the local machine:
1
| app install:plugin java_perf.zip |
Add the plugin to my project
I thought that I’d create a blank java project real quick
1
2
| cd workspace
app create:project . myproject java |
now we can add the spring plugin and our new java:perf plugin to our project
1
2
3
| cd myproject
app add:plugin java:spring
app add:plugin java:perf |
You can now directly modify the java_perf.rb file in your install directory
- windows: c:/Program Files/Appcelerator/releases/plugin/java_perf/1.0
- unix: /usr/local/Appcelerator/releases/plugin/java_perf/1.0
- mac os: /Library/Appcelerator/releases/plugin/java_perf/1.0
I suggest that you continue to modify the java_perf.rb this way to debug it and then finalize by copying back over to $HOME/workspace/java_perf
Next Steps
As a final parting you can release your new plugin so that others may be able to leverage it
1
2
| cd $HOME/workspace/java_perf
app release java_perf.zip |
-andrew
this article is cross posted at:
http://zuerchtech.com/2008/3/4/implementing-an-appcelerator-plugin
Popularity: 15% [?]