|
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..."); |
| } |
| |
| } |
| |
|
|
|