/******************************************************************************* | |
* 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 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.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 = SiteLocal.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); | |
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); | |
if (site instanceof ITimestamp) { | |
siteTimestamps.put(site.getURL(), new Long(((ITimestamp)site).getTimestamp().getTime())); | |
} else { | |
try { | |
Response response = UpdateCore.getPlugin().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(); | |
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))) { | |
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 { | |
ISite site = null; | |
try { | |
monitor.worked(1); | |
site = createSite(factory, fixedUrl, monitor); | |
httpSitesUpdatedUrls.put(url.toExternalForm(), fixedUrl); | |
} catch (CoreException ce) { | |
if (monitor.isCanceled()) | |
return null; | |
if (!fixedUrl.equals(url)) { | |
// try with original url | |
site = createSite(factory, url, monitor); | |
httpSitesUpdatedUrls.put(url.toExternalForm(), url); | |
} else { | |
throw ce; | |
} | |
} | |
return site; | |
} catch(CoreException ce) { | |
throw Utilities.newCoreException(NLS.bind(Messages.InternalSiteManager_UnableToAccessURL, (new String[] { url.toExternalForm() })), ce); | |
} | |
} | |
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(); | |
} | |
} |