/******************************************************************************* * 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(); } }