hermes.browser.HermesBrowser.java Source code

Java tutorial

Introduction

Here is the source code for hermes.browser.HermesBrowser.java

Source

/* 
 * Copyright 2003,2004,2005,2006 Colin Crist
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package hermes.browser;

import hermes.ConnectionListener;
import hermes.Domain;
import hermes.Hermes;
import hermes.HermesConfigurationListener;
import hermes.HermesContext;
import hermes.HermesException;
import hermes.HermesInitialContextFactory;
import hermes.HermesLoader;
import hermes.HermesRepositoryManager;
import hermes.JAXBHermesLoader;
import hermes.JNDIContextFactory;
import hermes.SingletonManager;
import hermes.SystemProperties;
import hermes.browser.actions.ActionFactory;
import hermes.browser.actions.BrowserAction;
import hermes.browser.actions.MessageStoreBrowserAction;
import hermes.browser.actions.QueueBrowseAction;
import hermes.browser.components.ActionsPanel;
import hermes.browser.components.BrowserTree;
import hermes.browser.components.DockableToolPanel;
import hermes.browser.components.Log4JOutputViewer;
import hermes.browser.components.NavigableComponent;
import hermes.browser.components.WatchDockableFrame;
import hermes.browser.dialog.ClasspathIdCellEdtitor;
import hermes.browser.dialog.DirectoryCellEditor;
import hermes.browser.dialog.DomainCellEditor;
import hermes.browser.dialog.HermesCellEditor;
import hermes.browser.dialog.SelectorImpl;
import hermes.browser.dialog.SelectorImplCellEditor;
import hermes.browser.jython.JythonDockableFrame;
import hermes.browser.model.BrowserTreeModel;
import hermes.browser.tasks.HermesBrowserTaskListener;
import hermes.browser.tasks.TaskSupport;
import hermes.browser.tasks.ThreadPool;
import hermes.config.DestinationConfig;
import hermes.config.HermesConfig;
import hermes.config.NamingConfig;
import hermes.config.WatchConfig;
import hermes.fix.FIXPrettyPrinter;
import hermes.fix.FIXUtils;
import hermes.impl.ConfigDAO;
import hermes.impl.ConfigDAOImpl;
import hermes.impl.FileRepositoryManager;
import hermes.impl.SimpleClassLoaderManager;
import hermes.renderers.RendererManager;
import hermes.store.MessageStore;
import hermes.util.JVMUtils;
import hermes.util.TextUtils;

import java.awt.BorderLayout;
import java.awt.HeadlessException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.metal.MetalLookAndFeel;

import jsyntaxpane.DefaultSyntaxKit;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.log4j.Logger;
import org.python.core.PyException;

import com.jidesoft.action.CommandBar;
import com.jidesoft.action.DefaultDockableBarDockableHolder;
import com.jidesoft.comparator.ObjectComparatorManager;
import com.jidesoft.converter.ObjectConverterManager;
import com.jidesoft.dialog.JideOptionPane;
import com.jidesoft.docking.DefaultDockingManager;
import com.jidesoft.docking.event.DockableFrameAdapter;
import com.jidesoft.docking.event.DockableFrameEvent;
import com.jidesoft.document.DocumentComponent;
import com.jidesoft.document.DocumentComponentEvent;
import com.jidesoft.document.DocumentComponentListener;
import com.jidesoft.document.DocumentPane;
import com.jidesoft.grid.CellEditorManager;
import com.jidesoft.grid.CellRendererManager;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.status.MemoryStatusBarItem;
import com.jidesoft.status.ProgressStatusBarItem;
import com.jidesoft.status.StatusBar;
import com.jidesoft.status.TimeStatusBarItem;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideScrollPane;
import com.jidesoft.swing.SplashScreen;
import com.jidesoft.utils.Lm;

/**
 * HermesBrowser. A Swing GUI for working with JMS
 * 
 * @author colincrist@hermesjms.com
 * @version $Id: HermesBrowser.java,v 1.94 2007/02/18 19:01:44 colincrist Exp $
 */
public class HermesBrowser extends DefaultDockableBarDockableHolder implements HermesUI {
    public static final int DEFAULT_MAX_CACHED_MESSAGES = 1000;
    public static final long DEFAULT_QUEUE_BROWSE_CONSUMER_TIMEOUT = 10000;

    private static final String DEFAULT_PROFILE_NAME = "hermes.layout";
    private static final String HERMES_TITLE = "Hermes " + Hermes.VERSION;
    private static final Logger log = Logger.getLogger(HermesBrowser.class);
    private static final RendererManager rendererManager = new RendererManager();
    private static final ConfigDAO configDAO = new ConfigDAOImpl();
    private static final long serialVersionUID = 995079090594726460L;
    private static HermesBrowser ui;
    private static final String USER_PROFILE_NAME = "hermes.layout." + System.getProperty("user.name");
    private boolean restricted = System.getProperty(SystemProperties.RESTRICTED) != null;

