The Project        Download   Javadoc   SourceForge

Controller

The Controller isolates business logic from presentation. Every instantiated controller is added to a pool of controllers. Through the pool, its possible reach any controller.

Controllers facilitate the reuse and iteration between Swing components. Each Controller is responsible for a Swing component and must implement the following methods:

  • getComponent to get the controlled component
  • isComponentInstancied to indicates whether the controller is instantiated

Example:

 public class MainFrame extends JFrame{ 
  
   public MainFrame() { 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setSize(500, 400); 
    setLocationRelativeTo(null); 
   } 
  
 ... 
  
 } 
  
 public class MainController extends Controller<MainFrame>{ 
  
   private MainFrame component; 
  
   @Override 
   protected MainFrame getComponent() { 
    if (component == null) { 
      component = new MainFrame(); 
    } 
    return component; 
   } 
  
   @Override 
   public boolean isComponentInstancied() { 
    return (component != null); 
   } 
  
   public void show() { 
    getComponent().setVisible(true); 
   } 
  
   public static void main(String args[]) { 
    MainController main = new MainController(); 
    main.show(); 
   } 
 } 

There are several methods to get a Controller from the pool. It's possible to get one controller or all controllers of a specific class.

Instantiation, finalization and hierarchical groups

There are some options to instantiate a controller:

  • using the constructor: instantiates the controller and creates a new group for it
  • using the static method get(Class): gets the first controller of a specific class from the pool. If there is no controller for the class, one will be instantiated through the constructor.
  • using the method createChild(Class): can only be used from a controller. The new instantiated controller will join to the group and be a child controller in the hierarchy. Both controllers will be connected.

Example:

 // creating Group 1   
 Controller<?> cA = new Controller1();   
  
 Controller<?> cB = cA.createChild(Controller2.class);   
 Controller<?> cC = cA.createChild(Controller2.class);   
  
 Controller<?> cD = cC.createChild(Controller3.class);   
  
 // creating Group 2   
 Controller<?> cE = new Controller1();   
  
 Controller<?> cF = cE.createChild(Controller2.class);   
  
 // creating Group 3   
 Controller<?> cG = Controller.get(Controller4.class); 

  • Controller.get(Controller1.class) will returns the first instance of the Controller1 class: cA
  • Controller.getAll(Controller1.class) will returns all instances of the Controller1 class: cA and cE
  • cD.getRoot() will returns the cA instance
  • cD.getParent() will returns the cC instance
  • cA.getChildren() will returns the cB and cC instances
  • cA.getChild(Controller2.class) will returns the first instance of the Controller2 class: cB
  • cB.getGroup().get(Controller1.class) will returns the cA instance.
  • cA.getGroup().get(Controller2.class) will returns the first instance of the Controller2 class: cB
  • cA.getGroup().getAll(Controller2.class) will returns all instances of the Controller2 class: cB and cC

Controllers can be removed from the pool through free method. The children controllers will be automatically removed together their parents controllers. A controller with the state of permanent set as TRUE can't be removed from the pool unless the parent has bean removed.

The methods beforeFreeController and afterFreeController are run before and after the controller is removed from the pool. The default afterFreeController implementation dispose the component if it is instancied and extends from Window.

  • cD.free() will remove the cD instance
  • cC.free() will remove the cC and cD instances
  • cA.free() will remove the cA, cB, cC and cD instances
  • cB.getGroup().free() will remove the cA, cB, cC and cD instances
DebugWindow

Displays the status of the pool.

Use the static method showDebugWindow to show the DebugWindow

Annotations
  • ChildController - defines that a controller can't be instantiated by constructor or get method, only through createChild method.
  • Singleton - defines a controller as singleton.
Messages (publish/subscriber/filter)

Enables controllers to exchange messages.

Any controller can send a message through the pool to the other controllers. The message can be configured to allow its return to his publisher.

