Combine the power of WebSphere sMash with Adobe Flex

These days, everything from getting your local weather to sharing a video with your 500 closest friends is driven by a Web 2.0 application. With more environments relying on Web 2.0, IBM has released WebSphere sMash, an application framework designed around core concepts such as agile development, simplicity, and REST-ful interfaces. While most WebSphere sMash examples have user interfaces expressed using Ajax and either plain HTML or the Dojo Toolkit, this article shows how a simple sample application can be enhanced to support a Web 2.0 user interface written in Adobe Flex. Server implementations are provided in both Groovy and PHP. This article is for intermediate developers who have experience using REST and developing with the Adobe Flex Development Kit. This content is part of the IBM WebSphere Developer Technical Journal.

Jorge Rasillo (jarasill@us.ibm.com), Staff Software Engineer, IBM

Jorge RasilloJorge Rasillo is a software engineer at IBM Austin. He is currently a part of the AIX Scale Out and Solutions team working on a Blue Cloud solution. When he is not playing with his son or hanging out with his wife, he spends time training for triathlons.



Mike Burr (burrm@us.ibm.com), Senior Software Engineer, IBM

Author photoMike Burr is a software engineer at IBM Raleigh. He works in the WebSphere Technology Institute exploring possible future directions for IBM’s WebSphere line of products.



13 August 2008

Also available in Chinese Russian

Introduction

The term Web 2.0 is often overloaded. Perhaps this term is best defined as an architectural style that leverages rapid application programming interfaces, such as REST (REpresentational State Transfer), to develop an application that is consumable.

As an architectural style, Web 2.0 does not dictate any particular technologies on either the client (browser) or server side. In fact, one attractive characteristic of Web 2.0 applications is the clean separation of client and server technologies. This decoupling enables you to select client- and server-side technologies based on their suitably for the situation at hand, rather than dictating a "one size fits all" solution.

On the server side, WebSphere sMash is especially well-suited for developers with Java™ backgrounds who require the rapid time-to-value typically associated with dynamic scripting languages. Its support of both Groovy (a dynamic script language with Java syntax) and PHP makes WebSphere sMash immediately accessible to a broad spectrum of developers.

Although it does not dictate a client-side technology, WebSphere sMash applications are most often coupled with user interfaces expressed in HTML/Ajax, sometimes extended with the Dojo Toolkit. While these technologies fit the bill for many user interfaces, other applications might call for richer user interaction and a more mature framework. Adobe Flex, now at version 3, provides such a framework and commands significant mindshare in the Rich Internet Application (RIA) space.

This article outlines approaches that are useful in combining WebSphere sMash with Adobe Flex, by taking a simple to-do WebSphere sMash application and building a visually appealing user interface in Adobe Flex. The application is intentionally simple to more clearly demonstrate the techniques used to connect WebSphere sMash with Adobe Flex. In keeping with the WebSphere sMash philosophy, all communications between the browser and server are RESTful and use standard data encodings. To show the flexibility of both WebSphere sMash and Adobe Flex, multiple variations of the application are shown to demonstrate:

  • The WebSphere sMash application expressed in both Groovy and PHP.
  • Data transfer between the WebSphere sMash and Adobe Flex code using both XML and JSON.

Using WebSphere sMash

If you’re not familiar with it, WebSphere sMash originated as an incubator project called Project Zero, a community-driven commercial development project, and was developed with three things in mind: simplicity, agility, and speed. These attributes make for a robust framework that delivers applications that are reusable, easy to create, and adapt to change with minimal effort. With agility in mind, WebSphere sMash enables many businesses today that need applications developed in a hurry to deliver stable applications, developed quickly and simply.

WebSphere sMash’s dependency management systems eliminate many of the hassles that come with deploying an application, making it easy to transfer applications through different environments without having to worry about classpath dependencies. Unlike many other application environments, WebSphere sMash only includes the modules it needs, yielding applications with much smaller footprints, and initializes in seconds, making it an excellent agile development environment.

Web 2.0 and REST-style programming