    public static HermesBrowser getBrowser() {

        return ui;
    }

    public static ConfigDAO getConfigDAO() {
        return configDAO;
    }

    public static RendererManager getRendererManager() {
        return rendererManager;
    }

    public void setConfig(HermesConfig config) {

    }

    public static void main(String[] args) {
        log.debug("Hermes Browser " + Hermes.VERSION + " starting...");
        log.debug("working directory: " + new File(".").getAbsolutePath());

        Hermes.events.addConnectionListener(new ConnectionListener() {
            public void onConnectionOpen(Hermes hermes) {
                log.debug("Connection " + hermes.getId() + " opened");
            }

            public void onConnectionClosed(Hermes hermes) {
                log.debug("Connection " + hermes.getId() + " closed");
            }
        });

        //
        // Need to bootstrap objects into the singleton manager... hack for now.

        JVMUtils.forceInit(SingletonManager.class);
        JVMUtils.forceInit(ThreadPool.class);
        JVMUtils.forceInit(SimpleClassLoaderManager.class);

        //
        // Commented out as this is for debug use only.
        // RepaintManager.setCurrentManager(new ThreadCheckingRepaintManager());

        //
        // Note this is the license for the JIDE Framework, it is licenced
        // to Colin Crist and the Hermes project and should not be used for any
        // other purpose
        //

        Lm.verifyLicense("Colin Crist", "Hermes", "9vkNAfxF1lvVyW7uZXYjpxFskycSGLw1");

        //
        // See http://www.jidesoft.com for licensing terms.

        //
        // Register a converter from a String to a File with PropertyUtils.

        ConvertUtils.register(new Converter() {
            public Object convert(Class arg0, Object filename) {
                return new File((String) filename);
            }
        }, File.class);

        SplashScreen.create(IconCache.getIcon("hermes.splash"));
        SplashScreen.show();

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    ui = new HermesBrowser(HERMES_TITLE);

                    ui.initJIDE();

                    try {
                        ui.loadConfig();
                    } catch (NamingException ex) {
                        log.fatal("cannot initialise hermes: " + ex.getMessage(), ex);

                        System.exit(1);
                    } catch (HeadlessException ex) {
                        log.fatal("cannot initialise hermes browser, no head: " + ex.getMessage(), ex);
                        System.exit(1);
                    }

                    ui.initUI();
                    ui.init();

                    ui.getLayoutPersistence().setProfileKey(ui.getUserProfileName());
                    ui.getLayoutPersistence().loadLayoutData();

                    // This must be done after the layout has been set otherwise
                    // the
                    // frames are hidden.

                    final ArrayList<WatchConfig> tmpList = new ArrayList<WatchConfig>(ui.getConfig().getWatch());

                    ui.getLoader().getConfig().getWatch().clear();

                    for (WatchConfig wConfig : tmpList) {
                        ui.createWatch(wConfig);
                    }

                    ui.firstLoad = false;
                } catch (Exception ex) {
                    log.fatal("cannot initialise hermes browser: " + ex.getMessage(), ex);
                }
            }
        });
    }

    private static void setStatusMessage(final String statusMessage) {
        if (ui != null && ui.progressStatus != null && statusMessage != null) {
            if (SwingUtilities.isEventDispatchThread()) {
                ui.progressStatus.setStatus(statusMessage);
            } else {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        ui.progressStatus.setStatus(statusMessage);
                    }
                });
            }
        }
    }

    private ActionFactory actionFactory = new ActionFactory(this);
    private ActionsPanel actionsPane;
    private DocumentPane browserPane;

    //
    // Structure for this window

    private JythonDockableFrame jythonFrame;
    private BrowserTreeDockableFrame browserTreePane;
    private Context context;
    private String currentConfig;
    private UIMessageSink defaultMessageSink;
    private boolean firstLoad = true;
    private File lastOpenConfigDirectory;
    private File lastUploadDirectory;

    //
    // Hermes related stuff

    private HermesLoader loader;
    private JMenuBar menuBar;
    private ProgressStatusBarItem progressStatus;

    //
    // Standard contents

    private Map<String, WatchDockableFrame> queueWatchFrames = new HashMap<String, WatchDockableFrame>();
    private HermesRepositoryManager repManager;
    private StatusBar statusBar;
    private DockableToolPanel toolsPane;

    //
    // Listeners...

    private Set<DocumentComponentListener> documentComponentListeners = new HashSet<DocumentComponentListener>();
    private Set<ListSelectionListener> messageSelectionListeners = new HashSet<ListSelectionListener>();

    /**
     * Start the GUI up....
     */
    public HermesBrowser(String arg0) throws HeadlessException {
        super(arg0);

        // Funnell interesting messages onto the UI...

        defaultMessageSink = new UIMessageSink() {
            /*
             * (non-Javadoc)
             * 
             * @see hermes.browser.UIMessageSink#add(java.lang.String)
             */
            public void add(String message) {
                setStatusMessage(message);

            }

            /*
             * (non-Javadoc)
             * 
             * @see hermes.browser.UIMessageSink#add(java.lang.StringBuffer)
             */
            public void add(StringBuffer message) {
                setStatusMessage(message.toString());
            }
        };

        // Listen to asynchronous tasks...

        TaskSupport.addGlobalListener(new HermesBrowserTaskListener(this));
    }

    /**
     * A repository manager monitors a directory for XML files containing JMS
     * messages.
     * 
     * @return
     */
    public HermesRepositoryManager getRepositoryManager() {
        return repManager;
    }

    /**
     * Register that the user has created a new DestinationConfig, i.e. queue or
     * topic in the main tree.
     * 
     * @param hermes
     * @param dConfig
     * @throws JMSException
     */
    public void addDestinationConfig(Hermes hermes, DestinationConfig dConfig) throws JMSException {
        loader.addDestinationConfig(hermes, dConfig);
    }

    /**
     * Add a listener for messages selected in a browse document. The listener
     * will be added to the currently active table and removed when its
     * deactivated or closed.
     * 
     * @param listener
     */
    public void addMessageSelectionListener(ListSelectionListener listener) {
        messageSelectionListeners.add(listener);
    }

    /**
     * Add a listener to any document component that gets created in the future.
     * 
     * @param listener
     */
    public void addDocumentComponentListener(DocumentComponentListener listener) {
        documentComponentListeners.add(listener);
    }

    public int getSendPersistence() {
        return DeliveryMode.PERSISTENT;
    }

    /**
     * Sets the configuration URL.
     * 
     * @param currentConfig
     */
    public void setCurrentConfig(String currentConfig) {
        this.currentConfig = currentConfig;
    }

    /**
     * Add an BrowserAction to the document pane, registering the required
     * listeners and giving it focus.
     * 
     * @param action
     */
    public void addDocumentComponent(final DocumentComponent document) {
        log.debug("addDocument() name=" + document.getName());

        if (getDocumentPane().isDocumentOpened(document.getName())) {
            DocumentComponent existing = getDocumentPane().getDocument(document.getName());

            if (document != existing) {
                getDocumentPane().closeDocument(document.getName());
            }
        }

        //
        // Add/remove listeners for document lifecycle.

        for (final DocumentComponentListener listener : documentComponentListeners) {
            document.addDocumentComponentListener(listener);
        }

        document.addDocumentComponentListener(AutoRefreshCheckBox.getInstance());

        document.addDocumentComponentListener(new DocumentComponetListenerSupport() {
            @Override
            public void documentComponentClosed(DocumentComponentEvent arg0) {
                for (final DocumentComponentListener listener : documentComponentListeners) {
                    document.removeDocumentComponentListener(listener);
                }

                document.removeDocumentComponentListener(AutoRefreshCheckBox.getInstance());
            }
        });

        //
        // Add/remove listeners for navigation control

        if (document instanceof NavigableComponent) {
            final NavigableComponent component = (NavigableComponent) document;

            for (final ListSelectionListener listener : messageSelectionListeners) {
                component.getListSelectionModel().addListSelectionListener(listener);
            }

            document.addDocumentComponentListener(new DocumentComponetListenerSupport() {
                @Override
                public void documentComponentClosed(DocumentComponentEvent arg0) {
                    for (final ListSelectionListener listener : messageSelectionListeners) {
                        component.getListSelectionModel().removeListSelectionListener(listener);
                    }
                }
            });
        }

        getDocumentPane().openDocument(document);
        getDocumentPane().setActiveDocument(document.getName());

    }

    /**
     * Create a new dockable panel for watching all the queues configured on the
     * given Hermes.
     * 
     * @param watchId
     * @param hermes
     */
    public synchronized void addOrCreateWatch(String watchId, Hermes hermes) {
        WatchDockableFrame frame = null;

        if (queueWatchFrames.containsKey(watchId)) {
            frame = queueWatchFrames.get(watchId);
        } else {
            WatchConfig wConfig = HermesBrowser.getConfigDAO().createWatchConfig();
            wConfig.setId(watchId);

            frame = createWatch(wConfig);
        }

        frame.addWatch(hermes);
    }

    /**
     * Create/add the given destination to the new/existing watch panel.
     * 
     * @param watchId
     * @param hermes
     * @param destination
     */
    public synchronized void addOrCreateWatch(String watchId, Hermes hermes, DestinationConfig destination) {
        WatchDockableFrame frame = null;

        if (queueWatchFrames.containsKey(watchId)) {
            frame = queueWatchFrames.get(watchId);
        } else {
            WatchConfig wConfig = HermesBrowser.getConfigDAO().createWatchConfig();
            wConfig.setId(watchId);

            frame = createWatch(wConfig);
        }

        DestinationConfig dConfig = HermesBrowser.getConfigDAO().duplicateForWatch(destination, hermes);

        frame.addWatch(hermes.getId(), dConfig);
    }

    /**
     * Backup the configuration into <config>.backup.
     * 
     * @throws HermesException
     */
    public void backupConfig() throws HermesException {
        loader.backup();
    }

    /**
     * Close all the watch panel.
     */
    private void closeWatches() {
        for (final Map.Entry<String, WatchDockableFrame> entry : queueWatchFrames.entrySet()) {
            final WatchDockableFrame frame = entry.getValue();
            frame.close();
            getDockingManager().removeFrame(entry.getKey());
        }
    }

    /**
     * Create a new Watch dockable frame from the given watch configuration and
     * add it to the docking manager and the XML configuration.
     * 
     * @param watchConfig
     */
    private WatchDockableFrame createWatch(final WatchConfig wConfig) {
        final WatchDockableFrame frame = new WatchDockableFrame(wConfig);
        queueWatchFrames.put(wConfig.getId(), frame);

        frame.addDockableFrameListener(new DockableFrameAdapter() {
            public void dockableFrameHidden(DockableFrameEvent arg0) {
                log.debug("watch frame " + wConfig.getId() + " removed, clearing up");

                try {
                    getConfig().getWatch().remove(wConfig);
                    queueWatchFrames.remove(wConfig.getId());
                } catch (HermesException ex) {
                    Hermes.ui.getDefaultMessageSink().add("Unable to remove watch " + wConfig.getId()
                            + " from configuration: " + ex.getMessage());
                }

                getDockingManager().removeFrame(wConfig.getId());
                frame.close();
            }
        });

        getDockingManager().addFrame(frame);
        frame.setVisible(true);

        try {
            getConfig().getWatch().add(wConfig);
        } catch (HermesException ex) {
            Hermes.ui.getDefaultMessageSink()
                    .add("Unable to add watch " + wConfig.getId() + " to configuration: " + ex.getMessage());
        }

        frame.updateNow();

        return frame;
    }

    /**
     * Get the (inappopriately named) action factory to create long running
     * browse tasks.
     * 
     * @return
     */
    public ActionFactory getActionFactory() {
        return actionFactory;
    }

    /**
     * Get the panal containing the long running actions (tasks).
     * 
     * @return
     */
    public ActionsPanel getActionsPanel() {
        return actionsPane;
    }

    /**
     * Get the configuration tree of sessions, contexts etc.
     * 
     * @return
     */
    public BrowserTree getBrowserTree() {
        return browserTreePane.getBrowserTree();
    }

    public Context createContext(String id) throws JMSException, NamingException, InvocationTargetException,
            IOException, IllegalAccessException, NoSuchMethodException {
        final NamingConfig config = getBrowserTree().getBrowserModel().getNamingConfigTreeNode(id).getConfig();
        final JNDIContextFactory factory = new JNDIContextFactory(config);
        return factory.createContext();
    }

    /**
     * Get the current configuration model.
     * 
     * @return
     * @throws HermesException
     */
    public HermesConfig getConfig() throws HermesException {
        return loader.getConfig();
    }

    /**
     * Get the current context of configured Hermes instances.
     * 
     * @return
     */
    public Context getContext() {
        return context;
    }

    /**
     * Get the URL of the current configuration.
     * 
     * @return
     */
    public String getCurrentConfigURL() {
        if (currentConfig == null) {
            String rval = System.getProperty("hermes");

            if (rval == null) {
                File dotHermes = new File(JVMUtils.getUserHome() + File.separator + ".hermes");

                if (!dotHermes.exists()) {
                    if (dotHermes.mkdir()) {
                        log.debug("created new directory: " + dotHermes.getAbsolutePath());
                    } else {

                        log.error("could not create directory: " + dotHermes.getAbsolutePath());
                        log.error("properties set are listed to stdout.");

                        System.getProperties().list(System.out);
                        System.exit(1);

                    }
                }

                File hermesXML = new File(dotHermes, "hermes-config.xml");

                try {
                    if (!hermesXML.exists()) {
                        hermesXML.createNewFile();
                        InputStream istream = getClass().getClassLoader()
                                .getResourceAsStream("hermes/bootstrap/default-hermes-config.xml"); // ClassLoader.getSystemResourceAsStream("hermes/bootstrap/default-hermes-config.xml");
                        OutputStream ostream = new FileOutputStream(hermesXML);

                        int i;
                        while ((i = istream.read()) != -1) {
                            ostream.write(i);
                        }

                        ostream.close();

                        log.debug("bootstrapped empty config to " + hermesXML.getPath());
                    }

                    return hermesXML.toURI().getPath();

                } catch (IOException e) {
                    log.error(e.getMessage(), e);

                }

                return null;
            } else {
                return rval;
            }
        } else {
            return currentConfig;
        }
    }

    /**
     * Get the sink for informative messages during tasks.
     */
    public UIMessageSink getDefaultMessageSink() {
        return defaultMessageSink;
    }

    /**
     * Get the document pane where queue/topic/context browses.
     * 
     * @return
     */
    public DocumentPane getDocumentPane() {
        return browserPane;
    }

    /**
     * Get the current loader used to create Hermes instances from the XML.
     * 
     * @return
     */
    public HermesLoader getLoader() {
        return loader;
    }

    /**
     * Gets the maximum number of messages to be displayed in a message browse
     * table, -1 means show them all which could get a bit memory hungry.
     * 
     * @return
     * @throws HermesException
     */
    public int getMaxMessagesInBrowserPane() throws HermesException {
        return (loader.getConfig().getMaxMessagesInBrowserPane() == 0) ? DEFAULT_MAX_CACHED_MESSAGES
                : loader.getConfig().getMaxMessagesInBrowserPane();

    }

    public long getQueueBrowseConsumerTimeout() throws HermesException {
        return (loader.getConfig().getQueueBrowseConsumerTimeout() == 0) ? DEFAULT_QUEUE_BROWSE_CONSUMER_TIMEOUT
                : loader.getConfig().getQueueBrowseConsumerTimeout();
    }

    /**
     * Gets the repository manager for XML message files.
     * 
     * @return
     */
    public HermesRepositoryManager getMessageRepository() {
        return repManager;
    }

    /**
     * Get the threadpool to dispatch long running tasks to.
     */
    public ThreadPool getThreadPool() {
        return ThreadPool.get();
    }

    /**
     * Get the profile name to save/load layout configuration with.
     * 
     * @return
     */
    public String getUserProfileName() {
        return USER_PROFILE_NAME;
    }

    /**
     * Get the watch frame for the give name.
     * 
     * @return Returns the queueWatchPane.
     */
    public WatchDockableFrame getWatchFrame(String id) {
        return (WatchDockableFrame) queueWatchFrames.get(id);
    }

    /**
     * Initialisation of non-GUI components - can be run on any thread.
     * 
     * @throws NamingException
     * @throws JMSException
     */
    private void init() throws NamingException, JMSException, IOException {
        // Set up the repository manager

        HermesConfig config = (HermesConfig) context.lookup(HermesContext.CONFIG);

        if (config.getMessageFilesDir() == null) {
            config.setMessageFilesDir("./messages");
        }

        File repDir = new File(TextUtils.replaceClasspathVariables(config.getMessageFilesDir()));

        try {
            loader.save();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        if (!repDir.exists()) {
            repDir.mkdir();
        }

        repManager = new FileRepositoryManager(repDir, 5000);
        repManager.addRepositoryListener((BrowserTreeModel) getBrowserTree().getModel());

        log.debug("setting maxThreadPoolSize");

        if (config.getMaxThreadPoolSize() == 0) {
            config.setMaxThreadPoolSize(1);
        }

        ThreadPool.get().setThreads(config.getMaxThreadPoolSize());
    }

    private void initJIDE() throws UnsupportedLookAndFeelException, ClassNotFoundException, InstantiationException,
            IllegalAccessException {
        try {
            LookAndFeelFactory.installJideExtension();
        } catch (IllegalArgumentException e) {
            log.error("l&f incompatible with JIDE, trying metal: " + e.getMessage(), e);

            UIManager.setLookAndFeel(new MetalLookAndFeel());
            LookAndFeelFactory.installJideExtension();
        }

        ObjectConverterManager.initDefaultConverter();
        CellEditorManager.initDefaultEditor();
        CellRendererManager.initDefaultRenderer();
        ObjectComparatorManager.initDefaultComparator();

        LookAndFeelFactory.UIDefaultsCustomizer uiDefaultsCustomizer = new LookAndFeelFactory.UIDefaultsCustomizer() {
            public void customize(UIDefaults defaults) {
                Map painter = (Map) defaults.get("Theme.painter");
                // ThemePainter painter = (ThemePainter)
                // defaults.get("Theme.painter");

                defaults.put("OptionPaneUI", "com.jidesoft.plaf.basic.BasicJideOptionPaneUI");
                defaults.put("OptionPane.showBanner", Boolean.FALSE); // show
                // banner
                // or
                // not.
                // default
                // is
                // true

                defaults.put("OptionPane.bannerBackgroundDk", painter.get("OptionPane.bannerBackgroundDk"));
                defaults.put("OptionPane.bannerBackgroundLt", painter.get("OptionPane.bannerBackgroundLt"));

                defaults.put("OptionPane.bannerBackgroundDirection", Boolean.TRUE); // default
                // is
                // true

                // optionally, you can set a Paint object for BannerPanel. If
                // so, the three UIDefaults related to banner background above
                // will be ignored.
                defaults.put("OptionPane.bannerBackgroundPaint", null);

                defaults.put("OptionPane.buttonAreaBorder", BorderFactory.createEmptyBorder(6, 6, 6, 6));
                defaults.put("OptionPane.buttonOrientation", new Integer(SwingConstants.RIGHT));
            }
        };
        uiDefaultsCustomizer.customize(UIManager.getDefaults());

    }

    /**
     * Initialisation of GUI components, must be run on the Swing dispatch
     * thread.
     * 
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws UnsupportedLookAndFeelException
     * @throws HermesException
     */
    private void initUI() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException, HermesException {
        if (System.getProperty("swing.defaultlaf") == null) {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

                /**
                 * http://hermesjms.com/jira/browse/HJMS-16 I've not implemented
                 * this fully as the L&F class name is not all we need to
                 * persist, JIDE seems to add in lots of extension stuff and I
                 * don't see how to persist/restor them yet. if
                 * (TextUtils.isEmpty(getConfig().getLookAndFeel())) {
                 * UIManager.
                 * setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
                 * else { UIManager.setLookAndFeel(getConfig().getLookAndFeel())
                 * ; }
                 */
            } catch (Throwable e) {
                log.error("cannot load l&f, trying metal: " + e.getMessage(), e);

                UIManager.setLookAndFeel(new MetalLookAndFeel());
            }
        } else {
            UIManager.setLookAndFeel(System.getProperty("swing.defaultlaf"));
        }

        if (getConfig().isEnableJython() && jythonFrame == null) {
            jythonFrame = new JythonDockableFrame();
            getDockingManager().addFrame(jythonFrame);
        }

        if (!getConfig().isEnableJython() && jythonFrame != null) {
            getDockingManager().removeFrame(jythonFrame.getKey());
            jythonFrame = null;
        }

        CellEditorManager.registerEditor(Domain.class, new DomainCellEditor());
        CellEditorManager.registerEditor(SelectorImpl.class, new SelectorImplCellEditor());
        CellEditorManager.registerEditor(File.class, new DirectoryCellEditor(), DirectoryCellEditor.CONTEXT);
        CellEditorManager.registerEditor(String.class, new ClasspathIdCellEdtitor(),
                ClasspathIdCellEdtitor.CONTEXT);
        CellEditorManager.registerEditor(Hermes.class, new HermesCellEditor());

        ObjectComparatorManager.registerComparator(Date.class, new DateComparator());
        ObjectComparatorManager.registerComparator(Integer.class, new IntegerComparator());
        ObjectComparatorManager.registerComparator(Long.class, new LongComparator());

        DefaultSyntaxKit.initKit();

        browserPane = new MainDocumentPane();
        // Shows us the memory usage and lets the user GC

        MemoryStatusBarItem memoryStatusBar = new MemoryStatusBarItem();
        memoryStatusBar.setPreferredWidth(100);

        // General informative messages go here..

        progressStatus = new ProgressStatusBarItem();

        statusBar = new StatusBar();
        statusBar.add(progressStatus, JideBoxLayout.VARY);
        statusBar.add(new TimeStatusBarItem(), JideBoxLayout.FLEXIBLE);
        statusBar.add(memoryStatusBar, JideBoxLayout.FLEXIBLE);

        // The tools panel includes the running tasks, Jython console and log
        // console.

        actionsPane = new ActionsPanel();

        toolsPane = new DockableToolPanel();
        toolsPane.addToolPanel("Tasks", new JideScrollPane(actionsPane));
        toolsPane.addToolPanel("Log", new Log4JOutputViewer(""));

        browserTreePane = new BrowserTreeDockableFrame();
        browserTreePane.setLoader(loader);

        // Get the menu bar initialised...

        setJMenuBar(new MenuBar(this));
        setIconImage(IconCache.getIcon("hermes.icon").getImage());

        //
        // Layout management initialisation

        getDockingManager().setUsePref(false);
        getDockingManager().setProfileKey(USER_PROFILE_NAME);
        getDockingManager().setInitSplitPriority(DefaultDockingManager.SPLIT_SOUTH_NORTH_EAST_WEST);
        getDockingManager().getWorkspace().add(browserPane, BorderLayout.CENTER);
        getDockingManager().addFrame(browserTreePane);
        getDockingManager().addFrame(toolsPane);

        getDockableBarManager().addDockableBar(new MainToolBar());
        getDockableBarManager().addDockableBar(new MessageToolBar());
        getDockableBarManager().addDockableBar(new ConfigurationToolBar());
        getDockableBarManager().addDockableBar(new JNDIToolBar());

        getContentPane().add(statusBar, BorderLayout.AFTER_LAST_LINE);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        toFront();

        setStatusMessage("Ready");
        SplashScreen.hide();

        //
        // Raise the swing thread to max priority

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
            }
        });
    }

    /**
     * Bit of a hack this one it tells us if there is a some kind of browse task
     * running and the user has selected one or more messages in the tree.
     * 
     * @return
     */
    public boolean isBrowseActionSelected() {
        if (browserPane.getActiveDocument() instanceof BrowserAction) {
            final BrowserAction action = (BrowserAction) browserPane.getActiveDocument();

            if (action.getSelectedMessages().size() > 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * Initialise the underlying Hermes that we're gonna do all our work with
     * 
     * @throws HermesException
     * @throws NamingException
     */
    public void loadConfig() throws NamingException, HermesException {
        Properties props = new Properties();
        Context oldContext = context;
        HermesConfig oldConfig = null;

        props.put(Context.INITIAL_CONTEXT_FACTORY, HermesInitialContextFactory.class.getName());
        props.put(Context.PROVIDER_URL, getCurrentConfigURL());
        props.put("hermes.loader", JAXBHermesLoader.class.getName());

        log.debug("props=" + props);

        Iterator listeners = null;

        if (loader != null) {
            listeners = loader.getConfigurationListeners();
            oldConfig = loader.getConfig();
        }

        if (oldConfig != null) {
            Set naming = new HashSet();
            naming.addAll(oldConfig.getNaming());

            for (Iterator iter = naming.iterator(); iter.hasNext();) {
                NamingConfig oldNaming = (NamingConfig) iter.next();

                loader.notifyNamingRemoved(oldNaming);
            }
        }

        context = new InitialContext(props);
        loader = (HermesLoader) context.lookup(HermesContext.LOADER);

        if (listeners != null) {
            while (listeners.hasNext()) {
                loader.addConfigurationListener((HermesConfigurationListener) listeners.next());
            }
        }

        if (oldContext != null) {
            for (NamingEnumeration iter = oldContext.listBindings(""); iter.hasMoreElements();) {
                Binding binding = (Binding) iter.next();

                try {
                    if (oldContext.lookup(binding.getName()) instanceof Hermes) {
                        Hermes hermes = (Hermes) oldContext.lookup(binding.getName());
                        Hermes newHermes = null;

                        try {
                            newHermes = (Hermes) context.lookup(hermes.getId());
                        } catch (NamingException e) {
                            // NOP
                        }

                        if (newHermes == null) {
                            loader.notifyHermesRemoved(hermes);
                        }
                    }
                } catch (NamingException ex) {
                    // NOP
                }
            }
        }

        if (!firstLoad) {
            closeWatches();
            final ArrayList tmpList = new ArrayList();
            tmpList.addAll(loader.getConfig().getWatch());
            loader.getConfig().getWatch().clear();

            for (Iterator iter = tmpList.iterator(); iter.hasNext();) {
                WatchConfig wConfig = (WatchConfig) iter.next();
                createWatch(wConfig);
            }
        }

        setTitle("HermesJMS - " + TextUtils.crumble(getCurrentConfigURL(), 100));
    }

    /**
     * Replace all the destinations that are on a Hermes configuration, used
     * after a discover has occured. Not the best codepath.
     * 
     * @param hermes
     * @param dConfigs
     * @throws JMSException
     */
    public void replaceDestinationConfigs(Hermes hermes, Collection dConfigs) throws JMSException {
        loader.replaceDestinationConfigs(hermes, dConfigs);
    }

    /**
     * Restore the configuration from a backup.
     * 
     * @throws HermesException
     */
    public void restoreConfig() throws HermesException {
        loader.restore();
    }

    /**
     * Save the current configuration.
     * 
     * @throws HermesException
     */
    public void saveConfig() throws HermesException {
        if (!isRestrictedWithWarning()) {
            loader.save();
        }
    }

    public void showInformationDialog(final String message) {
        Runnable r = new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(HermesBrowser.this, message, "Information",
                        JOptionPane.INFORMATION_MESSAGE);
            }
        };

        if (SwingUtilities.isEventDispatchThread()) {
            r.run();
        } else {
            SwingUtilities.invokeLater(r);
        }
    }

    /**
     * Show an error dialog with the given message, will dispatch to the evet
     * thread if needed.
     * 
     * @param message
     */
    public void showErrorDialog(final String message) {
        Runnable r = new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(HermesBrowser.this, message, "Error", JOptionPane.ERROR_MESSAGE);
            }
        };

        if (SwingUtilities.isEventDispatchThread()) {
            r.run();
        } else {
            SwingUtilities.invokeLater(r);
        }
    }

    /**
     * Show an error message with the message from the exception and also log it
     * to Log4j.
     * 
     * @param message
     * @param t
     */
    public void showErrorDialog2(final String message, final Throwable t) {
        log.error(t.getMessage(), t);

        Runnable r = new Runnable() {
            public void run() {
                if (t instanceof PyException) {
                    PyException pyT = (PyException) t;

                    JOptionPane.showMessageDialog(HermesBrowser.this, message + ": " + pyT.traceback.dumpStack(),
                            "Error", JOptionPane.ERROR_MESSAGE);
                } else {

                    JOptionPane.showMessageDialog(HermesBrowser.this, message + ": " + t.getMessage(), "Error",
                            JOptionPane.ERROR_MESSAGE);
                }
            }
        };

        if (SwingUtilities.isEventDispatchThread()) {
            r.run();
        } else {
            SwingUtilities.invokeLater(r);
        }
    }

    public void showErrorDialog(final String message, final Throwable t) {
        Runnable r = new Runnable() {
            public void run() {
                String detail = null;

                if (t instanceof PyException) {
                    StringBuffer s = new StringBuffer();
                    PyException pyT = (PyException) t;
                    pyT.traceback.dumpStack(s);

                    detail = s.toString();
                } else {
                    StringWriter s = new StringWriter();
                    PrintWriter p = new PrintWriter(s);
                    t.printStackTrace(p);
                    detail = s.toString();
                }

                JideOptionPane optionPane = new JideOptionPane(message, JOptionPane.ERROR_MESSAGE,
                        JideOptionPane.CLOSE_OPTION, UIManager.getIcon("OptionPane.errorIcon"));
                optionPane.setTitle(message);

                if (detail != null) {
                    optionPane.setDetails(detail);
                }
                JDialog dialog = optionPane.createDialog(HermesBrowser.this, "Error");
                dialog.setResizable(true);
                dialog.pack();
                dialog.setVisible(true);
            }
        };

        if (SwingUtilities.isEventDispatchThread()) {
            r.run();
        } else {
            SwingUtilities.invokeLater(r);
        }
    }

    /**
     * Show an error message with the message from the exception and also log it
     * to Log4j.
     * 
     * @param message
     * @param t
     */
    public void showErrorDialog(Throwable t) {
        showErrorDialog("Error: ", t);
    }

    /**
     * Is this Hermes running in the restricted mode? If so then a dialog is
     * show telling the user they are not permissioned to do the action.
     * 
     * @return
     */
    public boolean isRestrictedWithWarning() {
        if (isRestricted()) {
            showErrorDialog("You do not have permissions to perform this action.");
        }

        return isRestricted();
    }

    /**
     * Are message stores disabled?
     * 
     * @return
     */
    public boolean isMessageStoresDisabled() {
        return System.getProperty(SystemProperties.DISABLE_MESSAGE_STORES) != null;
    }

    /**
     * Is this Hermes running in the restricted mode?
     * 
     * @return
     */
    public boolean isRestricted() {
        return restricted;
    }

    public CommandBar createDockableBar(String name) {
        return new CommandBar(name);
    }

    public Hermes getHermes() {
        if (getDocumentPane().getActiveDocument() instanceof BrowserAction) {
            BrowserAction action = (BrowserAction) getDocumentPane().getActiveDocument();
            return action.getHermes();
        } else {
            return null;
        }
    }

    public static void browseQueue(String hermesId, String queue) throws NamingException, JMSException {
        Hermes hermes = (Hermes) HermesBrowser.getBrowser().getContext().lookup(hermesId);
        DestinationConfig config = hermes.getDestinationConfig(queue, Domain.QUEUE);

        HermesBrowser.getBrowser().getActionFactory().createQueueBrowseAction(hermes, config);
    }

    public void setFIXPrettyPrinter(FIXPrettyPrinter printer) {
        FIXUtils.setPrettyPrinter(printer);
    }

    public FIXPrettyPrinter getFIXPrettyPrinter() {
        return FIXUtils.getPrettyPrinter() == null ? FIXUtils.getDefaultPrettyPrinter()
                : FIXUtils.getPrettyPrinter();
    }

    public Collection<Message> getSelectedMessages() {
        if (getDocumentPane().getActiveDocument() instanceof BrowserAction) {
            BrowserAction action = (BrowserAction) getDocumentPane().getActiveDocument();
            return action.getSelectedMessages();

        } else {
            return Collections.EMPTY_LIST;
        }
    }

    public MessageStoreBrowserAction getOpenStoreBrowser(MessageStore store) {
        for (int d = 0; d < HermesBrowser.getBrowser().getDocumentPane().getDocumentCount(); d++) {
            DocumentComponent doc = HermesBrowser.getBrowser().getDocumentPane().getDocumentAt(d);
            if (doc instanceof MessageStoreBrowserAction) {
                MessageStoreBrowserAction sBrowser = (MessageStoreBrowserAction) doc;
                if (sBrowser.getMessageStore().equals(store)) {
                    return sBrowser;
                }
            }
        }
        return null;
    }

    public QueueBrowseAction getOpenQueueBrowser(DestinationConfig config) {
        for (int d = 0; d < HermesBrowser.getBrowser().getDocumentPane().getDocumentCount(); d++) {
            DocumentComponent doc = HermesBrowser.getBrowser().getDocumentPane().getDocumentAt(d);
            if (doc instanceof QueueBrowseAction) {
                QueueBrowseAction qBrowser = (QueueBrowseAction) doc;
                if (qBrowser.getDestinationConfig().equals(config)) {
                    return qBrowser;
                }
            }
        }
        return null;
    }
}