Example:

 public class UpdateMessage extends Message{ 
 ... 
 } 
  
 public class ViewerController extends Controller<ViewerFrame>{ 
  
   public ViewerController() { 
    registerSubscriber(UpdateMessage.class, new Subscriber() { 
      @Override 
      public void performMessage(Message message) { 
       performMessage((UpdateMessage) message); 
      } 
    }); 
   } 
  
   private void performMessage(UpdateMessage msg) { 
    msg.getValues(); 
    ... 
   } 
  
 ... 
 } 
  
 public class EditorController extends Controller<EditorFrame>{ 
  
   private void confirmAction() { 
    UpdateMessage msg = new UpdateMessage(); 
    msg.setValues(...); 
    publish(msg); 
   } 
  
 ... 
 } 

It is possible to limit the exchange of messages by filters.

Example:

 public class ViewerController extends Controller<ViewerFrame>{ 
  
   public ViewerController() { 
    registerSubscriber(UpdateMessage.class, new Subscriber() { 
      @Override 
      public void performMessage(Message message) { 
       performMessage((UpdateMessage) message); 
      } 
    }); 
  
    addMessageFilter(new MessageFilter() { 
      @Override 
      public boolean accepts(Message message) { 
       ... 
       return false; 
      } 
    }); 
   } 
 ... 
 } 
  
 public class UpdateMessage extends Message{ 
  
   public UpdateMessage() { 
    addSubscriberFilter(new SubscriberFilter() { 
      @Override 
      public boolean accepts(Subscriber subscriber) { 
       ... 
       return false; 
      } 
  
      @Override 
      public boolean accepts(Controller<?> controller) { 
       ... 
       return false; 
      } 
    }); 
   } 
  
 ... 
 } 
Modal functions

Has the addModal method to shows a modal

The standard modal messages:

  • showInformationModal method: shows a information modal message.

  • showErrorModal method: shows a error modal message.

  • showWarningModal method: shows a warning modal message.

  • showQuestionModal method: shows a question modal message.

  • showConfirmationModal method: shows a confirmation modal message.

Notes:

  • modals are added to the parent frame of controlled component through the Modal functions.
  • the buttons text can be changed forwarding or implementing a new bundle resource.
Task execution
  • tasks are executed through the TaskManager functions for the group controller.
  • exists a modal effect to the execution of tasks defined by the TaskExecutionProgress. It is a listener for the TaskManager. Use: TaskManager.addListener(new TaskExecutionProgressListener())
Task examples

Abstract controller:

 public abstract class AbstractExampleController extends 
     Controller<ExampleFrame>{ 
 
   private ExampleFrame component; 
 
   @Override 
   protected ExampleFrame getComponent() { 
     if (component == null) { 
       component = new ExampleFrame(); 
 
       component.getLoadButton().addActionListener(new ActionListener() { 
         @Override 
         public void actionPerformed(ActionEvent e) { 
           loadAction(); 
         } 
       }); 
     } 
     return component; 
   } 
 
   @Override 
   public boolean isComponentInstancied() { 
     if (component != null) { 
       return true; 
     } 
     return false; 
   } 
 
   protected List<String> fetchCountries() throws Exception { 
     Thread.sleep(4000); 
     return Country.getCountries(); 
   } 
 
   protected void logCountriesCount(int count) throws Exception { 
     Thread.sleep(4000); 
     // logging 
   } 
 
   protected abstract void loadAction(); 
 
 } 

Simple task example:

 public class SimpleExampleController extends AbstractExampleController{ 
 
   @Override 
   protected void loadAction() { 
     Task<List<String>> fetchCountriesTask = new Task<List<String>>() { 
       @Override 
       protected void doInBackground() throws Exception { 
         setResult(fetchCountries()); 
       } 
 
       @Override 
       protected void done() { 
         getComponent().populate(getResult()); 
       } 
     }; 
 
     execute(fetchCountriesTask, "fetching countries..."); 
   } 
 
 } 

