Convergence of Technologies II: Restlets, Highslide Viewer & SlideShowPro for Flash

Posted: 08/14/2009 by Serge Ilyn

What This Is All About

Slide show for a travel site that relies heavily on photo galleries is a must. One of my requirements for slides shows was to use pop-ups (demo: slideshow) so that such shows are optional if Web users may want to watch them. I decided to purchase SlideShowPro for Flash component and combine it with Highslide Viewer pop-ups as well as database driven dynamic content generation. Obviously, the latter is implemented using Restlets. The whole project did not seem too complex; all ingredients of the solution are well documented and known. With enough attention to details and APIs, I have expected to complete it in no time. In this post I will tell you about my experience so that if you want to implement something similar, you can adapt my implementation to your needs.

First, several words about components I used: Highslide and SlideShowPro (assuming at this point that Restlets do not need any introduction). In my previous post about Google Maps in pop-ups I already talked about Highslide JS - a solid open source image, media and gallery pop-up viewer Javascript library. It is really good and completely free for non-commercial sites ($29 for all other sites).

SlideShowPro for Flash is an XML driven Flash component to play photo, video and sound media. It allows for creating aesthetically pleasing appearances with endless customization options available through Flash's Component Inspector Panel. SlideShowPro for Flash is distributed as an extension for Flash and as a stand-alone, customizable SWF for web developers without Flash. Both are included in the single purchase with the price tag of $39.

I knew that Highslide can show Flash movies as pop-ups. However, to implement this task, I decided to keep using iframes as I did with Google Maps. One of the reasons was already accumulated experience in using Highslide with iframes. But more importantly, I found that it may be difficult to configure the component using SWF directly in Highslide: a lot of parameters to pass and the necessity to deal with two things as once: Highslide and SlideShowPro. With iframe approach, I could implement and deploy my shows as a regular Web page and show it in iframe later.

To be fair, I have to mention that Highslide JS has now it's own support for photo galleries. But I had never considered it as an option - SlideShowPro is far more superior in what it can do with various media.

Where To Start

Highslide

Since three parts based on three technologies are involved, you will have to deal with all of them. Fortunately, Highslide was easy - in fact, nothing new at all in addition to how I used this library to show Google Maps. This is also true for the type of links to open pop-ups:

<a href="/slideframe/my-article-ids" onclick="return hs.htmlExpand(this, { 
objectType: 'iframe', width: '680', height: '540'} )">Slideshow</a>

If you compare the above code with a sample link in my post about maps, you will see that in addition to a different URI, the has width: '680', height: '540' parameters passed to the Highslide "expander." Here, I take advantage of the smart way in which Highslide component allows for several levels of customization. Remember, the pop-up sizes I specify for Highslide in the HEAD node of the page are still there. However, since for my slide show pop-ups I need them to be bigger, I can override page-wide settings with new ones valid only for a specific link.

We'll talk about my URI /slideframe/my-article-ids later. For the moment I simply want to stress that it points to a page with SlideShowPro SWF. In terms of Restlet, this resource is identified by the /slideframe/{my-article-ids} URI pattern.

SlideShowPro

To explain how to setup SlideShowPro component for the task, I would have to write a novel. Fortunately, SlideShowPro developers provides outstanding by its clarity and coverage documentation. Please read it! I will highlight only those moments where I think problems are possible.

One of such moments is the need to modify the default component that assumes a static XML feed, to a more flexible approach where the URI for XML feed can be passed to SWF at run-time. This modification involves a little ActionScript fiddling in Adobe Flash CS3/CS4, but not worry - the whole process is described in details in documentation that comes with SlideShowPro. In addition, you will be required to modify and HTML page that is generated when you publish your .fla Flash source file.

Since we are also facing the issue of generating a dynamic content using Restlets, I would like to highlight some important things. Basically, the modification of the HTML page I mentioned involves adding an additional attribute/parameter, FlashVars, to <embed> and <object> tags as well as to the AC_RunActiveContent Javascript used to handle SWF. In this FlashVars we will specify values for two attributes: let's call them xmlfile and xmlfiletype. The attribute we need to pay attention is xmlfile since it will point to the resource with XML describing your gallery (albums, images and sound),

