### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.ui.tests Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui.tests/META-INF/MANIFEST.MF,v retrieving revision 1.4 diff -u -r1.4 MANIFEST.MF --- META-INF/MANIFEST.MF 27 Sep 2007 09:32:38 -0000 1.4 +++ META-INF/MANIFEST.MF 28 Sep 2007 15:58:34 -0000 @@ -25,6 +25,7 @@ org.eclipse.jdt.ui.tests.core;x-internal:=true, org.eclipse.jdt.ui.tests.core.source;x-internal:=true, org.eclipse.jdt.ui.tests.dialogs;x-internal:=true, + org.eclipse.jdt.ui.tests.jarexport, org.eclipse.jdt.ui.tests.leaks;x-internal:=true, org.eclipse.jdt.ui.tests.model;x-internal:=true, org.eclipse.jdt.ui.tests.packageview;x-internal:=true, Index: test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui.tests/test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java,v retrieving revision 1.50 diff -u -r1.50 JavaProjectHelper.java --- test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java 29 May 2007 18:18:29 -0000 1.50 +++ test plugin/org/eclipse/jdt/testplugin/JavaProjectHelper.java 28 Sep 2007 15:58:34 -0000 @@ -339,6 +339,20 @@ * @throws CoreException Creation failed */ public static IPackageFragmentRoot addSourceContainer(IJavaProject jproject, String containerName, IPath[] inclusionFilters, IPath[] exclusionFilters) throws CoreException { + return addSourceContainer(jproject, containerName, inclusionFilters, exclusionFilters, null); + } + + /** + * Adds a source container to a IJavaProject. + * @param jproject The parent project + * @param containerName The name of the new source container + * @param inclusionFilters Inclusion filters to set + * @param exclusionFilters Exclusion filters to set + * @param outputLocation The location where class files are written to, null for project output folder + * @return The handle to the new source container + * @throws CoreException Creation failed + */ + public static IPackageFragmentRoot addSourceContainer(IJavaProject jproject, String containerName, IPath[] inclusionFilters, IPath[] exclusionFilters, String outputLocation) throws CoreException { IProject project= jproject.getProject(); IContainer container= null; if (containerName == null || containerName.length() == 0) { @@ -352,7 +366,15 @@ } IPackageFragmentRoot root= jproject.getPackageFragmentRoot(container); - IClasspathEntry cpe= JavaCore.newSourceEntry(root.getPath(), inclusionFilters, exclusionFilters, null); + IPath outputPath= null; + if (outputLocation != null) { + IFolder folder= project.getFolder(outputLocation); + if (!folder.exists()) { + CoreUtility.createFolder(folder, false, true, null); + } + outputPath= folder.getFullPath(); + } + IClasspathEntry cpe= JavaCore.newSourceEntry(root.getPath(), inclusionFilters, exclusionFilters, outputPath); addToClasspath(jproject, cpe); return root; } Index: ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java,v retrieving revision 1.50 diff -u -r1.50 AutomatedSuite.java --- ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java 6 Aug 2007 13:55:58 -0000 1.50 +++ ui/org/eclipse/jdt/ui/tests/AutomatedSuite.java 28 Sep 2007 15:58:34 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 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 @@ -21,6 +21,7 @@ import org.eclipse.jdt.ui.tests.buildpath.BuildpathModifierActionTest; import org.eclipse.jdt.ui.tests.callhierarchy.CallHierarchyContentProviderTest; import org.eclipse.jdt.ui.tests.core.CoreTests; +import org.eclipse.jdt.ui.tests.jarexport.JarExportTests; import org.eclipse.jdt.ui.tests.packageview.PackageExplorerTests; import org.eclipse.jdt.ui.tests.quickfix.QuickFixTest; import org.eclipse.jdt.ui.tests.search.SearchTest; @@ -67,6 +68,8 @@ addTest(JUnitJUnitTests.suite()); addTest(BuildpathModifierActionTest.suite()); + + addTest(JarExportTests.suite()); } } Index: ui/org/eclipse/jdt/ui/tests/jarexport/JarExportTests.java =================================================================== RCS file: ui/org/eclipse/jdt/ui/tests/jarexport/JarExportTests.java diff -N ui/org/eclipse/jdt/ui/tests/jarexport/JarExportTests.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/ui/tests/jarexport/JarExportTests.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2007 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.ui.tests.jarexport; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class JarExportTests { + + public static Test suite() { + TestSuite suite= new TestSuite("Test for org.eclipse.jdt.ui.tests.jarexport"); + //$JUnit-BEGIN$ + suite.addTest(FatJarExportTests.allTests()); + //$JUnit-END$ + return suite; + } +} Index: ui/org/eclipse/jdt/ui/tests/jarexport/FatJarExportTests.java =================================================================== RCS file: ui/org/eclipse/jdt/ui/tests/jarexport/FatJarExportTests.java diff -N ui/org/eclipse/jdt/ui/tests/jarexport/FatJarExportTests.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/ui/tests/jarexport/FatJarExportTests.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,311 @@ +/******************************************************************************* + * Copyright (c) 2007 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.ui.tests.jarexport; + +import java.io.File; +import java.util.zip.ZipFile; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; + +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; + +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; + +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil; +import org.eclipse.jdt.internal.ui.jarpackagerfat.FatJarBuilder; +import org.eclipse.jdt.internal.ui.jarpackagerfat.FatJarPackageWizardPage; +import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext; + +import org.eclipse.jdt.testplugin.JavaProjectHelper; +import org.eclipse.jdt.testplugin.JavaTestPlugin; + +import org.eclipse.jdt.ui.tests.core.ProjectTestSetup; + +public class FatJarExportTests extends TestCase { + + private static final Class THIS= FatJarExportTests.class; + + public static Test suite() { + return allTests(); + } + + public static Test allTests() { + return new ProjectTestSetup(new TestSuite(THIS)); + } + + private IJavaProject fProject; + private IPackageFragmentRoot fMainRoot; + + /** + * {@inheritDoc} + */ + protected void setUp() throws Exception { + fProject= ProjectTestSetup.getProject(); + + fMainRoot= JavaProjectHelper.addSourceContainer(fProject, "src"); + IPackageFragment fragment= fMainRoot.createPackageFragment("org.eclipse.jdt.ui.test", true, null); + StringBuffer buf= new StringBuffer(); + buf.append("package org.eclipse.jdt.ui.test;\n"); + buf.append("import mylib.Foo;\n"); + buf.append("public class Main {\n"); + buf.append(" public static void main(String[] args) {\n"); + buf.append(" new Foo();\n"); + buf.append(" new Foo.FooInner();\n"); + buf.append(" new Foo.FooInner.FooInnerInner();\n"); + buf.append(" }\n"); + buf.append("}\n"); + fragment.createCompilationUnit("Main.java", buf.toString(), true, null); + } + + /** + * {@inheritDoc} + */ + protected void tearDown() throws Exception { + JavaProjectHelper.clear(fProject, ProjectTestSetup.getDefaultClasspath()); + } + + private static String getFooContent() { + StringBuffer buf= new StringBuffer(); + buf.append("package mylib;\n"); + buf.append("public class Foo {\n"); + buf.append(" public static class FooInner {\n"); + buf.append(" public static class FooInnerInner {\n"); + buf.append(" }\n"); + buf.append(" }\n"); + buf.append("}\n"); + return buf.toString(); + } + + private static void assertFatJarExport(IJavaProject project, String archiveName) throws Exception { + //create class files + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null); + + IMarker[] markers= ResourcesPlugin.getWorkspace().getRoot().findMarkers(null, true, IResource.DEPTH_INFINITE); + for (int i= 0; i < markers.length; i++) { + IMarker marker= markers[i]; + if (marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO) == IMarker.SEVERITY_ERROR) { + assertTrue((String) marker.getAttribute(IMarker.MESSAGE), false); + } + } + + //create data + JarPackageData data= createJarPackageData(project, archiveName); + + //create archive + ZipFile generatedArchive= createArchive(data); + + //assert archive content as expected + assertNotNull(generatedArchive); + assertNotNull(generatedArchive.getEntry("org/eclipse/jdt/ui/test/Main.class")); + assertNotNull(generatedArchive.getEntry("mylib/Foo.class")); + assertNotNull(generatedArchive.getEntry("mylib/Foo$FooInner.class")); + assertNotNull(generatedArchive.getEntry("mylib/Foo$FooInner$FooInnerInner.class")); + } + + private static JarPackageData createJarPackageData(IJavaProject project, String archiveName) throws CoreException { + JarPackageData data= new JarPackageData(); + data.setJarBuilder(new FatJarBuilder()); + + IPath destination= ResourcesPlugin.getWorkspace().getRoot().getLocation().append(archiveName); + data.setJarLocation(destination); + + ILaunchConfiguration launchConfig= createTempLaunchConfig(project); + + MultiStatus status= new MultiStatus(JavaUI.ID_PLUGIN, 0, "", null); + Object[] children= FatJarPackageWizardPage.getSelectedElementsWithoutContainedChildren(launchConfig, data, new BusyIndicatorRunnableContext(), status); + assertTrue(getProblems(status), status.getSeverity() == IStatus.OK || status.getSeverity() == IStatus.INFO); + data.setElements(children); + return data; + } + + private static String getProblems(MultiStatus status) { + StringBuffer result= new StringBuffer(); + + IStatus[] children= status.getChildren(); + for (int i= 0; i < children.length; i++) { + result.append(children[i].getMessage()).append("\n"); + } + + return result.toString(); + } + + /* + * From org.eclipse.jdt.internal.debug.ui.launcher.JavaApplicationLaunchShortcut + * + * For internal use only (testing), clients must not call. + */ + public static ILaunchConfiguration createTempLaunchConfig(IJavaProject project) { + String projectName= project.getElementName(); + + String configname= "fatjar_cfg_eraseme_" + projectName; //$NON-NLS-1$ + ILaunchConfiguration config= null; + ILaunchConfigurationWorkingCopy wc= null; + try { + ILaunchManager launchManager= DebugPlugin.getDefault().getLaunchManager(); + ILaunchConfigurationType configType= launchManager.getLaunchConfigurationType(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION); + wc= configType.newInstance(null, launchManager.generateUniqueLaunchConfigurationNameFrom(configname)); + } catch (CoreException e) { + JavaPlugin.log(e); + return null; + } + + wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, "org.eclipse.jdt.ui.test.Main"); + wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName); + try { + config= wc.doSave(); + } catch (CoreException e) { + JavaPlugin.log(e); + } + + return config; + } + + private static ZipFile createArchive(JarPackageData data) throws Exception, CoreException { + IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + + IJarExportRunnable op= data.createJarExportRunnable(window.getShell()); + window.run(false, false, op); + + IStatus status= op.getStatus(); + if (status.getSeverity() == IStatus.ERROR) + throw new CoreException(status); + + return JarPackagerUtil.getArchiveFile(data.getJarLocation()); + } + + public void testExportSameSrcRoot() throws Exception { + IPackageFragment pack= fMainRoot.createPackageFragment("mylib", true, null); + try { + pack.createCompilationUnit("Foo.java", getFooContent(), true, null); + + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + pack.delete(true, null); + } + } + + public void testExportSrcRootWithOutputFolder() throws Exception { + IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(fProject, "other", new IPath[0], new IPath[0], "otherout"); + try { + IPackageFragment pack= root.createPackageFragment("mylib", true, null); + pack.createCompilationUnit("Foo.java", getFooContent(), true, null); + + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeSourceContainer(fProject, root.getElementName()); + } + } + + public void testExportOtherSrcRoot() throws Exception { + IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(fProject, "other"); + try { + IPackageFragment pack= root.createPackageFragment("mylib", true, null); + pack.createCompilationUnit("Foo.java", getFooContent(), true, null); + + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeSourceContainer(fProject, root.getElementName()); + } + } + + public void testExportOtherProject() throws Exception { + IJavaProject otherProject= JavaProjectHelper.createJavaProject("OtherProject", "bin"); + try { + otherProject.setRawClasspath(ProjectTestSetup.getDefaultClasspath(), null); + + IPackageFragmentRoot root= JavaProjectHelper.addSourceContainer(otherProject, "other"); + IPackageFragment pack= root.createPackageFragment("mylib", true, null); + pack.createCompilationUnit("Foo.java", getFooContent(), true, null); + + JavaProjectHelper.addRequiredProject(fProject, otherProject); + + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeFromClasspath(fProject, otherProject.getProject().getFullPath()); + JavaProjectHelper.delete(otherProject); + } + } + + public void testExportInternalLib() throws Exception { + File lib= JavaTestPlugin.getDefault().getFileInPlugin(JavaProjectHelper.MYLIB); + IPackageFragmentRoot root= JavaProjectHelper.addLibraryWithImport(fProject, Path.fromOSString(lib.getPath()), null, null); + + try { + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeFromClasspath(fProject, root.getPath()); + } + } + + public void testExportExternalLib() throws Exception { + File lib= JavaTestPlugin.getDefault().getFileInPlugin(JavaProjectHelper.MYLIB); + IPackageFragmentRoot root= JavaProjectHelper.addLibrary(fProject, Path.fromOSString(lib.getPath())); + + try { + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeFromClasspath(fProject, root.getPath()); + } + } + + public void testClassFolder() throws Exception { + File lib= JavaTestPlugin.getDefault().getFileInPlugin(JavaProjectHelper.MYLIB); + + IPackageFragmentRoot root= JavaProjectHelper.addClassFolderWithImport(fProject, "cf", null, null, lib); + try { + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeFromClasspath(fProject, root.getPath()); + } + } + + public void testVariable() throws Exception { + File lib= JavaTestPlugin.getDefault().getFileInPlugin(JavaProjectHelper.MYLIB); + JavaCore.setClasspathVariable("MYLIB", Path.fromOSString(lib.getPath()), null); + + JavaProjectHelper.addVariableEntry(fProject, new Path("MYLIB"), null, null); + try { + assertFatJarExport(fProject, getName() + ".jar"); + } finally { + JavaProjectHelper.removeFromClasspath(fProject, new Path("MYLIB")); + } + } +} #P org.eclipse.jdt.ui Index: plugin.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/plugin.properties,v retrieving revision 1.479 diff -u -r1.479 plugin.properties --- plugin.properties 19 Sep 2007 13:54:56 -0000 1.479 +++ plugin.properties 28 Sep 2007 15:58:35 -0000 @@ -189,6 +189,8 @@ jarExportWizard.label=JAR file jarExportWizard.description=Export resources into a JAR file on the local file system. +fatJarExportWizard.label=Runnable JAR file +fatJarExportWizard.description=Export all resources required to run an application into a JAR file on the local file system. createJarAction.label=Create &JAR createJarAction.tooltip=Creates the JAR Based on the Selected JAR Description File Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/plugin.xml,v retrieving revision 1.761 diff -u -r1.761 plugin.xml --- plugin.xml 19 Sep 2007 13:12:16 -0000 1.761 +++ plugin.xml 28 Sep 2007 15:58:37 -0000 @@ -1906,6 +1906,19 @@ class="org.eclipse.core.resources.IResource"> + + + %fatJarExportWizard.description + + + + Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWizardPage.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWizardPage.java,v retrieving revision 1.77 diff -u -r1.77 JarPackageWizardPage.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWizardPage.java 29 May 2007 18:41:48 -0000 1.77 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWizardPage.java 28 Sep 2007 15:58:38 -0000 @@ -10,7 +10,6 @@ *******************************************************************************/ package org.eclipse.jdt.internal.ui.jarpackager; -import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.Iterator; @@ -20,7 +19,6 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -36,10 +34,7 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.TreeItem; @@ -56,7 +51,6 @@ import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.dialogs.WizardExportResourcesPage; import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService; @@ -82,13 +76,12 @@ import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.filters.EmptyInnerPackageFilter; import org.eclipse.jdt.internal.ui.util.ExceptionHandler; -import org.eclipse.jdt.internal.ui.util.SWTUtil; import org.eclipse.jdt.internal.ui.viewsupport.LibraryFilter; /** * Page 1 of the JAR Package wizard */ -class JarPackageWizardPage extends WizardExportResourcesPage implements IJarPackageWizardPage { +class JarPackageWizardPage extends AbstractJarDestinationWizardPage { private JarPackageData fJarPackage; private IStructuredSelection fInitialSelection; @@ -101,9 +94,6 @@ private Button fExportRefactoringsCheckbox; private Link fRefactoringLink; - private Combo fDestinationNamesCombo; - private Button fDestinationBrowseButton; - private Button fCompressCheckbox; private Button fOverwriteCheckbox; private Button fIncludeDirectoryEntriesCheckbox; @@ -116,8 +106,6 @@ private static final String STORE_EXPORT_OUTPUT_FOLDERS= PAGE_NAME + ".EXPORT_OUTPUT_FOLDER"; //$NON-NLS-1$ private static final String STORE_EXPORT_JAVA_FILES= PAGE_NAME + ".EXPORT_JAVA_FILES"; //$NON-NLS-1$ - private static final String STORE_DESTINATION_NAMES= PAGE_NAME + ".DESTINATION_NAMES_ID"; //$NON-NLS-1$ - private static final String STORE_REFACTORINGS= PAGE_NAME + ".REFACTORINGS"; //$NON-NLS-1$ private static final String STORE_COMPRESS= PAGE_NAME + ".COMPRESS"; //$NON-NLS-1$ private final static String STORE_OVERWRITE= PAGE_NAME + ".OVERWRITE"; //$NON-NLS-1$ @@ -129,9 +117,12 @@ /** * Create an instance of this class + * + * @param jarPackage an object containing all required information to make an export + * @param selection the initial selection */ public JarPackageWizardPage(JarPackageData jarPackage, IStructuredSelection selection) { - super(PAGE_NAME, selection); + super(PAGE_NAME, selection, jarPackage); setTitle(JarPackagerMessages.JarPackageWizardPage_title); setDescription(JarPackagerMessages.JarPackageWizardPage_description); fJarPackage= jarPackage; @@ -207,39 +198,6 @@ } /** - * Answer the contents of the destination specification widget. If this - * value does not have the required suffix then add it first. - * - * @return java.lang.String - */ - protected String getDestinationValue() { - String destinationText= fDestinationNamesCombo.getText().trim(); - if (destinationText.indexOf('.') < 0) - destinationText += getOutputSuffix(); - return destinationText; - } - - /** - * Answer the string to display in self as the destination type - * - * @return java.lang.String - */ - protected String getDestinationLabel() { - return JarPackagerMessages.JarPackageWizardPage_destination_label; - } - - /** - * Answer the suffix that files exported from this wizard must have. - * If this suffix is a file extension (which is typically the case) - * then it must include the leading period character. - * - * @return java.lang.String - */ - protected String getOutputSuffix() { - return "." + JarPackagerUtil.JAR_EXTENSION; //$NON-NLS-1$ - } - - /** * Returns an iterator over this page's collection of currently-specified * elements to be exported. This is the primary element selection facility * accessor for subclasses. @@ -257,15 +215,10 @@ * internalSaveWidgetValues. */ public final void saveWidgetValues() { + super.saveWidgetValues(); // update directory names history IDialogSettings settings= getDialogSettings(); if (settings != null) { - String[] directoryNames= settings.getArray(STORE_DESTINATION_NAMES); - if (directoryNames == null) - directoryNames= new String[0]; - directoryNames= addToHistory(directoryNames, getDestinationValue()); - settings.put(STORE_DESTINATION_NAMES, directoryNames); - settings.put(STORE_EXPORT_CLASS_FILES, fJarPackage.areClassFilesExported()); settings.put(STORE_EXPORT_OUTPUT_FOLDERS, fJarPackage.areOutputFoldersExported()); settings.put(STORE_EXPORT_JAVA_FILES, fJarPackage.areJavaFilesExported()); @@ -298,21 +251,7 @@ fExportOutputFoldersCheckbox.setSelection(fJarPackage.areOutputFoldersExported()); fExportJavaFilesCheckbox.setSelection(fJarPackage.areJavaFilesExported()); - // destination - if (fJarPackage.getJarLocation().isEmpty()) - fDestinationNamesCombo.setText(""); //$NON-NLS-1$ - else - fDestinationNamesCombo.setText(fJarPackage.getJarLocation().toOSString()); - IDialogSettings settings= getDialogSettings(); - if (settings != null) { - String[] directoryNames= settings.getArray(STORE_DESTINATION_NAMES); - if (directoryNames == null) - return; // ie.- no settings stored - if (! fDestinationNamesCombo.getText().equals(directoryNames[0])) - fDestinationNamesCombo.add(fDestinationNamesCombo.getText()); - for (int i= 0; i < directoryNames.length; i++) - fDestinationNamesCombo.add(directoryNames[i]); - } + super.restoreWidgetValues(); // options if (fExportRefactoringsCheckbox != null) @@ -326,6 +265,8 @@ * Initializes the JAR package from last used wizard page values. */ protected void initializeJarPackage() { + super.initializeJarPackage(); + IDialogSettings settings= getDialogSettings(); if (settings != null) { // source @@ -339,12 +280,6 @@ fJarPackage.setCompress(settings.getBoolean(STORE_COMPRESS)); fJarPackage.setIncludeDirectoryEntries(settings.getBoolean(STORE_INCLUDE_DIRECTORY_ENTRIES)); fJarPackage.setOverwrite(settings.getBoolean(STORE_OVERWRITE)); - - // destination - String[] directoryNames= settings.getArray(STORE_DESTINATION_NAMES); - if (directoryNames == null) - return; // ie.- no settings stored - fJarPackage.setJarLocation(Path.fromOSString(directoryNames[0])); } } @@ -365,16 +300,7 @@ fJarPackage.setExportJavaFiles(fExportJavaFilesCheckbox.getSelection()); fJarPackage.setElements(getSelectedElements()); - // destination - String comboText= fDestinationNamesCombo.getText(); - IPath path= Path.fromOSString(comboText); - - if (path.segmentCount() > 0 && ensureTargetFileIsValid(path.toFile()) && path.getFileExtension() == null) - // append .jar - path= path.addFileExtension(JarPackagerUtil.JAR_EXTENSION); - - fJarPackage.setJarLocation(path); - + super.updateModel(); // options if (fExportRefactoringsCheckbox != null) fJarPackage.setRefactoringAware(fExportRefactoringsCheckbox.getSelection()); @@ -386,85 +312,6 @@ } /** - * Returns a boolean indicating whether the passed File handle is - * is valid and available for use. - * - * @return boolean - */ - protected boolean ensureTargetFileIsValid(File targetFile) { - if (targetFile.exists() && targetFile.isDirectory() && fDestinationNamesCombo.getText().length() > 0) { - setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_exportDestinationMustNotBeDirectory); - fDestinationNamesCombo.setFocus(); - return false; - } - if (targetFile.exists()) { - if (!targetFile.canWrite()) { - setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_jarFileExistsAndNotWritable); - fDestinationNamesCombo.setFocus(); - return false; - } - } - return true; - } - - /* - * Overrides method from WizardExportPage - */ - protected void createDestinationGroup(Composite parent) { - - initializeDialogUnits(parent); - - // destination specification group - Composite destinationSelectionGroup= new Composite(parent, SWT.NONE); - GridLayout layout= new GridLayout(); - layout.numColumns= 3; - destinationSelectionGroup.setLayout(layout); - destinationSelectionGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); - - new Label(destinationSelectionGroup, SWT.NONE).setText(getDestinationLabel()); - - // destination name entry field - fDestinationNamesCombo= new Combo(destinationSelectionGroup, SWT.SINGLE | SWT.BORDER); - fDestinationNamesCombo.addListener(SWT.Modify, this); - fDestinationNamesCombo.addListener(SWT.Selection, this); - GridData data= new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL); - data.widthHint= SIZING_TEXT_FIELD_WIDTH; - fDestinationNamesCombo.setLayoutData(data); - - // destination browse button - fDestinationBrowseButton= new Button(destinationSelectionGroup, SWT.PUSH); - fDestinationBrowseButton.setText(JarPackagerMessages.JarPackageWizardPage_browseButton_text); - fDestinationBrowseButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); - SWTUtil.setButtonDimensionHint(fDestinationBrowseButton); - fDestinationBrowseButton.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - handleDestinationBrowseButtonPressed(); - } - }); - } - - /** - * Open an appropriate destination browser so that the user can specify a source - * to import from - */ - protected void handleDestinationBrowseButtonPressed() { - FileDialog dialog= new FileDialog(getContainer().getShell(), SWT.SAVE); - dialog.setFilterExtensions(new String[] {"*.jar", "*.zip"}); //$NON-NLS-1$ //$NON-NLS-2$ - - String currentSourceString= getDestinationValue(); - int lastSeparatorIndex= currentSourceString.lastIndexOf(File.separator); - if (lastSeparatorIndex != -1) { - dialog.setFilterPath(currentSourceString.substring(0, lastSeparatorIndex)); - dialog.setFileName(currentSourceString.substring(lastSeparatorIndex + 1, currentSourceString.length())); - } - else - dialog.setFileName(currentSourceString); - String selectedFileName= dialog.open(); - if (selectedFileName != null) - fDestinationNamesCombo.setText(selectedFileName); - } - - /** * Returns the resource for the specified path. * * @param path the path for which the resource should be returned @@ -655,21 +502,6 @@ setErrorMessage(null); return complete; } - - /* - * Implements method from Listener - */ - public void handleEvent(Event e) { - if (getControl() == null) - return; - update(); - } - - protected void update() { - updateModel(); - updateWidgetEnablements(); - updatePageCompletion(); - } protected void updatePageCompletion() { boolean pageComplete= isPageComplete(); @@ -691,51 +523,6 @@ /* * Overrides method from WizardDataTransferPage */ - protected boolean validateDestinationGroup() { - if (fDestinationNamesCombo.getText().length() == 0) { - // Clear error - if (getErrorMessage() != null) - setErrorMessage(null); - if (getMessage() != null) - setMessage(null); - return false; - } - if (fJarPackage.getAbsoluteJarLocation().toString().endsWith("/")) { //$NON-NLS-1$ - setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_exportDestinationMustNotBeDirectory); - fDestinationNamesCombo.setFocus(); - return false; - } - // Check if the Jar is put into the workspace and conflicts with the containers - // exported. If the workspace isn't on the local files system we are fine since - // the Jar is always created in the local file system - IPath workspaceLocation= ResourcesPlugin.getWorkspace().getRoot().getLocation(); - if (workspaceLocation != null && workspaceLocation.isPrefixOf(fJarPackage.getAbsoluteJarLocation())) { - int segments= workspaceLocation.matchingFirstSegments(fJarPackage.getAbsoluteJarLocation()); - IPath path= fJarPackage.getAbsoluteJarLocation().removeFirstSegments(segments); - IResource resource= ResourcesPlugin.getWorkspace().getRoot().findMember(path); - if (resource != null && resource.getType() == IResource.FILE) { - // test if included - if (JarPackagerUtil.contains(JarPackagerUtil.asResources(fJarPackage.getElements()), (IFile)resource)) { - setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_cantExportJARIntoItself); - return false; - } - } - } - // Inform user about relative directory - String currentMessage= getMessage(); - if (!(new File(fDestinationNamesCombo.getText()).isAbsolute())) { - if (currentMessage == null) - setMessage(JarPackagerMessages.JarPackageWizardPage_info_relativeExportDestination, IMessageProvider.INFORMATION); - } else { - if (currentMessage != null) - setMessage(null); - } - return ensureTargetFileIsValid(fJarPackage.getAbsoluteJarLocation().toFile()); - } - - /* - * Overrides method from WizardDataTransferPage - */ protected boolean validateOptionsGroup() { return true; } @@ -799,13 +586,6 @@ return null; } - /** - * Set the current input focus to self's destination entry field - */ - protected void giveFocusToDestination() { - fDestinationNamesCombo.setFocus(); - } - /* * Overrides method from WizardExportResourcePage */ @@ -849,13 +629,6 @@ } /* - * Implements method from IJarPackageWizardPage. - */ - public void finish() { - saveWidgetValues(); - } - - /* * Method declared on IWizardPage. */ public void setPreviousPage(IWizardPage page) { Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerUtil.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerUtil.java,v retrieving revision 1.26 diff -u -r1.26 JarPackagerUtil.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerUtil.java 8 Jun 2006 16:14:26 -0000 1.26 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerUtil.java 28 Sep 2007 15:58:38 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 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 @@ -13,20 +13,28 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.jar.JarEntry; import java.util.zip.CRC32; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; @@ -107,14 +115,15 @@ * Computes and returns the elements as resources. * The underlying resource is used for Java elements. * + * @param elements elements for which to retrieve the resources from * @return a List with the selected resources */ - public static List asResources(Object[] fSelectedElements) { - if (fSelectedElements == null) + public static List asResources(Object[] elements) { + if (elements == null) return null; - List selectedResources= new ArrayList(fSelectedElements.length); - for (int i= 0; i < fSelectedElements.length; i++) { - Object element= fSelectedElements[i]; + List selectedResources= new ArrayList(elements.length); + for (int i= 0; i < elements.length; i++) { + Object element= elements[i]; if (element instanceof IJavaElement) { selectedResources.add(((IJavaElement)element).getResource()); } @@ -133,6 +142,7 @@ /** * Gets the name of the manifest's main class * + * @param jarPackage * @return a string with the name */ static String getMainClassName(JarPackageData jarPackage) { @@ -171,8 +181,10 @@ } /** - * Tells whether the specified manifest main class is valid. + * Tells whether the specified manifest main class is valid.\ * + * @param data + * @param context * @return true if a main class is specified and valid */ public static boolean isMainClassValid(JarPackageData data, IRunnableContext context) { @@ -257,4 +269,45 @@ entry.setSize(size); entry.setCrc(crc.getValue()); } + + /** + * The archive file at the given location + * + * @param location + * the location of the archive file + * @return the archive or null if it could not be retrieved + * @throws CoreException + * if the archive could not be read + * + * @since 3.4 + */ + public static ZipFile getArchiveFile(IPath location) throws CoreException { + File localFile= null; + + IResource file= ResourcesPlugin.getWorkspace().getRoot().findMember(location); + if (file != null) { + // internal resource + URI fileLocation= file.getLocationURI(); + + IFileStore fileStore= EFS.getStore(fileLocation); + localFile= fileStore.toLocalFile(EFS.NONE, null); + if (localFile == null) + // non local file system + localFile= fileStore.toLocalFile(EFS.CACHE, null); + } else { + // external resource -> it is ok to use toFile() + localFile= location.toFile(); + } + + if (localFile == null) + return null; + + try { + return new ZipFile(localFile); + } catch (ZipException e) { + throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, e.getLocalizedMessage(), e)); + } catch (IOException e) { + throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, e.getLocalizedMessage(), e)); + } + } } \ No newline at end of file Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.java,v retrieving revision 1.16 diff -u -r1.16 JarPackagerMessages.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.java 18 Apr 2006 16:27:32 -0000 1.16 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.java 28 Sep 2007 15:58:38 -0000 @@ -248,6 +248,8 @@ public static String JarPackageReader_error_tagPathNotFound; + public static String JarPackageReader_error_unknownJarBuilder; + public static String JarPackageReader_jarPackageReaderWarnings; public static String JarPackageReader_warning_javaElementDoesNotExist; Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarFileExportOperation.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarFileExportOperation.java,v retrieving revision 1.100 diff -u -r1.100 JarFileExportOperation.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarFileExportOperation.java 23 Aug 2007 13:48:47 -0000 1.100 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarFileExportOperation.java 28 Sep 2007 15:58:37 -0000 @@ -29,8 +29,10 @@ import java.util.Set; import java.util.jar.Manifest; import java.util.zip.ZipException; +import java.util.zip.ZipFile; import org.eclipse.core.filesystem.EFS; + import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -76,7 +78,6 @@ import org.eclipse.jdt.ui.jarpackager.IJarDescriptionWriter; import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable; import org.eclipse.jdt.ui.jarpackager.JarPackageData; -import org.eclipse.jdt.ui.jarpackager.JarWriter3; import org.eclipse.jdt.internal.ui.IJavaStatusConstants; import org.eclipse.jdt.internal.ui.JavaPlugin; @@ -100,7 +101,7 @@ } } - private JarWriter3 fJarWriter; + private JarBuilder fJarBuilder; private JarPackageData fJarPackage; private JarPackageData[] fJarPackages; private Shell fParentShell; @@ -206,9 +207,21 @@ continue; } - // Should not happen since we only export source files - if (resource == null) + if (resource == null) { + if (element instanceof IPackageFragmentRoot) { + IPackageFragmentRoot root= (IPackageFragmentRoot) element; + if (root.isArchive()) { + try { + ZipFile file= JarPackagerUtil.getArchiveFile(root.getPath()); + if (file != null) + count+= file.size(); + } catch (CoreException e) { + JavaPlugin.log(e); + } + } + } continue; + } } else resource= (IResource)element; @@ -340,8 +353,10 @@ } private void exportJavaElement(IProgressMonitor progressMonitor, IJavaElement je) throws InterruptedException { - if (je.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT && ((IPackageFragmentRoot)je).isArchive()) + if (je.getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT && ((IPackageFragmentRoot)je).isArchive()) { + fJarBuilder.addJar((IPackageFragmentRoot) je, progressMonitor); return; + } Object[] children= fJavaElementContentProvider.getChildren(je); for (int i= 0; i < children.length; i++) @@ -365,7 +380,7 @@ try { IPath destinationPath= resource.getFullPath().removeFirstSegments(leadingSegmentsToRemove); progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, destinationPath.toString())); - fJarWriter.write((IFile)resource, destinationPath); + fJarBuilder.addFile((IFile)resource, destinationPath); } catch (CoreException ex) { Throwable realEx= ex.getStatus().getException(); if (realEx instanceof ZipException && realEx.getMessage() != null && realEx.getMessage().startsWith("duplicate entry:")) //$NON-NLS-1$ @@ -428,7 +443,7 @@ || (fJarPackage.areJavaFilesExported() && (isNonJavaResource || (pkgRoot != null && !isClassFile(resource)) || (isInClassFolder && isClassFile(resource) && !fJarPackage.areClassFilesExported())))) { try { progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, destinationPath.toString())); - fJarWriter.write((IFile) resource, destinationPath); + fJarBuilder.addFile((IFile)resource, destinationPath); } catch (CoreException ex) { Throwable realEx= ex.getStatus().getException(); if (realEx instanceof ZipException && realEx.getMessage() != null && realEx.getMessage().startsWith("duplicate entry:")) //$NON-NLS-1$ @@ -462,7 +477,7 @@ IFile file= (IFile)iter.next(); IPath classFilePath= baseDestinationPath.append(file.getName()); progressMonitor.subTask(Messages.format(JarPackagerMessages.JarFileExportOperation_exporting, classFilePath.toString())); - fJarWriter.write(file, classFilePath); + fJarBuilder.addFile(file, classFilePath); } } catch (CoreException ex) { addToStatus(ex); @@ -857,8 +872,11 @@ buildProjects(subProgressMonitor); } else progressMonitor.beginTask("", totalWork); //$NON-NLS-1$ - - fJarWriter= fJarPackage.createJarWriter3(fParentShell); + + fJarBuilder = fJarPackage.getJarBuilder(); + fJarPackage.setManifestProvider(fJarBuilder.getManifestProvider()); + fJarBuilder.open(fJarPackage, fParentShell, fStatus); + exportSelectedElements(progressMonitor); if (getStatus().getSeverity() != IStatus.ERROR) { progressMonitor.subTask(JarPackagerMessages.JarFileExportOperation_savingFiles); @@ -868,8 +886,8 @@ addToStatus(ex); } finally { try { - if (fJarWriter != null) - fJarWriter.close(); + if (fJarBuilder != null) + fJarBuilder.close(); } catch (CoreException ex) { addToStatus(ex); } Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.properties,v retrieving revision 1.58 diff -u -r1.58 JarPackagerMessages.properties --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.properties 5 Jun 2007 11:40:50 -0000 1.58 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackagerMessages.properties 28 Sep 2007 15:58:38 -0000 @@ -118,6 +118,7 @@ JarPackageReader_error_illegalValueForBooleanAttribute= Invalid format. The value for a boolean attribute is invalid. JarPackageReader_error_tagNameNotFound= Invalid format. The tag 'name' cannot be found. JarPackageReader_error_tagPathNotFound= Invalid format. The tag 'path' cannot be found. +JarPackageReader_error_unknownJarBuilder=Jar builder ''{0}'' is unkown JarPackageReader_error_tagHandleIdentifierNotFoundOrEmpty= Invalid format: The tag 'handleIdentifier' cannot be found or is empty. JarPackageReader_warning_javaElementDoesNotExist= Warning: Java element does not exist in workspace JarPackageReader_error_duplicateTag= Invalid format. {0} is a duplicate tag. Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageReader.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageReader.java,v retrieving revision 1.38 diff -u -r1.38 JarPackageReader.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageReader.java 31 Aug 2006 09:59:16 -0000 1.38 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageReader.java 28 Sep 2007 15:58:37 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 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 @@ -23,11 +23,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IFolder; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; - import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -36,6 +31,10 @@ import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; @@ -43,12 +42,6 @@ import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService; import org.eclipse.ltk.core.refactoring.history.RefactoringHistory; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; @@ -59,8 +52,15 @@ import org.eclipse.jdt.ui.jarpackager.IJarDescriptionReader; import org.eclipse.jdt.ui.jarpackager.JarPackageData; -import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.IJavaStatusConstants; +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.jarpackagerfat.FatJarBuilder; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; /** * Reads data from an InputStream and returns a JarPackage @@ -74,6 +74,7 @@ /** * Reads a Jar Package from the underlying stream. * It is the client's responsibility to close the stream. + * @param inputStream */ public JarPackageReader(InputStream inputStream) { Assert.isNotNull(inputStream); @@ -139,6 +140,9 @@ if (jarPackage.areGeneratedFilesExported()) xmlReadManifest(jarPackage, element); xmlReadSelectedElements(jarPackage, element); + + // fatjar read builder props + xmlReadFatjar(jarPackage, element); } return jarPackage; } @@ -403,4 +407,19 @@ protected void addWarning(String message, Throwable error) { fWarnings.add(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), 0, message, error)); } + + private void xmlReadFatjar(JarPackageData jarPackage, Element element) throws java.io.IOException { + if (element.getNodeName().equals("fatjar")) { //$NON-NLS-1$ + String id = element.getAttribute("builder"); //$NON-NLS-1$ + if (FatJarBuilder.BUILDER_ID.equals(id)) { + jarPackage.setJarBuilder(new FatJarBuilder()); + } else if (PlainJarBuilder.BUILDER_ID.equals(id)) { + //the default anyway + } else { + throw new IOException(Messages.format(JarPackagerMessages.JarPackageReader_error_unknownJarBuilder, id)); + } + jarPackage.setLaunchConfigurationName(element.getAttribute("launchConfig")); //$NON-NLS-1$ + } + } + } Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWriter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWriter.java,v retrieving revision 1.37 diff -u -r1.37 JarPackageWriter.java --- ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWriter.java 31 Aug 2006 09:59:16 -0000 1.37 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarPackageWriter.java 28 Sep 2007 15:58:38 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 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 @@ -34,7 +34,6 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; - import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy; @@ -64,6 +63,9 @@ /** * Create a JarPackageWriter on the given output stream. * It is the clients responsibility to close the output stream. + * + * @param outputStream + * @param encoding */ public JarPackageWriter(OutputStream outputStream, String encoding) { Assert.isNotNull(outputStream); @@ -84,6 +86,7 @@ * Writes a XML representation of the JAR specification * to to the underlying stream. * + * @param jarPackage * @exception IOException if writing to the underlying stream fails */ public void writeXML(JarPackageData jarPackage) throws IOException { @@ -109,6 +112,8 @@ xmlWriteManifest(jarPackage, document, xmlJarDesc); xmlWriteSelectedElements(jarPackage, document, xmlJarDesc); + xmlWriteFatjar(jarPackage, document, xmlJarDesc); + try { // Write the document to the stream Transformer transformer=TransformerFactory.newInstance().newTransformer(); @@ -285,4 +290,11 @@ public IStatus getStatus() { return new Status(IStatus.OK, JavaPlugin.getPluginId(), 0, "", null); //$NON-NLS-1$ } + + private void xmlWriteFatjar(JarPackageData jarPackage, Document document, Element xmlJarDesc) throws DOMException { + Element fatjar= document.createElement("fatjar"); //$NON-NLS-1$ + xmlJarDesc.appendChild(fatjar); + fatjar.setAttribute("builder", jarPackage.getJarBuilder().getId()); //$NON-NLS-1$ + fatjar.setAttribute("launchConfig", jarPackage.getLaunchConfigurationName()); //$NON-NLS-1$ + } } Index: ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java,v retrieving revision 1.128 diff -u -r1.128 JavaPluginImages.java --- ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java 23 Aug 2007 10:44:59 -0000 1.128 +++ ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java 28 Sep 2007 15:58:37 -0000 @@ -394,6 +394,7 @@ public static final ImageDescriptor DESC_WIZBAN_REFACTOR_PULL_UP= createUnManaged(T_WIZBAN, "pullup_wiz.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_WIZBAN_REFACTOR_FIX_DEPRECATION= createUnManaged(T_WIZBAN, "fixdepr_wiz.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_WIZBAN_JAR_PACKAGER= createUnManaged(T_WIZBAN, "jar_pack_wiz.png"); //$NON-NLS-1$ + public static final ImageDescriptor DESC_WIZBAN_FAT_JAR_PACKAGER= createUnManaged(T_WIZBAN, "fatjar_pack_wiz.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_WIZBAN_REFACTOR_EXTRACT_SUPERTYPE= createUnManaged(T_WIZBAN, "extractsupertype_wiz.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_WIZBAN_REPLACE_JAR= createUnManaged(T_WIZBAN, "replacejar_wiz.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_WIZBAN_JAVA_WORKINGSET= createUnManaged(T_WIZBAN, "java_workingset_wiz.png");//$NON-NLS-1$ Index: ui/org/eclipse/jdt/ui/jarpackager/JarWriter3.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/jarpackager/JarWriter3.java,v retrieving revision 1.19 diff -u -r1.19 JarWriter3.java --- ui/org/eclipse/jdt/ui/jarpackager/JarWriter3.java 31 Aug 2006 09:59:17 -0000 1.19 +++ ui/org/eclipse/jdt/ui/jarpackager/JarWriter3.java 28 Sep 2007 15:58:38 -0000 @@ -50,7 +50,6 @@ import org.eclipse.swt.widgets.Shell; - import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy; @@ -162,6 +161,7 @@ * * @throws IOException * if an I/O error has occurred + * @throws CoreException */ protected void addDirectories(IResource resource, IPath destinationPath) throws IOException, CoreException { IContainer parent= null; @@ -250,6 +250,51 @@ // fJarOutputStream.closeEntry(); } } + + /** + * Creates a new JarEntry with the passed path and contents, and writes it + * to the current archive. + * + * @param contentStream the content to write + * @param path the path inside the archive + * + * @throws IOException if an I/O error has occurred + * @throws CoreException if the resource can-t be accessed + * + * @since 3.4 + */ + public void addStream(InputStream contentStream, String path) throws IOException, CoreException { + JarEntry newEntry= new JarEntry(path.replace(File.separatorChar, '/')); + byte[] readBuffer= new byte[4096]; + + if (fJarPackage.isCompressed()) + newEntry.setMethod(ZipEntry.DEFLATED); + // Entry is filled automatically. + else { + newEntry.setMethod(ZipEntry.STORED); + // JarPackagerUtil.calculateCrcAndSize(newEntry, resource.getContents(false), readBuffer); + } + + long lastModified= System.currentTimeMillis(); + + // Set modification time + newEntry.setTime(lastModified); + + try { + fJarOutputStream.putNextEntry(newEntry); + int count; + while ((count= contentStream.read(readBuffer, 0, readBuffer.length)) != -1) + fJarOutputStream.write(readBuffer, 0, count); + } finally { + /* + * Commented out because some JREs throw an NPE if a stream + * is closed twice. This works because + * a) putNextEntry closes the previous entry + * b) closing the stream closes the last entry + */ + // fJarOutputStream.closeEntry(); + } + } /** * Creates a new JAR file entry containing the refactoring history. @@ -427,6 +472,7 @@ * if the meta file could not be found * @throws IOException * if an input/output error occurs + * @throws CoreException */ private void writeMetaData(final JarPackageData data, final File file, final IPath path) throws FileNotFoundException, IOException, CoreException { Assert.isNotNull(data); Index: ui/org/eclipse/jdt/ui/jarpackager/JarPackageData.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/jarpackager/JarPackageData.java,v retrieving revision 1.42 diff -u -r1.42 JarPackageData.java --- ui/org/eclipse/jdt/ui/jarpackager/JarPackageData.java 22 Jun 2006 09:14:49 -0000 1.42 +++ ui/org/eclipse/jdt/ui/jarpackager/JarPackageData.java 28 Sep 2007 15:58:38 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2006 IBM Corporation and others. + * Copyright (c) 2000, 2007 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 @@ -13,15 +13,15 @@ import java.io.InputStream; import java.io.OutputStream; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; - import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; + import org.eclipse.swt.widgets.Shell; import org.eclipse.jface.operation.IRunnableContext; @@ -31,13 +31,14 @@ import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IType; - import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.jarpackager.JarBuilder; import org.eclipse.jdt.internal.ui.jarpackager.JarFileExportOperation; import org.eclipse.jdt.internal.ui.jarpackager.JarPackageReader; import org.eclipse.jdt.internal.ui.jarpackager.JarPackageWriter; import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil; import org.eclipse.jdt.internal.ui.jarpackager.ManifestProvider; +import org.eclipse.jdt.internal.ui.jarpackager.PlainJarBuilder; import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext; /** @@ -144,10 +145,17 @@ // The refactoring descriptors to export private RefactoringDescriptorProxy[] fRefactoringDescriptors= {}; + // Builder used by the JarFileExportOperation to build the jar file + private JarBuilder fJarBuilder; + + // The launch configuration used by the fat jar builder to determine dependencies + private String fLaunchConfigurationName; + /** * Creates a new Jar Package Data structure */ public JarPackageData() { + setJarBuilder(new PlainJarBuilder()); setExportClassFiles(true); setExportOutputFolders(false); setUseSourceFolderHierarchy(false); @@ -1162,4 +1170,47 @@ public void setExportStructuralOnly(boolean structural) { fRefactoringStructural= structural; } + + /** + * Returns the jar builder to use to build the jar described by this package data. + * + * @return the builder to use + * @since 3.4 + */ + public JarBuilder getJarBuilder() { + return fJarBuilder; + } + + /** + * Set the jar builder to use to build the jar. + * + * @param jarBuilder + * the builder to use + * @since 3.4 + */ + public void setJarBuilder(JarBuilder jarBuilder) { + fJarBuilder= jarBuilder; + } + + /** + * Get the name of the launch configuration from which to create an executable jar. + * + * @return the name of the launch configuration + * @since 3.4 + */ + public String getLaunchConfigurationName() { + return fLaunchConfigurationName; + } + + /** + * Set the name of the launch configuration form which to create an executable jar. + * + * @param name + * name of the launch configuration + * @since 3.4 + */ + public void setLaunchConfigurationName(String name) { + fLaunchConfigurationName= name; + } + } Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/META-INF/MANIFEST.MF,v retrieving revision 1.56 diff -u -r1.56 MANIFEST.MF --- META-INF/MANIFEST.MF 4 Sep 2007 08:40:24 -0000 1.56 +++ META-INF/MANIFEST.MF 28 Sep 2007 15:58:37 -0000 @@ -40,7 +40,7 @@ org.eclipse.jdt.internal.corext.refactoring.util;x-internal:=true, org.eclipse.jdt.internal.corext.template.java;x-internal:=true, org.eclipse.jdt.internal.corext.util;x-friends:="org.eclipse.jdt.junit", - org.eclipse.jdt.internal.ui;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui", + org.eclipse.jdt.internal.ui;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui", org.eclipse.jdt.internal.ui.actions;x-friends:="org.eclipse.jdt.junit", org.eclipse.jdt.internal.ui.browsing;x-internal:=true, org.eclipse.jdt.internal.ui.callhierarchy;x-internal:=true, @@ -53,6 +53,7 @@ org.eclipse.jdt.internal.ui.infoviews;x-internal:=true, org.eclipse.jdt.internal.ui.jarimport;x-internal:=true, org.eclipse.jdt.internal.ui.jarpackager;x-internal:=true, + org.eclipse.jdt.internal.ui.jarpackagerfat;x-internal:=true, org.eclipse.jdt.internal.ui.javadocexport;x-internal:=true, org.eclipse.jdt.internal.ui.javaeditor;x-friends:="org.eclipse.jdt.junit", org.eclipse.jdt.internal.ui.javaeditor.saveparticipant;x-internal:=true, @@ -87,9 +88,9 @@ org.eclipse.jdt.internal.ui.text.template.contentassist;x-internal:=true, org.eclipse.jdt.internal.ui.text.template.preferences;x-internal:=true, org.eclipse.jdt.internal.ui.typehierarchy;x-internal:=true, - org.eclipse.jdt.internal.ui.util;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui", + org.eclipse.jdt.internal.ui.util;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui", org.eclipse.jdt.internal.ui.viewsupport;x-friends:="org.eclipse.jdt.junit", - org.eclipse.jdt.internal.ui.wizards;x-friends:="org.eclipse.jdt.junit, org.eclipse.jdt.apt.ui", + org.eclipse.jdt.internal.ui.wizards;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.apt.ui", org.eclipse.jdt.internal.ui.wizards.buildpaths;x-internal:=true, org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage;x-internal:=true, org.eclipse.jdt.internal.ui.wizards.dialogfields;x-friends:="org.eclipse.jdt.apt.ui", Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperties.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperties.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperties.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperties.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * TODO: Remove, not used? + * @since 3.4 + */ +public class JarBuilderProperties { + + private JarBuilderProperty[] fProperties; + + public JarBuilderProperties(JarBuilderProperty[] properties) { + fProperties= properties; + } + + public JarBuilderProperty[] getProperties() { + return fProperties; + } + + public String xmlExport() throws IOException { + + String result; + DocumentBuilder docBuilder= null; + DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + try { + docBuilder= factory.newDocumentBuilder(); + } catch (ParserConfigurationException ex) { + throw new IOException(FatJarPackagerMessages.JarWriter_error_couldNotGetXmlBuilder); + } + Document document= docBuilder.newDocument(); + + xmlExport(document, null); + + try { + // Write the document to the stream + Transformer transformer= TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$ + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$ + DOMSource source= new DOMSource(document); + StringWriter writer= new StringWriter(); + StreamResult strResult= new StreamResult(writer); + transformer.transform(source, strResult); + result= writer.toString(); + } catch (TransformerException e) { + throw new IOException(FatJarPackagerMessages.JarWriter_error_couldNotTransformToXML); + } + + return result.trim(); + } + + public void xmlExport(Document document, Element parent) { + // Create the document + Element xmlProps= document.createElement("props"); //$NON-NLS-1$ + if (parent == null) { + document.appendChild(xmlProps); + } else { + parent.appendChild(xmlProps); + } + + for (int i= 0; i < fProperties.length; i++) { + JarBuilderProperty property= fProperties[i]; + xmlProps.setAttribute(property.getName(), property.getValue()); + } + + } + + public void xmlImport(String propertiesImportData) throws IOException { + + DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); + factory.setValidating(false); + DocumentBuilder parser= null; + Element xmlProps= null; + try { + parser= factory.newDocumentBuilder(); + StringReader reader= new StringReader(propertiesImportData); + xmlProps= parser.parse(new InputSource(reader)).getDocumentElement(); + } catch (ParserConfigurationException ex) { + throw new IOException(ex.getLocalizedMessage()); + } catch (SAXException ex) { + throw new IOException(ex.getLocalizedMessage()); + } finally { + } + xmlImport(xmlProps); + } + + public void xmlImport(Element xmlProps) throws IOException { + + if (!xmlProps.getNodeName().equals("props")) { //$NON-NLS-1$ + throw new IOException("invalid XML format "); //$NON-NLS-1$ + } + NamedNodeMap map= xmlProps.getAttributes(); + for (int j= 0; j < map.getLength(); j++) { + Node item= map.item(j); + String name= item.getNodeName(); + String value= item.getNodeValue(); + setProperty(name, value); + } + } + + + private boolean setProperty(String name, String value) { + boolean result= false; + for (int i= 0; i < fProperties.length; i++) { + JarBuilderProperty property= fProperties[i]; + if (name.equals(property.getName())) { + property.setValue(value); + result= true; + break; + } + } + return result; + } + + public String toString() { + String result; + try { + result= xmlExport(); + } catch (IOException e) { + result= "" + e.getLocalizedMessage() + ""; //$NON-NLS-1$ //$NON-NLS-2$ + } + return result; + } + + public JarBuilderProperty getProperty(String propertyName) { + JarBuilderProperty result= null; + JarBuilderProperty[] props= getProperties(); + for (int i= 0; i < props.length; i++) { + if (propertyName.equals(props[i].getName())) { + result= props[i]; + break; + } + } + return result; + } + +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizardPage.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizardPage.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizardPage.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizardPage.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,514 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.viewers.IStructuredSelection; + +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfiguration; + +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchScope; + +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; +import org.eclipse.jdt.launching.IRuntimeClasspathEntry; +import org.eclipse.jdt.launching.JavaRuntime; + +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.jarpackager.AbstractJarDestinationWizardPage; +import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil; +import org.eclipse.jdt.internal.ui.search.JavaSearchScopeFactory; +import org.eclipse.jdt.internal.ui.util.MainMethodSearchEngine; + +/** + * First page for the runnable jar export wizard + * @since 3.4 + */ +public class FatJarPackageWizardPage extends AbstractJarDestinationWizardPage implements Listener { + + private abstract static class LaunchConfigurationElement { + + public abstract ILaunchConfiguration getLaunchConfiguration(); + + public abstract String getLaunchConfigurationName(); + + public void dispose() { + //do nothing + } + } + + private static class ExistingLaunchConfigurationElement extends LaunchConfigurationElement { + + private ILaunchConfiguration fLaunchConfiguration; + private final String fProjectName; + + public ExistingLaunchConfigurationElement(ILaunchConfiguration launchConfiguration, String projectName) { + fLaunchConfiguration= launchConfiguration; + fProjectName= projectName; + } + + /** + * {@inheritDoc} + */ + public ILaunchConfiguration getLaunchConfiguration() { + return fLaunchConfiguration; + } + + /** + * {@inheritDoc} + */ + public String getLaunchConfigurationName() { + return fProjectName + " : " + fLaunchConfiguration.getName(); //$NON-NLS-1$ + } + + } + + private static final String PAGE_NAME= "FatJarPackageWizardPage"; //$NON-NLS-1$ + private static final String STORE_LAUNCH_CONFIGURATION_SELECTION_NAME= PAGE_NAME + ".LAUNCH_CONFIGURATION_SELECTION_NAME"; //$NON-NLS-1$ + private static final String STORE_DESTINATION_ELEMENT= PAGE_NAME + ".DESTINATION_PATH_SELECTION"; //$NON-NLS-1$ + + private final JarPackageData fJarPackage; + /** + * Model for the launch combo box. Element: {@link LaunchConfigurationElement} + */ + private final ArrayList fLauchConfigurationModel; + + private Combo fLaunchConfigurationCombo; + + public FatJarPackageWizardPage(JarPackageData jarPackage, IStructuredSelection selection) { + super(PAGE_NAME, selection, jarPackage); + setTitle(FatJarPackagerMessages.JarPackageWizardPage_title); + setDescription(FatJarPackagerMessages.FatJarPackageWizardPage_description); + fJarPackage= jarPackage; + fLauchConfigurationModel= new ArrayList(); + } + + /** + * {@inheritDoc} + */ + public void createControl(Composite parent) { + Composite composite= new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + composite.setLayout(new GridLayout(1, false)); + + Label description= new Label(composite, SWT.NONE); + GridData gridData= new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + description.setLayoutData(gridData); + description.setText(FatJarPackagerMessages.FatJarPackageWizardPage_launchConfigGroupTitle); + + createLaunchConfigSelectionGroup(composite); + + Label label= new Label(composite, SWT.NONE); + label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + label.setText(FatJarPackagerMessages.FatJarPackageWizardPage_destinationGroupTitle); + + createDestinationGroup(composite); + + restoreWidgetValues(); + + update(); + + Dialog.applyDialogFont(composite); + setControl(composite); + } + + protected String getDestinationLabel() { + return null; + } + + private void createLaunchConfigSelectionGroup(Composite parent) { + Composite composite= new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + composite.setLayout(new GridLayout(1, false)); + + fLaunchConfigurationCombo= new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY); + fLaunchConfigurationCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + fLauchConfigurationModel.addAll(Arrays.asList(getLaunchConfigurations())); + String[] names= new String[fLauchConfigurationModel.size()]; + for (int i= 0, size= fLauchConfigurationModel.size(); i < size; i++) { + LaunchConfigurationElement element= (LaunchConfigurationElement) fLauchConfigurationModel.get(i); + names[i]= element.getLaunchConfigurationName(); + } + fLaunchConfigurationCombo.setItems(names); + + fLaunchConfigurationCombo.addListener(SWT.Selection, this); + fLaunchConfigurationCombo.addListener(SWT.Modify, this); + } + + protected void updateWidgetEnablements() { + } + + public boolean isPageComplete() { + boolean complete= validateDestinationGroup(); + complete= validateLaunchConfigurationGroup() && complete; + if (complete) + setErrorMessage(null); + return complete; + } + + private boolean validateLaunchConfigurationGroup() { + return fLaunchConfigurationCombo.getSelectionIndex() != -1; + } + + private LaunchConfigurationElement[] getLaunchConfigurations() { + ArrayList result= new ArrayList(); + + try { + ILaunchConfiguration[] launchconfigs= DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations(); + + for (int i= 0; i < launchconfigs.length; i++) { + ILaunchConfiguration launchconfig= launchconfigs[i]; + + String projectName= launchconfig.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$ + result.add(new ExistingLaunchConfigurationElement(launchconfig, projectName)); + } + } catch (CoreException e) { + JavaPlugin.log(e); + } + + return (LaunchConfigurationElement[]) result.toArray(new LaunchConfigurationElement[result.size()]); + } + + public Object[] getSelectedElementsWithoutContainedChildren(MultiStatus status) { + try { + LaunchConfigurationElement element= (LaunchConfigurationElement) fLauchConfigurationModel.get(fLaunchConfigurationCombo.getSelectionIndex()); + ILaunchConfiguration launchconfig= element.getLaunchConfiguration(); + fJarPackage.setLaunchConfigurationName(element.getLaunchConfigurationName()); + + return getSelectedElementsWithoutContainedChildren(launchconfig, fJarPackage, getContainer(), status); + } catch (CoreException e) { + JavaPlugin.log(e); + } + + return null; + } + + private static IJavaProject[] getProjectSearchOrder(String projectName) { + + ArrayList projectNames= new ArrayList(); + projectNames.add(projectName); + + int nextProject= 0; + while (nextProject < projectNames.size()) { + String nextProjectName= (String) projectNames.get(nextProject); + IJavaProject jproject= getJavaProject(nextProjectName); + + if (jproject != null) { + try { + String[] childProjectNames= jproject.getRequiredProjectNames(); + for (int i= 0; i < childProjectNames.length; i++) { + if (!projectNames.contains(childProjectNames[i])) { + projectNames.add(childProjectNames[i]); + } + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } + } + nextProject+= 1; + } + + ArrayList result= new ArrayList(); + for (int i= 0, size= projectNames.size(); i < size; i++) { + String name= (String) projectNames.get(i); + IJavaProject project= getJavaProject(name); + if (project != null) + result.add(project); + } + + return (IJavaProject[]) result.toArray(new IJavaProject[result.size()]); + } + + private static IJavaProject getJavaProject(String projectName) { + IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + if (project == null) + return null; + + IJavaProject result= JavaCore.create(project); + if (result == null) + return null; + + if (!result.exists()) + return null; + + return result; + } + + private static IPath[] getClasspath(ILaunchConfiguration configuration, MultiStatus status) throws CoreException { + IRuntimeClasspathEntry[] entries= JavaRuntime.computeUnresolvedRuntimeClasspath(configuration); + entries= JavaRuntime.resolveRuntimeClasspath(entries, configuration); + + HashSet userEntries= new HashSet(entries.length); + for (int i= 0; i < entries.length; i++) { + if (entries[i].getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) { + + String location= entries[i].getLocation(); + if (location != null) { + IPath entry= Path.fromOSString(location); + if (userEntries.contains(entry)) { + String message= Messages.format("The selected launch configuration resolves to the duplicate runtime classpath entries at ''{0}'': Check your classpath settings and remove the duplicate entries.", entry); + status.add(new Status(IStatus.WARNING, JavaUI.ID_PLUGIN, message)); + } else { + userEntries.add(entry); + } + } + } + } + return (IPath[]) userEntries.toArray(new IPath[userEntries.size()]); + } + + private static String getMainClass(ILaunchConfiguration launchConfig, MultiStatus status) { + String result= null; + if (launchConfig != null) { + try { + result= launchConfig.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String) null); + } catch (CoreException e) { + JavaPlugin.log(e); + } + } + if (result == null) { + status.add(new Status(IStatus.WARNING, JavaUI.ID_PLUGIN, "The selected launch configuration has no type with a main method attached. The resulting jar will not be runnable.")); + result= ""; //$NON-NLS-1$ + } + return result; + } + + /** + * @param classpathEntries the path to the package fragment roots + * @param projectName the root of the project dependency tree + * @param status a status to report problems to + * @return all package fragment roots corresponding to each classpath entry start the search at project with projectName + */ + private static IPackageFragmentRoot[] getRequiredPackageFragmentRoots(IPath[] classpathEntries, final String projectName, MultiStatus status) { + HashSet result= new HashSet(); + + IJavaProject[] searchOrder= getProjectSearchOrder(projectName); + + for (int i= 0; i < classpathEntries.length; i++) { + IPath entry= classpathEntries[i]; + IPackageFragmentRoot[] elements= findRootsForClasspath(entry, searchOrder); + if (elements == null) { + status.add(new Status(IStatus.WARNING, JavaUI.ID_PLUGIN, Messages.format(FatJarPackagerMessages.FatJarPackageWizardPage_error_missingClassFile, entry))); + } else { + for (int j= 0; j < elements.length; j++) { + result.add(elements[j]); + } + } + } + + return (IPackageFragmentRoot[]) result.toArray(new IPackageFragmentRoot[result.size()]); + } + + private static IPackageFragmentRoot[] findRootsForClasspath(IPath entry, IJavaProject[] searchOrder) { + for (int i= 0; i < searchOrder.length; i++) { + IPackageFragmentRoot[] elements= findRootsInProject(entry, searchOrder[i]); + if (elements.length != 0) { + return elements; + } + } + return null; + } + + private static IPackageFragmentRoot[] findRootsInProject(IPath entry, IJavaProject project) { + ArrayList result= new ArrayList(); + + try { + IPackageFragmentRoot[] roots= project.getPackageFragmentRoots(); + for (int i= 0; i < roots.length; i++) { + IPackageFragmentRoot packageFragmentRoot= roots[i]; + if (isRootAt(packageFragmentRoot, entry)) + result.add(packageFragmentRoot); + } + } catch (Exception e) { + JavaPlugin.log(e); + } + + return (IPackageFragmentRoot[]) result.toArray(new IPackageFragmentRoot[result.size()]); + } + + private static boolean isRootAt(IPackageFragmentRoot root, IPath entry) { + try { + IClasspathEntry cpe= root.getRawClasspathEntry(); + if (cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE) { + IPath outputLocation= cpe.getOutputLocation(); + if (outputLocation == null) + outputLocation= root.getJavaProject().getOutputLocation(); + + IPath location= ResourcesPlugin.getWorkspace().getRoot().findMember(outputLocation).getLocation(); + if (entry.equals(location)) + return true; + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } + + IResource resource= root.getResource(); + if (resource != null && entry.equals(resource.getLocation())) + return true; + + IPath path= root.getPath(); + if (path != null && entry.equals(path)) + return true; + + return false; + } + + private static IType findMainMethodByName(String name, IPackageFragmentRoot[] classpathResources, IRunnableContext context) throws CoreException { + + List resources= JarPackagerUtil.asResources(classpathResources); + if (resources == null) { + return null; + } + + for (Iterator iterator= resources.iterator(); iterator.hasNext();) { + IResource element= (IResource) iterator.next(); + if (element == null) + iterator.remove(); + } + + IJavaSearchScope searchScope= JavaSearchScopeFactory.getInstance().createJavaSearchScope((IResource[]) resources.toArray(new IResource[resources.size()]), true); + MainMethodSearchEngine engine= new MainMethodSearchEngine(); + try { + IType[] mainTypes= engine.searchMainMethods(context, searchScope, 0); + for (int i= 0; i < mainTypes.length; i++) { + if (mainTypes[i].getFullyQualifiedName().equals(name)) + return mainTypes[i]; + } + } catch (InvocationTargetException ex) { + JavaPlugin.log(ex); + } catch (InterruptedException e) { + // null + } + + return null; + } + + public void dispose() { + super.dispose(); + if (fLauchConfigurationModel != null) { + for (int i= 0, size= fLauchConfigurationModel.size(); i < size; i++) { + LaunchConfigurationElement element= (LaunchConfigurationElement) fLauchConfigurationModel.get(i); + element.dispose(); + } + } + } + + protected void restoreWidgetValues() { + + IDialogSettings settings= getDialogSettings(); + if (settings != null) { + String name= settings.get(STORE_LAUNCH_CONFIGURATION_SELECTION_NAME); + if (name != null) { + String[] items= fLaunchConfigurationCombo.getItems(); + for (int i= 0; i < items.length; i++) { + if (name.equals(items[i])) { + fLaunchConfigurationCombo.select(i); + } + } + } + + String destinationPath= settings.get(STORE_DESTINATION_ELEMENT); + if (destinationPath != null && destinationPath.length() > 0) { + fJarPackage.setJarLocation(Path.fromOSString(destinationPath)); + } + } + + super.restoreWidgetValues(); + } + + /** + * {@inheritDoc} + */ + protected void saveWidgetValues() { + super.saveWidgetValues(); + + IDialogSettings settings= getDialogSettings(); + if (settings != null) { + int index= fLaunchConfigurationCombo.getSelectionIndex(); + if (index == -1) { + settings.put(STORE_LAUNCH_CONFIGURATION_SELECTION_NAME, ""); //$NON-NLS-1$ + } else { + String selectedItem= fLaunchConfigurationCombo.getItem(index); + settings.put(STORE_LAUNCH_CONFIGURATION_SELECTION_NAME, selectedItem); + } + + IPath location= fJarPackage.getJarLocation(); + if (location == null) { + settings.put(STORE_DESTINATION_ELEMENT, ""); //$NON-NLS-1$ + } else { + settings.put(STORE_DESTINATION_ELEMENT, location.toOSString()); + } + } + } + + /* + * For internal use only (testing), clients must not call. + */ + public static Object[] getSelectedElementsWithoutContainedChildren(ILaunchConfiguration launchconfig, JarPackageData data, IRunnableContext context, MultiStatus status) throws CoreException { + if (launchconfig == null) + return new Object[0]; + + String projectName= launchconfig.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$ + + IPath[] classpath= getClasspath(launchconfig, status); + IPackageFragmentRoot[] classpathResources= getRequiredPackageFragmentRoots(classpath, projectName, status); + + String mainClass= getMainClass(launchconfig, status); + IType mainType= findMainMethodByName(mainClass, classpathResources, context); + if (mainType == null) { + status.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, FatJarPackagerMessages.FatJarPackageWizardPage_error_noMainMethod)); + } + data.setManifestMainClass(mainType); + + return classpathResources; + } + +} Index: ui/org/eclipse/jdt/internal/ui/jarpackager/JarBuilder.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackager/JarBuilder.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackager/JarBuilder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/JarBuilder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackager; + +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.MultiStatus; +import org.eclipse.core.runtime.Status; + +import org.eclipse.core.resources.IFile; + +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.ui.jarpackager.IManifestProvider; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.IJavaStatusConstants; +import org.eclipse.jdt.internal.ui.JavaPlugin; + +/** + * Base class for all jar builders. A jar builder is used by + * the {@link JarFileExportOperation} to build a jar file. + * + * @since 3.4 + */ +public abstract class JarBuilder { + + private MultiStatus fStatus; + + /** + * @return the unique id of this builder + */ + public abstract String getId(); + + /** + * @return the manifest provider to build the manifest + */ + public abstract IManifestProvider getManifestProvider(); + + /** + * Called when building of the jar starts + * + * @param jarPackage + * the package to build + * @param shell + * shell to show dialogs in, null if no dialog must be shown + * @param status + * a status to use to report status to the user + * @throws CoreException + */ + public void open(JarPackageData jarPackage, Shell shell, MultiStatus status) throws CoreException { + fStatus= status; + } + + /** + * Add the given resource to the archive at the given path + * + * @param resource + * the file to be written + * @param destinationPath + * the path for the file inside the archive + * @throws CoreException + */ + public abstract void addFile(IFile resource, IPath destinationPath) throws CoreException; + + /** + * Add the given package fragment root to the archive. The root is an archive. + * + * @param root + * the package fragment root to add + * @param monitor + * a monitor to report progress to + */ + public abstract void addJar(IPackageFragmentRoot root, IProgressMonitor monitor); + + /** + * Called when building of the jar finished. + * + * @throws CoreException + */ + public abstract void close() throws CoreException; + + //some methods for convenience + protected final void addInfo(String message, Throwable error) { + fStatus.add(new Status(IStatus.INFO, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); + } + + protected final void addWarning(String message, Throwable error) { + fStatus.add(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); + } + + protected final void addError(String message, Throwable error) { + fStatus.add(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, error)); + } + + protected final void addToStatus(CoreException ex) { + IStatus status= ex.getStatus(); + String message= ex.getLocalizedMessage(); + if (message == null || message.length() < 1) { + message= JarPackagerMessages.JarFileExportOperation_coreErrorDuringExport; + status= new Status(status.getSeverity(), status.getPlugin(), status.getCode(), message, ex); + } + fStatus.add(status); + } +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.properties =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.properties diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.properties --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.properties 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,27 @@ +############################################################################### +# Copyright (c) 2007 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 +############################################################################### + +JarPackageWizard_windowTitle= Runnable JAR Export +JarPackageWizard_jarExport_title= Runnable JAR Export +FatJarBuilder_error_exportingStream=Exporting stream to {0} failed. +FatJarBuilder_error_readingArchiveFile=Could not read jar file ''{0}''. Reason: {1} +FatJarPackageWizardPage_description=Select a launch configuration to use to create a runnable JAR. +FatJarPackageWizardPage_destinationGroupTitle=Select the export destination: +FatJarPackageWizardPage_error_missingClassFile=Fat Jar Export: Could not find classpath entry for ''{0}'' +FatJarPackageWizardPage_error_noMainMethod=Could not find main method from given launch configuration. +FatJarPackageWizardPage_launchConfigGroupTitle=Select the launch configuration: +JarPackageWizard_jarExportError_title= Runnable JAR Export Error +JarPackageWizard_jarExportError_message= Creation of runnable JAR failed + +JarPackageWizardPage_title= Runnable JAR File Specification + +JarWriter_error_couldNotGetXmlBuilder = Could not get XML builder +JarWriter_error_couldNotTransformToXML= Could not transform to XML Index: ui/org/eclipse/jdt/internal/ui/jarpackager/PlainJarBuilder.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackager/PlainJarBuilder.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackager/PlainJarBuilder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/PlainJarBuilder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackager; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.MultiStatus; + +import org.eclipse.core.resources.IFile; + +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.ui.jarpackager.IManifestProvider; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; +import org.eclipse.jdt.ui.jarpackager.JarWriter3; + +/** + * Jar builder for the plain jar exported. Does not export required archives. + * + * @since 3.4 + */ +public class PlainJarBuilder extends JarBuilder { + + public static final String BUILDER_ID= "org.eclipse.jdt.ui.plain_jar_builder"; //$NON-NLS-1$ + + private JarPackageData fJarPackage; + private JarWriter3 fJarWriter; + + /** + * {@inheritDoc} + */ + public String getId() { + return BUILDER_ID; + } + + /** + * {@inheritDoc} + */ + public IManifestProvider getManifestProvider() { + return new ManifestProvider(); + } + + /** + * {@inheritDoc} + */ + public void open(JarPackageData jarPackage, Shell displayShell, MultiStatus statusMsg) throws CoreException { + super.open(jarPackage, displayShell, statusMsg); + fJarPackage = jarPackage; + fJarWriter = new JarWriter3(fJarPackage, displayShell); + } + + /** + * {@inheritDoc} + */ + public void addFile(IFile resource, IPath destinationPath) throws CoreException { + fJarWriter.write(resource, destinationPath); + } + + /** + * {@inheritDoc} + */ + public void addJar(IPackageFragmentRoot archiveRoot, IProgressMonitor progressMonitor) { + //do nothing, plain jar builder can not handle archives, use fat jar builder + } + + /** + * {@inheritDoc} + */ + public void close() throws CoreException { + fJarWriter.close(); + } + +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackagerMessages.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +import org.eclipse.osgi.util.NLS; + +public final class FatJarPackagerMessages extends NLS { + + private static final String BUNDLE_NAME= "org.eclipse.jdt.internal.ui.jarpackagerfat.FatJarPackagerMessages";//$NON-NLS-1$ + + public static String JarPackageWizard_jarExport_title; + public static String JarPackageWizard_jarExportError_message; + public static String FatJarBuilder_error_exportingStream; + + public static String FatJarBuilder_error_readingArchiveFile; + + public static String FatJarPackageWizardPage_destinationGroupTitle; + public static String FatJarPackageWizardPage_error_missingClassFile; + public static String FatJarPackageWizardPage_error_noMainMethod; + public static String FatJarPackageWizardPage_launchConfigGroupTitle; + public static String FatJarPackageWizardPage_description; + + public static String JarPackageWizard_jarExportError_title; + public static String JarPackageWizard_windowTitle; + + public static String JarPackageWizardPage_title; + + public static String JarWriter_error_couldNotGetXmlBuilder; + public static String JarWriter_error_couldNotTransformToXML; + + static { + NLS.initializeMessages(BUNDLE_NAME, FatJarPackagerMessages.class); + } + + private FatJarPackagerMessages() { + // Do not instantiate + } +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarManifestProvider.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarManifestProvider.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarManifestProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarManifestProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.ui.jarpackager.IManifestProvider; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil; + +/** + * A manifest provider creates manifest files for a fat jar. + * + * @since 3.4 + */ +public class FatJarManifestProvider implements IManifestProvider { + + private static final String SEALED_VALUE= "true"; //$NON-NLS-1$ + private static final String UNSEALED_VALUE= "false"; //$NON-NLS-1$ + + private FatJarBuilder fBuilder; + + public FatJarManifestProvider(FatJarBuilder builder) { + fBuilder = builder; + } + + /** + * {@inheritDoc} + */ + public Manifest create(JarPackageData jarPackage) throws CoreException { + Manifest result; + Manifest ownManifest = createOwn(jarPackage); + setManifestClasspath(ownManifest, fBuilder.getManifestClasspath()); + if (fBuilder.isMergeManifests()) { + List otherManifests = new ArrayList(); + Object[] elements = jarPackage.getElements(); + for (int i = 0; i < elements.length; i++) { + Object element = elements[i]; + if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot)element).isArchive()) { + ZipFile zip = JarPackagerUtil.getArchiveFile(((IPackageFragmentRoot) element).getPath()); + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry)entries.nextElement(); + if (entry.getName().equalsIgnoreCase("META-INF/MANIFEST.MF")) { //$NON-NLS-1$ + try { + Manifest otherManifest = new Manifest(zip.getInputStream(entry)); + otherManifests.add(otherManifest); + } catch (IOException e) { + JavaPlugin.log(e); + } + } + } + } + } + result = merge(ownManifest, otherManifests); + } + else { + result = ownManifest; + } + return result; + } + + private void setManifestClasspath(Manifest ownManifest, String manifestClasspath) { + if ((manifestClasspath != null) && !manifestClasspath.trim().equals("")) { //$NON-NLS-1$ + Attributes mainAttr = ownManifest.getMainAttributes(); + mainAttr.putValue("Class-Path", manifestClasspath); //$NON-NLS-1$ + } + } + + private Manifest merge(Manifest ownManifest, List otherManifests) { + Manifest mergedManifest = new Manifest(ownManifest); + Map mergedEntries = mergedManifest.getEntries(); + for (Iterator iter = otherManifests.iterator(); iter.hasNext();) { + Manifest otherManifest = (Manifest)iter.next(); + Map otherEntries = otherManifest.getEntries(); + for (Iterator iterator = otherEntries.keySet().iterator(); iterator.hasNext();) { + String attributeName = (String)iterator.next(); + if (mergedEntries.containsKey(attributeName)) { + // TODO: WARNING + } + else { + mergedEntries.put(attributeName, otherEntries.get(attributeName)); + } + } + } + return mergedManifest; + } + + private Manifest createOwn(JarPackageData jarPackage) throws CoreException { + if (jarPackage.isManifestGenerated()) + return createGeneratedManifest(jarPackage); + + try { + return createSuppliedManifest(jarPackage); + } catch (IOException ex) { + throw JarPackagerUtil.createCoreException(ex.getLocalizedMessage(), ex); + } + } + + /** + * {@inheritDoc} + */ + public Manifest createDefault(String manifestVersion) { + Manifest manifest= new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, manifestVersion); + return manifest; + } + + /** + * Hook for subclasses to add additional manifest entries. + * + * @param manifest the manifest to which the entries should be added + * @param jarPackage the JAR package specification + */ + protected void putAdditionalEntries(Manifest manifest, JarPackageData jarPackage) { + } + + private Manifest createGeneratedManifest(JarPackageData jarPackage) { + Manifest manifest= new Manifest(); + putVersion(manifest, jarPackage); + putSealing(manifest, jarPackage); + putMainClass(manifest, jarPackage); + putAdditionalEntries(manifest, jarPackage); + return manifest; + } + + private void putVersion(Manifest manifest, JarPackageData jarPackage) { + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, jarPackage.getManifestVersion()); + } + + private void putSealing(Manifest manifest, JarPackageData jarPackage) { + if (jarPackage.isJarSealed()) { + manifest.getMainAttributes().put(Attributes.Name.SEALED, SEALED_VALUE); + IPackageFragment[] packages= jarPackage.getPackagesToUnseal(); + if (packages != null) { + for (int i= 0; i < packages.length; i++) { + Attributes attributes= new Attributes(); + attributes.put(Attributes.Name.SEALED, UNSEALED_VALUE); + manifest.getEntries().put(getInManifestFormat(packages[i]), attributes); + } + } + } + else { + IPackageFragment[] packages= jarPackage.getPackagesToSeal(); + if (packages != null) + for (int i= 0; i < packages.length; i++) { + Attributes attributes= new Attributes(); + attributes.put(Attributes.Name.SEALED, SEALED_VALUE); + manifest.getEntries().put(getInManifestFormat(packages[i]), attributes); + } + } + } + + private void putMainClass(Manifest manifest, JarPackageData jarPackage) { + if (jarPackage.getManifestMainClass() != null && jarPackage.getManifestMainClass().getFullyQualifiedName().length() > 0) + manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, jarPackage.getManifestMainClass().getFullyQualifiedName()); + } + + private String getInManifestFormat(IPackageFragment packageFragment) { + String name= packageFragment.getElementName(); + return name.replace('.', '/') + '/'; + } + + private Manifest createSuppliedManifest(JarPackageData jarPackage) throws CoreException, IOException { + Manifest manifest; + // No need to use buffer here because Manifest(...) does + InputStream stream= jarPackage.getManifestFile().getContents(false); + try { + manifest= new Manifest(stream); + } finally { + if (stream != null) + stream.close(); + } + return manifest; + } + +} Index: ui/org/eclipse/jdt/internal/ui/jarpackager/AbstractJarDestinationWizardPage.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackager/AbstractJarDestinationWizardPage.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackager/AbstractJarDestinationWizardPage.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackager/AbstractJarDestinationWizardPage.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackager; + +import java.io.File; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.viewers.IStructuredSelection; + +import org.eclipse.ui.dialogs.WizardExportResourcesPage; + +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.util.SWTUtil; + +/** + * A wizard page containing a destination block for a jar file. Including + * all required validation code. Clients should overwrite createControl. + * + * @since 3.4 + */ +public abstract class AbstractJarDestinationWizardPage extends WizardExportResourcesPage implements IJarPackageWizardPage { + + private final String fStoreDestinationNamesId; + + private Combo fDestinationNamesCombo; + private Button fDestinationBrowseButton; + private final JarPackageData fJarPackage; + + public AbstractJarDestinationWizardPage(String pageName, IStructuredSelection selection, JarPackageData jarPackage) { + super(pageName, selection); + fStoreDestinationNamesId= pageName + ".DESTINATION_NAMES_ID"; //$NON-NLS-1$ + fJarPackage= jarPackage; + } + + /* + * Overrides method from WizardExportPage + */ + protected void createDestinationGroup(Composite parent) { + + initializeDialogUnits(parent); + + // destination specification group + Composite destinationSelectionGroup= new Composite(parent, SWT.NONE); + GridLayout layout= new GridLayout(); + layout.numColumns= 3; + destinationSelectionGroup.setLayout(layout); + destinationSelectionGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + + String label= getDestinationLabel(); + if (label != null) { + new Label(destinationSelectionGroup, SWT.NONE).setText(label); + } + + // destination name entry field + fDestinationNamesCombo= new Combo(destinationSelectionGroup, SWT.SINGLE | SWT.BORDER); + fDestinationNamesCombo.addListener(SWT.Modify, this); + fDestinationNamesCombo.addListener(SWT.Selection, this); + GridData data= new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL); + data.widthHint= SIZING_TEXT_FIELD_WIDTH; + data.horizontalSpan= label == null ? 2 : 1; + fDestinationNamesCombo.setLayoutData(data); + + // destination browse button + fDestinationBrowseButton= new Button(destinationSelectionGroup, SWT.PUSH); + fDestinationBrowseButton.setText(JarPackagerMessages.JarPackageWizardPage_browseButton_text); + fDestinationBrowseButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); + SWTUtil.setButtonDimensionHint(fDestinationBrowseButton); + fDestinationBrowseButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + handleDestinationBrowseButtonPressed(); + } + }); + } + + /** + * Open an appropriate destination browser so that the user can specify a source + * to import from + */ + protected void handleDestinationBrowseButtonPressed() { + FileDialog dialog= new FileDialog(getContainer().getShell(), SWT.SAVE); + dialog.setFilterExtensions(new String[] {"*.jar", "*.zip"}); //$NON-NLS-1$ //$NON-NLS-2$ + + String currentSourceString= getDestinationValue(); + int lastSeparatorIndex= currentSourceString.lastIndexOf(File.separator); + if (lastSeparatorIndex != -1) { + dialog.setFilterPath(currentSourceString.substring(0, lastSeparatorIndex)); + dialog.setFileName(currentSourceString.substring(lastSeparatorIndex + 1, currentSourceString.length())); + } + else + dialog.setFileName(currentSourceString); + String selectedFileName= dialog.open(); + if (selectedFileName != null) + fDestinationNamesCombo.setText(selectedFileName); + } + + + /** + * Answer the contents of the destination specification widget. If this + * value does not have the required suffix then add it first. + * + * @return java.lang.String + */ + protected String getDestinationValue() { + String destinationText= fDestinationNamesCombo.getText().trim(); + if (destinationText.indexOf('.') < 0) + destinationText += getOutputSuffix(); + return destinationText; + } + + /** + * Answer the string to display in self as the destination type + * + * @return java.lang.String + */ + protected String getDestinationLabel() { + return JarPackagerMessages.JarPackageWizardPage_destination_label; + } + + /** + * Answer the suffix that files exported from this wizard must have. + * If this suffix is a file extension (which is typically the case) + * then it must include the leading period character. + * + * @return java.lang.String + */ + protected String getOutputSuffix() { + return "." + JarPackagerUtil.JAR_EXTENSION; //$NON-NLS-1$ + } + + protected void restoreWidgetValues() { + // destination + if (fJarPackage.getJarLocation().isEmpty()) + fDestinationNamesCombo.setText(""); //$NON-NLS-1$ + else + fDestinationNamesCombo.setText(fJarPackage.getJarLocation().toOSString()); + IDialogSettings settings= getDialogSettings(); + if (settings != null) { + String[] directoryNames= settings.getArray(fStoreDestinationNamesId); + if (directoryNames == null) + return; // ie.- no settings stored + if (! fDestinationNamesCombo.getText().equals(directoryNames[0])) + fDestinationNamesCombo.add(fDestinationNamesCombo.getText()); + for (int i= 0; i < directoryNames.length; i++) + fDestinationNamesCombo.add(directoryNames[i]); + } + } + + protected void updateModel() { + // destination + String comboText= fDestinationNamesCombo.getText(); + IPath path= Path.fromOSString(comboText); + + if (path.segmentCount() > 0 && ensureTargetFileIsValid(path.toFile()) && path.getFileExtension() == null) + // append .jar + path= path.addFileExtension(JarPackagerUtil.JAR_EXTENSION); + + fJarPackage.setJarLocation(path); + } + + /** + * Returns a boolean indicating whether the passed File handle is + * is valid and available for use. + * + * @param targetFile the target + * @return boolean + */ + protected boolean ensureTargetFileIsValid(File targetFile) { + if (targetFile.exists() && targetFile.isDirectory() && fDestinationNamesCombo.getText().length() > 0) { + setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_exportDestinationMustNotBeDirectory); + fDestinationNamesCombo.setFocus(); + return false; + } + if (targetFile.exists()) { + if (!targetFile.canWrite()) { + setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_jarFileExistsAndNotWritable); + fDestinationNamesCombo.setFocus(); + return false; + } + } + return true; + } + + /* + * Overrides method from WizardDataTransferPage + */ + protected boolean validateDestinationGroup() { + if (fDestinationNamesCombo.getText().length() == 0) { + // Clear error + if (getErrorMessage() != null) + setErrorMessage(null); + if (getMessage() != null) + setMessage(null); + return false; + } + if (fJarPackage.getAbsoluteJarLocation().toString().endsWith("/")) { //$NON-NLS-1$ + setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_exportDestinationMustNotBeDirectory); + fDestinationNamesCombo.setFocus(); + return false; + } + // Check if the Jar is put into the workspace and conflicts with the containers + // exported. If the workspace isn't on the local files system we are fine since + // the Jar is always created in the local file system + IPath workspaceLocation= ResourcesPlugin.getWorkspace().getRoot().getLocation(); + if (workspaceLocation != null && workspaceLocation.isPrefixOf(fJarPackage.getAbsoluteJarLocation())) { + int segments= workspaceLocation.matchingFirstSegments(fJarPackage.getAbsoluteJarLocation()); + IPath path= fJarPackage.getAbsoluteJarLocation().removeFirstSegments(segments); + IResource resource= ResourcesPlugin.getWorkspace().getRoot().findMember(path); + if (resource != null && resource.getType() == IResource.FILE) { + // test if included + if (JarPackagerUtil.contains(JarPackagerUtil.asResources(fJarPackage.getElements()), (IFile)resource)) { + setErrorMessage(JarPackagerMessages.JarPackageWizardPage_error_cantExportJARIntoItself); + return false; + } + } + } + // Inform user about relative directory + String currentMessage= getMessage(); + if (!(new File(fDestinationNamesCombo.getText()).isAbsolute())) { + if (currentMessage == null) + setMessage(JarPackagerMessages.JarPackageWizardPage_info_relativeExportDestination, IMessageProvider.INFORMATION); + } else { + if (currentMessage != null) + setMessage(null); + } + return ensureTargetFileIsValid(fJarPackage.getAbsoluteJarLocation().toFile()); + } + + /** + * Set the current input focus to self's destination entry field + */ + protected void giveFocusToDestination() { + fDestinationNamesCombo.setFocus(); + } + + /** + * {@inheritDoc} + */ + protected void saveWidgetValues() { + IDialogSettings settings= getDialogSettings(); + if (settings != null) { + String[] directoryNames= settings.getArray(fStoreDestinationNamesId); + if (directoryNames == null) + directoryNames= new String[0]; + directoryNames= addToHistory(directoryNames, getDestinationValue()); + settings.put(fStoreDestinationNamesId, directoryNames); + } + } + + /** + * Initializes the JAR package from last used wizard page values. + */ + protected void initializeJarPackage() { + IDialogSettings settings= getDialogSettings(); + if (settings != null) { + // destination + String[] directoryNames= settings.getArray(fStoreDestinationNamesId); + if (directoryNames == null) + return; // ie.- no settings stored + fJarPackage.setJarLocation(Path.fromOSString(directoryNames[0])); + } + } + + /* + * Implements method from IJarPackageWizardPage. + */ + public void finish() { + saveWidgetValues(); + } + + /* + * Implements method from Listener + */ + public void handleEvent(Event e) { + if (getControl() == null) + return; + update(); + } + + protected void update() { + updateModel(); + updateWidgetEnablements(); + updatePageCompletion(); + } + + protected void updatePageCompletion() { + boolean pageComplete= isPageComplete(); + setPageComplete(pageComplete); + if (pageComplete) + setErrorMessage(null); + } +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarBuilder.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarBuilder.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarBuilder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarBuilder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,206 @@ +package org.eclipse.jdt.internal.ui.jarpackagerfat; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.OperationCanceledException; + +import org.eclipse.core.resources.IFile; + +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.ui.jarpackager.IManifestProvider; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; +import org.eclipse.jdt.ui.jarpackager.JarWriter3; + +import org.eclipse.jdt.internal.ui.jarpackager.JarBuilder; +import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil; + +public class FatJarBuilder extends JarBuilder { + + public static final String BUILDER_ID= "org.eclipse.jdt.ui.fat_jar_builder"; //$NON-NLS-1$ + +// private static final String PROPS_MERGEMANIFESTS= "mergemanifests"; //$NON-NLS-1$ +// private static final String PROPS_REMOVESIGNERS= "removesigners"; //$NON-NLS-1$ +// private static final String PROPS_MANIFESTCLASSPATH= "manifestclasspath"; //$NON-NLS-1$ + + private boolean fMergeManifests; + private boolean fRemoveSigners; + private String fManifestClasspath; + + private JarPackageData fJarPackage; + private JarWriter3 fJarWriter; + + /** + * {@inheritDoc} + */ + public String getId() { + return BUILDER_ID; + } + + /** + * {@inheritDoc} + */ + public IManifestProvider getManifestProvider() { + return new FatJarManifestProvider(this); + } + + public String getManifestClasspath() { + return fManifestClasspath; + } + + public boolean isMergeManifests() { + return fMergeManifests; + } + + public boolean isRemoveSigners() { + return fRemoveSigners; + } + + /** + * {@inheritDoc} + */ + public void open(JarPackageData jarPackage, Shell displayShell, MultiStatus status) throws CoreException { + super.open(jarPackage, displayShell, status); +// ExecutableJarBuilderProperty[] jarBuilderProperties= getExecutableJarBuilderProperties(); + + fMergeManifests= true;//getBooleanValue(jarBuilderProperties, PROPS_MERGEMANIFESTS, true); + fRemoveSigners= true;//getBooleanValue(jarBuilderProperties, PROPS_REMOVESIGNERS, true); + fManifestClasspath= "";//getValue(jarBuilderProperties, PROPS_MANIFESTCLASSPATH, ""); //$NON-NLS-1$ + + fJarPackage= jarPackage; + fJarWriter= new JarWriter3(fJarPackage, displayShell); + } + + /** + * {@inheritDoc} + */ + public void addFile(IFile resource, IPath destinationPath) throws CoreException { + fJarWriter.write(resource, destinationPath); + } + + /** + * {@inheritDoc} + */ + public void addJar(IPackageFragmentRoot archiveRoot, IProgressMonitor progressMonitor) { + try { + ZipFile jarFile= JarPackagerUtil.getArchiveFile(archiveRoot.getPath()); + String readableJarName= archiveRoot.getElementName(); + addJar(readableJarName, jarFile, progressMonitor); + jarFile.close(); + } catch (IOException ex) { + addJarWarning(archiveRoot.getElementName(), ex); + } catch (CoreException ex) { + addJarWarning(archiveRoot.getElementName(), ex); + } + } + + private void addJar(String readableJarName, ZipFile jarFile, IProgressMonitor progressMonitor) { + Enumeration jarEntriesEnum= jarFile.entries(); + while (jarEntriesEnum.hasMoreElements()) { + ZipEntry jarEntry= (ZipEntry) jarEntriesEnum.nextElement(); + if (!jarEntry.isDirectory()) { + String entryName= jarEntry.getName(); + InputStream stream= null; + try { + stream= jarFile.getInputStream(jarEntry); + addFile(entryName, stream); + stream.close(); + } catch (IOException e) { + addJarWarning(readableJarName, e); + } + } + progressMonitor.worked(1); + if (progressMonitor.isCanceled()) + throw new OperationCanceledException(); + } + } + + private void addFile(String destinationPath, InputStream fileStream) { + // Handle META-INF/MANIFEST.MF + if (destinationPath.equalsIgnoreCase("META-INF/MANIFEST.MF") //$NON-NLS-1$ + || (isRemoveSigners() && destinationPath.startsWith("META-INF/") && destinationPath.endsWith(".SF"))) { //$NON-NLS-1$//$NON-NLS-2$ + return; + } + try { + fJarWriter.addStream(fileStream, destinationPath); + } catch (CoreException ex) { + Throwable realEx= ex.getStatus().getException(); + if (realEx instanceof ZipException && realEx.getMessage() != null && realEx.getMessage().startsWith("duplicate entry:")) //$NON-NLS-1$ + addWarning(ex.getMessage(), realEx); + else + addToStatus(ex); + } catch (IOException ex) { + if (ex instanceof ZipException && ex.getMessage() != null && ex.getMessage().startsWith("duplicate entry:")) {//$NON-NLS-1$ + // ignore duplicates in META-INF (*.SF, *.RSA) + if (!destinationPath.startsWith("META-INF/")) { //$NON-NLS-1$ + addWarning(ex.getMessage(), ex); + } + } else + addError(Messages.format(FatJarPackagerMessages.FatJarBuilder_error_exportingStream, destinationPath), ex); + } + } + + /** + * {@inheritDoc} + */ + public void close() throws CoreException { + if (fJarWriter != null) { + fJarWriter.close(); + } + } + + private void addJarWarning(String archiveRootName, Throwable ex) { + addWarning(Messages.format(FatJarPackagerMessages.FatJarBuilder_error_readingArchiveFile, new Object[] {archiveRootName, ex.getLocalizedMessage()}), ex); + } + +// private static String getValue(ExecutableJarBuilderProperty[] jarBuilderProperties, String name, String defaultValue) { +// String result= defaultValue; +// if ((name != null) && (jarBuilderProperties != null)) { +// for (int i= 0; i < jarBuilderProperties.length; i++) { +// if (name.equals(jarBuilderProperties[i].getName())) { +// result= jarBuilderProperties[i].getValue(); +// break; +// } +// } +// } +// return result; +// } +// +// private static boolean getBooleanValue(ExecutableJarBuilderProperty[] jarBuilderProperties, String name, boolean defaultValue) { +// boolean result= defaultValue; +// if (name != null) { +// for (int i= 0; i < jarBuilderProperties.length; i++) { +// if (name.equals(jarBuilderProperties[i].getName())) { +// result= jarBuilderProperties[i].getBooleanValue(); +// break; +// } +// } +// } +// return result; +// } +// +// private static ExecutableJarBuilderProperty[] getExecutableJarBuilderProperties() { +// ExecutableJarBuilderProperty[] jbProperties= { +// new ExecutableJarBuilderProperty(ExecutableJarBuilderProperty.PROPERTYTYPE_BOOLEAN, "mergemanifests", "true", //$NON-NLS-2$ +// "Merge attributes from all included libs together. Use this if the output jar produces an 'SecurityException: no manifiest section for signature file entry ...'"), +// new ExecutableJarBuilderProperty(ExecutableJarBuilderProperty.PROPERTYTYPE_BOOLEAN, "removesigners", "true", //$NON-NLS-2$ +// "Remove signer files (*.SF) in META-INF. Use this if the output jar produces an 'SecurityException: invalid SHA1 signature file digest for ...'"), +// new ExecutableJarBuilderProperty(ExecutableJarBuilderProperty.PROPERTYTYPE_STRING, "manifestclasspath", "", //$NON-NLS-2$ +// "Define the Class-Path attribute separated by spaces. Folders must end with an '/'. Example: '. xclasses/ lib/test.jar'"), }; +// return jbProperties; +// } + +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperty.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperty.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperty.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/JarBuilderProperty.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +/** + * TODO: Remove, not used? + * @since 3.4 + */ +public class JarBuilderProperty { + + public final static int PROPERTYTYPE_STRING= 1; + public final static int PROPERTYTYPE_BOOLEAN= 2; + + private int propertyType; + private String name; + private String value; + private String tip; + + public JarBuilderProperty(int propertyType, String name, String value, String tip) { + this.propertyType= propertyType; + this.name= name; + this.value= value; + this.tip= tip; + } + + public int getType() { + return propertyType; + } + + public boolean isBooleanType() { + return getType() == PROPERTYTYPE_BOOLEAN; + } + + public boolean isStringType() { + return getType() == PROPERTYTYPE_STRING; + } + + public String getName() { + return name; + } + + public String getTip() { + return tip; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value= value; + } + + public boolean getBooleanValue() { + return (value != null) && Boolean.getBoolean(value); + } + + public void setBooleanValue(boolean value) { + this.value= Boolean.toString(value); + } + + public void exportToString(StringBuffer out) { + out.append(""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public String toString() { + StringBuffer result= new StringBuffer(); + result.append("P[").append(Integer.toString(propertyType)).append("|").append(getName()).append("='").append(getValue()).append("']"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + return result.toString(); + } +} Index: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizard.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizard.java diff -N ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizard.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/jarpackagerfat/FatJarPackageWizard.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2007 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.jarpackagerfat; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Iterator; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; + +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; + +import org.eclipse.ui.IExportWizard; +import org.eclipse.ui.IWorkbench; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; + +import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable; +import org.eclipse.jdt.ui.jarpackager.JarPackageData; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.JavaPluginImages; +import org.eclipse.jdt.internal.ui.util.ExceptionHandler; + +/** + * Wizard for exporting resources from the workspace to a Fat Java Archive (JAR) file. + * The exported jar will contain all required libraries. + * + * @since 3.4 + */ +public class FatJarPackageWizard extends Wizard implements IExportWizard { + + private static String DIALOG_SETTINGS_KEY= "FatJarPackageWizard"; //$NON-NLS-1$ + + private boolean fHasNewDialogSettings; + private boolean fInitializeFromJarPackage; + private JarPackageData fJarPackage; + private FatJarPackageWizardPage fJarPackageWizardPage; + private IStructuredSelection fSelection; + + /** + * Creates a wizard for exporting workspace resources to a JAR file. + */ + public FatJarPackageWizard() { + IDialogSettings workbenchSettings= JavaPlugin.getDefault().getDialogSettings(); + IDialogSettings section= workbenchSettings.getSection(DIALOG_SETTINGS_KEY); + if (section == null) + fHasNewDialogSettings= true; + else { + fHasNewDialogSettings= false; + setDialogSettings(section); + } + } + + /** + * {@inheritDoc} + */ + public void addPages() { + super.addPages(); + fJarPackageWizardPage= new FatJarPackageWizardPage(fJarPackage, fSelection); + addPage(fJarPackageWizardPage); + } + + /** + * Exports the JAR package. + * + * @param op the operation to run + * @param wizardPageStatus the status returned by the wizard page + * @return a boolean indicating success or failure + */ + protected boolean executeExportOperation(IJarExportRunnable op, IStatus wizardPageStatus) { + try { + getContainer().run(true, true, op); + } catch (InterruptedException e) { + return false; + } catch (InvocationTargetException ex) { + if (ex.getTargetException() != null) { + ExceptionHandler.handle(ex, getShell(), FatJarPackagerMessages.JarPackageWizard_jarExportError_title, FatJarPackagerMessages.JarPackageWizard_jarExportError_message); + return false; + } + } + IStatus status= op.getStatus(); + if (!status.isOK()) { + if (!wizardPageStatus.isOK()) { + if (!(status instanceof MultiStatus)) + status= new MultiStatus(status.getPlugin(), status.getCode(), status.getMessage(), status.getException()); + + ((MultiStatus)status).add(wizardPageStatus); + } + ErrorDialog.openError(getShell(), FatJarPackagerMessages.JarPackageWizard_jarExport_title, null, status); + return !(status.matches(IStatus.ERROR)); + } else if (!wizardPageStatus.isOK()) { + ErrorDialog.openError(getShell(), FatJarPackagerMessages.JarPackageWizard_jarExport_title, null, wizardPageStatus); + } + return true; + } + + public IWizardPage getNextPage(IWizardPage page) { + return super.getNextPage(page); + } + + public IWizardPage getPreviousPage(IWizardPage page) { + return super.getPreviousPage(page); + } + + /** + * @return all java projects which contain the selected elements in the active workbench window + */ + protected IStructuredSelection getSelectedJavaProjects() { + ISelection currentSelection= JavaPlugin.getActiveWorkbenchWindow().getSelectionService().getSelection(); + if (currentSelection instanceof IStructuredSelection) { + IStructuredSelection structuredSelection= (IStructuredSelection) currentSelection; + HashSet selectedElements= new HashSet(); + Iterator iter= structuredSelection.iterator(); + while (iter.hasNext()) { + Object selectedElement= iter.next(); + if (selectedElement instanceof IJavaElement) { + IJavaProject javaProject= ((IJavaElement)selectedElement).getJavaProject(); + if (javaProject != null) + selectedElements.add(javaProject); + } + } + return new StructuredSelection(selectedElements); + } else + return StructuredSelection.EMPTY; + } + + /** + * {@inheritDoc} + */ + public void init(IWorkbench workbench, IStructuredSelection selection) { + fSelection= getSelectedJavaProjects(); + fJarPackage= new JarPackageData(); + setInitializeFromJarPackage(false); + setWindowTitle(FatJarPackagerMessages.JarPackageWizard_windowTitle); + setDefaultPageImageDescriptor(JavaPluginImages.DESC_WIZBAN_FAT_JAR_PACKAGER); + setNeedsProgressMonitor(true); + } + + /** + * Initializes this wizard from the given JAR package description. + * + * @param workbench + * the workbench which launched this wizard + * @param jarPackage + * the JAR package description used to initialize this wizard + */ + public void init(IWorkbench workbench, JarPackageData jarPackage) { + Assert.isNotNull(workbench); + Assert.isNotNull(jarPackage); + fJarPackage= jarPackage; + setInitializeFromJarPackage(true); + setWindowTitle(FatJarPackagerMessages.JarPackageWizard_windowTitle); + setDefaultPageImageDescriptor(JavaPluginImages.DESC_WIZBAN_FAT_JAR_PACKAGER); + setNeedsProgressMonitor(true); + } + + boolean isInitializingFromJarPackage() { + return fInitializeFromJarPackage; + } + + /** + * {@inheritDoc} + */ + public boolean performFinish() { + fJarPackage.setJarBuilder(new FatJarBuilder()); + MultiStatus status= new MultiStatus(JavaPlugin.getPluginId(), IStatus.OK, "Jar export finished with problems. See details for additional infos.", null); + Object[] elements= fJarPackageWizardPage.getSelectedElementsWithoutContainedChildren(status); + fJarPackage.setElements(elements); + + if (!executeExportOperation(fJarPackage.createJarExportRunnable(getShell()), status)) + return false; + + // Save the dialog settings + if (fHasNewDialogSettings) { + IDialogSettings workbenchSettings= JavaPlugin.getDefault().getDialogSettings(); + IDialogSettings section= workbenchSettings.getSection(DIALOG_SETTINGS_KEY); + section= workbenchSettings.addNewSection(DIALOG_SETTINGS_KEY); + setDialogSettings(section); + } + + fJarPackageWizardPage.finish(); + return true; + } + + void setInitializeFromJarPackage(boolean state) { + fInitializeFromJarPackage= state; + } +}