dcsimg
September 22, 2018
Hot Topics:

Patterns and Java - A Matter of Good Taste

  • November 17, 1999
  • By Peter C. Mehlitz
  • Send Email »
  • More Articles »

  Listing 1
The Future pattern

 

/*
 * This example is based on pg. 333 of
 *   Doug Lea, "Concurrent Programming in Java -- Design Principles and Patterns"
 *
 * It demonstrates the use of Futures (concurrent Proxy with join synchronization
 * via access methods) in the context of a Image rendering process.
 *
 * The rendering process itself utilizes an Abstract Factory and a
 * configurable Singleton to choose from various possible threading strategies
 * (strictly sync, thread pools, per-render thread etc.).
 * 
 * The example demonstrates the use of interfaces, reflection, inner classes
 * and synchronization for design pattern implementation
 */

// this unifies "real" Pics and Pic - futures
interface Pic {
  Image getImage();
}

// abstracts away from the render process
interface Renderer {
  Pic render( URL url );
} 

// abstracts away from raw data format
interface RawRenderer {
  Pic render ( InputStream s );
}

// utilize a configurable singleton pattern to decide upon render stratgies, use
// RendererFactory as singleton anchor and base for concrete factories
// (if it doesn't act as a backup factory, RendererFactory should be abstract)
//------------------------------------------------------------------------------
abstract class RendererFactory {
  static RendererFactory singleton;

  public static synchronized RendererFactory getFactory() {
    if ( singleton == null ){
      try {
        Class cls = Class.forName( System.getProperty( "RenderFactory"));
        singleton = cls.newInstance();
      }
      catch ( Exception x ) { /* report, choose backup factory */ }
    }
    return singleton;
  }

  //.. backup factory impl might go here (if not abstract), otherwise:
  public Renderer getRenderer( URL src ); // enforce overloading
  public RawRenderer getRawRenderer ( InputStream s );
}

// concrete renderer factory
//------------------------------------------------------------------------------
public class AdaptiveRendererFactory extends RendererFactory {
  // create Renderer according to URL protocol
  public Renderer getRenderer ( URL src ){
    String protocol = src.getProtocol();
    if ( "http".equals( src.getProtocol() ) ){
      // we don't know how long this will take, turn it async
      return new AsyncRenderer( src, this);
    }
    //..
  }

  // create concrete RawRenderer for png, gif, jpeg..
  public RawRenderer getRawRenderer(InputStream s){..}
}

// concrete renderer, which uses futures to enable async rendering
//------------------------------------------------------------------------------
public class AsyncRenderer implements Renderer {
  RendererFactory factory;// used as a strategy object for getting a RawRenderer
  final URL src;          // deferred final (because of run) -> set in ctors

  public AsyncRenderer ( URL src, RendererFactory factory ){
    this.src = src;
    this.factory = factory;
  }

  // inner class because setPic should not be accessible outside
  // AsyncRenderer object
  class FuturePic implements Pic {
    Pic pic = null;  // this will hold out resolved future

    // block until future got resolved
    public synchronized Image getImage() {
      while ( pic == null ){
        try { wait(); }
        catch ( InterruptedException x ) { return null; }
      }
      return pic.getImage();
    }

    // this is called to resolve our future, unblock clients
    synchronized void setPic ( Pic pic ){
      this.pic = pic;
      notifyAll();
    }
  }

  public Pic render () {
    // 'final' because it is used in inner class
    final FuturePic future = new FuturePic();

    Runnable r = new Runnable() {
      // this is our primitive operation called from start()
      public void run() {
        try {
          InputStream s = src.openStream();
          RawRenderer br = factory.getRawRenderer( s);
          future.setPic( br.render());  // resolve future
          s.close();
        }
        catch ( Exception x ) { throw new RenderException(..); }
      }
    }

    new Thread( r).start(); // this is the template method calling run
    return future;          // return (probably unresolved) future right away
  }
}


  // client code
  ...
  Renderer r = RendererFactory.getFactory().getRenderer( url);
  try {
    Pic pic = r.render();  // just a future, but rendering has been kicked off

    /* do useful stuff while rendering is on the way */

    Image im = pic.getImage() /* this will block until future got resolved */
    if ( im != null )
      processImage( im);
  }
  catch ( RenderException x ) { /* report error */ }
  ...






Page 3 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.

Sitemap

Thanks for your registration, follow us on our social networks to keep up-to-date