Configure SLF4J/Logback for a standalone application

Most examples for SLF4J/Logback you can find on the internet are about how web applications are configured. But if you have a command line or JavaFX application, you’ll require a different setup. Most probably you want a local ‘logback.xml’ that is located in your application’s folder or in the home directory of the user. But how to configure such a SLF4J/Logback for a Java SE application?

The good news is, that there is already a tiny library that does the trick: ext4logback. It allows you simply to specify the location of your ‘logback.xml’ and does all the initialization for you. It also creates a default logback XML configuration if no file exists at startup.

Simply add the dependency to your Maven POM:

<dependency>
    <groupId>org.fuin</groupId>
    <artifactId>ext4logback</artifactId>
    <version>0.2.0</version>
</dependency>

Then you can just initialize the log in your applications ‘main’ method:

/**
 * Starts the application.
 * 
 * @param args
 *            Only optional argument is the 'logback.xml' file path and
 *            name. If no argument is provided it's assumed that the file name 
 *            is 'logback.xml' and it's in the current directory.
 */
public static void main(final String[] args) {
    try {
        // Initializes Logback by reading the XML config file.
        // If the file does not exist, it will be created with some defaults.
        // This is a convenience method that directly uses the main method's arguments.
        new LogbackStandalone().init(args, new NewLogConfigFileParams("your.app.package", "myapp"));
        LOG.info("Application running...");
        // Your code goes here...
        System.exit(0);
    } catch (RuntimeException ex) {
        ex.printStackTrace(System.err);
        System.exit(1);
    }
}

In Search of the Holy Grail of Swing MVC (Part 4)

Designing the Module

Now that we have established how to connect the controller and it’s view, we should step back and think about the structure of the whole dialog.

At the Java One 2009, Kenn Orr delivered an interesting keynote, in which he discussed Component Oriented Design.

His main ideas regarding Component Oriented Design are as follows:

  1. Expose a small set of functionalities as a service. Only give the API consumer access to functionality in the component’s contract.
  2. The look and implementation of a user interface portion of the component is almost completely hidden from clients; the only exposure of the UI is via a getComponent method which returns a JComponent. Thus, the implementation of the visual representation of the component may change freely over time, as the developer has nothing to hook onto. Swing was intended to have this separation (think UI delegates and models), however, many widgets aggregate some of the UI and model methods within the widget API
  3. Components do not extend anything. Aggregation is the name of the game. To build a more complex component, developers can assemble pre-built components.

Here, he was basically adressing Swing components, but I believe the same idea also applies to dialogs.

What does a typical usage of a login dialog look like?

// Get the login module from somewhere
LoginModule module = ...
try {
    // Show the login dialog with a predefined username
    String username = module.login("john");
    LOG.info("Login successful: " + username);
} catch (final CanceledException ex) {
    // User canceled the login process
    LOG.error(ex.getMessage());
}

The module’s interface is clearly fairly small:

public interface LoginModule {

    // Login with a predefined username
    public String login(String username) throws CanceledException;

    // Login with empty dialog
    public String login() throws CanceledException;

}

There is one big problem with this design, namely that the controller cannot implement the interface directly because it forwards control to the user. The latter means that the “login(..)” method will show the window and then immediately return to the caller (without result). As you may remember, the login process is finished when the user presses OK or CANCEL and the appropriate controller method is called. No return value is available until then, meaning that the above usage example will not work!

Transforming the Module Interface

To avoid this problem, let’s transform the interface:

@ModuleRef(LoginModule.class)
public interface LoginModuleImplIntf {

    public void login(LoginListener listener, String username);

    public void login(LoginListener listener);

    // Listener to get informed about the result
    public interface LoginListener {

        public void success(String username);

        public void failure(CanceledException ex);

    }

}

This is an exact 1:1 transformation of the above code. You may have noticed the “@ModuleRef” annotation, which connects the two interfaces. I’ll return to this point later. For now, we will add additional annotations to the Module interface:

@ModulImplIntfRef(LoginModuleImplIntf.class)
public interface LoginModule {

    @WaitForUserInput
    public String login(String username) throws CanceledException;

    @WaitForUserInput
    public String login() throws CanceledException;

}

Both classes are now connected using two simple annotations @ModulImplIntfRef and @ModuleRef. But what is the purpose of the @WaitForUserInput annotation? It is simply a marker informing us that the control will be forwarded to the user by means of this method, and it may take some time before a result is generated. All three annotations will later be used by a code generator I created to connect the Module, Controller, and View.

Controller acts as Module

In this example, I would like the controller to act as the module, meaning that it must implement the new LoginModuleImplIntf:

