blob: f01650115a3db99de268812252c197f8c2d72d34 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.internal.core;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.update.configuration.ILocalSite;
import org.eclipse.update.core.ISite;
import org.eclipse.update.core.ISiteFactory;
import org.eclipse.update.core.ISiteFactoryExtension;
import org.eclipse.update.core.JarContentReference;
import org.eclipse.update.core.Site;
import org.eclipse.update.core.Utilities;
import org.eclipse.update.core.model.InvalidSiteTypeException;
import org.eclipse.update.internal.core.connection.ConnectionFactory;
import org.eclipse.update.internal.core.connection.IResponse;
import org.eclipse.update.internal.model.ITimestamp;
/**
*
*/
public class InternalSiteManager {
public static ILocalSite localSite;
public static final String DEFAULT_SITE_TYPE = SiteURLContentProvider.SITE_TYPE;
private static final String DEFAULT_EXECUTABLE_SITE_TYPE = SiteFileContentProvider.SITE_TYPE;
private static Map estimates;
// cache found sites
private static Map sites = new HashMap();
// cache http updated url
private static Map httpSitesUpdatedUrls = new HashMap();
// cache timestamps
private static Map siteTimestamps = new HashMap();
public static boolean globalUseCache = true;
// true if an exception occured creating localSite
// so we cache it and don't attempt to create it again
private static CoreException exceptionOccured = null;
/*
* @see SiteManager#getLocalSite()
*/
public static ILocalSite getLocalSite() throws CoreException {
return internalGetLocalSite();
}
/*
* Internal call if optimistic reconciliation needed
*/
private static ILocalSite internalGetLocalSite() throws CoreException {
// if an exception occured while retrieving the Site
// rethrow it
if (exceptionOccured != null)
throw exceptionOccured;
if (localSite == null) {
try {
localSite = LocalSite.internalGetLocalSite();
} catch (CoreException e) {
exceptionOccured = e;
throw e;
}
}
return localSite;
}
private static boolean isValidCachedSite(URL siteURL) {
if (!sites.containsKey(siteURL.toExternalForm()))
return false;
Long timestamp = (Long)siteTimestamps.get(siteURL);
if (timestamp == null)
return false;
long localLastModified = timestamp.longValue();
return UpdateManagerUtils.isSameTimestamp(siteURL, localLastModified);
}
/*
* @see ILocalSite#getSite(URL)
*/
public static ISite getSite(URL siteURL, boolean useCache, IProgressMonitor monitor) throws CoreException {
ISite site = null;
if (monitor==null) monitor = new NullProgressMonitor();
if (siteURL == null)
return null;
// use cache if set up globally (globalUseCache=true)
// and passed as parameter (useCache=true)
if (httpSitesUpdatedUrls.containsKey(siteURL.toExternalForm())) {
siteURL = (URL)httpSitesUpdatedUrls.get(siteURL.toExternalForm());
}
String siteURLString = siteURL.toExternalForm();
if ((useCache && globalUseCache) && isValidCachedSite(siteURL)) {
site = (ISite) sites.get(siteURLString);
UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
return site;
}
// try adding "eclipse" to the site url, in case this is an extension site
if ("file".equals(siteURL.getProtocol()) ) { //$NON-NLS-1$
File f = new File(siteURL.getFile());
if (f.isDirectory() && !"eclipse".equals(f.getName())) { //$NON-NLS-1$
f = new File(f, "eclipse"); //$NON-NLS-1$
try {
if ((useCache && globalUseCache) && isValidCachedSite(f.toURL())) {
site = (ISite) sites.get(f.toURL().toExternalForm());
return site;
}
} catch (MalformedURLException e) {
}
}
}
// consider file protocol also if the URL points to a directory
// and no site.xml exist
// if the user points to a file, consider DEFAULT_SITE_TYPE
// site.xml will have to specify the type
boolean fileProtocol = "file".equalsIgnoreCase(siteURL.getProtocol()); //$NON-NLS-1$
boolean directoryExists = false;
if (fileProtocol) {
File dir;
dir = new File(siteURL.getFile());
if (dir != null && dir.isDirectory()) {
if (!(new File(dir, Site.SITE_XML).exists()))
directoryExists = true;
}
}
//PERF: if file: <path>/ and directory exists then consider executable
monitor.beginTask(Messages.InternalSiteManager_ConnectingToSite, 8);
if (fileProtocol && directoryExists) {
site = attemptCreateSite(DEFAULT_EXECUTABLE_SITE_TYPE, siteURL, monitor);
monitor.worked(4); // only one attempt
} else {
try {
monitor.worked(3);
site = attemptCreateSite(DEFAULT_SITE_TYPE, siteURL, monitor);
monitor.worked(1);
} catch (CoreException preservedException) {
if (!monitor.isCanceled()) {
// attempt a retry is the protocol is file, with executbale type
if (!fileProtocol)
throw preservedException;
try {
site = attemptCreateSite(DEFAULT_EXECUTABLE_SITE_TYPE, siteURL, monitor);
} catch (CoreException retryException) {
IStatus firstStatus = preservedException.getStatus();
MultiStatus multi = new MultiStatus(firstStatus.getPlugin(), IStatus.OK, Messages.InternalSiteManager_FailedRetryAccessingSite, retryException);
multi.addAll(firstStatus);
throw preservedException;
}
}
}
}
if (site != null) {
sites.put(site.getURL().toExternalForm(), site);
UpdateCore.getPlugin().getUpdateSession().markVisited(site.getURL());
if (site instanceof ITimestamp) {
siteTimestamps.put(site.getURL(), new Long(((ITimestamp)site).getTimestamp().getTime()));
} else {
try {
IResponse response = ConnectionFactory.get(URLEncoder.encode(siteURL));
siteTimestamps.put(siteURL, new Long(response.getLastModified()));
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}
//flush the JarFile we may hold on to
// we keep the temp not to create them again
JarContentReference.shutdown(); // make sure we are not leaving jars open for this site
//flush mapping of downloaded JAR files
// FIXME : provide better cache flushing after 2.1
// FIXED: everything downloaded is cached and timestamped.
// Timestamps are compared to lastModifed on the server
// and we download only when there is a differenc
// Utilities.flushLocalFile();
return site;
}
/*
* Attempt to create a site
* if the site guessed is not the type found,
* attempt to create a type with the type found in the site.xml
*/
private static ISite attemptCreateSite(String guessedTypeSite, URL siteURL, IProgressMonitor monitor) throws CoreException {
if (monitor == null) monitor = new NullProgressMonitor();
ISite site = null;
try {
monitor.worked(1);
site = createSite(guessedTypeSite, siteURL, monitor);
monitor.worked(1); // if no error, occurs the retry branch doesn't need to be executed
} catch (InvalidSiteTypeException e) {
if (monitor.isCanceled()) return null;
// the type in the site.xml is not the one expected
// attempt to use this type instead
//DEBUG:
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_TYPE) {
UpdateCore.debug("The Site :" + siteURL.toExternalForm() + " is a different type than the guessed type based on the protocol. new Type:" + e.getNewType()); //$NON-NLS-1$ //$NON-NLS-2$
}
try {
if (e.getNewType() == null)
throw e;
site = createSite(e.getNewType(), siteURL, monitor);
} catch (InvalidSiteTypeException e1) {
throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToCreateSiteWithType, (new String[] { e.getNewType(), siteURL.toExternalForm() })), e1);
}
}
return site;
}
/*
* create an instance of a class that implements ISite
*
* the URL can be of the following form
* 1 protocol://...../
* 2 protocol://.....
* 3 protocol://..../site.xml
* 4 protocol://...#...
*
* 1 If the file of the file of teh url ends with '/', attempt to open the stream.
* if it fails, add site.xml and attempt to open the stream
*
* 2 attempt to open the stream
* fail
* add '/site.xml' and attempt to open the stream
* sucess
* attempt to parse, if it fails, add '/site.xml' and attempt to open the stream
*
* 3 open the stream
*
* 4 open the stream
*/
private static ISite createSite(String siteType, URL url, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
if (monitor == null) monitor = new NullProgressMonitor();
//ISite site = null;
ISiteFactory factory = SiteTypeFactory.getInstance().getFactory(siteType);
URL fixedUrl;
// see if we need to (and can) fix url by adding site.xml to it
try {
if ( (url.getRef() != null) || (url.getFile().endsWith(Site.SITE_XML) || (url.getProtocol().equalsIgnoreCase("file")))) { //$NON-NLS-1$
fixedUrl = url;
} else if (url.getFile().endsWith("/")) { //$NON-NLS-1$
fixedUrl = new URL(url, Site.SITE_XML);
} else {
fixedUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + "/" + Site.SITE_XML); //$NON-NLS-1$
}
} catch (MalformedURLException mue) {
fixedUrl = url;
}
try {
try {
monitor.worked(1);
return createSite( factory, fixedUrl, url, monitor);
} catch (CoreException ce) {
if (monitor.isCanceled())
return null;
if (!fixedUrl.equals(url)) {
// try with original url
return createSite( factory, url, url, monitor);
} else if (url.getProtocol().equalsIgnoreCase("file") && ! url.getFile().endsWith(Site.SITE_XML)){ //$NON-NLS-1$
try {
if (url.getFile().endsWith("/")) { //$NON-NLS-1$
return createSite(factory, new URL(url,
Site.SITE_XML), url, monitor);
} else {
return createSite(factory, new URL(url
.getProtocol(), url.getHost(), url
.getPort(), url.getFile()
+ "/" + Site.SITE_XML), url, monitor); //$NON-NLS-1$
}
} catch (MalformedURLException mue) {
throw ce;
}
} else {
throw ce;
}
}
} catch(CoreException ce) {
throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToAccessURL, (new String[] { url.toExternalForm() })), ce);
}
}
private static ISite createSite(ISiteFactory factory, URL url, URL originalUrl, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
ISite site;
site = createSite(factory, url, monitor);
httpSitesUpdatedUrls.put(originalUrl.toExternalForm(), url);
return site;
}
private static ISite createSite(ISiteFactory factory, URL url, IProgressMonitor monitor) throws CoreException, InvalidSiteTypeException {
if (factory instanceof ISiteFactoryExtension)
return ((ISiteFactoryExtension)factory).createSite(url, monitor);
else
return factory.createSite(url);
}
/*
* Creates a new site on the file system
* This is the only Site we can create.
*
* @param siteLocation
* @throws CoreException
*/
public static ISite createSite(File siteLocation) throws CoreException {
ISite site = null;
if (siteLocation != null) {
try {
URL siteURL = siteLocation.toURL();
site = getSite(siteURL, false, null);
} catch (MalformedURLException e) {
throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToCreateURL, (new String[] { siteLocation.getAbsolutePath() })), e);
}
}
return site;
}
/**
* Method downloaded.
* @param downloadSize size downloaded in bytes
* @param time time in seconds
* @param url
*/
public static void downloaded(long downloadSize, long time, URL url) {
if (downloadSize <= 0 || time < 0)
return;
String host = url.getHost();
long sizeByTime = (time == 0) ? 0 : downloadSize / time;
Long value = new Long(sizeByTime);
if (estimates == null) {
estimates = new HashMap();
} else {
Long previous = (Long) estimates.get(host);
if (previous != null) {
value = new Long((previous.longValue() + sizeByTime) / 2);
}
}
estimates.put(host, value);
}
/**
* Method getEstimatedTransferRate rate bytes/seconds.
* @param host
* @return long
*/
public static long getEstimatedTransferRate(String host) {
if (estimates == null)
return 0;
Long value = (Long) estimates.get(host);
if (value == null)
return 0;
return value.longValue();
}
}