blob: bbeffa13a572c1265960f4596016ffe49169fd90 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 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.URL;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.update.core.model.*;
import org.eclipse.update.internal.core.InternalSiteManager;
import org.eclipse.update.internal.core.Policy;
import org.eclipse.update.internal.core.UpdateCore;
/**
* Base implementation of a feature content provider.
* This class provides a set of helper methods useful for implementing
* feature content providers. In particular, methods dealing with
* downloading and caching of feature files.
* <p>
* This class must be subclassed by clients.
* </p>
* @see org.eclipse.update.core.IFeatureContentProvider
* @since 2.0
*/
public abstract class FeatureContentProvider implements IFeatureContentProvider {
private static final boolean SWITCH_COPY_LOCAL = true;
/**
*
*/
public class FileFilter {
private String filterString = null;
private IPath filterPath = null;
/**
* Constructor for FileFilter.
*/
public FileFilter(String filter) {
super();
this.filterString = filter;
this.filterPath = new Path(filter);
}
/**
* returns true if the name matches the rule
*/
public boolean accept(String name) {
if (name == null)
return false;
// no '*' pattern matching
// must be equals
IPath namePath = new Path(name);
if (filterPath.lastSegment().indexOf('*') == -1) {
return filterPath.equals(namePath);
}
// check same file extension if extension exists (a.txt/*.txt)
// or same file name (a.txt,a.*)
String extension = filterPath.getFileExtension();
if (!extension.equals("*")) {
if (!extension.equalsIgnoreCase(namePath.getFileExtension()))
return false;
} else {
IPath noExtension = filterPath.removeFileExtension();
String fileName = noExtension.lastSegment();
if (!fileName.equals("*")) {
if (!namePath.lastSegment().startsWith(fileName))
return false;
}
}
// check same path
IPath p1 = namePath.removeLastSegments(1);
IPath p2 = filterPath.removeLastSegments(1);
return p1.equals(p2);
}
}
private URL base;
private IFeature feature;
private File tmpDir; // local work area for each provider
public static final String JAR_EXTENSION = ".jar"; //$NON-NLS-1$
private static final String DOT_PERMISSIONS = "permissions.properties";
private static final String EXECUTABLES = "permissions.executable";
// lock
private final static Object lock = new Object();
/**
* Feature content provider constructor
*
* @param base feature URL. The interpretation of this URL
* is specific to each content provider.
* @since 2.0
*/
public FeatureContentProvider(URL base) {
this.base = base;
this.feature = null;
}
/**
* Returns the feature url.
* @see IFeatureContentProvider#getURL()
*/
public URL getURL() {
return base;
}
/**
* Returns the feature associated with this content provider.
* @see IFeatureContentProvider#getFeature()
*/
public IFeature getFeature() {
return feature;
}
/**
* Sets the feature associated with this content provider.
* @see IFeatureContentProvider#setFeature(IFeature)
*/
public void setFeature(IFeature feature) {
this.feature = feature;
}
/**
* Returns the specified reference as a local file system reference.
* If required, the file represented by the specified content
* reference is first downloaded to the local system
*
* @param ref content reference
* @param monitor progress monitor, can be <code>null</code>
* @exception IOException
* @exception CoreException
* @since 2.0
*/
public ContentReference asLocalReference(ContentReference ref, InstallMonitor monitor) throws IOException, CoreException {
// check to see if this is already a local reference
if (ref.isLocalReference())
return ref;
// check to see if we already have a local file for this reference
String key = ref.toString();
// need to synch as another thread my have created the file but
// is still copying into it
File localFile = null;
synchronized (lock) {
localFile = Utilities.lookupLocalFile(key);
if (localFile != null)
return ref.createContentReference(ref.getIdentifier(), localFile);
//
// download the referenced file into local temporary area
InputStream is = null;
OutputStream os = null;
localFile = Utilities.createLocalFile(getWorkingDirectory(), null /*name*/
);
boolean sucess = false;
if (monitor != null) {
monitor.saveState();
monitor.setTaskName(Policy.bind("FeatureContentProvider.Downloading"));
//$NON-NLS-1$
monitor.subTask(ref.getIdentifier() + " "); //$NON-NLS-1$
monitor.setTotalCount(ref.getInputSize());
monitor.showCopyDetails(true);
}
try {
try {
is = ref.getInputStream();
} catch (IOException e) {
throw Utilities.newCoreException(Policy.bind("FeatureContentProvider.UnableToRetrieve", new Object[] { ref }), e);
}
try {
os = new BufferedOutputStream(new FileOutputStream(localFile));
} catch (FileNotFoundException e) {
throw Utilities.newCoreException(Policy.bind("FeatureContentProvider.UnableToCreate", new Object[] { localFile }), e);
}
Date start = new Date();
Utilities.copy(is, os, monitor);
Date stop = new Date();
long timeInseconds = (stop.getTime()-start.getTime())/1000; // time in milliseconds /1000 = time in seconds
InternalSiteManager.downloaded(ref.getInputSize(),(timeInseconds),ref.asURL());
sucess = true;
// file is downloaded succesfully, map it
Utilities.mapLocalFile(key,localFile);
} catch (ClassCastException e) {
throw Utilities.newCoreException(Policy.bind("FeatureContentProvider.UnableToCreate", new Object[] { localFile }), e);
} finally {
//Do not close IS if user cancel,
//closing IS will read the entire Stream until the end
if (sucess && is != null)
try {
is.close();
} catch (IOException e) {
}
if (os != null)
try {
os.close(); // should flush buffer stream
} catch (IOException e) {
}
if (monitor != null)
monitor.restoreState();
}
} // end lock
ContentReference reference = ref.createContentReference(ref.getIdentifier(), localFile);
return reference;
}
/**
* Returns the specified reference as a local file.
* If required, the file represented by the specified content
* reference is first downloaded to the local system
*
* @param ref content reference
* @param monitor progress monitor, can be <code>null</code>
* @exception IOException
* @exception CoreException
* @since 2.0
*/
public File asLocalFile(ContentReference ref, InstallMonitor monitor) throws IOException, CoreException {
File file = ref.asFile();
if (file != null && !SWITCH_COPY_LOCAL)
return file;
ContentReference localRef = asLocalReference(ref, monitor);
file = localRef.asFile();
return file;
}
/**
* Returns working directory for this content provider
*
* @return working directory
* @exception IOException
* @since 2.0
*/
protected File getWorkingDirectory() throws IOException {
if (tmpDir == null)
tmpDir = Utilities.createWorkingDirectory();
return tmpDir;
}
/**
* Returns the total size of all archives required for the
* specified plug-in and non-plug-in entries (the "packaging" view).
* @see IFeatureContentProvider#getDownloadSizeFor(IPluginEntry[], INonPluginEntry[])
*/
public long getDownloadSizeFor(IPluginEntry[] pluginEntries, INonPluginEntry[] nonPluginEntries) {
long result = 0;
// if both are null or empty, return UNKNOWN size
if ((pluginEntries == null || pluginEntries.length == 0) && (nonPluginEntries == null || nonPluginEntries.length == 0)) {
return ContentEntryModel.UNKNOWN_SIZE;
}
// loop on plugin entries
long size = 0;
if (pluginEntries != null)
for (int i = 0; i < pluginEntries.length; i++) {
size = ((PluginEntryModel) pluginEntries[i]).getDownloadSize();
if (size == ContentEntryModel.UNKNOWN_SIZE) {
return ContentEntryModel.UNKNOWN_SIZE;
}
result += size;
}
// loop on non plugin entries
if (nonPluginEntries != null)
for (int i = 0; i < nonPluginEntries.length; i++) {
size = ((NonPluginEntryModel) nonPluginEntries[i]).getDownloadSize();
if (size == ContentEntryModel.UNKNOWN_SIZE) {
return ContentEntryModel.UNKNOWN_SIZE;
}
result += size;
}
return result;
}
/**
* Returns the total size of all files required for the
* specified plug-in and non-plug-in entries (the "logical" view).
* @see IFeatureContentProvider#getInstallSizeFor(IPluginEntry[], INonPluginEntry[])
*/
public long getInstallSizeFor(IPluginEntry[] pluginEntries, INonPluginEntry[] nonPluginEntries) {
long result = 0;
// if both are null or empty, return UNKNOWN size
if ((pluginEntries == null || pluginEntries.length == 0) && (nonPluginEntries == null || nonPluginEntries.length == 0)) {
return ContentEntryModel.UNKNOWN_SIZE;
}
// loop on plugin entries
long size = 0;
if (pluginEntries != null)
for (int i = 0; i < pluginEntries.length; i++) {
size = ((PluginEntryModel) pluginEntries[i]).getInstallSize();
if (size == ContentEntryModel.UNKNOWN_SIZE) {
return ContentEntryModel.UNKNOWN_SIZE;
}
result += size;
}
// loop on non plugin entries
if (nonPluginEntries != null)
for (int i = 0; i < nonPluginEntries.length; i++) {
size = ((NonPluginEntryModel) nonPluginEntries[i]).getInstallSize();
if (size == ContentEntryModel.UNKNOWN_SIZE) {
return ContentEntryModel.UNKNOWN_SIZE;
}
result += size;
}
return result;
}
/**
* Returns the path identifier for a plugin entry.
* <code>plugins/&lt;pluginId>_&lt;pluginVersion>.jar</code>
* @return the path identifier
*/
protected String getPathID(IPluginEntry entry) {
return Site.DEFAULT_PLUGIN_PATH + entry.getVersionedIdentifier().toString() + JAR_EXTENSION;
}
/**
* Returns the path identifer for a non plugin entry.
* <code>features/&lt;featureId>_&lt;featureVersion>/&lt;dataId></code>
* @return the path identifier
*/
protected String getPathID(INonPluginEntry entry) {
String nonPluginBaseID = Site.DEFAULT_FEATURE_PATH + feature.getVersionedIdentifier().toString() + "/";
//$NON-NLS-1$
return nonPluginBaseID + entry.getIdentifier();
}
/**
* Sets the permission of all the ContentReferences
* Check for the .permissions contentReference and use it
* to set the permissions of other ContentReference
*
* @return void
*/
protected void validatePermissions(ContentReference[] references) {
if (references == null || references.length == 0)
return;
Map permissions = getPermissions(references);
if (permissions.isEmpty())
return;
for (int i = 0; i < references.length; i++) {
ContentReference contentReference = references[i];
String id = contentReference.getIdentifier();
Object value = null;
if ((value = matchesOneRule(id, permissions)) != null) {
Integer permission = (Integer) value;
contentReference.setPermission(permission.intValue());
}
}
}
/**
* Returns the value of the matching rule or <code>null</code> if none found.
* A rule is matched if the id is equals to a key, or if the id is resolved by a key.
* if the id is <code>/path/file.txt</code> it is resolved by <code>/path/*</code>
* or <code>/path/*.txt</code>
*
* @param id the identifier
* @param permissions list of rules
* @return Object the value of the matcing rule or <code>null</code>
*/
private Object matchesOneRule(String id, Map permissions) {
Set keySet = permissions.keySet();
Iterator iter = keySet.iterator();
while (iter.hasNext()) {
FileFilter rule = (FileFilter) iter.next();
if (rule.accept(id)) {
return permissions.get(rule);
}
}
return null;
}
/*
* returns the permission MAP
*/
private Map getPermissions(ContentReference[] references) {
Map result = new HashMap();
// search for .permissions
boolean notfound = true;
ContentReference permissionReference = null;
for (int i = 0; i < references.length && notfound; i++) {
ContentReference contentReference = references[i];
if (DOT_PERMISSIONS.equals(contentReference.getIdentifier())) {
notfound = false;
permissionReference = contentReference;
}
}
if (notfound)
return result;
Properties prop = new Properties();
try {
prop.load(permissionReference.getInputStream());
} catch (IOException e) {
UpdateCore.warn("", e);
}
String executables = prop.getProperty(EXECUTABLES);
if (executables == null)
return result;
StringTokenizer tokenizer = new StringTokenizer(executables, ",");
Integer defaultExecutablePermission = new Integer(ContentReference.DEFAULT_EXECUTABLE_PERMISSION);
while (tokenizer.hasMoreTokens()) {
FileFilter filter = new FileFilter(tokenizer.nextToken());
result.put(filter, defaultExecutablePermission);
}
return result;
}
}