/**
 * Example login module and controller implementation.
 */
public class LoginControllerImpl implements LoginController, LoginModuleImplIntf {

    :

    private LoginListener listener;

    private WindowManager windowManager;

    :

    /**
     * {@inheritDoc}
     */
    public final void cancel() {
        LOG.info("cancel");

        // Hide the UI
        windowManager.close();

        if (listener != null) {
            // Notify the listener that the login was canceled
            listener.failure(new CanceledException());
            listener = null;
        }

    }

    /**
     * {@inheritDoc}
     */
    public final void verify(final String username, final char[] password) {
        LOG.info("verify '" + username + "'");

        if (isPasswordCorrect(password)) {
            LOG.info("LOGIN OK!");

            // Hide the UI
            windowManager.close();

            // Notify the listener that the login was successful
            listener.success(username);
            listener = null;

        } else {
            final String message = "INVALID USERNAME OR PASSWORD";
            LOG.info(message);
            view.setMessage(message);
        }

    }

    /**
     * {@inheritDoc}
     */
    public final void login(final LoginListener listener, final String username) {
        LOG.info("login '" + username + "'");

        // Show the UI
        windowManager.open();

        // Set values in view
        this.view.setUsername(username);
        this.view.setMessage("");

        // Keep the listener to inform on "cancel()" or "verify(..)"
        this.listener = listener;

    }

    /**
     * {@inheritDoc}
     */
    public final void login(final LoginListener listener) {
        LOG.info("login");

        // Show the UI
        windowManager.open();

        // Set values in view
        this.view.setUsername("");
        this.view.setMessage("");

        // Keep the listener to inform on "cancel()" or "verify(..)"
        this.listener = listener;

    }

    :

}

(Only new or changed methods are included in the above code; the rest is identical to the Dummy Controller Implementation in Part 3.)

The WindowManager is a simple interface that makes it possible for the controller to display or hide its window.

Redesigned Example

The “LoginDialogBetterApproach” example now looks like this:

/**
 * Better approach using an easy framework to connect controller and view.
 */
public final class LoginDialogBetterApproach {

    :

    /**
     * Start the application in calling (main) thread.
     */
    public final void start() {

        LOG.info("start()");

        try {

            // Initialize Look and Feel
            Utils4Swing.initSystemLookAndFeel();

            // Create view (=panel)
            final LoginPanel view = new LoginPanel();

            // Create controller
            final LoginController ctrl = new LoginControllerImpl();

            // The package we'll use for the generated byte code
            final String packageName = "org.fuin.examples.apps4swing.generated";

            // Connect module, controller and view
            final ModuleControllerViewConnector<LoginModule, LoginController, LoginView> cvc =
                new ModuleControllerViewConnector<LoginModule, LoginController, LoginView>(
                    "Login", // Basic name for the classes
                    packageName, // Controller package
                    LoginController.class, // Controller interface
                    ctrl, // Controller implementation
                    packageName, // View package
                    LoginView.class, // View interface
                    view, // View implementation
                    packageName, // Module package
                    LoginModule.class, // Module interface
                    createExecutorService(),
                    4);

            final LoginModule module = cvc.getModule();
            try {
                final String username = module.login("john");
                LOG.info("Login successful: " + username);
            } catch (final CanceledException ex) {
                LOG.error(ex.getMessage());
            }
            LOG.info("exit(0)");
            System.exit(0);
        } catch (final Throwable t) {
            LOG.error("exit(1)", t);
            System.exit(1);
        }

    }

    :

    /**
     * Starts the example.
     *
     * @param args
     *            Not used.
     */
    public static void main(final String[] args) {
        configureLog4J();
        new LoginDialogBetterApproach().start();
    }

}

Entering the password ‘test’ results in the following output:


[main] - start()
[pool-1-thread-1] - login 'john'
[AWT-EventQueue-0] - SET USERNAME 'john'
[AWT-EventQueue-0] - SET MESSAGE ''
[pool-1-thread-2] - verify 'john'
[pool-1-thread-2] - LOGIN OK!
[main] - Login successful: john
[main] - exit(0)

As you can see, the main threads will wait until the login result is made available.

Summary

Defining a new dialog now involves the follwing steps:

  1. Create the Controller interface (to be used by the View).
  2. Create the View interface (to be used by the Controller).
  3. Create the Module interface (for external use).
  4. Transform the Module interface into an Implementation Module interface (to be used by the module implementation).
  5. Annotate the two module interfaces with @ModulImplIntfRef, @ModuleRef, and @WaitForUserInput.
  6. Create a controller that implements the Module Implementation Interface and the Controller Interface.
  7. Create a view that implements the View interface (such as a JPanel).
  8. Use the ModuleControllerViewConnector to connect the Module, Controller, and View.

