fuin.org

Small Open Source Java Tools and Libraries

Optimized View and Logic (Controller) Separation with Swing


Part 4: Simple Utilization for the Developer

If you scrutinize the actual objective, you will realize that it says Simple Utilization for the Developer and not Simple Technology.
 
No one would expect a J2EE Server, for instance, to have a particularly simple internal structure. However, a good interface makes such a complex piece of technology relatively easy to use for a programmer. It conceals its own complexity from the application developer (see EJB2 vs. EJB3).
 
The same is true for our approach: The classes stipulated disappear in a small in-house developed framework (JmsMvc4Swing) and the programmer can focus entirely on the development of his/her application.
 
To this end, the generation of the required classes occurs on-the-fly based on the already compiled controller surface. The request looks something like this:
package org.fuin.jaddr.part6;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.fuin.jmsmvc4swing.base.ControllerPair;
import org.fuin.jmsmvc4swing.base.JmsJndiEnvironment;
import org.fuin.jmsmvc4swing.base.JmsJndiEnvironmentImpl;
import org.fuin.jmsmvc4swing.model.ControllerModel;

/**
 * Java Swing based address manager.
 */
public class AddressExample {

    // Alternatively we can use another provider like ActiveMQ
    // props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
    // props.put(Context.PROVIDER_URL, "tcp://localhost:61616");
    // String topicConnectionFactoryKey = "TopicConnectionFactory";

    public static void main(final String[] args) throws NamingException {

        // Define the JMS Environment
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "net.walend.somnifugi.SomniTopicContextFactory");
        String topicConnectionFactoryKey = "ConnectionFactory";

        // Open a connection to JMS
        JmsJndiEnvironment env = new JmsJndiEnvironmentImpl(new InitialContext(props),
                topicConnectionFactoryKey);
        env.open();

        // Define a topic for our controller
        String topicName = AddressController.class.getName();

        // Create a controller model based on the interface
        ControllerModel<AddressController> controllerModel = new ControllerModel<AddressController>("org.fuin.jaddr.onthefly", AddressController.class);

        // Create "on-the-fly" the necessary instances
        ControllerPair<AddressController> pair = controllerModel.createOnTheFly(env, topicName, new AddressControllerImpl());

        // Start the receiver for the controller
        pair.getReceiver().start();

        // Create a sender for the view
        AddressListPanel panel = new AddressListPanel(pair.getSender());
        // TODO Make the panel visible

    }

}
If required, a Java source code can also be generated as an alternative.
 
To make sure this model works, some additions will have to be made to the AddressController interface beforehand. The AddressController extends a standardized Controller Interface and the Listeners extends the ControllerResultListener interface:
package org.fuin.jaddr.part6;

import java.util.List;

import org.fuin.jmsmvc4swing.base.Controller;
import org.fuin.jmsmvc4swing.base.ControllerResultListener;
import org.fuin.jmsmvc4swing.base.MethodCancelable;
import org.fuin.jmsmvc4swing.base.ProgressDeterminate;

/**
 * Address handling.
 */
public interface AddressController extends Controller {

    /**
     * Loads a list of addresses and notifies a listener.
     *
     * @param selectedAddress
     *            Currently selected address or null if no address is selected.
     * @param listener
     *            Gets informed about the results.
     */
    @MethodCancelable
    @ProgressDeterminate
    public void loadAddresses(Address selectedAddress, LoadAddressesListener listener);

    /**
     * Listens to the results of the
     * <code>loadAddresses(LoadAddressesListener)</code> method.
     */
    public interface LoadAddressesListener extends ControllerResultListener {

        /**
         * Sets the address list.
         *
         * @param list
         *            Address list.
         */
        public void setAddresses(List<Address> list);

        /**
         * Select the given address.
         *
         * @param id
         *            Address to be selected.
         */
        public void selectAddress(Address address);

    }

    /**
     * Deletes an address.
     *
     * @param address
     *            Address to delete.
     * @param listener
     *            Gets notified about deletion result.
     */
    public void deleteAddress(Address address, DeleteAddressListener listener);

    /**
     * Listens to the results of the
     * <code>deleteAddress(Address, DeleteAddressListener)</code> method.
     */
    public interface DeleteAddressListener extends ControllerResultListener {

        /**
         * The address was deleted.
         *
         * @param address
         *            Successfully removed address.
         */
        public void addressDeleted(Address address);

    }

}
The Controller Interface is a straight-forward Tag Interface. The ControllerResultListener, on the other hand, defines important basic events that are of interest when any controller method is requested:
package org.fuin.jmsmvc4swing.base;

/**
 * Base class for listeners that want to be informed about method results.
 */
public interface ControllerResultListener {

    /**
     * Controller started working.
     */
    public void started();

    /**
     * Controller signals progress.
     *
     * @param progressInfo
     *            Progress informations.
     */
    public void progress(ProgressInfo progressInfo);

    /**
     * Controller finished work.
     */
    public void succeded();

    /**
     * Work was interrupted by an exception.
     *
     * @param ex
     *            Cause.
     */
    public void failed(Exception ex);

}
In addition to Start, Success or Error the controller can also signal the progression of the process (via ProgressInfo) on the surface.
 
As a Listener for both controller methods, the Panel will also have to implement the new methods. We instantly combine this with the implementation of the subsequent requirement (the "Blocking of the Surface During Prolonged Tasks").
 
Next Page: Part 5: Blocking of the Surface During Prolonged Tasks
 

 
Page: 1 / 2 / 3 / 4 / 5 / 6 / 7