Designing a Fully Scalable Application

Designing a Fully Scalable Application

Scalable Stage and Dispatcher

MantaRay provides two types of mediators, point-to-point (stage) and publish-subscribe (dispatcher), which answer different mediation needs. Together, they form a complete set that serves all of the mediation needs described in this article.

Stage

The SEDA project defines a Staged Event-Driven Architecture that introduces a well decoupled methodology for module interaction where stages are used to moderate between modules. Modules queue events into stages, while other modules that serve as handlers to these stages receive the events, triggering an operation. These modules, in turn, queue events into other stages as needed.

Figure 6 shows the decoupling modules with a stage.

Figure 6
Figure 6. Decoupling modules with a stage

The MantaRay project takes the stage idea to the next level. Modules obtain a reference to stage through a factory object. The factory dynamically creates the proper implementation, depending on whether the stage is in a distributed environment or in memory.

Several modules (or several instances of the same module) can add themselves as handlers to the same stage, but a single event is sent to one and only one handler. An event can be any object that implements the marker interface Serializable. Most Java objects can be serialized, but objects like Socket and OutputStream can not cannot be serialized because by nature they cannot be passed through the network. You can add this marker interface to any object without needing to implement additional methods.

In the WebMonitor example, the GUI modules send a request to the engine to monitor a URL through a stage. The engines register themselves as handlers to the stage, which in turn acts as a software load balancer in addition to its role as a mediator.

Dispatcher

The dispatcher is very similar to a stage, with one significant difference. As opposed to a staged event that has one and only one handler, a dispatcher event is sent to all handlers that have added themselves to the dispatcher. Thus, a dispatcher serves as a one-to-many mediator.

Figure 7 shows the decoupling modules with a dispatcher.

Figure 7
Figure 7. Decoupling modules with a dispatcher

The same roles apply to the events dispatched on a dispatcher as to the events queued to a stage. Additionally, the methodology used to obtain a reference to the dispatcher through a factory is the same as the one used to obtain a stage.

In the WebMonitor example, engines notify the GUI about changes to the status of the monitored URLs through a dispatcher. All of the GUI modules register themselves as handlers to the dispatcher, and all of them get notifications about changes to the status of the monitored URLs.

Below is a short code example of how the GUI and the engine work with the stage and the dispatcher:

GUI Code

    import org.mr.api.blocks.ScalableDispatcher;

    import org.mr.api.blocks.ScalableFactory;

    import org.mr.api.blocks.ScalableHandler;

    import org.mr.api.blocks.ScalableStage;

    ...

    public class WebMonitorGui implements ActionListener

    , ScalableHandler{    

    // the input text of the url to be checked

    JTextField urlInput;

         

    // The outgoing stage to the engine

    public ScalableStage engineStage;

    

     // The inbound dispatcher from the engine

    public ScalableDispatcher guiDispatcher;

    

    /**

     * The GUI gets a reference to the incoming

     * dispatcher and the outgoing stage,

     * the distributed parameter is passed to the

     * factory of these objects

     * @param distributed. if this boolean is true then 

     * this sample is running in a distributed environment

     * and the engine is in a different VM

     */

    public WebMonitorGui(boolean distributed){

        // get the stage from the factory

        engineStage = ScalableFactory.getStage("engine"

            , distributed);

        // get the dispatcher from the factory

        guiDispatcher = ScalableFactory.getDispatcher(

            "gui", distributed);

        

        // register this object has handler to all

        // incoming events

        guiDispatcher.addHandler(this);

    }

    

    /**

     * Start the SWING GUI

     */

    public void startGUI(){

    //Make sure we have nice GUI.

        ..

    }//startGUI

    

    /**

     * Called when there is an input from the user

     * sends the URL input from the user to the engine

     * via the stage

     */

    public void actionPerformed(ActionEvent e) {

        engineStage.queue(urlInput.getText());

        

    }

    

    /**

     * This is an implementation method of 

     * ScalableHandler interface

     * Called by the dispatcher when an event (results)

     * is received from the engine, updates the display

     */

    public void handle(Object event) {

        HashMap result = (HashMap) event;

        Iterator urls = result.keySet().iterator();

        while(urls.hasNext()){

            String url = (String) urls.next();

            String status = (String) result.get(url);

            updateURLStatus(url,status);

        }    

    }

    

}//WebMonitorGui

Engine

    import org.mr.api.blocks.ScalableDispatcher;

    import org.mr.api.blocks.ScalableFactory;

    import org.mr.api.blocks.ScalableHandler;

    import org.mr.api.blocks.ScalableStage;

    ...

    

    public class WebMonitorEngine extends Thread

     implements ScalableHandler {

     

     //Inbound stage this engine gets its URL 

     //to check from this stage

    public ScalableStage engineStage;

    

     // Outbound dispatcher this engine returns a

     // result map on this dispatcher

    public ScalableDispatcher guiDispatcher;

    

     // the result map

    public HashMap urlsToStatus = new HashMap();

    

    /**

     * @param distributed if this boolean is true

     * then this sample is  running in a distributed

     * environment, the engine is in a different VM

     */

    public WebMonitorEngine(boolean distributed){

    

        //get the inbound stage and register as handler

        engineStage = ScalableFactory.getStage("engine"

            , distributed);

        engineStage.addHandler(this);

        // get the outbound dispatcher

        guiDispatcher = ScalableFactory.getDispatcher(

            "gui", distributed);

    }

    

    /**

     * This is an implementation method of

     * ScalableHandler interface. Called by the stage

     * when an event (request) was received from

     * the GUI, adds the URL to the "to checked" map

     * called urlsToStatus

     */

    public  void handle(Object event) {

            // The event is a string like "java.sun.com"

            String urlStr = (String) event;

            // put in map of URLs to be checked

            urlsToStatus.put(urlStr, "Checking");

        }

        

    }

    

    /**

     * The engine is a thread that runs and checks the

     * URL and creates a report about status changes

     */

    public void run(){

        while(true){

            HashMap result= getUrlNewStatus();

                // only is result is not empty then send it

                if(!result.isEmpty())

                    guiDispatcher.dispatch(urlsToStatus);

            }// while

        }// run

        

    }

}//WebMonitorEngine

The full code of the WebMonitor example using both stage and dispatcher methodologies can be found in the sample folder of MantaRay's latest release. This article simplified the code example to make it more suitable for the format of an article.

Conclusion

We all hope that we are successful, that our clients like the software we have developed, and that the software will be widely used, but we must make sure that we are ready for this success. We must plan ahead in order to ensure that when the time comes and millions of users are happily using our product, it can gracefully and flexibly scale up to handle any additional load, necessary modifications, and additional functionality.

MantaRay's scalable set of utilities makes it easy to create an application that is ready to be scaled up from day one, with no code modification. A factory method dynamically creates the required module-decoupling implementation, whether it is distributed or in memory, thus seamlessly transforming a small-scale application into an enterprise-grade one.

Resources

  • MantaRay project page on SourceForge
  • MantaRay home page
  • The SEDA project
  • MVC paradigm

Amir Shevat is a senior software developer with eight years of experience in computing.


Return to ONJava.com.

Prev  [1] [2] 

Close    To Top
  • Prev Article-Java:
  • Next Article-Java:
  • Now: Tutorial for Web and Software Design > Java > Java EE > Java Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction