blob: 19392688718da18662871bfc22c58bae923cfb8e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.jarimport;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.runtime.Assert;
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.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ui.IImportWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
import org.eclipse.ltk.core.refactoring.history.RefactoringHistory;
import org.eclipse.ltk.ui.refactoring.history.RefactoringHistoryControlConfiguration;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptor;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil;
import org.eclipse.jdt.internal.ui.refactoring.binary.BinaryRefactoringHistoryWizard;
/**
* Import wizard to import a refactoring-aware Java Archive (JAR) file.
* <p>
* This class may be instantiated and used without further configuration; this
* class is not intended to be subclassed.
* </p>
* <p>
* Example:
*
* <pre>
* IWizard wizard= new JarImportWizard();
* wizard.init(workbench, selection);
* WizardDialog dialog= new WizardDialog(shell, wizard);
* dialog.open();
* </pre>
*
* During the call to <code>open</code>, the wizard dialog is presented to
* the user. When the user hits Finish, the user-selected JAR file is inspected
* for associated refactorings, the wizard executes eventual refactorings,
* copies the JAR file over its old version, the dialog closes, and the call to
* <code>open</code> returns.
* </p>
*
* @since 3.2
*/
public final class JarImportWizard extends BinaryRefactoringHistoryWizard implements IImportWizard {
/** Proxy which requests the refactoring history from the import data */
private final class RefactoringHistoryProxy extends RefactoringHistory {
/** The cached refactoring history delta */
private RefactoringDescriptorProxy[] fHistoryDelta= null;
/**
* {@inheritDoc}
*/
public RefactoringDescriptorProxy[] getDescriptors() {
if (fHistoryDelta != null)
return fHistoryDelta;
final RefactoringHistory incoming= fImportData.getRefactoringHistory();
if (incoming != null) {
fHistoryDelta= incoming.getDescriptors();
final IPackageFragmentRoot root= fImportData.getPackageFragmentRoot();
if (root != null) {
try {
final URI uri= getLocationURI(root.getRawClasspathEntry());
if (uri != null) {
final File file= new File(uri);
if (file.exists()) {
ZipFile zip= null;
try {
zip= new ZipFile(file, ZipFile.OPEN_READ);
ZipEntry entry= zip.getEntry(JarPackagerUtil.getRefactoringsEntry());
if (entry != null) {
InputStream stream= null;
try {
stream= zip.getInputStream(entry);
final RefactoringHistory existing= RefactoringCore.getHistoryService().readRefactoringHistory(stream, JavaRefactoringDescriptor.JAR_IMPORTABLE | JavaRefactoringDescriptor.JAR_REFACTORABLE);
if (existing != null)
fHistoryDelta= incoming.removeAll(existing).getDescriptors();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException exception) {
// Do nothing
}
}
}
}
} catch (IOException exception) {
// Just leave it
}
}
}
} catch (CoreException exception) {
JavaPlugin.log(exception);
}
}
return fHistoryDelta;
}
return new RefactoringDescriptorProxy[0];
}
/**
* {@inheritDoc}
*/
public boolean isEmpty() {
final RefactoringDescriptorProxy[] proxies= getDescriptors();
if (proxies != null)
return proxies.length == 0;
return true;
}
/**
* {@inheritDoc}
*/
public RefactoringHistory removeAll(final RefactoringHistory history) {
throw new UnsupportedOperationException();
}
}
/** The dialog settings key */
private static String DIALOG_SETTINGS_KEY= "JarImportWizard"; //$NON-NLS-1$
/**
* Is the specified class path entry pointing to a valid location for
* import?
*
* @param entry
* the class path entry
* @return <code>true</code> if it is a valid package fragment root,
* <code>false</code> otherwise
*/
public static boolean isValidClassPathEntry(final IClasspathEntry entry) {
Assert.isNotNull(entry);
final int kind= entry.getEntryKind();
if (kind == IClasspathEntry.CPE_LIBRARY)
return entry.getContentKind() == IPackageFragmentRoot.K_BINARY;
else if (kind == IClasspathEntry.CPE_VARIABLE)
return true; // be optimistic
return false;
}
/**
* Is the specified java project a valid project for import?
*
* @param project
* the java project
* @throws JavaModelException
* if an error occurs
*/
public static boolean isValidJavaProject(final IJavaProject project) throws JavaModelException {
Assert.isNotNull(project);
return project.getProject().isAccessible();
}
/** The refactoring history proxy */
private final RefactoringHistoryProxy fHistoryProxy;
/** The jar import data */
private final JarImportData fImportData= new JarImportData();
/** The jar import page, or <code>null</code> */
private JarImportWizardPage fImportPage= null;
/** Is the wizard part of an import wizard? */
private boolean fImportWizard= true;
/** Has the wizard new dialog settings? */
private boolean fNewSettings;
/**
* Creates a new jar import wizard.
*/
public JarImportWizard() {
super(JarImportMessages.JarImportWizard_window_title, JarImportMessages.RefactoringImportPreviewPage_title, JarImportMessages.RefactoringImportPreviewPage_description);
fImportData.setRefactoringAware(true);
fImportData.setIncludeDirectoryEntries(true);
fHistoryProxy= new RefactoringHistoryProxy();
setInput(fHistoryProxy);
final IDialogSettings section= JavaPlugin.getDefault().getDialogSettings().getSection(DIALOG_SETTINGS_KEY);
if (section == null)
fNewSettings= true;
else {
fNewSettings= false;
setDialogSettings(section);
}
setConfiguration(new RefactoringHistoryControlConfiguration(null, false, false) {
public String getProjectPattern() {
return JarImportMessages.JarImportWizard_project_pattern;
}
public String getWorkspaceCaption() {
return JarImportMessages.JarImportWizard_workspace_caption;
}
});
setDefaultPageImageDescriptor(JavaPluginImages.DESC_WIZBAN_REPLACE_JAR);
}
/**
* Creates a new jar import wizard.
*
* @param wizard
* <code>true</code> if the wizard is part of an import wizard,
* <code>false</code> otherwise
*/
public JarImportWizard(final boolean wizard) {
this();
fImportWizard= wizard;
setWindowTitle(JarImportMessages.JarImportWizard_replace_title);
}
/**
* {@inheritDoc}
*/
protected void addUserDefinedPages() {
fImportPage= new JarImportWizardPage(this, fImportWizard);
addPage(fImportPage);
}
/**
* {@inheritDoc}
*/
public boolean canFinish() {
return super.canFinish() && fImportData.getPackageFragmentRoot() != null && fImportData.getRefactoringFileLocation() != null;
}
/**
* {@inheritDoc}
*/
protected boolean deconfigureClasspath(final IClasspathEntry[] entries, final IProgressMonitor monitor) throws CoreException {
final boolean rename= fImportData.isRenameJarFile();
if (rename && !fCancelled) {
final IPackageFragmentRoot root= getPackageFragmentRoot();
if (root != null) {
final IClasspathEntry entry= root.getRawClasspathEntry();
for (int index= 0; index < entries.length; index++) {
if (entries[index].equals(entry)) {
final IPath path= getTargetPath(entries[index]);
if (path != null)
entries[index]= JavaCore.newLibraryEntry(path, entries[index].getSourceAttachmentPath(), entries[index].getSourceAttachmentRootPath(), entries[index].getAccessRules(), entries[index].getExtraAttributes(), entries[index].isExported());
}
}
}
}
if (!fCancelled)
replaceJarFile(new SubProgressMonitor(monitor, 100, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
return rename;
}
/**
* Returns the jar import data.
*
* @return the jar import data
*/
public JarImportData getImportData() {
return fImportData;
}
/**
* {@inheritDoc}
*/
public IWizardPage getNextPage(final IWizardPage page) {
if (page == fImportPage && fImportData.getRefactoringHistory() == null)
return null;
return super.getNextPage(page);
}
/**
* {@inheritDoc}
*/
protected IPackageFragmentRoot getPackageFragmentRoot() {
return fImportData.getPackageFragmentRoot();
}
/**
* {@inheritDoc}
*/
protected RefactoringHistory getRefactoringHistory() {
return fHistoryProxy;
}
/**
* Returns the target path to be used for the updated classpath entry.
*
* @param entry
* the classpath entry
* @return the target path, or <code>null</code>
* @throws CoreException
* if an error occurs
*/
private IPath getTargetPath(final IClasspathEntry entry) throws CoreException {
final URI location= getLocationURI(entry);
if (location != null) {
final URI target= getTargetURI(location);
if (target != null) {
IPath path= URIUtil.toPath(target);
if (path != null) {
final IPath workspace= ResourcesPlugin.getWorkspace().getRoot().getLocation();
if (workspace.isPrefixOf(path)) {
path= path.removeFirstSegments(workspace.segmentCount());
path= path.setDevice(null);
path= path.makeAbsolute();
}
}
return path;
}
}
return null;
}
/**
* Returns the target uri taking any renaming of the jar file into account.
*
* @param uri
* the location uri
* @return the target uri
* @throws CoreException
* if an error occurs
*/
private URI getTargetURI(final URI uri) throws CoreException {
final IFileStore parent= EFS.getStore(uri).getParent();
if (parent != null) {
final URI location= fImportData.getRefactoringFileLocation();
if (location != null)
return parent.getChild(EFS.getStore(location).getName()).toURI();
}
return uri;
}
/**
* {@inheritDoc}
*/
public void init(final IWorkbench workbench, final IStructuredSelection selection) {
if (selection != null && selection.size() == 1) {
final Object element= selection.getFirstElement();
if (element instanceof IPackageFragmentRoot) {
final IPackageFragmentRoot root= (IPackageFragmentRoot) element;
try {
final IClasspathEntry entry= root.getRawClasspathEntry();
if (isValidClassPathEntry(entry))
fImportData.setPackageFragmentRoot(root);
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
}
}
}
}
/**
* {@inheritDoc}
*/
public boolean performFinish() {
if (fNewSettings) {
final IDialogSettings settings= JavaPlugin.getDefault().getDialogSettings();
IDialogSettings section= settings.getSection(DIALOG_SETTINGS_KEY);
section= settings.addNewSection(DIALOG_SETTINGS_KEY);
setDialogSettings(section);
}
fImportPage.performFinish();
return super.performFinish();
}
/**
* Replaces the old jar file with the new one.
*
* @param monitor
* the progress monitor to use
* @throws CoreException
* if an error occurs
*/
private void replaceJarFile(final IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask(JarImportMessages.JarImportWizard_cleanup_import, 250);
final URI location= fImportData.getRefactoringFileLocation();
if (location != null) {
final IPackageFragmentRoot root= fImportData.getPackageFragmentRoot();
if (root != null) {
final URI uri= getLocationURI(root.getRawClasspathEntry());
if (uri != null) {
final IFileStore store= EFS.getStore(location);
if (fImportData.isRenameJarFile()) {
final URI target= getTargetURI(uri);
store.copy(EFS.getStore(target), EFS.OVERWRITE, new SubProgressMonitor(monitor, 50, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
if (!uri.equals(target))
EFS.getStore(uri).delete(EFS.NONE, new SubProgressMonitor(monitor, 50, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
} else
store.copy(EFS.getStore(uri), EFS.OVERWRITE, new SubProgressMonitor(monitor, 100, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
if (fJavaProject != null)
fJavaProject.getResource().refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 50, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
return;
}
}
}
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), 0, JarImportMessages.JarImportWizard_error_copying_jar, null));
} finally {
monitor.done();
}
}
}