Many confuse the term REST with architecture; rather, it is used here as an application programming interface that enables a Web 2.0 architecture. REST interfaces expose the traditional list/create/read/update/delete operations using the standard GET, POST, PUT and DELETE HTTP methods. Examples of some of these methods will be discussed later.

With Web 2.0, businesses are seeing real benefits in exposing their internal services and data sources to the Web in new formats that are easier for browser-based applications to use (for example ATOM, JSON, RSS, RESTful interfaces). Companies like Google and Amazon are leading the Web 2.0 world with APIs that enable developers to leverage existing functionality and build on top with minimal effort.

AppBuilder

AppBuilder is a tool for developing WebSphere sMash applications. (The .zip file included with this article was packaged using AppBuilder.) AppBuilder enables you to quickly build applications by providing a built-in editor with syntax highlighting, start and stop the server, and have access to the runtime log and trace via the console. AppBuilder is available from the Project Zero website (see Resources).

Figure 1. AppBuilder capabilities for syntax highlighting in the application editor
Figure 1. AppBuilder capabilities for syntax highlighting in the application editor
Figure 2. Runtime log tab in the file editor
Figure 2. Runtime log tab in the file editor

Groovy and PHP

The main focus here is to showcase the consumability of existing application by building an Adobe Flex front-end, and so only certain aspects of the WebSphere sMash infrastructure are covered in this article.

One of the attributes of WebSphere sMash is its ability to create applications very rapidly, and it does so by leveraging the power of scripting languages like Groovy and PHP.

WebSphere sMash has built-in conventions that make creating a RESTful resource in your application simple and straightforward. Any Groovy or PHP script placed in a WebSphere sMash application’s app/resources directory are automatically exposed as RESTful resources as follows:

Table 1. Scripts exposed as RESTful resources
HTTP methodURIScript method
GET/resources/<resource>onList()
POST/resources/<resource>onCreate()
GET/resources/<resource>/<id>onRetrieve()
PUT/resources/<resource>/<id>onUpdate()
DELETE/resources/<resource>/<id>onDelete()

See Resource (REST) programming model and conventions for more information.

The first task will be to create the server-side implementation of the to-do list application.

Sample to-do service with Groovy

Groovy is a scripting language for programmers that can’t live without their Java. Featuring easy integration with existing Java code and scripting abilities, Groovy lives up to its expectation for speed and simplicity.

The code uses the app zone in the global context to store the user’s to-do list. These are the methods used here:

  • onList: Lists the current to-do items.
  • onCreate: Creates a new entry in the to-do list by adding the specified item.
  • onRetrieve: Lists an item based on its index ID.
  • onDelete: Deletes an entry from the to-do list.

The application is initially built to return to data in an XML format. The code shown here is virtually identical to the sample REST resource shown in the Project Zero article referenced above. The complete WebSphere sMash source for the snippets below can be found in CombiningThePowerOfWSWithAdobeFlex/src/TodoService-1.0.0/TodoService/app/resources/todos_xml_grovy.groovy in the download file included with this article.

Listing 1. onList() event handler
def onList() {
    logger.INFO {"onList(): called"}
 
    def todos = app.todosXML[]
 
    if (todos == null) {
        todos = []
    }
    else {
        todos = todos.values()
    }
 
    outputXML(todos)
    logger.INFO {"onList(): returning ${todos}"}
}
Listing 2. onCreate() event handler
def onCreate() {
    logger.INFO {"onCreate(): called"}
 
    def item = request.params.item[]
    request.status = HttpURLConnection.HTTP_BAD_REQUEST
 
    if (item != null && item.length() > 0) {
        def todos = app.todosXML[]
        def index = app.index[]
 
        if (todos == null) {
            todos = [:]
            index = 0
        }
 
        index++
        todos.put(index, [id:index, value:item])
 
        app.todosXML = todos
        app.index = index
 
        request.status = HttpURLConnection.HTTP_CREATED
        request.headers.out.Location = request.uri[] + '/' + index
 
        logger.INFO {"onCreate(): created id ${index} -> ${item}"}
    }
}
Listing 3. onRetrieve event handler
def onRetrieve() {
    logger.INFO {"onRetrieve(): called"}
 
    def id = request.params.todos_xml_groovyId[]
 
    if (id != null) {
        def todos = app.todosXML[]
        def value = todos.get(id.toInteger())
 
        if (value != null) {
            outputXML(value)
            logger.INFO {"onRetrieve(): returning ${value}"}
            return
        }
    }
 
    send404()
}
Listing 4. onDelete event handler
def onDelete() {
    logger.INFO {"onDelete(): called"}
 
    def id = request.params.todos_xml_groovyId[]
 
    if (id != null) {
        def todos = app.todosXML[]
 
        if (todos.remove(id.toInteger())) {
            app.todosXML = todos
            logger.INFO {"onDelete(): deleted ${id}"}
            return
        }
    }
 
    send404()
}
Listing 5. Response rendering done in the outputXML method
def outputXML(data) {
    logger.INFO {"converting ${data} to XML"}
 
    request.headers.out.'Content-Type'='application/xml'
    request.view = 'XML'
    request.xml.output = data
    render()
}