I specified FlashVars in my project like this:

'FlashVars','xmlfile=/gallery/${articleIDs}&xmlfiletype=Default',

If you work with Restlets and Freemarker templates, it should look familiar to you. The ${articleIDs} part is a Freemarker place holder that can be set, for example, as a Java bean attribute value, and the whole thing, /gallery/${articleIDs}, is nothing more than a resource identified by /gallery/{my-article-ids} URI pattern. Obviously, the make this work, I renamed the HTML file generated by Adobe Flash (when I published my Flash source file) so that it can be interpreted as a Freemarker template file. For example, if the original file were slideshow.html, I would rename it to slideshow.ftl.

To sum up modifications needed for the Flash part of the implementation:

  1. Customize the default SlideShowPro component (as described in details in documentation) so that it can take any XML source specified through the page with published SWF
  2. Rename the HTML file generated during SWF publishing so that it can be interpreted as a Freemarker template
  3. While specifying XML source for the SWF, use Freemarker syntax and Restlet way of identifying resource: like /gallery/${articleIDs}

Sample Freemarker template with all changes can be downloaded here

Restlet Part of the Project

To understand what kind of support for all this we need from the server, let's go through the whole process step-by-step. When a Web user clicks on a link like this slideshow, the Highslide component tries to create a pop-up. While doing this, it will requests from the server an HTML content for the iframe. When iframe (which contains SWF movie) is loaded, the SWF will start rendering a slide show component and as a part of this process it will request from the server an XML definition of the slide show gallery. After that, while showing specific pictures (as defined in XML), it will request from the server image data.

As you can see three steps relating to the server side take place here:

  1. A request is sent for the iframe content: such requests have format similar to /slideframe/000010D2
  2. A request is sent for the XML definition of the slide show gallery: such requests have format similar to /gallery/000010D2
  3. Requests are sent for specific image data as images are being rendered.

As far as our project is concerned, we have to implement support only for the first two steps - if your server can server image data, that will be good enough already. So, let's consider how first two steps can be implemented with Restlets.

Although I am talking about Restlets, any server technology and/or framework can be used to implement the functionality we need. Moreover, conceptually, all such implementations will be almost identical. As far as Restlet implementation is concerned, it relies completely on a framework I described previously in my Restlet Cookbook series of articles. If you are not familiar with them, you may find beneficial to read Restlet Cookbook - An Approach To Site Design (Recipe 1) and Restlet Cookbook - Site Application (Recipe 2).

Obviously, we need to enable our Restlet code to identify the specific requests. This is done in a usual Restlet way - see Listing 1

Listing 1: Attaching URI Patterns to Restlet Router
...
    // slideshow frame to show in popup - "ids" in this URI is comma-delimited 
list of artcle IDs included in the gallery
    router.attach("/slideframe/{ids}", SlideShowFrameResource.class);
    // slideshow xml - "ids" in this URI is comma-delimited list of artcle IDs 
included in the gallery
    router.attach("/gallery/{ids}", SlideShowGalleryResource.class);
...

As it follows from the above, I will need two "resource" classes - classes extending org.restlet.resource.Resource as required by Restlet API. As always, to design "resource" classes I will use composition to include data types abstracting data involved. Since SlideShowFrameResource class is supposed to produce an iframe content I will create the SlideShowFramePage class. It's design is very simple since the only data item it should handle is the slide show ID (which is the same as article ID): remember this definition I mentioned above - 'FlashVars','xmlfile=/gallery/${articleIDs}&xmlfiletype=Default' ? This ${articleIDs} will come from SlideShowFramePage as its only attribute.

Same way, SlideShowGalleryResource class will rely on its own data related constructs. To understand what these constructs are, let's look at a sample XML defining a simple gallery (it's described nicely in SlideShowPro documentation, but it can be handy to show a sample here to illustrate the design of our classes) - see Listing 2.

Listing 2: SlideShowPro XML Definition
<?xml version="1.0" encoding="UTF-8"?>
<gallery>
   <album title="...." description="...." lgpath="..." tnpath="....." 
