tag that contains a set of special attributes. Multiple instances of a given component can be declared by introducing additional
tags without the need to include the JavaScript source file again. This makes integration simple and intuitive. Furthermore, to prevent name collision issues between devices, we require that each device be associated with a universally unique identifier or UUID [11]. The following code skeleton illustrates how the HelloWorld.js device implementation self-associates itself with a UUID: declareImplementation( "E4D9BBE5C7AC436cABCA04F235FEA34D”, function(props) { // your code goes here }, “My HelloWorld.js Device”);
included, the following example illustrates how an instance of the TimeOut.js device, “bar,” can be set to time out in one second by specifying its “timeout_in” property in its declaration:
3.4 Composition The traditional model employed by most Object-Oriented JavaScript APIs uses inheritance for code reuse. Code reuse via inheritance leads to tightly coupled implementations that often become difficult to extend or replace without the potential of introducing instability to the system [7]. An extensible software system, however, must be able to adapt to new tasks without the need to access their internal implementations [12]. The black box pattern allows the system to stay flexible with respect to changes and extensions by adopting a loosely coupled component architecture. The basic philosophy behind black box composition is that it allows engineers to create new design patterns by interconnecting an arbitrary graph of design patterns, and the resulting pattern can in turn be used in another pattern [7]. In this model, we rely on the substitutability of interfaces and the ability to select appropriate interfaces at deployment or run time to build a system [7]. To illustrate the idea, suppose that we want to take the two devices and create a system that will wait one second before popping up a “Hello World” alert box. Figure 1 illustrates the design of such a system:
The arguments to declareImplementation consist of the device’s UUID, followed by its class constructor, ending with an optional argument that provides its humanreadable name. The implementation of the HelloWorld.js device can be included in an HTML file using the tag:
We can then declare an instance of the HelloWorld.js device and associate it with a local id such as “foo”:
3.3 Parameterization In order to allow a degree of customization to an otherwise immutable black box, we provide a mechanism by which the individual devices can be parameterized during declaration. This also allows multiple instances of the same device to take on different properties. Assuming that the implementation of the TimeOut.js device is
Figure 1. System Diagram
To create this system, we need to define a dataflow between the two devices. To address the dataflow, we introduce the notion of delivery “channels” connecting existing pairs of input and output terminals. There can be many channels between arbitrary pairs of input and output terminals, and when a message is posted on an output terminal, it is delivered to all input terminals that have channels between them. The dataflow shown in Figure 1 can be created with the following function call: connectTerminals([“bar,” “timed_out”], [“foo,” “greet”]);
This instructs all messages posted on the output terminal timed_out on bar to be delivered to the input terminal greet on foo. Messages may arrive at the input terminal greet at any given time with a guarantee that subsequent message arrivals will not interrupt the handling of this
message. Instead, these new messages will get queued for later handling. It should be noted that the destination of all messages posted to the output terminal timed_out is hidden from bar.
Figure 2 illustrates the compositional model used to create this Web application, along with the terminal connections among the JavaScript devices.
4. Runtime Environment 4.1 Asynchronous Message Passing In order to construct and run the individual JavaScript devices and to facilitate the dataflow among them, the architecture provides a runtime kernel called “JavaScript Star,” or “JsStar.” JsStar is a JavaScript source file that contains the minimum amount of code required to implement a kernel that can construct the devices and provide a message-passing infrastructure among them. By default, the kernel process is invoked upon completion of the page load, but this is configurable. The simplest way to activate the kernel is to include the runtime source in the HTML file along with the devices: Figure 2. System Diagram
If a JavaScript device has an input terminal named “%startup,” a message will be sent to the terminal when all the devices in the given HTML document have finished constructing and the terminal connections among all devices have been established. At this point, the JavaScript devices are free to engage in asynchronous message passing. Message arrivals on input terminals can be handled by functions that are defined and registered inside the class constructor, as follows: this.onGreet=function(msg){ alert(“Hello World”); } this.onMsg(“greet,” “onGreet”);
Messages can be posted to an output terminal using the device’s postMessage method: this.postMessage(“timed_out,” 1);
4.2 Runtime Characteristics The JsStar kernel is a 3KB gzipped JavaScript source file that, upon constructing all the devices in the HTML document, sits idle unless a device posts a message that requires delivery. Therefore, it is non-compute intensive and allows the individual JavaScript devices to utilize the CPU cycles they need to carry out their tasks.
5. Architecture Evaluation To gain a better insight into the development of an actual Web application using the proposed paradigm, we will look at a more complex example: an interactive map.
The diagram shows a total of 10 device instances and 6 device implementations used to create the application. There are two devices that warrant special consideration. The devices “zip_code_to_geo_code” and “map” are composite devices made from two JavaScript devices. A composite device is packaged as single HTML file and included in the data flow through the use of another JavaScript device known as the “Composite Device Proxy”. Through a composite device proxy the runtime can deliver messages directly to the related composite devices as if they were just another JavaScript device. 5.1 Rapid Prototyping Capability Starting from a plain HTML page that contains the JsStar kernel, we add the first two JavaScript devices: “zip_code_entry” and “go_button,” which are instances of the Text.js and Button.js device implementations, respectively. We configure the zip_code_entry device to be labeled “Type Zip Code Here,” and the go_button device to be labeled “Go.”
Now we add two additional JavaScript devices: “zip_code_to_geo_code” and “alert,” which are instances of the CompositeProxy.js and Alert.js device implementations. We then configure the zip_code_to_geo_code device to load the zip_code.html composite device. We can then connect the “user_event” output terminal of the go_button device to the “value_request” input terminal of the zip_code_entry
device. The connection from the “value_response” output terminal of the zip_code_entry device is then made to the “zip_code” input terminal of the zip_code_to_geo_code device. Finally, we connect the “geo_code” output terminal of the zip_code_to_geo_code device to the “message” input terminal of the alert device.
corresponding map commands when they are clicked: “pan_south,” “pan_north,” “pan_east,” “pan_west,” “zoom_in,” and “zoom_out.” To route these commands to the map, we connect the “user_event” output terminal of all of the buttons to the “request” input terminal of the map device.
We can now enter a zip code, hit the “Go” button, and observe an alert box displaying the geo code value corresponding to the zip code.
When we reload the page and click the newly added buttons, we are now able to pan and zoom the map without requiring a page refresh.
Notice how the zip_code_to_geo_code device completely encapsulates and hides the complexity of the device’s internals. In practice, the device makes a connection to the zipinfo.com Web site to grab the longitude and latitude value for a given zip code in real time. However, from the perspective of the component user, it is no more complicated than posting a zip code message and letting the runtime deliver the value to the zip_code input terminal of the zip_code_to_geo_code device. Now we can replace the alert device with another instance of the CompositeProxy.js device implementation, identify it as “map,” and configure it to load the “map.html” composite device. We will also need to reconfigure the terminal connections so that the output of the zip_code_to_geo_code device now gets connected to the geo_code input terminal of the new map device. We then set the CSS attributes of the map device so that the view port is large enough to display the entire map image. When we reload the page, we can see the map device rendering a default geographical location.
5.2 Seamless Component Substitution The map device in the previous example uses a homegrown map server that has not been optimized. For a better user experience, we might want to take advantage of a popular online map service such as Map Blast [13]. So we prepare a source file for a standalone JavaScript device called “MapBlast.js” that has the exact same interface contract as the original map.html composite device. We can then replace the old map device by including the JavaScript source code for the MapBlast.js device and replacing the
tag used for the previous map device with the new “map_blast” device. Now when we reload the page, we see the map_blast device rendering the map for the default location. If you enter the zip code and hit “Go,” you’ll also realize that you can interact with the map in exactly the same way as the old map. Notice that the rest of the devices in the system required no modification to make this happen.
We can now enter a zip code, hit “Go,” and watch the map device render the area around the zip code in place without refreshing the page.
To complete the interaction, we add 6 more buttons: north_button, south_button, east_button, west_button, zoom_in_button and zoom_out_button. Since we already have included the source code for the Button.js device, we simply need to add 6 additional
tags with the appropriate labels. The buttons can then be parameterized through the use of the properties attribute to emit
This pattern can be extended to allow one to choose different map devices depending on circumstances. For example, you may opt to use a Flash-based map for browsers that already have the plug-in, after doing primitive plug-in availability inspection on the client-side. If a standard set of geo-coordinate input terminals emerges for devices such as maps, it is conceivable that an economy of software devices will arise. Such economy
will increase the quality and availability of components, and ultimately provide users with better experiences. 5.3 Extension Through Composition Suppose we want to add a feature to the application by displaying the weather for the location specified by the zip code when the user hits “Go.” All we have to do is add a new device called “weather” that takes a zip code as a valid input for its zip_code input terminal. We can then simply connect the value_response output terminal of the zip_code_entry device to the zip_code input terminal of the weather device.
Component architectures based on the black box pattern are not a new concept. However, Web development has yet to benefit from such traditional programming techniques and software engineering design practices. With this paper, the architecture presented has defined the key concepts that enable highly extensible JavaScriptbased Web applications to foster the richer and more responsive user experience that traditional Web applications often lack. Moreover, with sophisticated Web browsers being nearly ubiquitous [15], the timing cannot be better. Please visit http://beaker.maya.com/jda/ .
References: [1] M. Gaedke & Jörn Rehse, Supporting compositional reuse in component-based Web engineering, Proc. ACM Symposium on Applied Computing, Como, Italy 2000, 927-933.
The fact that zip code was used as one of the currencies in the system allowed the application to be quickly extended with a weather device that takes zip code as input.
6. Conclusion Web applications built using the proposed paradigm are insulated from vendor lock-in problems, and also are nimble enough to respond quickly to changes in requirements and feature additions. Since the system follows a modular design pattern, the paradigm naturally lends itself to high level of code reuse as well. Future work will include a Web-based visual IDE that will ease the burden of keeping track of the numerous terminals attached to the devices and aid in visualizing the devices and the established channels among their terminals. For the architecture to help raise the bar on general Web application usability, it will be important to promote a market where JavaScript devices can flourish [14]. Such a market can help raise the visibility and discoverability of high-quality software components that can be used to extend a given system with desired features and interaction capabilities. One opportunity presented by this architecture, as a natural extension of IDA, is to allow for the distribution of compute units between the client and the server. A general-purpose design schematic stored in a repository [11] can hold enough information to arbitrarily determine at run time which components will be executed on the client and which will be executed on the server. The main idea behind this future work is to make it possible for devices to communicate seamlessly regardless of their implementation language, platform, or location.
[2] Ronan Barrett & Sarah Jane Delany, openMVC: A Non-Proprietary Component-Based Framework for Web Applications, Alternate track papers & posters, Proc. 13th international World Wide Web Conference, New York, NY, USA, 2004, 464-465. [3] Jian Yang, Web Service Componentization, Communications of the ACM, 46 (10), 2003, 35-40. [4] Macromedia Flash http://www.macromedia.com/flash/ [5] MAYA Design, Inc. http://www.maya.com/ [6] Software Reuse and Re-engineering http://frakes.cs.vt.edu/5744pdf/reuse.pdf [7] Gamma, E., Helm, R., Johnson, R., & Vlissides, J. Design patterns: Elements of reusable object-oriented software (Reading, MA: Addison-Wesley, 1994). [8] Curl, Inc., http://www.curl.com/ [9] DynAPI http://dynapi.sourceforge.net/ [10] Dojo http://www.dojotoolkit.org/ [11] Peter Lucas & Jeff Senn, Toward the Universal Database: U-forms and the VIA Repository, March 2002 [12] Shriram Krishnamurthi & Matthias Felleisen, Toward a formal theory of extensible software. Proc. 6th ACM SIGSOFT International Symposium on Foundations of Software Engineering, Lake Buena Vista, FL, USA, 1998, 88 – 98. [13] Map Blast http://www.mapblast.com/ [14] T. Ravichandran and Marcus A. Rothenberger Software reuse strategies and component markets Communications of the ACM 46 (8), 2003, 109-114. [15] Browser Market Share Study. http://www.ejanco.com/browser.htm