Please note that steps 1-6 are completely independent of the underlying UI framework (like Swing).

Here is a short UML diagram portraying the current implementation:

UML diagram

As usual, you can find the code for the example here:

(The Apps4J and Apps4Swing libraries have not yet been officially published.)

In Search of the Holy Grail of Swing MVC (Part 3)

Now, let’s create some code example for the described design.

We’re going to create a small login dialog:

The Interfaces

First, we create the interface for the view:

/**
 * Login view used by the controller.
 */
public interface LoginView extends View<LoginController> {

	/**
	 * Sets the username in the view.
	 *
	 * @param username Username to set.
	 */
	public void setUsername(String username);

	/**
	 * Sets a message in the view.
	 *
	 * @param message Message to set.
	 */
	public void setMessage(String message);

}

As you can see, the view involves only two methods. The first is to set the username to a default value, and the second, to set an error message, should the username or password prove incorrect. The view extends a View interface that contains standard methods shared by all view implementations.

Next, we turn to the interface for the controller:

/**
 * Example login controller used by the view.
 */
public interface LoginController extends Controller<LoginView> {

	/**
	 * Try to login with the username and password.
	 *
	 * @param username Username.
	 * @param password Password.
	 */
	public void login(String username, char[] password);

	/**
	 * Cancel the login process.
	 */
	public void cancel();

}

The two methods correspond to the two buttons on the form. The controller extends a Controller interface that contains standard methods shared by all controller implementations.

The Implementation

At this point, we will create implementations for the two interfaces.

A standard JPanel, implementing the View:

/**
 * Example login panel.
 */
public class LoginPanel extends JPanel implements LoginView {

	private static final Logger LOG = LoggerFactory.getLogger(LoginPanel.class);

	private LoginController ctrl;

	/**
	 * {@inheritDoc}
	 */
	public JPanel getViewUI() {
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	public LoginController getController() {
		return ctrl;
	}

	/**
	 * {@inheritDoc}
	 */
	public void setController(LoginController ctrl) {
		this.ctrl = ctrl;
	}

	/**
	 * {@inheritDoc}
	 */
	public void block() {
		// TODO We don't want to do this for now to keep the example simple
	}

	/**
	 * {@inheritDoc}
	 */
	public void unblock() {
		// TODO Implement this later!
	}

	/**
	 * {@inheritDoc}
	 */
	public void setUsername(String username) {
		LOG.info("SET USERNAME '" + username + "'");
		textFieldUsername.setText(username);
	}

	/**
	 * {@inheritDoc}
	 */
	public void setMessage(String message) {
		LOG.info("SET MESSAGE '" + message + "'");
		labelMessage.setText(message);
	}

	:

	/**
	 * Connect buttons with controller.
	 */
	private void initHandler() {
		buttonOK.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// Call the controller to handle the login process
				ctrl.login(textFieldUsername.getText(), textFieldPassword
						.getPassword());
			}
		});
		buttonCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// Call the controller to cancel the login
				ctrl.cancel();
			}
		});
		setPreferredSize(new Dimension(300, 200));
	}

	:

}

A dummy Controller implementation:

/**
 * Example login controller implementation.
 */
public class LoginControllerImpl implements LoginController {

	private static final Logger LOG = LoggerFactory.getLogger(LoginControllerImpl.class);

	// This is basically NOT a good idea! The
	// controller should NOT contain a direct
	// reference to the UI framework (Swing)!
	// This is only done to keep the example simple.
	private JFrame frame;

	private LoginView view;