tn="...." audio="..." >
      <img src="" tn="" caption="" />
      ...
   </album>
   <album title="...." description="...." lgpath="..." tnpath="....." 
tn="...." audio="..." >
      <img src="" tn="" caption="" />
      ...
   </album>
    ...
</gallery>

Although full definition allows for more options, the sample above illustrates all most important elements and attributes necessary to define an instance of SlideShowPro slide show. As you can see it includes "gallery" - a root element and one or more "album" nodes where each album may have one or more "img" nodes. The "img" elements includes three attributes: (1) src - absolute or relative path to the large image, (2) tn - absolute or relative path to the thumbnail image, and (3) caption.

The "album" elements can have several attributes that facilitate image management on the server: (1) lgpath - path to a folder with large images, (2) tnpath - path to a folder with thumbnail images, (3) tn - path to the thumbnail image associated with the album and (4) audio - path to an MP3 file that can be played back while watching the album.

Obviously, there are many ways you can model in OOP language this XML structure. I decided to create:

  • SlideShowGallery class - modelling the gallery element
  • SlideShowAlbum class - modelling an album element
  • SlideShowAlbumItem class - modelling an img element

The design of all these classes is pretty much straightforward. They are all Java Beans that follow the design of the XML slide show definition. As an example, let's look at SlideShowGallery class (Listing 3); it will help me illustrate how I handle multiple albums.

Listing 3: SlideShowGallery
public class SlideShowGallery {
  /** Array of article IDs that are included in this SlideShowGallery */
  String[] articleIDs;

  public SlideShowGallery(String[] articleIDs) {
    this.articleIDs = articleIDs; }

  /** Vector of SlideShowAlbum's */
  Vector currentEntries;
  public Vector getCurrentEntries() {
    return currentEntries; }

  public String[] getArticleIDs() {
    return articleIDs; }

  public void setCurrentEntries(Vector currentEntries) {
    this.currentEntries = currentEntries; }

  public void setArticleIDs(String[] articleIDs) {
    this.articleIDs = articleIDs; }

  public String getSlideShowGalleryRepresentation() {
    StringBuffer result = new StringBuffer("<?xml version=\"1.0\" 
encoding=\"UTF-8\"?><gallery>\n");

    // add albums to the gallery
    SlideShowAlbum album;
    Iterator iter = getCurrentEntries().iterator();
    while (iter.hasNext()) {
      album = (SlideShowAlbum) iter.next();
      result.append(album.getSlideShowAlbumRepresentation());
    }
    result.append("</gallery>\n");

    return result.toString();
  }

}

Two things to look at in SlideShowGallery. First, you can see that I actually allow for more than one slide show ID specified as String[] articleIDs; array (I will show you later how IDs get into this array). Second, there is a vanilla getSlideShowGalleryRepresentation() method that produces XML. Note that it relies on similar method in the "album" class and in its turn on similar method in the "album item" class. Basically, that's it as far as data support for the SlideShowGalleryResource class. It's time to look at the latter (see Listing 4)

Listing 4: SlideShowGalleryResource
public class SlideShowGalleryResource extends NaviquanBaseHTMLResource {
  SlideShowGallery slideShowGallery;

  public SlideShowGalleryResource(Context context, Request request, Response 
response) {
    super(context, request, response);
    String articleIDs = (String) request.getAttributes().get("ids");
    
     slideShowGallery = new SlideShowGallery(articleIDs.split(","));

  }

  @Override
  public Representation getRepresentation(Variant variant) {
    Representation result = null;
    try {
      populateFromNotes(getRequest(), slideShowGallery);
      result = new 
StringRepresentation(slideShowGallery.getSlideShowGalleryRepresentation(), 
MediaType.TEXT_XML, Language.ENGLISH_US);
    }
    catch (Exception ex) {
      ex.printStackTrace(); }

    return result;
  }

  public Pagable getPagable() {
    return null; }

  private void populateFromDatabase(Request request, SlideShowGallery 
slideShowGallery) throws NaviquanException, PoolException {

  }

}

