Java tutorial
/* * 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 } } } }