	/**
	 * Constructor with frame.
	 *
	 * @param frame
	 *            Frame.
	 */
	public LoginControllerImpl(final JFrame frame) {
		super();
		this.frame = frame;
		this.frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(final WindowEvent e) {
				cancel();
			}
		});

	}

	/**
	 * Current thread sleeps for some time.
	 *
	 * @param millis
	 *            Milliseconds.
	 */
	private void sleep(final long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Checks if the password is "test".
	 *
	 * @param input
	 *            Password to check.
	 *
	 * @return If the password was "test" <code>true</code> else
	 *         <code>false</code>
	 */
	private boolean isPasswordCorrect(final char[] input) {

		// Simulate long user/pw check
		sleep(5000);

		boolean isCorrect = true;
		final char[] correctPassword = { 't', 'e', 's', 't' };

		if (input.length != correctPassword.length) {
			isCorrect = false;
		} else {
			isCorrect = Arrays.equals(input, correctPassword);
		}
		// Zero out the password.
		Arrays.fill(correctPassword, '0');
		return isCorrect;
	}

	/**
	 * Sets the view.
	 *
	 * @param view
	 *            View.
	 */
	public final void setView(final LoginView view) {
		this.view = view;
		this.view.setUsername("test");
		this.view.setMessage("");
	}

	/**
	 * {@inheritDoc}
	 */
	public final void cancel() {
		LOG.info("CANCEL");
		System.exit(1);
	}

	/**
	 * {@inheritDoc}
	 */
	public final void login(final String username, final char[] password) {
		LOG.info("LOGIN USER " + username);

		if (isPasswordCorrect(password)) {
			LOG.info("LOGIN OK!");
			System.exit(0);
		} else {
			final String message = "INVALID USERNAME OR PASSWORD";
			LOG.info(message);
			view.setMessage(message);
		}

	}

}

The Naïve Approach

Things have been easy up to this point. Now, let’s connect the view of the controller with a Naïve Approach:

/**
 * Naive approach to connect controller and view.
 */
public final class LoginDialogNaiveApproach {

	/**
	 * Runs in the Event Dispatch Thread (EDT).
	 */
	private void startIntern() {

		// Initialize Look and Feel
		Utils4Swing.initSystemLookAndFeel();

		// Create view (=panel) and show it in a frame
		final LoginPanel view = new LoginPanel();
		final JFrame frame = Utils4Swing.createShowAndPosition("Password Example Dialog", view,
				false, new ScreenCenterPositioner());
		frame.getRootPane().setDefaultButton(view.getDefaultButton());

		// Create controller
		final LoginController ctrl = new LoginControllerImpl(frame);

		// Connect controller and view
		ctrl.setView(view);
		view.setController(ctrl);

	}

	/**
	 * Start the application in EDT thread.
	 */
	public final void start() {
		if (SwingUtilities.isEventDispatchThread()) {
			startIntern();
		} else {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					startIntern();
				}
			});
		}
	}

	private static void configureLog4J() {
		:
	}

	/**
	 * Starts the example.
	 *
	 * @param args
	 *            Not used.
	 */
	public static void main(final String[] args) {
		configureLog4J();
		new LoginDialogNaiveApproach().start();
	}

}

Running the example and simply pressing OK results in the following console output:

[AWT-EventQueue-0 ] -SET USERNAME ‘test’
[AWT-EventQueue-0 ] -SET MESSAGE ”
[AWT-EventQueue-0 ] – LOGIN USER test
[AWT-EventQueue-0 ] – INVALID USERNAME OR PASSWORD
[AWT-EventQueue-0 ] – SET MESSAGE ‘INVALID USERNAME OR PASSWORD’

Everything is carried out within the Event Dispatch Thread… When the example is executed and the OK button is pressed, you will notice that it locks up, that is to say, that it will remain pressed until to the controller method returns, a situation wish to have no part of, as this is not what we want!

The Superior Approach

If the design described in the previous articles is used, it’s quite simple to get things done the right way:

/**
 * Better approach using an easy framework to connect controller and view.
 */
public final class LoginDialogBetterApproach {

	private static ExecutorService createExecutorService() {
		final ExecutorService executorService = Executors.newCachedThreadPool();
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				// shutdown thread pool
				executorService.shutdown();
			}
		});
		return executorService;
	}

	/**
	 * Runs in the Event Dispatch Thread (EDT).
	 */
	private void startIntern() {

		// Initialize Look and Feel
		Utils4Swing.initSystemLookAndFeel();

		// Create view (=panel) and show it in a frame
		final LoginPanel view = new LoginPanel();
		final JFrame frame = Utils4Swing.createShowAndPosition("Password Example Dialog", view,
				false, new ScreenCenterPositioner());
		frame.getRootPane().setDefaultButton(view.getDefaultButton());

		// Create controller
		final LoginController ctrl = new LoginControllerImpl(frame);

		// Connect controller and view
		new ControllerViewConnector<LoginController, LoginView>("Login", 	"org.fuin.apps4swing.example.controller.swing", LoginController.class, ctrl, "org.fuin.apps4swing.example.view.swing", LoginView.class, view, createExecutorService(), 4);

	}

	/**
	 * Start the application in EDT thread.
	 */
	public final void start() {
		if (SwingUtilities.isEventDispatchThread()) {
			startIntern();
		} else {
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					startIntern();
				}
			});
		}
	}

	private static void configureLog4J() {
		:
	}

	/**
	 * Starts the example.
	 *
	 * @param args
	 *            Not used.
	 */
	public static void main(final String[] args) {
		configureLog4J();
		new LoginDialogBetterApproach().start();
	}

}

