--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2008, 2011 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
+ * Ferenc Hechler, ferenc_hechler@users.sourceforge.net - 219530 [jar application] add Jar-in-Jar ClassLoader option
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.ui.jarpackagerfat;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.zip.ZipFile;
+
+import org.eclipse.swt.widgets.Shell;
+
+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.jdt.core.IPackageFragmentRoot;
+
+import org.eclipse.jdt.ui.jarpackager.IManifestProvider;
+import org.eclipse.jdt.ui.jarpackager.JarPackageData;
+
+import org.eclipse.jdt.internal.ui.jarpackager.JarPackagerUtil;
+
+/**
+ * A jar builder which extracts the required libraries into a folder next to the generated jar.
+ *
+ * @since 3.5
+ */
+public class UnpackJarBuilder extends FatJarBuilder {
+
+ public static final String BUILDER_ID= "org.eclipse.jdt.ui.unpack_jar_builder"; //$NON-NLS-1$
+ private static final String SUBFOLDER_SUFFIX= "_lib"; //$NON-NLS-1$
+
+ private final String fSubfolder;
+ private final IPath fSubfolderPath;
+
+ private JarPackageData fJarPackage;
+
+ private Set<String> jarNames;
+
+ public UnpackJarBuilder(JarPackageData jarPackage) {
+ fSubfolder= jarPackage.getAbsoluteJarLocation().removeFileExtension().lastSegment() + SUBFOLDER_SUFFIX;
+ fSubfolderPath= jarPackage.getAbsoluteJarLocation().removeLastSegments(1).append(fSubfolder);
+ fJarPackage= jarPackage;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getId() {
+ return BUILDER_ID;
+ }
+
+ /**
+ * we do not need to merge any manifests here.
+ * @return false
+ */
+ @Override
+ public boolean isMergeManifests() {
+ return false;
+ }
+
+ /**
+ * we do not need to remove signers here.
+ * @return false
+ */
+ @Override
+ public boolean isRemoveSigners() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IManifestProvider getManifestProvider() {
+ return new FatJarManifestProvider(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getManifestClasspath() {
+ Set<String> renamedJarNames= new HashSet<String>();
+ Object[] elements= fJarPackage.getElements();
+ for (int i= 0; i < elements.length; i++) {
+ Object element= elements[i];
+ if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot)element).isArchive()) {
+ String jarName= ((IPackageFragmentRoot)element).getPath().toFile().getName();
+ while (renamedJarNames.contains(jarName)) {
+ jarName= FatJarPackagerUtil.nextNumberedFileName(jarName);
+ }
+ renamedJarNames.add(jarName);
+ }
+ }
+ StringBuffer result= new StringBuffer();
+ result.append("."); //$NON-NLS-1$
+ for (Iterator<String> iterator= renamedJarNames.iterator(); iterator.hasNext();) {
+ String jarName= iterator.next();
+ result.append(" ").append(fSubfolder).append("/").append(jarName); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return result.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void open(JarPackageData jarPackage, Shell displayShell, MultiStatus status) throws CoreException {
+ super.open(jarPackage, displayShell, status);
+ fJarPackage= jarPackage;
+ jarNames= new HashSet<String>();
+ createBlankSubfolder(displayShell, jarPackage.allowOverwrite());
+ }
+
+ /**
+ * creates the subfolder or cleanup an existing subfolder. A dialog will ask the user.
+ *
+ * @param parent the parent for the dialog, or <code>null</code> if no dialog should be
+ * presented
+ * @param allowOverwrite true if the packager is allowed to overwrite existing folders
+ * @throws CoreException if creation of folder failed
+ */
+ protected void createBlankSubfolder(Shell parent, boolean allowOverwrite) throws CoreException {
+ File folder= fSubfolderPath.toFile();
+ // Test if directory exists
+ if (!folder.exists()) {
+ // create sub-folder
+ if (!folder.mkdirs())
+ throw JarPackagerUtil.createCoreException("Could not create lib-folder '" + folder.getAbsolutePath() + "'", null); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ if (!folder.canWrite())
+ throw JarPackagerUtil.createCoreException("Folder '" + folder.getAbsolutePath() + "' is not writable", null); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!allowOverwrite)
+ if (parent == null || !JarPackagerUtil.askForOverwriteFolderPermission(parent, fSubfolderPath, true))
+ throw JarPackagerUtil.createCoreException("Folder '" + folder.getAbsolutePath() + "' exists and should not be overwritten", null); //$NON-NLS-1$ //$NON-NLS-2$
+ File[] jarFiles= folder.listFiles();
+ for (int i= 0; i < jarFiles.length; i++) {
+ if (!jarFiles[i].isFile())
+ throw JarPackagerUtil.createCoreException("Subfolder '" + jarFiles[i].getAbsolutePath() + "' exists", null); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!jarFiles[i].delete())
+ throw JarPackagerUtil.createCoreException("Could not delete file '" + jarFiles[i].getAbsolutePath() + "'", null); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+
+ public void writeArchive(ZipFile jarFile, IProgressMonitor progressMonitor) {
+ File jarPathFile= new File(jarFile.getName());
+ String jarName= jarPathFile.getName();
+ while (jarNames.contains(jarName)) {
+ jarName= FatJarPackagerUtil.nextNumberedFileName(jarName);
+ }
+ jarNames.add(jarName);
+ File destJarPathFile= new File(fSubfolderPath.toFile(), jarName);
+ copyFile(jarPathFile, destJarPathFile);
+ }
+
+ private void copyFile(File src, File dest) {
+ InputStream in= null;
+ OutputStream out= null;
+ try {
+ in= new FileInputStream(src);
+ out= new FileOutputStream(dest);
+ byte[] buf= new byte[4096];
+ int cnt= in.read(buf);
+ while (cnt > 0) {
+ out.write(buf, 0, cnt);
+ cnt= in.read(buf);
+ }
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ try {
+ out.close();
+ } catch (IOException ignore) {
+ }
+ try {
+ in.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+
+}