net.rim.ejde.internal.core.ContextManager.java Source code

Java tutorial

Introduction

Here is the source code for net.rim.ejde.internal.core.ContextManager.java

Source

/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import net.rim.ejde.IDebugConsoleWriter;
import net.rim.ejde.external.sourceMapper.SourceMapperAccess;
import net.rim.ejde.internal.builders.ClasspathChangeManager;
import net.rim.ejde.internal.builders.PreprocessedSourceMapper;
import net.rim.ejde.internal.internalplugin.InternalFragment;
import net.rim.ejde.internal.launching.EJDEDebugFilesClient;
import net.rim.ejde.internal.launching.IFledgeLaunchConstants;
import net.rim.ejde.internal.launching.IRunningFledgeLaunchConstants;
import net.rim.ejde.internal.legacy.RIADialog;
import net.rim.ejde.internal.model.BasicBlackBerryProperties;
import net.rim.ejde.internal.model.BlackBerryProject;
import net.rim.ejde.internal.model.BlackBerryProperties;
import net.rim.ejde.internal.ui.consoles.SimulatorOutputConsole;
import net.rim.ejde.internal.ui.preferences.PreferenceConstants;
import net.rim.ejde.internal.util.DebugUtils;
import net.rim.ejde.internal.util.InternalContextManagerUtils;
import net.rim.ejde.internal.util.PackagingUtils;
import net.rim.ejde.internal.util.RIAUtils;
import net.rim.ejde.internal.util.UpgradingNotification;
import net.rim.ejde.internal.util.VMToolsUtils;
import net.rim.ejde.internal.validation.ValidationManager;
import net.rim.ide.OSUtils;
import net.rim.ide.RIA;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchesListener2;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Version;

import com.thoughtworks.xstream.XStream;

/**
 * The activator class controls the plug-in life cycle
 */
public class ContextManager extends AbstractUIPlugin implements IDebugEventSetListener, ILaunchesListener2 {
    static private final Logger log = Logger.getLogger(ContextManager.class);

    private Hashtable<String, BlackBerryProperties> BBModelMap;
    private Hashtable<IPath, RIA> BBVMMap;
    private XStream _xStream;
    // The plug-in ID
    public static final String PLUGIN_ID = "net.rim.ejde";
    // The shared instance
    public static ContextManager PLUGIN;
    private ResourceBundle _coreResourcesBundle;
    private boolean _isSuspended;
    private Image _blankImage;
    private HashMap<Object, Image> _images = new HashMap<Object, Image>();

    {
        try {
            _coreResourcesBundle = ResourceBundle.getBundle("CorePluginResources"); //$NON-NLS-1$
        } catch (MissingResourceException x) {
            _coreResourcesBundle = null;
        }
    }

    /**
     * The constructor
     */
    public ContextManager() {
        PLUGIN = this;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext )
     */
    public void start(BundleContext context) throws Exception {
        log.trace("ContextManager starting, bundle version: " + context.getBundle().getVersion());
        super.start(context);
        BBModelMap = new Hashtable<String, BlackBerryProperties>();
        BBVMMap = new Hashtable<IPath, RIA>();
        // register classpath change listener
        ClasspathChangeManager classpathChangeManager = ClasspathChangeManager.getInstance();
        classpathChangeManager.addElementChangedListener();
        // register property change listener
        PropertyChangeListenerImp.addListener();
        BundleListenerHandler.getInstance(context);
        RuntimeInstallsHandler.getInstance();
        enableResourceChangeListener(true);
        // set preprocess mapper
        SourceMapperAccess.setSourceMapper(new PreprocessedSourceMapper());
        // initialize validation manager
        ValidationManager.getInstance();
        // Add launch and debug event listener used by debugging view
        DebugPlugin.getDefault().addDebugEventListener(this);
        DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);

        IPreferenceStore psc = ContextManager.getDefault().getPreferenceStore();