Sample to-do service with PHP

PHP is a general purpose scripting language (see Resources). This section shows a PHP implementation that is functionally equivalent to the Groovy implementation shown above. Syntactic differences are what separate these two implementations. Depending on the complexity of the objects being serialized, indirect rendering is handled well by WebSphere sMash.

The complete WebSphere sMash source for the code snippets below can be found in CombiningThePowerOfWSWithAdobeFlex/src/TodoService-1.0.0/TodoService/app/resources/todos_xml_php.php in the download file.

Listing 6. onList method()
function onList() {
 
    $todos = zget("/app/todos_xml_php");
 
    if ($todos == null) {
        $todos = array();
    }
 
    zput('/request/view', 'XML');
    zput('/request/xml/output', array_slice($todos, 0));
    zput('/request/xml/rootelement', 'arraylist');
    render_view();
}
Listing 7. onCreate method
function onCreate() {
 
    $item = zget("/request/params/item");
    zput("/request/status", 400);
 
    if ($item != null && strlen($item) > 0) {
        $todos = zget("/app/todos_xml_php");
        $index = zget("/app/index");
 
        if ($todos == null) {
            $todos = array();
            $index = 0;
        }
 
        $index++;
        $todos[$index] = array('id' => $index, 'value' => $item);
 
        zput("/app/todos_xml_php", $todos);
        zput("/app/index", $index);
 
        zput("/request/status", 201);
 
        $uri = zget("/request/uri");
        zput("/request/headers/out/Location", "$uri/$index");
    }
}
Listing 8. onRetrieve() method
function onRetrieve() {
 
    $id = zget("/request/params/todos_xml_phpId");
 
    if ($id != null) {
        $todos = zget("/app/todos_xml_php");
        $value = $todos[$id];
 
        if ($value != null) {
            zput('/request/view', 'XML');
            zput('/request/xml/output', $value);
            render_view();
            return;
        }
    }
 
    // Error handling
    zput("/request/status", 404);
    echo "An error occurred while processing your request";
}
Listing 9. onDelete method
function onDelete() {
 
    $id = zget("/request/params/todos_xml_phpId");
 
    if ($id != null) {
        $todos = zget("/app/todos_xml_php");
        unset($todos[$id]);
 
        zput("/app/todos_xml_php", $todos);
        return;
    }
 
    // Error handling
    zput("/request/status", 404);
    echo "An error occurred while processing your request";
}

JSON overview

