/******************************************************************************* * Copyright (c) 2000, 2010 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.update.core; import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.*; import org.eclipse.update.core.model.*; import org.eclipse.update.internal.core.*; /** * Local .jar file content reference. * <p> * This class may be instantiated or subclassed by clients. * </p> * <p> * <b>Note:</b> This class/interface is part of an interim API that is still under development and expected to * change significantly before reaching stability. It is being made available at this early stage to solicit feedback * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken * (repeatedly) as the API evolves. * </p> * @see org.eclipse.update.core.ContentReference * @see org.eclipse.update.core.JarEntryContentReference * @since 2.0 * @deprecated The org.eclipse.update component has been replaced by Equinox p2. * This API will be deleted in a future release. See bug 311590 for details. */ public class JarContentReference extends ContentReference { //private static ArrayList referenceList = new ArrayList(); private JarFile jarFile; /** * Content selector used in .jar operations. * Default implementation causes all file entries to be selected with * generated identifiers being the same as the original .jar entry name. * * @since 2.0 */ public static class ContentSelector { /** * Indicates whether the .jar entry should be selected. * Default behavior is to select all non-directory entries. * * @param entry .jar entry * @return <code>true</code> if entry is to be selected, * <code>false</code> otherwise * @since 2.0 */ public boolean include(JarEntry entry) { return entry == null ? false : !entry.isDirectory(); } /** * Defines the "symbolic" path identifier for the * entry. Default identifier is the same as the jar entry name. * * @param entry .jar entry * @return "symbolic" path identifier * @since 2.0 */ public String defineIdentifier(JarEntry entry) { return entry == null ? null : entry.getName(); } } /** * Create jar content reference from URL. * * @param id "symbolic" path identifier * @param url actual referenced URL * @since 2.0 */ public JarContentReference(String id, URL url) { super(id, url); this.jarFile = null; //referenceList.add(this); // keep track of archives } /** * Create jar content reference from file. * * @param id "symbolic" path identifier * @param file actual referenced file * @since 2.0 */ public JarContentReference(String id, File file) { super(id, file); this.jarFile = null; //referenceList.add(this); // keep track of archives } /** * A factory method to create a jar content reference. * * @param id "symbolic" path identifier * @param file actual referenced file * @return jar content reference * @since 2.0 */ public ContentReference createContentReference(String id, File file) { return new JarContentReference(id, file,true); } /** * Constructor JarContentReference. * @param id * @param file * @param b */ public JarContentReference(String id, File file, boolean b) { this(id,file); setTempLocal(b); } /** * Returns the content reference as a jar file. Note, that this method * <b>does not</b> cause the file to be downloaded if it * is not already local. * * @return reference as jar file * @exception IOException reference cannot be returned as jar file * @since 2.0 */ protected JarFile asJarFile() throws IOException { if (this.jarFile == null) { File file = asFile(); if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL) UpdateCore.debug("asJarFile :" + file); //$NON-NLS-1$ if (file != null && !file.exists()) { UpdateCore.warn("JarFile does not exits:" + file); //$NON-NLS-1$ throw new FileNotFoundException(file.getAbsolutePath()); } this.jarFile = new JarFile(file); } return jarFile; } /** * Unpacks the referenced jar archive into the specified location. * Returns content references to the unpacked files. * * @param dir location to unpack the jar into * @param selector selector, used to select entries to unpack, and to define * "symbolic" path identifiers for the entries. * @param monitor progress monitor * @exception IOException * @exception InstallAbortedException * @since 2.0 */ public ContentReference[] unpack(File dir, ContentSelector selector, InstallMonitor monitor) throws IOException, InstallAbortedException { // make sure we have a selector if (selector == null) selector = new ContentSelector(); // get archive content JarFile jarArchive = this.asJarFile(); List content = new ArrayList(); Enumeration entries = jarArchive.entries(); // run through the entries and unjar String entryId; JarEntry entry; InputStream is; OutputStream os; File localFile; try { if (monitor != null) { monitor.saveState(); monitor.setTaskName(Messages.JarContentReference_Unpacking); monitor.subTask(this.getIdentifier()); monitor.showCopyDetails(false); } while (entries.hasMoreElements()) { entry = (JarEntry) entries.nextElement(); if (entry != null && selector.include(entry)) { is = null; os = null; entryId = selector.defineIdentifier(entry); localFile = Utilities.createLocalFile(dir, entryId); // create temp file if (!entry.isDirectory()) { try { is = jarArchive.getInputStream(entry); os = new FileOutputStream(localFile); Utilities.copy(is, os, monitor); } finally { if (is != null) try { is.close(); } catch (IOException e) { } if (os != null) try { os.close(); } catch (IOException e) { } } content.add(new ContentReference(entryId, localFile)); } } } } finally { if (monitor != null) monitor.restoreState(); } return (ContentReference[]) content.toArray(new ContentReference[0]); } /** * Unpacks the named jar entry into the specified location. * Returns content reference to the unpacked file. * * @param dir location to unpack the jar into * @param entryName name of the jar entry * @param selector selector, used to define "symbolic" path identifier * for the entry * @param monitor progress monitor * @exception IOException * @exception InstallAbortedException * @since 2.0 */ public ContentReference unpack(File dir, String entryName, ContentSelector selector, InstallMonitor monitor) throws IOException, InstallAbortedException { // make sure we have a selector if (selector == null) selector = new ContentSelector(); // unjar the entry JarFile jarArchive = this.asJarFile(); entryName = entryName.replace(File.separatorChar, '/'); JarEntry entry = jarArchive.getJarEntry(entryName); String entryId; if (entry != null) { InputStream is = null; OutputStream os = null; entryId = selector.defineIdentifier(entry); File localFile = Utilities.createLocalFile(dir, entryId); // create temp file if (!entry.isDirectory()) { try { is = jarArchive.getInputStream(entry); os = new FileOutputStream(localFile); Utilities.copy(is, os, monitor); } finally { if (is != null) try { is.close(); } catch (IOException e) { } if (os != null) try { os.close(); } catch (IOException e) { } } return new ContentReference(entryId, localFile); } else return null; // entry was a directory } else throw new FileNotFoundException(this.asFile().getAbsolutePath() + " " + entryName); //$NON-NLS-1$ } /** * Peeks into the referenced jar archive. * Returns content references to the jar entries within the jar file. * * @param selector selector, used to select entries to return, and to define * "symbolic" path identifiers for the entries. * @param monitor progress monitor * @exception IOException * @since 2.0 */ public ContentReference[] peek(ContentSelector selector, InstallMonitor monitor) throws IOException { // make sure we have a selector if (selector == null) selector = new ContentSelector(); // get archive content JarFile jarArchive = this.asJarFile(); List content = new ArrayList(); Enumeration entries = jarArchive.entries(); // run through the entries and create content references JarEntry entry; String entryId; while (entries.hasMoreElements()) { entry = (JarEntry) entries.nextElement(); if (selector.include(entry)) { entryId = selector.defineIdentifier(entry); content.add(new JarEntryContentReference(entryId, this, entry)); } } return (ContentReference[]) content.toArray(new ContentReference[0]); } /** * Peeks into the referenced jar archive looking for the named entry. * Returns content reference to the jar entry within the jar file. * * @param entryName name of the jar entry * @param selector selector, used to define "symbolic" path identifier * for the entry * @param monitor progress monitor * @return the content reference ofr <code>null</null> if the entry doesn't exist * @exception IOException * @since 2.0 */ public ContentReference peek(String entryName, ContentSelector selector, InstallMonitor monitor) throws IOException { // make sure we have a selector if (selector == null) selector = new ContentSelector(); // assume we have a reference that represents a jar archive. JarFile jarArchive = this.asJarFile(); entryName = entryName.replace(File.separatorChar, '/'); JarEntry entry = jarArchive.getJarEntry(entryName); if (entry == null) return null; String entryId = selector.defineIdentifier(entry); return new JarEntryContentReference(entryId, this, entry); } /** * Closes the jar archive corresponding to this reference. * * @exception IOException * @since 2.0 */ public void closeArchive() throws IOException { if (this.jarFile != null) { this.jarFile.close(); this.jarFile = null; } } /** * Perform shutdown processing for jar archive handling. * This method is called when platform is shutting down. * It is not intended to be called at any other time under * normal circumstances. A side-effect of calling this method * is that all jars referenced by JarContentReferences are closed. * * @since 2.0 */ public static void shutdown() { /*for (int i = 0; i < referenceList.size(); i++) { JarContentReference ref = (JarContentReference) referenceList.get(i); try { ref.closeArchive(); // ensure we are not leaving open jars } catch (IOException e) { // we tried, nothing we can do ... } }*/ } }