        if (OSUtils.isMac() && !psc.getBoolean(IConstants.LC_FILTERING_SET_KEY)) {
            // For Mac, filter out simulator LaunchConfig(s), if not already
            // Once LC_filtering_set=true, there is no more forcing of this logic to allow diff testing
            IPreferenceStore psd = DebugUIPlugin.getDefault().getPreferenceStore();
            if (!psd.getBoolean(IInternalDebugUIConstants.PREF_FILTER_LAUNCH_TYPES)) {
                psc.setValue(IConstants.LC_FILTERING_SET_KEY, true);
                psd.setValue(IInternalDebugUIConstants.PREF_FILTER_LAUNCH_TYPES, true);
                String pftl = psd.getString(IInternalDebugUIConstants.PREF_FILTER_TYPE_LIST);
                if (pftl == null) {
                    pftl = "";
                }
                if (!pftl.contains(IFledgeLaunchConstants.LAUNCH_CONFIG_ID)) {
                    pftl += IFledgeLaunchConstants.LAUNCH_CONFIG_ID + IConstants.COMMA_MARK;
                }
                if (!pftl.contains(IRunningFledgeLaunchConstants.LAUNCH_CONFIG_ID)) {
                    pftl += IRunningFledgeLaunchConstants.LAUNCH_CONFIG_ID + IConstants.COMMA_MARK;
                }
                psd.setValue(IInternalDebugUIConstants.PREF_FILTER_TYPE_LIST, pftl);
            }
        }
        // check if we need to clean the workspace
        boolean needClean = psc.getBoolean(IConstants.NEED_CLEAN_WORKSPACE_KEY);
        if (needClean) {
            CleanWorkspaceJob job = new CleanWorkspaceJob("Cleaning workspace");
            job.schedule();
        }