True to its Web 2.0 nature, WebSphere sMash not only supports XML, but JavaScript™ Object Notation (JSON) as well. (See Resources for more JSON information. One of the big advantages of Groovy is its ability to easily parse XML and JSON without having to invest a lot of time writing parsing code.

WebSphere sMash can render an HTTP response body using direct API or indirect rendering. In both cases, indirect rendering is used here to produce XML and JSON output. Invoking a renderer generally involves these steps:

  1. Set the value of /request/view in the Global Context to the corresponding renderer.
  2. Set additional renderer-specific values into the GlobalContext, where appropriate.
  3. Invoke zero.core.views.ViewEngine.render().

The examples above produce XML data only. The next sections describe how to produce JSON data by modifying a minimal amount of code in Groovy and PHP.

The complete WebSphere sMash source files for producing JSON output can be found in CombiningThePowerOfWSWithAdobeFlex/src/TodoService-1.0.0/TodoService/app/resources/todos_json_groovy.groovy and CombiningThePowerOfWSWithAdobeFlex/src/TodoService-1.0.0/TodoService/app/resources/todos_json_php.php in the download file.

Listing 10. Producing JSON output with Groovy
def outputJson(data) {
    logger.INFO {"converting ${data} to JSON"}
 
    request.headers.out.'Content-Type'='application/json'
    request.view = 'JSON'
    request.json.output = data
    render()
}
Listing 11. Producing JSON output with PHP
zput('/request/view', 'JSON');
zput('/request/json/output', $todos);
render_view();

Using Adobe Flex

So far, this article has described how to build the back end of your application. Next, you will see how to build a browser-based application that interacts with the WebSphere sMash back end you just built.

Adobe Flex produces a platform-independent rich Internet application (RIA) that can be deployed consistently on all major browsers, desktops, and operating systems (see Resources). RIAs built with Adobe Flex can be run on browsers using the Adobe Flash player or on desktops using the Adobe Integrated Runtime (AIR).

The complete Adobe Flex source files for the snippets below can be found in CombiningThePowerOfWSWithAdobeFlex/src/todoJSON.mxml and CombiningThePowerOfWSWithAdobeFlex/src/todoXML.mxml in the download file.

Building an Adobe Flex application involves:

  1. Getting the data from WebSphere sMash

    Adobe Flex makes it easy to load external data with the HTTPService component (see Resources). Two ways of performing the HTTP requests are shown here, one dealing with XML and the other with JSON. Because Adobe Flex has built in support for XML (that is, it uses ECMAScript for XML (e4x) to parse the data), there is less code to write for this case. To support JSON serialization in Adobe Flex, the corelib library needs to be downloaded (see Resources). Listing 12 shows sample code that creates an HTTPService component and makes it accessible to the application for deleting, retrieving, and creating an item in the to-do list using the XML data produced by the WebSphere sMash application.

    The Adobe Flex MXML code in Listing 12 makes extensive use of Adobe Flex’s binding mechanisms (the variable names inside curly braces) to dynamically substitute resource names and IDs when the requests are sent at run time. The URLs specified on the <mx:HTTPService> elements will be mapped by WebSphere sMash to the Groovy or PHP scripts constructed above. The method attributes and URLs will determine which method or function in those scripts is invoked to handle the request.

    The result and fault attributes provide code to be executed on successful completion of the request and error conditions, respectively. Data binding elsewhere in the MXML code automatically handles the data returned by the list and retrieve calls. The create and delete calls refresh the data displayed by initiating another list when they complete.

    Listing 12. Create an HTTPService component using XML
    <!-- REST call to retrieve list of todo items -->
    <mx:HTTPService id="listTodosHS"
       url="/resources/{resource}" method="GET"
       resultFormat="e4x"/>
    
    <!-- REST call to fetch details on an item -->
    <mx:HTTPService id="retrieveTodoHS"
       url="/resources/{resource}/{idToRetrieve}" method="GET"
       resultFormat="e4x"
       result="detailsBox.visible = true"/>
    
    <!-- REST call to add a new todo item -->
    <mx:HTTPService id="createTodoHS"
       url="/resources/{resource}" method="POST"
       result="listTodosHS.send()"
       fault="listTodosHS.send()">
          <mx:request xmlns="">
             <item>{itemToAdd.text}</item>
          </mx:request>
    </mx:HTTPService>
    
    <!-- REST call to delete a todo item -->
    <mx:HTTPService id="deleteTodoHS"
       url="/resources/{resource}/{idToDelete}" method="POST"
       result="listTodosHS.send()"
       fault="listTodosHS.send()"/>

    By using the JSON library, you can produce similar functionality that parses JSON data produced by the WebSphere sMash application (Listing 13). The primary differences between this JSON code and the XML code shown in Listing 12 are the explicit calls to decode the JSON data in the result handlers of the list and retrieve calls.

    Listing 13. Create HTTPService component using JSON
    <!-- REST call to retrieve list of todo items -->
    <mx:HTTPService id="listTodosHS"
      url="/resources/{resource}" method="GET"
      resultFormat="text"
      result="todoItems = JSON.decode(listTodosHS.lastResult as String);"/>
    
    <!-- REST call to fetch details on an item -->
    <mx:HTTPService id="retrieveTodoHS"
      url="/resources/{resource}/{idToRetrieve}" method="GET"
      resultFormat="text"
     result="detailItem = JSON.decode(retrieveTodoHS.lastResult as String);
      detailsBox.visible = true;"/>
    
    <!-- REST call to add a new todo item -->
    <mx:HTTPService id="createTodoHS"
      url="/resources/{resource}" method="POST"
      result="listTodosHS.send()"
      fault="listTodosHS.send()">
          <mx:request xmlns="">
              <item>{itemToAdd.text}</item>
          </mx:request>
    </mx:HTTPService>
    
    <!-- REST call to delete a todo item -->
    <mx:HTTPService id="deleteTodoHS"
    0  url="/resources/{resource}/{idToDelete}" method="POST"
      result="listTodosHS.send()"
      fault="listTodosHS.send()"/>
  2. Parsing and displaying the data

    Adobe Flex components make it easy to process the results of the HTTPService request, as illustrated by Listing 14.

    Listing 14. Processing the HTTPService request
    <!-- todo items list -->
    <mx:HBox left="10" horizontalGap="15">
    <mx:VBox backgroundColor="white"
       paddingBottom="5" paddingLeft="5"
       paddingRight="5" paddingTop="5"
       cornerRadius="5" borderThickness="1"
       borderStyle="solid" borderColor="black"
       dropShadowEnabled="true" shadowDistance="3"
       shadowDirection="right">
         <mx:Text text="Your todo items:" fontWeight="bold" fontSize="14"/>
            <mx:Repeater id="todoItemsRp"
               dataProvider="{listTodosHS.lastResult.item}">
               <mx:HBox width="100%" verticalAlign="middle"
                  paddingBottom="3" paddingLeft="3"
                  paddingRight="3" paddingTop="3"
                  rollOver="event.currentTarget.setStyle
                                         ('backgroundColor', 0xffff88)"
                  rollOut="event.currentTarget.clearStyle
                                        ('backgroundColor')">
                  <mx:CheckBox click="deleteItem(event)"
                     toolTip="Click to delete item"/>
                  <mx:Text text="{todoItemsRp.currentItem.value}"/>
                  <mx:LinkButton label="details"
                     fontSize="8" textDecoration="underline"
                     click="getItemDetails(event)"/>
               </mx:HBox>
            </mx:Repeater>
    
            <mx:Spacer height="10"/>
    
    <mx:HBox width="100%" verticalAlign="middle">
       <mx:Text text="Add:"/>
       <mx:TextInput id="itemToAdd"
          toolTip="Press Enter to add the new item."
          enter="createTodoHS.send(); event.currentTarget.text = ''"/>
    </mx:HBox>
    </mx:VBox>
    
    <!-- details for an individual item -->
    <mx:VBox id="detailsBox" visible="false" showEffect="{fade}"
       backgroundColor="white"
       paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"
       cornerRadius="5" borderThickness="1"
       borderStyle="solid" borderColor="black"
       dropShadowEnabled="true" shadowDistance="3"
       shadowDirection="right">
       <mx:Text text="Item details:" fontWeight="bold" fontSize="14"/>
       <mx:Text text="ID: {retrieveTodoHS.lastResult.id}"/>
       <mx:Text text="Value:"/>
       <mx:TextArea text="{retrieveTodoHS.lastResult.value}"/>
    </mx:VBox>
    </mx:HBox>

Event handling in Adobe Flex

Adobe Flex uses ActionScript, an object-oriented scripting language based on ECMAScript (see Resources) that lets you create dynamic user interfaces to provide interactivity, such as event handling, as shown in Listing 15. Notice the additional steps required in the creationComplete() function to reconcile the way Adobe Flex generates HTTP REST calls with what WebSphere sMash expects to receive.

Listing 15. Adobe Flex code sample
/**
 * Logic to run after the mx:Application has been created.
 */
 internal function creationComplete():void {
    // initial population of the list
    listTodosHS.send();

    // Flex doesn't know how to generate an HTTP DELETE.
    // Fortunately, sMash/Zero will interpret an HTTP POST with
    // an X-Method-Override: DELETE header as a DELETE.
    deleteTodoHS.headers['X-Method-Override'] = 'DELETE';

    // set a dummy body for the POST so Flex won't change it to
    // a GET
   deleteTodoHS.request['foo'] = 'I really do want a POST';
  }


 /**
  * Called when the user requests details for an item.
  */
  internal function getItemDetails(event:MouseEvent):void {
     // find id of item to be deleted
     var lb:LinkButton = event.currentTarget as LinkButton;
     var i:int = lb.parent.parent.getChildIndex(lb.parent);
     idToRetrieve = listTodosHS.lastResult.item[i-1].id;

     // hide details box while we're getting details
     detailsBox.visible = false;

     // ask server for details
     retrieveTodoHS.send();
  }


  /**
   * Called when the user checks on a box to delete an item
   */
  internal function deleteItem(event:MouseEvent):void {
     // find id of item to be deleted
     var cb:CheckBox = event.currentTarget as CheckBox;
     var i:int = cb.parent.parent.getChildIndex(cb.parent);
     idToDelete = listTodosHS.lastResult.item[i-1].id;

     // hide details if deleting same item
     if (retrieveTodoHS.lastResult != null &&
     idToDelete == retrieveTodoHS.lastResult.id)
     detailsBox.visible = false;

     // tell server to delete item, list will be updated when
     // delete finishes
     deleteTodoHS.send();
  }

The download file included with this article contains the full source code for this sample program.


Putting it all together

Adobe Flex out-of-the-box does not support JSON serialization. To add this support, you need to download and add the corelib library from Adobe to the libs directory of the WebSphere sMash application (see Resources). To deploy the Adobe Flex application, the application (.swf) must be stored in the public directory of the WebSphere sMash application. The source code included with this article includes two Adobe Flex applications, the first one uses XML and the second uses JSON. With the WebSphere sMash server started, the applications can be accessed by navigating to http://localhost:8080/todoXML.html or http://localhost:8080/todoJSON.html, respectively.

In the figures below, you can see:

  • The application after the onList() method is invoked when the application is first loaded (Figure 3).
  • The Adobe Flex front end sends an HTTP POST request to add a new item to the to-do list (Figure 4).
  • The Adobe Flex interface listens for the onclick event (for when the checkbox is selected) for removing an item from the to-do list (Figure 5),
  • The onRetrieve() is called when you click an item in the to-do list (Figure 6 and 7).
  • The application can switch between Groovy and PHP server side implementations (Figure 8).
Figure 3. Application after the onList() method is invoked
Figure 3. Application after the onList() method is invoked
Figure 4. Add an item to the to-do list
Figure 4. Add an item to the to-do list
Figure 5. Remove an item from the to-do list
Figure 5. Remove an item from the to-do list
Figure 6. User selects an item in the to-do list
Figure 6. User selects an item in the to-do list
Figure 7. onRetrieve() method is called
Figure 7. onRetrieve() method is called
Figure 8. Application can switch between Groovy and PHP
Figure 8. Application can switch between Groovy and PHP

Conclusion

WebSphere sMash provides a simple, yet powerful framework for rapidly building Web applications. With support for both Groovy and PHP dynamic scripting languages, WebSphere sMash enables you to come up to speed and quickly begin developing Web 2.0 applications. This article demonstrated the RESTful, standards-based techniques you can use to combine rich, highly interactive user interfaces written in Adobe Flex with WebSphere sMash back end logic. See the Resources below for more detailed information about the topics covered here.


Download

DescriptionNameSize
Code samplesmash-flex-sample.zip427 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, SOA and web services
ArticleID=330263
ArticleTitle=Combine the power of WebSphere sMash with Adobe Flex
publish-date=08132008