001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.launcher;
011:
012: import java.io.File;
013: import java.io.FileInputStream;
014: import java.io.FileOutputStream;
015: import java.io.IOException;
016: import java.util.ArrayList;
017: import java.util.HashSet;
018: import java.util.Iterator;
019: import java.util.Properties;
020: import java.util.Set;
021: import java.util.Stack;
022: import java.util.StringTokenizer;
023:
024: import org.eclipse.core.resources.IProject;
025: import org.eclipse.core.resources.IResource;
026: import org.eclipse.core.resources.ResourcesPlugin;
027: import org.eclipse.core.runtime.CoreException;
028: import org.eclipse.core.runtime.IPath;
029: import org.eclipse.core.runtime.IProgressMonitor;
030: import org.eclipse.core.runtime.IStatus;
031: import org.eclipse.core.runtime.OperationCanceledException;
032: import org.eclipse.core.runtime.Path;
033: import org.eclipse.core.runtime.Status;
034: import org.eclipse.debug.core.ILaunchConfiguration;
035: import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
036: import org.eclipse.jdt.core.IClasspathEntry;
037: import org.eclipse.jdt.core.IJavaProject;
038: import org.eclipse.jdt.core.JavaCore;
039: import org.eclipse.jdt.core.JavaModelException;
040: import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
041: import org.eclipse.jface.dialogs.IDialogConstants;
042: import org.eclipse.jface.dialogs.MessageDialog;
043: import org.eclipse.jface.preference.IPreferenceStore;
044: import org.eclipse.ltk.core.refactoring.Change;
045: import org.eclipse.osgi.util.NLS;
046: import org.eclipse.pde.core.plugin.IPluginModelBase;
047: import org.eclipse.pde.core.plugin.PluginRegistry;
048: import org.eclipse.pde.internal.core.DependencyManager;
049: import org.eclipse.pde.internal.core.PDECore;
050: import org.eclipse.pde.internal.core.WorkspaceModelManager;
051: import org.eclipse.pde.internal.core.util.CoreUtility;
052: import org.eclipse.pde.internal.ui.IPDEUIConstants;
053: import org.eclipse.pde.internal.ui.IPreferenceConstants;
054: import org.eclipse.pde.internal.ui.PDEPlugin;
055: import org.eclipse.pde.internal.ui.PDEUIMessages;
056: import org.eclipse.pde.internal.ui.wizards.tools.OrganizeManifestsProcessor;
057: import org.eclipse.pde.ui.launcher.IPDELauncherConstants;
058: import org.eclipse.swt.widgets.Display;
059: import org.eclipse.swt.widgets.Shell;
060: import org.eclipse.ui.IWorkbenchWindow;
061:
062: public class LauncherUtils {
063:
064: private static final String TIMESTAMP = "timestamp"; //$NON-NLS-1$
065: private static final String FILE_NAME = "dep-timestamp.properties"; //$NON-NLS-1$
066: private static Properties fLastRun;
067:
068: public static Display getDisplay() {
069: Display display = Display.getCurrent();
070: if (display == null) {
071: display = Display.getDefault();
072: }
073: return display;
074: }
075:
076: public final static Shell getActiveShell() {
077: IWorkbenchWindow window = PDEPlugin.getDefault().getWorkbench()
078: .getActiveWorkbenchWindow();
079: if (window == null) {
080: IWorkbenchWindow[] windows = PDEPlugin.getDefault()
081: .getWorkbench().getWorkbenchWindows();
082: if (windows.length > 0)
083: return windows[0].getShell();
084: } else
085: return window.getShell();
086: return getDisplay().getActiveShell();
087: }
088:
089: public static boolean clearWorkspace(
090: ILaunchConfiguration configuration, String workspace,
091: IProgressMonitor monitor) throws CoreException {
092: // If the workspace is not defined, there is no workspace to clear
093: // What will happen is that the workspace chooser dialog will be
094: // brought up because no -data parameter will be specified on the
095: // launch
096: if (workspace.length() == 0) {
097: monitor.done();
098: return true;
099: }
100:
101: File workspaceFile = new Path(workspace).toFile()
102: .getAbsoluteFile();
103: if (configuration.getAttribute(IPDELauncherConstants.DOCLEAR,
104: false)
105: && workspaceFile.exists()) {
106: boolean doClear = !configuration.getAttribute(
107: IPDELauncherConstants.ASKCLEAR, true);
108: if (!doClear) {
109: int result = confirmDeleteWorkspace(workspaceFile);
110: if (result == 2 || result == -1) {
111: monitor.done();
112: return false;
113: }
114: doClear = result == 0;
115: }
116:
117: if (doClear) {
118: if (configuration.getAttribute(
119: IPDEUIConstants.DOCLEARLOG, false)) {
120: LauncherUtils.clearWorkspaceLog(workspace);
121: } else {
122: CoreUtility.deleteContent(workspaceFile);
123: }
124: }
125: }
126:
127: monitor.done();
128: return true;
129: }
130:
131: private static int confirmDeleteWorkspace(final File workspaceFile) {
132: String message = NLS
133: .bind(
134: PDEUIMessages.WorkbenchLauncherConfigurationDelegate_confirmDeleteWorkspace,
135: workspaceFile.getPath());
136: return generateDialog(message);
137: }
138:
139: public static boolean generateConfigIni() {
140: String message = PDEUIMessages.LauncherUtils_generateConfigIni;
141: return generateDialog(message) == 0;
142: }
143:
144: private static int generateDialog(final String message) {
145: final int[] result = new int[1];
146: getDisplay().syncExec(new Runnable() {
147: public void run() {
148: String title = PDEUIMessages.LauncherUtils_title;
149: MessageDialog dialog = new MessageDialog(
150: getActiveShell(), title, null, message,
151: MessageDialog.QUESTION, new String[] {
152: IDialogConstants.YES_LABEL,
153: IDialogConstants.NO_LABEL,
154: IDialogConstants.CANCEL_LABEL }, 0);
155: result[0] = dialog.open();
156: }
157: });
158: return result[0];
159: }
160:
161: public static void validateProjectDependencies(
162: ILaunchConfiguration launch, final IProgressMonitor monitor) {
163: IPreferenceStore store = PDEPlugin.getDefault()
164: .getPreferenceStore();
165: if (!store.getBoolean(IPreferenceConstants.PROP_AUTO_MANAGE))
166: return;
167:
168: String timeStamp, selected, deSelected;
169: boolean useDefault, autoAdd;
170: try {
171: timeStamp = launch.getAttribute(TIMESTAMP, "0"); //$NON-NLS-1$
172: selected = launch.getAttribute(
173: IPDELauncherConstants.SELECTED_WORKSPACE_PLUGINS,
174: ""); //$NON-NLS-1$
175: deSelected = launch.getAttribute(
176: IPDELauncherConstants.DESELECTED_WORKSPACE_PLUGINS,
177: ""); //$NON-NLS-1$
178: autoAdd = launch.getAttribute(
179: IPDELauncherConstants.AUTOMATIC_ADD, true);
180: useDefault = launch.getAttribute(
181: IPDELauncherConstants.USE_DEFAULT, true);
182: useDefault |= launch.getAttribute(
183: IPDELauncherConstants.USEFEATURES, false);
184: final ArrayList projects = new ArrayList();
185: if (useDefault)
186: handleUseDefault(timeStamp, projects);
187: else if (autoAdd)
188: handleDeselectedPlugins(timeStamp, deSelected, projects);
189: else
190: handleSelectedPlugins(timeStamp, selected, projects);
191:
192: if (!projects.isEmpty())
193: Display.getDefault().syncExec(new Runnable() {
194: public void run() {
195: OrganizeManifestsProcessor processor = new OrganizeManifestsProcessor(
196: projects);
197: initializeProcessor(processor);
198: try {
199: Change change = processor
200: .createChange(monitor);
201: change.perform(monitor);
202: // update table for each project with current time stamp
203: Properties table = getLastRun();
204: String ts = Long.toString(System
205: .currentTimeMillis());
206: Iterator it = projects.iterator();
207: while (it.hasNext())
208: table.put(((IProject) it.next())
209: .getName(), ts);
210: } catch (OperationCanceledException e) {
211: } catch (CoreException e) {
212: }
213: }
214: });
215:
216: ILaunchConfigurationWorkingCopy wc = null;
217: if (launch.isWorkingCopy())
218: wc = (ILaunchConfigurationWorkingCopy) launch;
219: else
220: wc = launch.getWorkingCopy();
221: wc.setAttribute(TIMESTAMP, Long.toString(System
222: .currentTimeMillis()));
223: wc.doSave();
224: } catch (CoreException e) {
225: }
226: }
227:
228: private static void initializeProcessor(
229: OrganizeManifestsProcessor processor) {
230: processor.setAddMissing(false);
231: processor.setRemoveUnresolved(false);
232: processor.setModifyDep(false);
233: processor.setRemoveLazy(false);
234: processor.setAddDependencies(true);
235: processor.setCalculateUses(false);
236: processor.setMarkInternal(false);
237: processor.setPrefixIconNL(false);
238: processor.setUnusedDependencies(false);
239: processor.setUnusedKeys(false);
240: }
241:
242: private static String getTimeStamp(IProject project) {
243: IJavaProject jp = JavaCore.create(project);
244: try {
245: long timeStamp = 0;
246: IClasspathEntry[] entries = jp.getResolvedClasspath(true);
247: for (int i = 0; i < entries.length; i++) {
248: if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
249: File file;
250: IPath location = entries[i].getOutputLocation();
251: if (location == null)
252: location = jp.getOutputLocation();
253: IResource res = project.getWorkspace().getRoot()
254: .findMember(location);
255: IPath path = res == null ? null : res.getLocation();
256: if (path == null)
257: continue;
258: file = path.toFile();
259: Stack files = new Stack();
260: files.push(file);
261: while (!files.isEmpty()) {
262: file = (File) files.pop();
263: if (file.isDirectory()) {
264: File[] children = file.listFiles();
265: for (int j = 0; j < children.length; j++)
266: files.push(children[j]);
267: } else if (file.getName().endsWith(".class") && timeStamp < file.lastModified()) //$NON-NLS-1$
268: timeStamp = file.lastModified();
269: }
270: }
271: }
272: String[] otherFiles = {
273: "META-INF/MANIFEST.MF", "build.properties" }; //$NON-NLS-1$ //$NON-NLS-2$
274: for (int i = 0; i < otherFiles.length; i++) {
275: IResource file = project.getFile(otherFiles[i]);
276: if (file != null) {
277: long fileTimeStamp = file.getRawLocation().toFile()
278: .lastModified();
279: if (timeStamp < fileTimeStamp)
280: timeStamp = fileTimeStamp;
281: }
282: }
283: return Long.toString(timeStamp);
284: } catch (JavaModelException e) {
285: }
286: return "0"; //$NON-NLS-1$
287: }
288:
289: private static void handleUseDefault(String launcherTimeStamp,
290: ArrayList projects) {
291: IProject[] projs = ResourcesPlugin.getWorkspace().getRoot()
292: .getProjects();
293: for (int i = 0; i < projs.length; i++) {
294: if (!WorkspaceModelManager.isPluginProject(projs[i]))
295: continue;
296: String timestamp = getTimeStamp(projs[i]);
297: if (timestamp.compareTo(launcherTimeStamp) > 0
298: && shouldAdd(projs[i], launcherTimeStamp, timestamp))
299: projects.add(projs[i]);
300: }
301: }
302:
303: private static void handleSelectedPlugins(String timeStamp,
304: String value, ArrayList projects) {
305: StringTokenizer tokenizer = new StringTokenizer(value, ","); //$NON-NLS-1$
306: while (tokenizer.hasMoreTokens()) {
307: value = tokenizer.nextToken();
308: int index = value.indexOf('@');
309: String id = index > 0 ? value.substring(0, index) : value;
310: IPluginModelBase base = PluginRegistry.findModel(id);
311: if (base != null) {
312: IResource res = base.getUnderlyingResource();
313: if (res != null) {
314: IProject project = res.getProject();
315: String projTimeStamp = getTimeStamp(project);
316: if (projTimeStamp.compareTo(timeStamp) > 0
317: && shouldAdd(project, timeStamp,
318: projTimeStamp))
319: projects.add(project);
320: }
321: }
322: }
323: }
324:
325: private static void handleDeselectedPlugins(
326: String launcherTimeStamp, String value, ArrayList projects) {
327: StringTokenizer tokenizer = new StringTokenizer(value, ","); //$NON-NLS-1$
328: HashSet deSelectedProjs = new HashSet();
329: while (tokenizer.hasMoreTokens())
330: deSelectedProjs.add(tokenizer.nextToken());
331:
332: IProject[] projs = ResourcesPlugin.getWorkspace().getRoot()
333: .getProjects();
334: for (int i = 0; i < projs.length; i++) {
335: if (!WorkspaceModelManager.isPluginProject(projs[i]))
336: continue;
337: IPluginModelBase base = PluginRegistry.findModel(projs[i]);
338: if (base == null
339: || base != null
340: && deSelectedProjs.contains(base.getPluginBase()
341: .getId()))
342: continue;
343: String timestamp = getTimeStamp(projs[i]);
344: if (timestamp.compareTo(launcherTimeStamp) > 0
345: && shouldAdd(projs[i], launcherTimeStamp, timestamp))
346: projects.add(projs[i]);
347: }
348: }
349:
350: public static final void shutdown() {
351: if (fLastRun == null)
352: return;
353: FileOutputStream stream = null;
354: try {
355: stream = new FileOutputStream(new File(getDirectory(),
356: FILE_NAME));
357: fLastRun.store(stream, "Cached timestamps"); //$NON-NLS-1$
358: stream.flush();
359: stream.close();
360: } catch (IOException e) {
361: PDECore.logException(e);
362: } finally {
363: try {
364: if (stream != null)
365: stream.close();
366: } catch (IOException e1) {
367: }
368: }
369: }
370:
371: private static File getDirectory() {
372: IPath path = PDECore.getDefault().getStateLocation().append(
373: ".cache"); //$NON-NLS-1$
374: File directory = new File(path.toOSString());
375: if (!directory.exists() || !directory.isDirectory())
376: directory.mkdirs();
377: return directory;
378: }
379:
380: private static Properties getLastRun() {
381: if (fLastRun == null) {
382: fLastRun = new Properties();
383: FileInputStream fis = null;
384: try {
385: File file = new File(getDirectory(), FILE_NAME);
386: if (file.exists()) {
387: fis = new FileInputStream(file);
388: fLastRun.load(fis);
389: fis.close();
390: }
391: } catch (IOException e) {
392: PDECore.logException(e);
393: } finally {
394: try {
395: if (fis != null)
396: fis.close();
397: } catch (IOException e1) {
398: }
399: }
400: }
401: return fLastRun;
402: }
403:
404: private static boolean shouldAdd(IProject proj, String launcherTS,
405: String fileSystemTS) {
406: String projTS = (String) getLastRun().get(proj.getName());
407: if (projTS == null)
408: return true;
409: return ((projTS.compareTo(launcherTS) < 0) || (projTS
410: .compareTo(fileSystemTS) < 0));
411: }
412:
413: public static boolean requiresUI(ILaunchConfiguration configuration) {
414: try {
415: String projectID = configuration
416: .getAttribute(
417: IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
418: ""); //$NON-NLS-1$
419: if (projectID.length() > 0) {
420: IResource project = PDEPlugin.getWorkspace().getRoot()
421: .findMember(projectID);
422: if (project instanceof IProject) {
423: IPluginModelBase model = PluginRegistry
424: .findModel((IProject) project);
425: if (model != null) {
426: Set plugins = DependencyManager
427: .getSelfAndDependencies(model);
428: return plugins.contains("org.eclipse.swt"); //$NON-NLS-1$
429: }
430: }
431: }
432: } catch (CoreException e) {
433: }
434: return true;
435: }
436:
437: public static boolean clearWorkspaceLog(String workspace) {
438: File logFile = new File(workspace,
439: ".metadata" + File.separator + ".log"); //$NON-NLS-1$ //$NON-NLS-2$
440: if (logFile != null && logFile.exists()) {
441: return logFile.delete();
442: }
443: return true;
444: }
445:
446: public static IStatus createErrorStatus(String message) {
447: return new Status(IStatus.ERROR, PDEPlugin.getPluginId(),
448: IStatus.OK, message, null);
449: }
450:
451: }
|