/******************************************************************************* | |
* Copyright (c) 2000, 2004 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.update.core; | |
import java.io.*; | |
import java.net.*; | |
import java.util.*; | |
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 | |
*/ | |
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(Policy.bind("JarContentReference.Unpacking")); //$NON-NLS-1$ | |
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 ... | |
} | |
} | |
} | |
} |