The output will be as follows:

[AWT-EventQueue-0 ] – SET USERNAME ‘test’
[AWT-EventQueue-0 ] – SET MESSAGE ”
[pool-1-thread-2 ] – LOGIN USER test
[pool-1-thread-2 ] – INVALID USERNAME OR PASSWORD
[AWT-EventQueue-0 ] – SET MESSAGE ‘INVALID USERNAME OR PASSWORD’

Now, the controller code is executed in a separate thread, while the methods of the panel are executed in the EDT thread.

The piece of code working its magic is as follows:

// Connect controller and view
new ControllerViewConnector<LoginController, LoginView>(
		"Login",
		"org.fuin.apps4swing.example.controller.swing",
		LoginController.class,
		ctrl,
		"org.fuin.apps4swing.example.view.swing",
		LoginView.class,
		view,
		createExecutorService(),
		4);

With this code, the ControllerQueue, ToControllerDispatcher, and ToViewDispatcher implementations are created on-the-fly and appropriately linked.

The complete code for the example can be found here:

(The Apps4J and Apps4Swing libraries have not yet been officially published)

As of yet, the path looks promising, but the quest continues.

In Search of the Holy Grail of Swing MVC (Part 2)

After describing the basic design idea in Part 1 now let’s get some meat on the design:

May look complicated but the application developer only deals with two interfaces (Controller and View) and two implementations (Controller1 and View1) as you can see here:

The ControllerQueue will also be used for parent to child controller communication:

In the next part I’ll create some code examples to demonstrate the above design idea.

And Now for Something Completely Different 🙂

ARTHUR: “Please go and tell your master that we have been charged by God with a sacred quest,  and if he will give us food and shelter for this night he can join us in our quest for the Holy Grail.”
MAN: “Well, I’ll ask him, but I don’t think he’ll be very keen. He’s already got one, you see?”
ARTHUR: “What?”
GALAHAD: “He says they’ve already got one!” (They are stunned.)
ARTHUR: “Are you sure he’s got one?”
MAN: “Oh yes.  It’s very nice”

In Search of the Holy Grail of Swing MVC (Part 1)

One of the greatest challenges for those developing with the Swing framework is that few instructions from Sun are currently available that explain the most expeditious ways of developing more comprehensive projects with Swing. The JFC (Java Foundation Classes) Library is, fundamentally, a gigantic – very powerful and highly flexible – tool box that makes it possible to implement virtually all client developments. Unfortunately, one is also compelled to do so on a relatively low abstraction level.

The term Model-View-Controller (MVC) as it relates to Swing, for instance, refers only to the interplay between data and graphical components (UI Controls). A structure that would meet the standards of a higher level MVC model, such as the one we are familiar with from the development of client server applications, is not available.

Currently, new attempts are underway to establish a Swing Application Framework in conjunction with the JSR-296, which aims to eliminate some of these weaknesses. The processing of prolonged duration function requests is accordingly going to be handled via so-called Tasks based on the familiar SwingWorker method.

One of the disadvantages of the SwingWorker pattern is the fact that the controller function is not clearly separated from the Surface, which results in the functions being scattered all across the entire UI code. This makes the creation of unit tests for the controller code more complicated or even impossible.

In Search of the Holy Grail of Swing MVC I think the following structure would be a good starting point for a common Swing Application Framework:

In Part 2 I’ll try to create a Real World implementation using the above basic design.

And Now for Something Completely Different 🙂

 “That is your purpose Arthur … the Quest for the Holy Grail … It is gone.”  All the KNIGHTS are left gasping in awe and wonderment. They all turn and look at ARTHUR.

Zooming Swing

There is a nice zoom function included in Firefox: You can use CTRL+ and CTRL- to zoom in and out of a website. Why isn’t such a function available for Swing applications? It shouldn’t be too complicated to create it!  So I started to create a new Scalable Layout Manager.

Here is a short preview of it: Flash Demo Video 

It already works with the following layouts:

  • Null (Absolute) Layout
  • Border Layout
  • Card Layout
  • Flow Layout
  • Gridbag Layout
  • JGoodies Layout

Still under work:

  • Box Layout
  • Grid Layout
  • Spring layout

Integration into existing applications is simple:

// Install scalable layout and CTRL+/CTRL- keys for scaling operations
ScalableLayoutUtils.installScalableLayoutAndKeys(new DefaultScalableLayoutRegistry(), frame, 0.1);

The source is available as part of the Utils4Swing5 library.