dcsimg
December 9, 2016
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.

Sitemap | Contact Us

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