        InternalContextManagerUtils.startupInitialize();
        InternalFragment.startup();
    }

    protected void refreshPluginActions() {
        super.refreshPluginActions();
        boolean needUpdateCheck = ContextManager.getDefault().getPreferenceStore()
                .getBoolean(PreferenceConstants.UPDATE_NOTIFY);
        log.trace("ContextManager startingneed update: " + needUpdateCheck);
        if (needUpdateCheck) {
            UpgradingNotification updateJob = new UpgradingNotification();
            updateJob.schedule();
        }
    }

    public XStream getXStream() {
        if (_xStream == null) {
            _xStream = new XStream();
            _xStream.alias(BasicBlackBerryProperties.MODEL_ALIAS_HEAD, BlackBerryProperties.class);
            _xStream.alias(BasicBlackBerryProperties.PACKAGING__ALIAS_HEAD,
                    BlackBerryProperties.ExtendedPackaging.class);
            _xStream.processAnnotations(BlackBerryProperties.class);
        }
        return _xStream;
    }

    /**
     * Get the RIA instance of the given <code>homePath</code>.
     *
     * @param homePath
     * @return
     */
    public RIA getRIA(String homePath) {
        return getRIA(new Path(homePath));
    }

    /**
     * Get the RIA instance of the given <code>homePath<code>.
     *
     * @param homePath
     *            the home path of the RIA
     * @return RIA instances or <code>null</code> if the corresponding RIA instance can not be found or created.
     */
    public RIA getRIA(IPath homePath) {
        if (homePath == null || homePath.isEmpty()) {
            log.error("getRIA(): RIA home path is empty.");
            return null;
        }
        RIA ria = BBVMMap.get(homePath);
        if (ria != null) {
            return ria;
        }
        String legacyJDEHome = RIAUtils.getValidJDEHome(homePath.toOSString());
        if (StringUtils.isBlank(legacyJDEHome)) {
            log.error("getRIA(): Invalid RIA home path: " + homePath.toOSString());
            return null;
        }
        // TODO:In the else part invoke the Mac/Linux version of executables
        if (OSUtils.isWindows()) {
            RIAUtils.initDLLs();
        }
        log.debug("RIA Initialization is started for " + homePath + ".....");
        long start = System.currentTimeMillis();
        String DLLPath = ContextManager.PLUGIN.getStateLocation().append("installDlls").toOSString();
        long stop = System.currentTimeMillis();
        ria = RiaMaker.createRia(legacyJDEHome, DLLPath);
        // hook to RIA dialog callback for missing debug files
        ria.setDialogCallback(new RIADialog());
        // enable logging
        String enableLog = System.getProperties().getProperty("JDWP_LOGGING"); //$NON-NLS-1$
        ria.setLogging(enableLog != null);
        log.debug("RIA Initialization finished in : " + (stop - start) + " ms");
        BBVMMap.put(homePath, ria);

        IPreferenceStore store = ContextManager.getDefault().getPreferenceStore();
        String serverURL = store.getString(PreferenceConstants.DEBUG_FILE_SERVER_URL);

        try {
            IPath vmToolPath = VMToolsUtils.getVMToolsFolderPath();
            ria.setDebugFilesClient(new EJDEDebugFilesClient(serverURL,
                    vmToolPath.toString() + File.separator + "BundleInfo", new DebugConsoleWriter()));
        } catch (IOException e) {
            log.error("Error retrieving vmtool path", e);
            return null;
        }

        return ria;
    }

    /**
     * Set the given <code>ria</code> to the cached RIA map.
     *
     * @param ria
     */
    synchronized public void setRIA(RIA ria) {
        if (ria != null) {
            BBVMMap.put(new Path(ria.getHomePath()), ria);
        }
    }

    /**
     * Enable ResourceChangeManager to listen to eclipse resource changes.
     */
    public void enableResourceChangeListener(boolean enabled) {
        IWorkspace workspace = ResourcesPlugin.getWorkspace();
        if (enabled) {
            workspace.addResourceChangeListener(ResourceChangeManager.getInstance(),
                    ResourceChangeManager.getFilter());
        } else {
            workspace.removeResourceChangeListener(ResourceChangeManager.getInstance());
        }

    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext )
     */
    public void stop(BundleContext context) throws Exception {
        super.stop(context);
        BundleListenerHandler.removeInstance(context);
        RuntimeInstallsHandler.removeInstance();
        enableResourceChangeListener(false);
        // remove property change listener
        PropertyChangeListenerImp.removeListener();
        // remove debug event and launch listener
        DebugPlugin.getDefault().removeDebugEventListener(this);
        DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
        // stop RIAs
        RIA ria = null;
        for (IPath home : BBVMMap.keySet()) {
            ria = BBVMMap.get(home);
            if (ria != null) {
                ria.stop(true);
            }
        }
        BBModelMap = null;
        PLUGIN = null;
        InternalContextManagerUtils.stopCleanup();
    }

    /**
     * Get the BlackBerry properties instances for the given <code>projectName</code>.
     * <p>
     * <b>This method needs to be called when a BlackBerry properties instance is required. </b>
     *
     *
     * @param projectName
     * @param forceLoad
     *            <code>true</code> force to load the properties from the project description file;
     *            <p>
     *            <code>false</code> if the properties is in the cache, return the cached properties;
     * @return The BlackBerry properties of the project or <code>null</code> if the project is a BlackBerry project but does not
     *         have a project description xml file or any exception occurred.
     */
    public BlackBerryProperties getBBProperties(String projectName, boolean forceLoad) {
        BlackBerryProperties properties = BBModelMap.get(projectName);
        if (properties != null && !forceLoad) {
            return properties;
        }
        IWorkspace eclipseWS = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot eclipseWSRoot = eclipseWS.getRoot();
        IProject project = eclipseWSRoot.getProject(projectName);
        // try to get properties from the project description file
        IFile propertiesFile = project.getFile(BlackBerryProject.METAFILE);
        if (propertiesFile.exists()) {
            properties = loadModelFromStore(propertiesFile.getLocation().toFile());
            if (properties != null) {
                if (properties.getModelVersion().equals("1.1.1")) {
                    boolean changed = false;
                    // if the project property file was created by ejde 1.1.1, we change the output folder to the default value
                    String oldOutputFolder = properties._packaging.getOutputFileName();
                    String defaultOutputFolder = PackagingUtils.getDefaultProjectOutputPrefix();
                    if (!oldOutputFolder.equalsIgnoreCase(defaultOutputFolder)) {
                        log.trace(
                                " Project property file was created by ejde 1.1.1, the output folder will be changed to the default value");
                        properties._packaging.setOutputFolder(PackagingUtils.getDefaultProjectOutputPrefix());
                        changed = true;
                    }
                    if (properties._application.getType().equals(BlackBerryProject.LIBRARY)
                            && !properties._application.isSystemModule()) {
                        log.trace(
                                " Project property file was created by ejde 1.1.1, the isSystemModule value is changed to true for a lib project");
                        properties._application.setIsSystemModule(true);
                        changed = true;
                    }
                    if (changed) {
                        properties.setModelVersion(BlackBerryProperties.getDefaultModelVersion());
                        IStatus status = ResourcesPlugin.getWorkspace().validateEdit(new IFile[] { propertiesFile },
                                null);
                        if (status.isOK()) {
                            commitModelToStore(properties, propertiesFile);
                        }
                    }
                }
                BBModelMap.put(projectName, properties);
            }
        } else {
            properties = new BlackBerryProperties();
            properties.setValidOutputFileName(project.getName());
        }
        return properties;
    }

    /**
     * Sets the given <code>properties</code> to the cached table.
     * <p>
     * <b>This method needs to be called when a BlackBerry properties instance is going to be set to the cached table or commit to
     * the filesystem. </b>
     *
     * @param name
     *            name of the BlackBerryProject the properties belong to
     * @param properties
     *            BlackBerryProperties
     * @param force
     *            <code>true</code> if the given <code>properties</code> is already cached, we replace it with the given one and
     *            commit it to file system
     *            <p>
     *            <code>false</code> if the given <code>properties</code> is already cached, do nothing
     *            </p>
     */
    public void setBBProperties(String name, BlackBerryProperties properties, boolean force) {
        log.trace("setBBProperties(); " + name + "; " + force);
        BlackBerryProperties oldProperties = BBModelMap.get(name);
        boolean isequ = properties.equals(oldProperties);
        if (isequ && !force) {
            return;
        }
        if (!isequ) {
            BBModelMap.put(name, properties);
        }
        IProject iProject = ResourcesPlugin.getWorkspace().getRoot().getProject(name);
        IFile propertiesFile = iProject.getFile(BlackBerryProject.METAFILE);
        try {
            if (propertiesFile.exists()) {
                propertiesFile.deleteMarkers(null, false, IResource.DEPTH_ZERO);
            }
        } catch (CoreException e) {
            log.error(e);
        }
        commitModelToStore(properties, propertiesFile);
    }

    public void removeBBProperties(String projectName) {
        BBModelMap.remove(projectName);
    }

    /**
     * Returns the shared instance
     *
     * @return the shared instance
     */
    public static ContextManager getDefault() {
        return PLUGIN;
    }

    /**
     * Returns an image descriptor for the image file at the given plug-in relative path
     *
     * @param path
     *            the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(String path) {
        return imageDescriptorFromPlugin(PLUGIN_ID, path);
    }

    /**
     * Returns the plugin's resource bundle,
     */
    public ResourceBundle getCoreResourcesBundle() {
        return _coreResourcesBundle;
    }

    /**
     * Returns the string from the plugin's resource bundle, or 'key' if not found.
     */
    public static String getResourceString(String key) {
        ResourceBundle bundle = PLUGIN.getCoreResourcesBundle();

        try {
            return (bundle != null) ? bundle.getString(key) : key;
        } catch (MissingResourceException e) {
            return key;
        }
    }

    public static Shell getActiveWorkbenchShell() {
        IWorkbenchWindow window = getActiveWorkbenchWindow();

        if (window != null) {
            return window.getShell();
        }

        return null;
    }

    public static IWorkbenchWindow getActiveWorkbenchWindow() {
        return PLUGIN.getWorkbench().getActiveWorkbenchWindow();
    }

    /**
     * Gets the active workbench page.
     *
     * @return the active workbench page
     */
    public static IWorkbenchPage getActiveWorkbenchPage() {
        IWorkbenchWindow window = getActiveWorkbenchWindow();
        if (window == null) {
            return null;
        }
        return window.getActivePage();
    }

    public BlackBerryProperties loadModelFromStore(File file) {
        BlackBerryProperties blackBerryProperties = null;

        if (null == file || !file.exists() || !file.isFile()) {
            return null;
        }
        log.trace("loading " + file.getPath());
        FileInputStream fileInputStream = null;

        try {
            fileInputStream = new FileInputStream(file);

            if (0 < fileInputStream.available()) {
                XStream xStream = getXStream();
                blackBerryProperties = (BlackBerryProperties) xStream.fromXML(fileInputStream);
            } else {
                blackBerryProperties = new BlackBerryProperties();
            }
        } catch (Throwable t) {
            log.debug("", t);
        } finally {
            if (null != fileInputStream) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    log.error("Error closing input stream", e);
                }
            }
        }
        log.trace("finished loading " + file.getPath());
        return blackBerryProperties;
    }

    private void outputAppDescriptorHeaderComment(ByteArrayOutputStream outputStream) throws IOException {
        StringBuffer temp = new StringBuffer("<!-- ");
        temp.append("This file has been generated by the BlackBerry Plugin for Eclipse v");

        Version v = ResourcesPlugin.getPlugin().getBundle().getVersion();
        temp.append(v.getMajor());
        temp.append(".");
        temp.append(v.getMinor());
        temp.append(".");
        temp.append(v.getMicro());

        temp.append(". -->\n\n");
        outputStream.write(temp.toString().getBytes());
    }

    private void commitModelToStore(BlackBerryProperties blackBerryProperties, IFile ifile) {
        if (null == blackBerryProperties) {
            return;
        }

        if (null == ifile) {
            return;
        }
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try {
            log.trace("Writing " + ifile.getLocation().toOSString());
            outputStream = new ByteArrayOutputStream();
            XStream xStream = getXStream();
            outputAppDescriptorHeaderComment(outputStream);
            xStream.toXML(blackBerryProperties, outputStream);
            inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            if (ifile.exists()) {
                ifile.setContents(inputStream, IFile.FORCE, new NullProgressMonitor());
            } else {
                ifile.create(inputStream, true, new NullProgressMonitor());
            }
        } catch (CoreException e) {
            log.error(e.getMessage());
        } catch (Throwable t) {
            log.error(t.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
        log.trace("Finish writing " + ifile.getLocation().toOSString());
    }

    static public Display getDisplay() {
        if (PlatformUI.isWorkbenchRunning()) {
            return PlatformUI.getWorkbench().getDisplay();
        }

        return Display.getDefault();
    }

    /**
     * (no java doc)
     *
     * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[]).
     *
     */
    public void handleDebugEvents(DebugEvent[] events) {
        if (events == null || events.length == 0)
            return;

        for (int i = 0; i < events.length; i++) {
            if (!DebugUtils.isFromRIMLaunch(events[i])) {
                continue;
            }
            if (events[i].getKind() == DebugEvent.SUSPEND && !_isSuspended) {
                _isSuspended = true;
            }

            else if (events[i].getKind() == DebugEvent.RESUME && _isSuspended) {
                _isSuspended = false;
            }
        } // end for
    }

    public boolean isSuspended() {
        return _isSuspended;
    }

    /**
     * @see ILaunchesListener2#launchesTerminated(ILaunch[]).
     */
    public void launchesTerminated(ILaunch[] launches) {
        if (!DebugUtils.hasRIMLaunch(launches)) {
            return;
        }
        RIA currentRIA = RIA.getCurrentDebugger();
        if (currentRIA != null) {
            // when debugger is terminated, close simulator as well
            currentRIA.stopSimulator();
        }
        _isSuspended = false;
    }

    /**
     * @see ILaunchesListener#launchesRemoved(ILaunch[]).
     */
    public void launchesRemoved(ILaunch[] launches) {
        // do nothing
    }

    /**
     * @see ILaunchesListener#launchesAdded(ILaunch[]).
     */
    public void launchesAdded(ILaunch[] launches) {
        // do nothing
    }

    /**
     * @see ILaunchesListener#launchesChanged(ILaunch[]).
     */
    public void launchesChanged(ILaunch[] launches) {
        // do nothing
    }

    private class CleanWorkspaceJob extends WorkspaceJob {

        public CleanWorkspaceJob(String name) {
            super(name);
            // TODO Auto-generated constructor stub
        }

        public boolean belongsTo(Object family) {
            return ResourcesPlugin.FAMILY_MANUAL_BUILD.equals(family);
        }

        @Override
        public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
            ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, monitor);
            ContextManager.getDefault().getPreferenceStore().setValue(IConstants.NEED_CLEAN_WORKSPACE_KEY, false);
            return Status.OK_STATUS;
        }

    }

    /**
     * Gets the install url.
     *
     * @return the install url
     */
    public URL getInstallURL() {
        return getBundle().getEntry("/"); //$NON-NLS-1$
    }

    /**
     * Gets the image from plugin.
     *
     * @param bundleID
     *            the bundle id
     * @param path
     *            the path
     *
     * @return the image from plugin
     */
    public Image getImageFromPlugin(String bundleID, String path) {
        ImageDescriptor desc = AbstractUIPlugin.imageDescriptorFromPlugin(bundleID, path);
        return (desc != null) ? get(desc) : getBlankImage();
    }

    /**
     * Gets the blank image.
     *
     * @return the blank image
     */
    public Image getBlankImage() {
        if (_blankImage == null) {
            _blankImage = ImageDescriptor.getMissingImageDescriptor().createImage();
        }
        return _blankImage;
    }

    /**
     * Gets the.
     *
     * @param desc
     *            the desc
     *
     * @return the image
     */
    public Image get(ImageDescriptor desc) {
        Object key = desc;

        Image image = _images.get(key);
        if (image == null) {
            image = desc.createImage();
            _images.put(key, image);
        }
        return image;
    }

    private class DebugConsoleWriter implements IDebugConsoleWriter {

        private SimulatorOutputConsole _console;
        private MessageConsoleStream _stream;

        public DebugConsoleWriter() {
            _console = SimulatorOutputConsole.getInstance();
        }

        public void init() {
            _stream = _console.newMessageStream();
        }

        public void log(String message) {
            _stream.println(message);
        }

        public void close() {
            try {
                if (_stream != null)
                    _stream.close();
            } catch (IOException e) {
                // do nothing
            }

        }
    }
}