As you can see from the above, I allow for several show IDs (delimited by comma) in one URI - something like

/slideframe/000010AE,000010CE,00001002,000010D2

When I read IDs values in the Restlet resource class, I simply split them "by comma." Basically, that's it. However, I would still like to clarify how I decided to handle multiple albums in the gallery. To do this, I invite you to look at the code for SlideShowFrameResource class (Listing 5).

Listing 5: SlideShowFrameResource
public class SlideShowFrameResource extends NaviquanBaseHTMLResource {

  SlideShowFramePage slideShowFramePage;
  String templateName;

  public SlideShowFrameResource(Context context, Request request, Response 
response) {
    super(context, request, response);
    String articleIDs = (String) request.getAttributes().get("ids");
    slideShowFramePage = new SlideShowFramePage(articleIDs);

    if (articleIDs.indexOf(",") > 0) {
      templateName = "slideshow2.ftl"; }
    else {
      templateName = "slideshow.ftl"; }
  }


  public Pagable getPagable() {
    return slideShowFramePage; }

  @Override
  public Representation getRepresentation(Variant variant) {
    Representation result = null;
    if (variant.getMediaType().equals(MediaType.TEXT_HTML)) {
      try {
        result = new TemplateRepresentation(templateName, 
Naviquan.freeMarkerConfig, getPagable(), MediaType.TEXT_HTML);
      }
      catch (Exception ex) {
        ex.printStackTrace();
      }
    }

    return result;
  }

}

This code shows that, in fact, I am using two Freemarker templates to handle my slide shows: slideshow2.ftl and slideshow.ftl. My little secret is that they use different SWFs. One SWF is configured to open an album (whatever it is), and the second is configured to show first the whole gallery (with as many albums as specified in XML). Try this: Slideshow with Four Albums.

Accordingly, SlideShowFrameResource uses one template with galleries with one album and another with multiple albums. I think this behavior can be easily achieved passing dynamically another parameter that would tell SlideShowPro how to open the movie - with the gallery or with an album. However, I have big plans for my slide shows, and I see that they will diverge more and more in future. In case like this, it will be much cleaner to use separate SWFs.


Recent Blogs

Convergence of Technologies II: Restlets, Highslide Viewer & SlideShowPro for Flash How to use Restlets, Highslide Viewer & Slide Show Pro Flash component to generate slide shows and show them in pop-up iframes 08/14/2009

Convergence of Technologies: Restlets, Highslide Viewer & Google Maps API How to use Restlets, Highslide Viewer & Google Maps API to generate Google maps using links on Web pages and show them in pop-up iframes. 08/13/2009

Ambimorphic, Mobile Configurations for Lamport Clocks After years of technical research into Smalltalk, with close cooperation with MIT Computer Science and Artificial Intelligence Laboratory (CSAIL) and its SCIgen, we have been able to show the construction of link-level acknowledgements. As a result, we propose an analysis of A* search, which we call Volt. 10/02/2008

Restlets and HTTP Sessions (Recipe 9) This recipe discusses some options in available to Web site developers using Restlet API to emulate traditional HttpSession's 07/31/2008

Restlet Cookbook - Delving into handleGet() and handlePost() (Recipe 8) This posting provides related examples that illustrate at least some simple things you may do with several handleX() methods where X may stand for various types of calls. 07/30/2008

Restlet Cookbook - How to enable SSL (Recipe 7) How to enable SSL on Restlet Web sites wihtout knowing too much keys, encryption, SSL and such. 07/29/2008

Restlet Cookbook - Using Filters in Restlet Applications (Recipe 6) This recipe contains code snippets illustrating the use of Filters in Restlet applications 03/09/2008

Restlet Cookbook - How to Create Virtual Hosts in Restlet Applications (Recipe 5) This recipe contains a code snippet for creating virtual hosts 02/24/2008

Popular HTML Escape Codes Here is a table of HTML escape codes for most frequently used symbols. If you use HTML, sooner or later you will find this table useful. 12/29/2007

Restlet Cookbook - Access Log (Recipe 4) This recipe describes access Logging using Restlet framework 11/09/2007

more...