001: /*******************************************************************************
002: * Copyright (c) 2000, 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.jdt.ui.wizards;
011:
012: import java.io.File;
013: import java.io.FileInputStream;
014: import java.io.FileOutputStream;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.io.OutputStream;
018: import java.lang.reflect.InvocationTargetException;
019: import java.net.URI;
020: import java.net.URISyntaxException;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.HashSet;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: import org.eclipse.core.filesystem.EFS;
029: import org.eclipse.core.filesystem.IFileInfo;
030: import org.eclipse.core.filesystem.IFileStore;
031:
032: import org.eclipse.core.runtime.Assert;
033: import org.eclipse.core.runtime.CoreException;
034: import org.eclipse.core.runtime.IPath;
035: import org.eclipse.core.runtime.IProgressMonitor;
036: import org.eclipse.core.runtime.IStatus;
037: import org.eclipse.core.runtime.NullProgressMonitor;
038: import org.eclipse.core.runtime.OperationCanceledException;
039: import org.eclipse.core.runtime.Path;
040: import org.eclipse.core.runtime.Status;
041: import org.eclipse.core.runtime.SubProgressMonitor;
042:
043: import org.eclipse.core.resources.IFolder;
044: import org.eclipse.core.resources.IProject;
045: import org.eclipse.core.resources.IResource;
046: import org.eclipse.core.resources.IResourceStatus;
047: import org.eclipse.core.resources.IWorkspaceRoot;
048: import org.eclipse.core.resources.ResourcesPlugin;
049:
050: import org.eclipse.jface.dialogs.ErrorDialog;
051: import org.eclipse.jface.operation.IRunnableWithProgress;
052:
053: import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation;
054:
055: import org.eclipse.jdt.core.IClasspathEntry;
056: import org.eclipse.jdt.core.IJavaProject;
057: import org.eclipse.jdt.core.JavaCore;
058:
059: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
060: import org.eclipse.jdt.internal.corext.util.Messages;
061:
062: import org.eclipse.jdt.ui.JavaUI;
063:
064: import org.eclipse.jdt.internal.ui.JavaPlugin;
065: import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
066: import org.eclipse.jdt.internal.ui.util.CoreUtility;
067: import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
068: import org.eclipse.jdt.internal.ui.wizards.ClassPathDetector;
069: import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
070:
071: /**
072: * The second page of the New Java project wizard. It allows to configure the build path and output location.
073: * As addition to the {@link JavaCapabilityConfigurationPage}, the wizard page does an
074: * early project creation (so that linked folders can be defined) and, if an
075: * existing external location was specified, detects the class path.
076: *
077: * <p>
078: * Clients may instantiate or subclass.
079: * </p>
080: *
081: * <p>
082: * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
083: * of a work in progress. This API is under review and may still change when finalized. Please send your
084: * comments to bug 160985.
085: * </p>
086: *
087: * @since 3.4
088: */
089: public class NewJavaProjectWizardPageTwo extends
090: JavaCapabilityConfigurationPage {
091:
092: private static final String FILENAME_PROJECT = ".project"; //$NON-NLS-1$
093: private static final String FILENAME_CLASSPATH = ".classpath"; //$NON-NLS-1$
094:
095: private final NewJavaProjectWizardPageOne fFirstPage;
096:
097: private URI fCurrProjectLocation; // null if location is platform location
098: private IProject fCurrProject;
099:
100: private boolean fKeepContent;
101:
102: private File fDotProjectBackup;
103: private File fDotClasspathBackup;
104: private Boolean fIsAutobuild;
105: private HashSet fOrginalFolders;
106:
107: /**
108: * Constructor for the {@link NewJavaProjectWizardPageTwo}.
109: *
110: * @param mainPage the first page of the wizard
111: */
112: public NewJavaProjectWizardPageTwo(
113: NewJavaProjectWizardPageOne mainPage) {
114: fFirstPage = mainPage;
115: fCurrProjectLocation = null;
116: fCurrProject = null;
117: fKeepContent = false;
118:
119: fDotProjectBackup = null;
120: fDotClasspathBackup = null;
121: fIsAutobuild = null;
122: }
123:
124: /* (non-Javadoc)
125: * @see org.eclipse.jdt.ui.wizards.JavaCapabilityConfigurationPage#useNewSourcePage()
126: */
127: protected final boolean useNewSourcePage() {
128: return true;
129: }
130:
131: /* (non-Javadoc)
132: * @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
133: */
134: public void setVisible(boolean visible) {
135: if (visible) {
136: IStatus status = changeToNewProject();
137: if (status != null && !status.isOK()) {
138: ErrorDialog
139: .openError(
140: getShell(),
141: NewWizardMessages.NewJavaProjectWizardPageTwo_error_title,
142: null, status);
143: }
144: } else {
145: removeProject();
146: }
147: super .setVisible(visible);
148: if (visible) {
149:
150: setFocus();
151: }
152: }
153:
154: private boolean hasExistingContent(URI realLocation)
155: throws CoreException {
156: IFileStore file = EFS.getStore(realLocation);
157: return file.fetchInfo().exists();
158: }
159:
160: private IStatus changeToNewProject() {
161: class UpdateRunnable implements IRunnableWithProgress {
162: public IStatus infoStatus = Status.OK_STATUS;
163:
164: public void run(IProgressMonitor monitor)
165: throws InvocationTargetException,
166: InterruptedException {
167: try {
168: if (fIsAutobuild == null) {
169: fIsAutobuild = Boolean.valueOf(CoreUtility
170: .enableAutoBuild(false));
171: }
172: infoStatus = updateProject(monitor);
173: } catch (CoreException e) {
174: throw new InvocationTargetException(e);
175: } catch (OperationCanceledException e) {
176: throw new InterruptedException();
177: } finally {
178: monitor.done();
179: }
180: }
181: }
182: UpdateRunnable op = new UpdateRunnable();
183: try {
184: getContainer().run(true, false,
185: new WorkspaceModifyDelegatingOperation(op));
186: return op.infoStatus;
187: } catch (InvocationTargetException e) {
188: final String title = NewWizardMessages.NewJavaProjectWizardPageTwo_error_title;
189: final String message = NewWizardMessages.NewJavaProjectWizardPageTwo_error_message;
190: ExceptionHandler.handle(e, getShell(), title, message);
191: } catch (InterruptedException e) {
192: // cancel pressed
193: }
194: return null;
195: }
196:
197: private static URI getRealLocation(String projectName, URI location) {
198: if (location == null) { // inside workspace
199: try {
200: URI rootLocation = ResourcesPlugin.getWorkspace()
201: .getRoot().getLocationURI();
202:
203: location = new URI(rootLocation.getScheme(), null, Path
204: .fromPortableString(rootLocation.getPath())
205: .append(projectName).toString(), null);
206: } catch (URISyntaxException e) {
207: Assert.isTrue(false, "Can't happen"); //$NON-NLS-1$
208: }
209: }
210: return location;
211: }
212:
213: private final IStatus updateProject(IProgressMonitor monitor)
214: throws CoreException, InterruptedException {
215: IStatus result = StatusInfo.OK_STATUS;
216: if (monitor == null) {
217: monitor = new NullProgressMonitor();
218: }
219: try {
220: monitor
221: .beginTask(
222: NewWizardMessages.NewJavaProjectWizardPageTwo_operation_initialize,
223: 7);
224: if (monitor.isCanceled()) {
225: throw new OperationCanceledException();
226: }
227:
228: String projectName = fFirstPage.getProjectName();
229:
230: fCurrProject = ResourcesPlugin.getWorkspace().getRoot()
231: .getProject(projectName);
232: fCurrProjectLocation = fFirstPage.getProjectLocationURI();
233:
234: URI realLocation = getRealLocation(projectName,
235: fCurrProjectLocation);
236: fKeepContent = hasExistingContent(realLocation);
237:
238: if (monitor.isCanceled()) {
239: throw new OperationCanceledException();
240: }
241:
242: if (fKeepContent) {
243: rememberExistingFiles(realLocation);
244: rememberExisitingFolders(realLocation);
245: }
246:
247: if (monitor.isCanceled()) {
248: throw new OperationCanceledException();
249: }
250:
251: try {
252: createProject(fCurrProject, fCurrProjectLocation,
253: new SubProgressMonitor(monitor, 2));
254: } catch (CoreException e) {
255: if (e.getStatus().getCode() == IResourceStatus.FAILED_READ_METADATA) {
256: result = new StatusInfo(
257: IStatus.INFO,
258: Messages
259: .format(
260: NewWizardMessages.NewJavaProjectWizardPageTwo_DeleteCorruptProjectFile_message,
261: e.getLocalizedMessage()));
262:
263: deleteProjectFile(realLocation);
264: if (fCurrProject.exists())
265: fCurrProject.delete(true, null);
266:
267: createProject(fCurrProject, fCurrProjectLocation,
268: null);
269: } else {
270: throw e;
271: }
272: }
273:
274: if (monitor.isCanceled()) {
275: throw new OperationCanceledException();
276: }
277:
278: initializeBuildPath(JavaCore.create(fCurrProject),
279: new SubProgressMonitor(monitor, 2));
280: configureJavaProject(new SubProgressMonitor(monitor, 3)); // create the Java project to allow the use of the new source folder page
281: } finally {
282: monitor.done();
283: }
284: return result;
285: }
286:
287: /**
288: * Evaluates the new build path and output folder according to the settings on the first page.
289: * The resulting build path is set by calling {@link #init(IJavaProject, IPath, IClasspathEntry[], boolean)}.
290: * Clients can override this method.
291: *
292: * @param javaProject the new project which is already created when this method is called.
293: * @param monitor the progress monitor
294: * @throws CoreException thrown when initializing the build path failed
295: */
296: protected void initializeBuildPath(IJavaProject javaProject,
297: IProgressMonitor monitor) throws CoreException {
298: if (monitor == null) {
299: monitor = new NullProgressMonitor();
300: }
301: monitor
302: .beginTask(
303: NewWizardMessages.NewJavaProjectWizardPageTwo_monitor_init_build_path,
304: 2);
305:
306: try {
307: IClasspathEntry[] entries = null;
308: IPath outputLocation = null;
309: IProject project = javaProject.getProject();
310:
311: if (fKeepContent) {
312: if (!project.getFile(FILENAME_CLASSPATH).exists()) {
313: final ClassPathDetector detector = new ClassPathDetector(
314: fCurrProject, new SubProgressMonitor(
315: monitor, 2));
316: entries = detector.getClasspath();
317: outputLocation = detector.getOutputLocation();
318: if (entries.length == 0)
319: entries = null;
320: } else {
321: monitor.worked(2);
322: }
323: } else {
324: List cpEntries = new ArrayList();
325: IWorkspaceRoot root = project.getWorkspace().getRoot();
326:
327: IClasspathEntry[] sourceClasspathEntries = fFirstPage
328: .getSourceClasspathEntries();
329: for (int i = 0; i < sourceClasspathEntries.length; i++) {
330: IPath path = sourceClasspathEntries[i].getPath();
331: if (path.segmentCount() > 1) {
332: IFolder folder = root.getFolder(path);
333: CoreUtility.createFolder(folder, true, true,
334: new SubProgressMonitor(monitor, 1));
335: }
336: cpEntries.add(sourceClasspathEntries[i]);
337: }
338:
339: cpEntries.addAll(Arrays.asList(fFirstPage
340: .getDefaultClasspathEntries()));
341:
342: entries = (IClasspathEntry[]) cpEntries
343: .toArray(new IClasspathEntry[cpEntries.size()]);
344:
345: outputLocation = fFirstPage.getOutputLocation();
346: if (outputLocation.segmentCount() > 1) {
347: IFolder folder = root.getFolder(outputLocation);
348: CoreUtility.createDerivedFolder(folder, true, true,
349: new SubProgressMonitor(monitor, 1));
350: }
351: }
352: if (monitor.isCanceled()) {
353: throw new OperationCanceledException();
354: }
355:
356: init(javaProject, outputLocation, entries, false);
357: } finally {
358: monitor.done();
359: }
360: }
361:
362: private void deleteProjectFile(URI projectLocation)
363: throws CoreException {
364: IFileStore file = EFS.getStore(projectLocation);
365: if (file.fetchInfo().exists()) {
366: IFileStore projectFile = file.getChild(FILENAME_PROJECT);
367: if (projectFile.fetchInfo().exists()) {
368: projectFile.delete(EFS.NONE, null);
369: }
370: }
371: }
372:
373: private void rememberExisitingFolders(URI projectLocation) {
374: fOrginalFolders = new HashSet();
375:
376: try {
377: IFileStore[] children = EFS.getStore(projectLocation)
378: .childStores(EFS.NONE, null);
379: for (int i = 0; i < children.length; i++) {
380: IFileStore child = children[i];
381: IFileInfo info = child.fetchInfo();
382: if (info.isDirectory() && info.exists()
383: && !fOrginalFolders.contains(child.getName())) {
384: fOrginalFolders.add(child);
385: }
386: }
387: } catch (CoreException e) {
388: JavaPlugin.log(e);
389: }
390: }
391:
392: private void restoreExistingFolders(URI projectLocation) {
393: try {
394: IFileStore[] children = EFS.getStore(projectLocation)
395: .childStores(EFS.NONE, null);
396: for (int i = 0; i < children.length; i++) {
397: IFileStore child = children[i];
398: IFileInfo info = child.fetchInfo();
399: if (info.isDirectory() && info.exists()
400: && !fOrginalFolders.contains(child)) {
401: child.delete(EFS.NONE, null);
402: fOrginalFolders.remove(child);
403: }
404: }
405:
406: for (Iterator iterator = fOrginalFolders.iterator(); iterator
407: .hasNext();) {
408: IFileStore deleted = (IFileStore) iterator.next();
409: deleted.mkdir(EFS.NONE, null);
410: }
411: } catch (CoreException e) {
412: JavaPlugin.log(e);
413: }
414: }
415:
416: private void rememberExistingFiles(URI projectLocation)
417: throws CoreException {
418: fDotProjectBackup = null;
419: fDotClasspathBackup = null;
420:
421: IFileStore file = EFS.getStore(projectLocation);
422: if (file.fetchInfo().exists()) {
423: IFileStore projectFile = file.getChild(FILENAME_PROJECT);
424: if (projectFile.fetchInfo().exists()) {
425: fDotProjectBackup = createBackup(projectFile,
426: "project-desc"); //$NON-NLS-1$
427: }
428: IFileStore classpathFile = file
429: .getChild(FILENAME_CLASSPATH);
430: if (classpathFile.fetchInfo().exists()) {
431: fDotClasspathBackup = createBackup(classpathFile,
432: "classpath-desc"); //$NON-NLS-1$
433: }
434: }
435: }
436:
437: private void restoreExistingFiles(URI projectLocation,
438: IProgressMonitor monitor) throws CoreException {
439: int ticks = ((fDotProjectBackup != null ? 1 : 0) + (fDotClasspathBackup != null ? 1
440: : 0)) * 2;
441: monitor.beginTask("", ticks); //$NON-NLS-1$
442: try {
443: IFileStore projectFile = EFS.getStore(projectLocation)
444: .getChild(FILENAME_PROJECT);
445: projectFile.delete(EFS.NONE, new SubProgressMonitor(
446: monitor, 1));
447: if (fDotProjectBackup != null) {
448: copyFile(fDotProjectBackup, projectFile,
449: new SubProgressMonitor(monitor, 1));
450: }
451: } catch (IOException e) {
452: IStatus status = new Status(
453: IStatus.ERROR,
454: JavaUI.ID_PLUGIN,
455: IStatus.ERROR,
456: NewWizardMessages.NewJavaProjectWizardPageTwo_problem_restore_project,
457: e);
458: throw new CoreException(status);
459: }
460: try {
461: IFileStore classpathFile = EFS.getStore(projectLocation)
462: .getChild(FILENAME_CLASSPATH);
463: classpathFile.delete(EFS.NONE, new SubProgressMonitor(
464: monitor, 1));
465: if (fDotClasspathBackup != null) {
466: copyFile(fDotClasspathBackup, classpathFile,
467: new SubProgressMonitor(monitor, 1));
468: }
469: } catch (IOException e) {
470: IStatus status = new Status(
471: IStatus.ERROR,
472: JavaUI.ID_PLUGIN,
473: IStatus.ERROR,
474: NewWizardMessages.NewJavaProjectWizardPageTwo_problem_restore_classpath,
475: e);
476: throw new CoreException(status);
477: }
478: }
479:
480: private File createBackup(IFileStore source, String name)
481: throws CoreException {
482: try {
483: File bak = File.createTempFile("eclipse-" + name, ".bak"); //$NON-NLS-1$//$NON-NLS-2$
484: copyFile(source, bak);
485: return bak;
486: } catch (IOException e) {
487: IStatus status = new Status(
488: IStatus.ERROR,
489: JavaUI.ID_PLUGIN,
490: IStatus.ERROR,
491: Messages
492: .format(
493: NewWizardMessages.NewJavaProjectWizardPageTwo_problem_backup,
494: name), e);
495: throw new CoreException(status);
496: }
497: }
498:
499: private void copyFile(IFileStore source, File target)
500: throws IOException, CoreException {
501: InputStream is = source.openInputStream(EFS.NONE, null);
502: FileOutputStream os = new FileOutputStream(target);
503: copyFile(is, os);
504: }
505:
506: private void copyFile(File source, IFileStore target,
507: IProgressMonitor monitor) throws IOException, CoreException {
508: FileInputStream is = new FileInputStream(source);
509: OutputStream os = target.openOutputStream(EFS.NONE, monitor);
510: copyFile(is, os);
511: }
512:
513: private void copyFile(InputStream is, OutputStream os)
514: throws IOException {
515: try {
516: byte[] buffer = new byte[8192];
517: while (true) {
518: int bytesRead = is.read(buffer);
519: if (bytesRead == -1)
520: break;
521:
522: os.write(buffer, 0, bytesRead);
523: }
524: } finally {
525: try {
526: is.close();
527: } finally {
528: os.close();
529: }
530: }
531: }
532:
533: /**
534: * Called from the wizard on finish.
535: *
536: * @param monitor the progress monitor
537: * @throws CoreException thrown when the project creation or configuration failed
538: * @throws InterruptedException thrown when the user cancelled the project creation
539: */
540: public void performFinish(IProgressMonitor monitor)
541: throws CoreException, InterruptedException {
542: try {
543: monitor
544: .beginTask(
545: NewWizardMessages.NewJavaProjectWizardPageTwo_operation_create,
546: 3);
547: if (fCurrProject == null) {
548: updateProject(new SubProgressMonitor(monitor, 1));
549: }
550: configureJavaProject(new SubProgressMonitor(monitor, 2));
551:
552: if (!fKeepContent) {
553: String compliance = fFirstPage.getCompilerCompliance();
554: if (compliance != null) {
555: IJavaProject project = JavaCore
556: .create(fCurrProject);
557: Map options = project.getOptions(false);
558: JavaModelUtil.setCompilanceOptions(options,
559: compliance);
560: JavaModelUtil.setDefaultClassfileOptions(options,
561: compliance); // complete compliance options
562: project.setOptions(options);
563: }
564: }
565: } finally {
566: monitor.done();
567: fCurrProject = null;
568: if (fIsAutobuild != null) {
569: CoreUtility
570: .enableAutoBuild(fIsAutobuild.booleanValue());
571: fIsAutobuild = null;
572: }
573: }
574: }
575:
576: private void removeProject() {
577: if (fCurrProject == null || !fCurrProject.exists()) {
578: return;
579: }
580:
581: IRunnableWithProgress op = new IRunnableWithProgress() {
582: public void run(IProgressMonitor monitor)
583: throws InvocationTargetException,
584: InterruptedException {
585: doRemoveProject(monitor);
586: }
587: };
588:
589: try {
590: getContainer().run(true, true,
591: new WorkspaceModifyDelegatingOperation(op));
592: } catch (InvocationTargetException e) {
593: final String title = NewWizardMessages.NewJavaProjectWizardPageTwo_error_remove_title;
594: final String message = NewWizardMessages.NewJavaProjectWizardPageTwo_error_remove_message;
595: ExceptionHandler.handle(e, getShell(), title, message);
596: } catch (InterruptedException e) {
597: // cancel pressed
598: }
599: }
600:
601: private final void doRemoveProject(IProgressMonitor monitor)
602: throws InvocationTargetException {
603: final boolean noProgressMonitor = (fCurrProjectLocation == null); // inside workspace
604: if (monitor == null || noProgressMonitor) {
605: monitor = new NullProgressMonitor();
606: }
607: monitor
608: .beginTask(
609: NewWizardMessages.NewJavaProjectWizardPageTwo_operation_remove,
610: 3);
611: try {
612: try {
613: URI projLoc = fCurrProject.getLocationURI();
614:
615: boolean removeContent = !fKeepContent
616: && fCurrProject
617: .isSynchronized(IResource.DEPTH_INFINITE);
618: if (!removeContent) {
619: restoreExistingFolders(projLoc);
620: }
621: fCurrProject.delete(removeContent, false,
622: new SubProgressMonitor(monitor, 2));
623:
624: restoreExistingFiles(projLoc, new SubProgressMonitor(
625: monitor, 1));
626: } finally {
627: CoreUtility
628: .enableAutoBuild(fIsAutobuild.booleanValue()); // fIsAutobuild must be set
629: fIsAutobuild = null;
630: }
631: } catch (CoreException e) {
632: throw new InvocationTargetException(e);
633: } finally {
634: monitor.done();
635: fCurrProject = null;
636: fKeepContent = false;
637: }
638: }
639:
640: /**
641: * Called from the wizard on cancel.
642: */
643: public void performCancel() {
644: removeProject();
645: }
646: }
|