Linked tasks example:

 public class LinkedExampleController extends AbstractExampleController{ 
 
   @Override 
   protected void loadAction() { 
     Task<List<String>> fetchCountriesTask = new Task<List<String>>() { 
       @Override 
       protected void doInBackground() throws Exception { 
         setResult(fetchCountries()); 
       } 
 
       @Override 
       protected void done() { 
         getComponent().populate(getResult()); 
       } 
     }; 
 
     LinkedTask<Void, List<String>> loggerTask = 
         new LinkedTask<Void, List<String>>() { 
           @Override 
           protected void doInBackground(List<String> linkedResult) 
               throws Exception { 
             int count = linkedResult.size(); 
             logCountriesCount(count); 
           } 
         }; 
 
     loggerTask.receiveResultFrom(fetchCountriesTask); 
 
     execute(fetchCountriesTask, "fetching countries..."); 
     execute(loggerTask, "logging..."); 
   } 
 
 } 
 

Error on task example:

 public class ErrorExampleController extends AbstractExampleController{ 
 
   @Override 
   protected void taskExecutionError(AbstractTask<?> task) { 
     getComponent().getLoadButton().setEnabled(false); 
     showErrorModal("Error", "Close the frame"); 
   } 
 
   @Override 
   protected void loadAction() { 
     Task<List<String>> fetchCountriesTask = new Task<List<String>>() { 
       @Override 
       protected void doInBackground() throws Exception { 
         if (true) { 
           throw new RemoteException("Error"); 
         } 
         setResult(fetchCountries()); 
       } 
 
       @Override 
       protected void done() { 
         getComponent().populate(getResult()); 
       } 
     }; 
 
     LinkedTask<Void, List<String>> loggerTask = 
         new LinkedTask<Void, List<String>>() { 
           @Override 
           protected void doInBackground(List<String> linkedResult) 
               throws Exception { 
             int count = linkedResult.size(); 
             logCountriesCount(count); 
           } 
         }; 
 
     loggerTask.receiveResultFrom(fetchCountriesTask); 
 
     execute(fetchCountriesTask, "fetching countries..."); 
     execute(loggerTask, "logging..."); 
   } 
 
 } 
 
 ... 
 
     HandlerExceptionManager.register(RemoteException.class, 
         new HandlerException() { 
           @Override 
           public void handle(Exception exception, 
                              HashMap<String, Object> parameters) { 
             System.out.println("Error on ControllerId: " 
                 + parameters.get(HandlerExceptionParameters.CONTROLLER_ID)); 
           } 
         }); 
 
 

Retry task example:

 public class RetryExampleController extends AbstractExampleController{ 
 
   @Override 
   protected void loadAction() { 
     Task<List<String>> fetchCountriesTask = new Task<List<String>>() { 
       @Override 
       protected void doInBackground() throws Exception { 
         if (true) { 
           throw new RemoteException(); 
         } 
         setResult(fetchCountries()); 
       } 
 
       @Override 
       protected void handleException(Exception e) { 
         if (e instanceof RemoteException) { 
           String title = "Error"; 
           String msg = "Do you want retry?"; 
           Icon icon = new ImageIcon(Images.WARNING); 
 
           final CustomPanel cp = new CustomPanel(title, msg, icon); 
 
           cp.addButton("Retry", new ActionListener() { 
             @Override 
             public void actionPerformed(ActionEvent e) { 
               retry(); 
               cp.closeModal(); 
             } 
           }); 
 
           cp.addButton("Cancel", new ActionListener() { 
             @Override 
             public void actionPerformed(ActionEvent e) { 
               cp.closeModal(); 
             } 
           }); 
 
           Controller<?> controller = getControllerWrapper().getController(); 
           controller.addModal(cp); 
         } else { 
           super.handleException(e); 
         } 
       } 
 
       @Override 
       protected void done() { 
         getComponent().populate(getResult()); 
       } 
     }; 
 
     LinkedTask<Void, List<String>> loggerTask = 
         new LinkedTask<Void, List<String>>() { 
           @Override 
           protected void doInBackground(List<String> linkedResult) 
               throws Exception { 
             int count = linkedResult.size(); 
             logCountriesCount(count); 
           } 
         }; 
 
     loggerTask.receiveResultFrom(fetchCountriesTask); 
 
     execute(fetchCountriesTask, "fetching countries..."); 
     execute(loggerTask, "logging..."); 
   } 
 
 } 
 
 

Partners