| /******************************************************************************* |
| * Copyright (c) 2005, 2009 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 |
| * Chris Aniszczyk (IBM Corp.) - Fixed NPE |
| *******************************************************************************/ |
| package org.eclipse.update.internal.core; |
| |
| import org.eclipse.update.core.IUpdateConstants; |
| |
| import java.io.*; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.update.core.*; |
| import org.eclipse.update.core.model.InstallAbortedException; |
| import org.eclipse.update.internal.core.connection.ConnectionFactory; |
| import org.eclipse.update.internal.core.connection.IResponse; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.Constants; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| |
| /** |
| * |
| */ |
| public class UpdateManagerUtils { |
| |
| private static boolean OS_UNIX = org.eclipse.osgi.service.environment.Constants.OS_HPUX |
| .equals(Platform.getOS()) |
| || org.eclipse.osgi.service.environment.Constants.OS_AIX |
| .equals(Platform.getOS()) |
| || org.eclipse.osgi.service.environment.Constants.OS_LINUX |
| .equals(Platform.getOS()) |
| || org.eclipse.osgi.service.environment.Constants.OS_SOLARIS |
| .equals(Platform.getOS()) |
| || org.eclipse.osgi.service.environment.Constants.OS_MACOSX |
| .equals(Platform.getOS()); |
| private static FragmentEntry[] noFragments = new FragmentEntry[0]; |
| private static Map table; |
| |
| static { |
| table = new HashMap(); |
| table.put("compatible", new Integer(IUpdateConstants.RULE_COMPATIBLE)); //$NON-NLS-1$ |
| table.put("perfect", new Integer(IUpdateConstants.RULE_PERFECT)); //$NON-NLS-1$ |
| table.put("equivalent", new Integer(IUpdateConstants.RULE_EQUIVALENT)); //$NON-NLS-1$ |
| table.put("greaterOrEqual", new Integer(IUpdateConstants.RULE_GREATER_OR_EQUAL)); //$NON-NLS-1$ |
| } |
| |
| // manage URL to File |
| private static Map urlFileMap; |
| |
| private static Map localFileFragmentMap; |
| private static Stack bufferPool; |
| private static final int BUFFER_SIZE = 4096; // 4kbytes |
| private static final int INCREMENT_SIZE = 10240; // 10kbytes |
| /** |
| * return the urlString if it is a absolute URL |
| * otherwise, return the default URL if the urlString is null |
| * The defaultURL may point ot a file, create a file URL then |
| * if the urlString or the default URL are relatives, prepend the rootURL to it |
| */ |
| public static URL getURL(URL rootURL, String urlString, String defaultURL) throws MalformedURLException { |
| URL url = null; |
| |
| // if no URL , provide Default |
| if (urlString == null || urlString.trim().equals("")) { //$NON-NLS-1$ |
| |
| // no URL, no default, return right now... |
| if (defaultURL == null || defaultURL.trim().equals("")) //$NON-NLS-1$ |
| return null; |
| else |
| urlString = defaultURL; |
| } |
| |
| // URL can be relative or absolute |
| if (urlString.startsWith("/") && urlString.length() > 1) //$NON-NLS-1$ |
| urlString = urlString.substring(1); |
| try { |
| url = new URL(urlString); |
| } catch (MalformedURLException e) { |
| // the url is not an absolute URL |
| // try relative |
| url = new URL(rootURL, urlString); |
| } |
| |
| return url; |
| } |
| |
| /** |
| * return a relative String to rootURL |
| * if url contains rootURL so |
| * new URL(rootURL, resultString) == url |
| * |
| */ |
| public static String getURLAsString(URL rootURL, URL url) { |
| String result = null; |
| |
| if (rootURL == null) { |
| return (url == null) ? null : url.toString(); |
| } |
| |
| // if no URL , return null |
| if (url != null) { |
| |
| result = url.toExternalForm(); |
| |
| if (rootURL.getHost() != null && !rootURL.getHost().equals(url.getHost())) |
| return result; |
| |
| if (rootURL.getProtocol() != null && !rootURL.getProtocol().equals(url.getProtocol())) |
| return result; |
| |
| if (rootURL.getPort() != url.getPort()) |
| return result; |
| |
| String rootURLFileString = rootURL.getFile(); |
| rootURLFileString = rootURLFileString.replace(File.separatorChar, '/'); |
| if (!rootURLFileString.endsWith("/")) { //$NON-NLS-1$ |
| int index = rootURLFileString.lastIndexOf('/'); |
| if (index != -1) { |
| rootURLFileString = rootURLFileString.substring(0, index); |
| } |
| } |
| String urlFileString = url.getFile(); |
| |
| if (urlFileString.startsWith(rootURLFileString)) { |
| result = urlFileString.substring(rootURLFileString.length()); |
| result = result.replace(File.separatorChar, '/'); |
| } else { |
| // we need to check the following |
| // file:/C:/ and file:C:/ |
| if ("file".equalsIgnoreCase(url.getProtocol())) { //$NON-NLS-1$ |
| File rootFile = new File(rootURLFileString); |
| File urlFile = new File(urlFileString); |
| |
| File relativePath = urlFile; |
| while (relativePath != null && !rootFile.equals(relativePath.getParentFile())) { |
| relativePath = relativePath.getParentFile(); |
| } |
| |
| if (relativePath == null) { |
| UpdateCore.warn("Cannot calculate relative path"); //$NON-NLS-1$ |
| return url.toString(); |
| } else { |
| String relativeRootString = relativePath.getParentFile().getAbsolutePath(); |
| String fullString = urlFile.getAbsolutePath(); |
| if (!fullString.startsWith(relativeRootString)) { |
| UpdateCore.warn("Full path:" + fullString + " does not start with " + relativeRootString); //$NON-NLS-1$ //$NON-NLS-2$ |
| return url.toString(); |
| } else { |
| String returnString = fullString.substring(relativeRootString.length() + 1); |
| if (urlFile.isDirectory()) |
| returnString += File.separator; |
| // we lost the last slash when tranforming in File |
| returnString = returnString.replace(File.separatorChar, '/'); |
| return returnString; |
| } |
| |
| } |
| |
| } else { |
| result = url.toString(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * returns a translated String |
| */ |
| public static String getResourceString(String infoURL, ResourceBundle bundle) { |
| String result = null; |
| if (infoURL != null) { |
| result = Platform.getResourceString(UpdateCore.getPlugin().getBundle(), infoURL, bundle); |
| } |
| return result; |
| } |
| |
| /** |
| * |
| */ |
| public static URL copyToLocal(InputStream sourceContentReferenceStream, String localName, InstallMonitor monitor) throws MalformedURLException, IOException, InstallAbortedException { |
| URL result = null; |
| // create the Dir if they do not exist |
| // get the path from the File to resolve File.separator.. |
| // do not use the String as it may contain URL like separator |
| File localFile = new File(localName); |
| int index = localFile.getPath().lastIndexOf(File.separator); |
| if (index != -1) { |
| File dir = new File(localFile.getPath().substring(0, index)); |
| if (!dir.exists()) |
| dir.mkdirs(); |
| } |
| |
| // transfer the content of the File |
| if (!localFile.isDirectory()) { |
| OutputStream localContentReferenceStream = new FileOutputStream(localFile); |
| try { |
| Utilities.copy(sourceContentReferenceStream, localContentReferenceStream, monitor); |
| } finally { |
| try { |
| localContentReferenceStream.close(); |
| } catch (IOException e){} |
| } |
| } |
| result = localFile.toURL(); |
| return result; |
| } |
| |
| /* |
| * [20305] need to slam permissions for executable libs on some |
| * platforms. This is a temporary fix |
| */ |
| public static void checkPermissions(ContentReference ref, String filePath) { |
| |
| if (ref.getPermission() != 0) { |
| UpdateCore.warn("Change permission for " + filePath + " to " + ref.getPermission()); //$NON-NLS-1$ //$NON-NLS-2$ |
| // FIXME: change the code to use JNI |
| } |
| |
| if (filePath != null && OS_UNIX && ref.getPermission() != 0) { |
| // add execute permission on shared libraries 20305 |
| // do not remove write permission 20896 |
| // chmod a+x *.sl |
| try { |
| Process pr = Runtime.getRuntime().exec(new String[] { "chmod", "a+x", filePath }); //$NON-NLS-1$ //$NON-NLS-2$ |
| Thread chmodOutput = new StreamConsumer(pr.getInputStream()); |
| chmodOutput.setName("chmod output reader"); //$NON-NLS-1$ |
| chmodOutput.start(); |
| Thread chmodError = new StreamConsumer(pr.getErrorStream()); |
| chmodError.setName("chmod error reader"); //$NON-NLS-1$ |
| chmodError.start(); |
| } catch (IOException ioe) { |
| } |
| |
| } |
| } |
| |
| /** |
| * Returns a random file name for the local system |
| * attempt to conserve the extension if there is a '.' in the path |
| * and no File.Seperator after the '.' |
| * |
| * \a\b\c.txt -> c987659385.txt |
| * c.txt -> c3854763.txt |
| * c -> c953867549 |
| */ |
| public static String getLocalRandomIdentifier(String remotePath, Date date) { |
| int dotIndex = remotePath.lastIndexOf("."); //$NON-NLS-1$ |
| int fileIndex = remotePath.lastIndexOf(File.separator); |
| // if there is a separator after the dot |
| // do not consider it as an extension |
| String ext = (dotIndex != -1 && fileIndex < dotIndex) ? remotePath.substring(dotIndex) : ""; //$NON-NLS-1$ |
| // the name is the string between the separator and the dot |
| // if there is no separator, it is the string up to the dot |
| // if there is no dot, go to the end of the string |
| if (fileIndex == -1) |
| fileIndex = 0; |
| if (dotIndex == -1) |
| dotIndex = remotePath.length(); |
| // if I have a separator and no dot: /a/b/c -> c |
| // if my separator is the last /a/b/c/, fileIndex and dotIndex are the same, so it will return the default temp name |
| String name = (fileIndex < dotIndex) ? remotePath.substring(fileIndex, dotIndex) : "Eclipse_Update_TMP_"; //$NON-NLS-1$ |
| String result = name + date.getTime() + ext; |
| return result; |
| } |
| |
| /** |
| * remove a file or directory from the file system. |
| * used to clean up install |
| */ |
| public static void removeFromFileSystem(File file) { |
| if (!file.exists() || !file.canWrite()) |
| return; |
| |
| if (file.isDirectory()) { |
| String[] files = file.list(); |
| if (files != null) // be careful since file.list() can return null |
| for (int i = 0; i < files.length; ++i) |
| removeFromFileSystem(new File(file, files[i])); |
| } |
| |
| if (!file.delete()) { |
| String msg = NLS.bind(Messages.UpdateManagerUtils_UnableToRemoveFile, (new String[] { file.getAbsolutePath() })); |
| UpdateCore.log(msg, new Exception()); |
| } |
| } |
| |
| /** |
| * remove all the empty directories recursively |
| * used to clean up install |
| */ |
| public static void removeEmptyDirectoriesFromFileSystem(File file) { |
| if (!file.isDirectory()) |
| return; |
| |
| String[] files = file.list(); |
| if (files != null) { // be careful since file.list() can return null |
| for (int i = 0; i < files.length; ++i) { |
| removeEmptyDirectoriesFromFileSystem(new File(file, files[i])); |
| } |
| } |
| if (!file.delete()) { |
| String msg = NLS.bind(Messages.UpdateManagerUtils_UnableToRemoveFile, (new String[] { file.getAbsolutePath() })); |
| UpdateCore.log(msg, new Exception()); |
| } |
| } |
| |
| /** |
| * Returns the plugin entries that are in source array and |
| * not in target array |
| */ |
| public static IPluginEntry[] diff(IPluginEntry[] sourceArray, IPluginEntry[] targetArray) { // No pluginEntry to Install, return Nothing to instal |
| if (sourceArray == null || sourceArray.length == 0) { |
| return new IPluginEntry[0]; |
| } // No pluginEntry installed, Install them all |
| if (targetArray == null || targetArray.length == 0) { |
| return sourceArray; |
| } // if a IPluginEntry from sourceArray is NOT in |
| // targetArray, add it to the list |
| List list1 = Arrays.asList(targetArray); |
| List result = new ArrayList(0); |
| for (int i = 0; i < sourceArray.length; i++) { |
| if (!list1.contains(sourceArray[i])) |
| result.add(sourceArray[i]); |
| } |
| |
| IPluginEntry[] resultEntry = new IPluginEntry[result.size()]; |
| if (result.size() > 0) |
| result.toArray(resultEntry); |
| return resultEntry; |
| } |
| |
| /** |
| * |
| */ |
| public static URL asDirectoryURL(URL url) throws MalformedURLException { |
| //url = URLEncoder.encode(url); |
| String path = url.getFile(); |
| if (!path.endsWith("/")) { //$NON-NLS-1$ |
| int index = path.lastIndexOf('/'); |
| if (index != -1) |
| path = path.substring(0, index + 1); |
| // ignore any ref in original URL |
| url = new URL(url.getProtocol(), url.getHost(), url.getPort(), path); |
| } |
| return url; |
| } |
| |
| /* |
| * Compares two URL for equality |
| * Return false if one of them is null |
| */ |
| public static boolean sameURL(URL url1, URL url2) { |
| |
| if (url1 == null || url2 == null) |
| return false; |
| if (url1 == url2) |
| return true; |
| if (url1.equals(url2)) |
| return true; |
| |
| // check if URL are file: URL as we may |
| // have 2 URL pointing to the same featureReference |
| // but with different representation |
| // (i.e. file:/C;/ and file:C:/) |
| if (!"file".equalsIgnoreCase(url1.getProtocol())) //$NON-NLS-1$ |
| return false; |
| if (!"file".equalsIgnoreCase(url2.getProtocol())) //$NON-NLS-1$ |
| return false; |
| |
| File file1 = getFileFor(url1);//new File(url1.getFile()); |
| File file2 = getFileFor(url2); |
| |
| if (file1 == null) |
| return false; |
| |
| return (file1.equals(file2)); |
| } |
| |
| /* |
| * Method getFileFor. |
| * @param url1 |
| * @return File |
| */ |
| private static File getFileFor(URL url1) { |
| if (urlFileMap == null) urlFileMap = new HashMap(); |
| if (urlFileMap.get(url1)!=null) return (File)urlFileMap.get(url1); |
| File newFile = new File(url1.getFile()); |
| urlFileMap.put(url1,newFile); |
| return newFile; |
| } |
| |
| /* |
| * returns the list of FeatureReference that are parent of |
| * the Feature or an empty array if no parent found. |
| * @param onlyOptional if set to <code>true</code> only return parents that consider the feature optional |
| * @param child |
| * @param possiblesParent |
| */ |
| public static IFeatureReference[] getParentFeatures(IFeature childFeature, IFeatureReference[] possiblesParent, boolean onlyOptional) throws CoreException { |
| |
| if (childFeature == null) |
| return new IFeatureReference[0]; |
| |
| List parentList = new ArrayList(); |
| IIncludedFeatureReference[] children = null; |
| IFeature compareFeature = null; |
| for (int i = 0; i < possiblesParent.length; i++) { |
| try { |
| IFeature possibleParentFeature = possiblesParent[i].getFeature(null); |
| if (possibleParentFeature != null) { |
| children = possibleParentFeature.getIncludedFeatureReferences(); |
| for (int j = 0; j < children.length; j++) { |
| try { |
| compareFeature = children[j].getFeature(null); |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); //$NON-NLS-1$ |
| } |
| if (childFeature.equals(compareFeature)) { |
| if (onlyOptional) { |
| if (UpdateManagerUtils.isOptional(children[j])) { |
| parentList.add(possiblesParent[i]); |
| } else { |
| UpdateCore.warn("Feature :" + children[j] + " not optional. Not included in parents list."); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } else { |
| parentList.add(possiblesParent[i]); |
| } |
| } |
| } |
| } |
| } catch (CoreException e) { |
| UpdateCore.warn("", e); //$NON-NLS-1$ |
| } |
| } |
| |
| IFeatureReference[] parents = new IFeatureReference[0]; |
| if (parentList.size() > 0) { |
| parents = new IFeatureReference[parentList.size()]; |
| parentList.toArray(parents); |
| } |
| return parents; |
| } |
| |
| /* |
| * If the return code of the HTTP connection is not 200 (OK) |
| * thow an IO exception |
| * |
| */ |
| public static void checkConnectionResult(IResponse response,URL url) throws IOException { |
| // did the server return an error code ? |
| int result = response.getStatusCode(); |
| |
| if (result != UpdateCore.HTTP_OK) { |
| String serverMsg = response.getStatusMessage(); |
| response.close(); |
| throw new FatalIOException(NLS.bind(Messages.ContentReference_HttpNok, (new Object[] { new Integer(result), serverMsg, url }))); |
| } |
| } |
| |
| public static class StreamConsumer extends Thread { |
| InputStream is; |
| byte[] buf; |
| public StreamConsumer(InputStream inputStream) { |
| super(); |
| this.setDaemon(true); |
| this.is = inputStream; |
| buf = new byte[512]; |
| } |
| public void run() { |
| try { |
| int n = 0; |
| while (n >= 0) |
| n = is.read(buf); |
| } catch (IOException ioe) { |
| } |
| } |
| } |
| |
| /** |
| * Return the optional children to install |
| * The optional features to install may not all be direct children |
| * of the feature. |
| * Also include non-optional features |
| * |
| * @param children all the nested features |
| * @param optionalfeatures optional features to install |
| * @return IFeatureReference[] |
| */ |
| public static IFeatureReference[] optionalChildrenToInstall(IFeatureReference[] children, IFeatureReference[] optionalfeatures) { |
| |
| List optionalChildrenToInstall = new ArrayList(); |
| for (int i = 0; i < children.length; i++) { |
| IFeatureReference optionalFeature = children[i]; |
| if (!UpdateManagerUtils.isOptional(optionalFeature)) { |
| optionalChildrenToInstall.add(optionalFeature); |
| } else { |
| for (int j = 0; j < optionalfeatures.length; j++) { |
| if (optionalFeature.equals(optionalfeatures[j])) { |
| optionalChildrenToInstall.add(optionalFeature); |
| break; |
| } |
| } |
| } |
| } |
| |
| IFeatureReference[] result = new IFeatureReference[optionalChildrenToInstall.size()]; |
| if (optionalChildrenToInstall.size() > 0) { |
| optionalChildrenToInstall.toArray(result); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * returns the mapping of matching rules |
| * the default returns perfect |
| * |
| * @since 2.0.2 |
| */ |
| public static int getMatchingRule(String rule) { |
| if (rule == null) |
| return IUpdateConstants.RULE_COMPATIBLE; |
| final Integer integer = (Integer) table.get(rule); |
| if (integer == null) |
| return IUpdateConstants.RULE_PERFECT; |
| int ruleInt = integer.intValue(); |
| if (ruleInt == IUpdateConstants.RULE_NONE) |
| return IUpdateConstants.RULE_PERFECT; |
| return ruleInt; |
| } |
| |
| /** |
| * returns the mapping of matching id rules |
| * the default returns perfect |
| * |
| * @since 2.0.2 |
| */ |
| public static int getMatchingIdRule(String rule) { |
| |
| if (rule == null) |
| return IUpdateConstants.RULE_COMPATIBLE; |
| if (rule!=null && rule.equalsIgnoreCase("prefix")) //$NON-NLS-1$ |
| return IUpdateConstants.RULE_PREFIX; |
| return IUpdateConstants.RULE_PERFECT; |
| } |
| |
| /** |
| * Method isOptional. |
| * @param featureReference |
| * @return boolean |
| */ |
| public static boolean isOptional(IFeatureReference featureReference) { |
| if (featureReference==null) return false; |
| if (featureReference instanceof IIncludedFeatureReference){ |
| return ((IIncludedFeatureReference)featureReference).isOptional(); |
| } |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| public static boolean isValidEnvironment(IPlatformEnvironment candidate) { |
| if (candidate==null) return false; |
| String os = candidate.getOS(); |
| String ws = candidate.getWS(); |
| String arch = candidate.getOSArch(); |
| String nl = candidate.getNL(); |
| if (os!=null && !isMatching(os, SiteManager.getOS())) return false; |
| if (ws!=null && !isMatching(ws, SiteManager.getWS())) return false; |
| if (arch!=null && !isMatching(arch, SiteManager.getOSArch())) return false; |
| if (nl!=null && !isMatchingLocale(nl, SiteManager.getNL())) return false; |
| return true; |
| } |
| |
| /* Original code - commented out to provide a replacement as per bug 98387 |
| |
| private static boolean isMatching(String candidateValues, String siteValues) { |
| if (siteValues==null) return false; |
| if ("*".equals(candidateValues)) return true; //$NON-NLS-1$ |
| if ("".equals(candidateValues)) return true; //$NON-NLS-1$ |
| siteValues = siteValues.toUpperCase(); |
| StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$ |
| while (stok.hasMoreTokens()) { |
| String token = stok.nextToken().toUpperCase(); |
| if (siteValues.indexOf(token)!=-1) return true; |
| } |
| return false; |
| } |
| */ |
| |
| /* |
| * Fixed bug 98387 |
| */ |
| |
| private static boolean isMatching(String candidateValues, String siteValues) { |
| if (siteValues==null) return false; |
| if ("*".equals(candidateValues)) return true; //$NON-NLS-1$ |
| if ("".equals(candidateValues)) return true; //$NON-NLS-1$ |
| StringTokenizer siteTokens = new StringTokenizer(siteValues, ","); //$NON-NLS-1$ |
| //$NON-NLS-1$ |
| while(siteTokens.hasMoreTokens()) { |
| StringTokenizer candidateTokens = new StringTokenizer |
| (candidateValues, ","); //$NON-NLS-1$ |
| String siteValue = siteTokens.nextToken(); |
| while (candidateTokens.hasMoreTokens()) { |
| if (siteValue.equalsIgnoreCase |
| (candidateTokens.nextToken())) return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * |
| */ |
| private static boolean isMatchingLocale(String candidateValues, String locale) { |
| if (locale==null) return false; |
| if ("*".equals(candidateValues)) return true; //$NON-NLS-1$ |
| if ("".equals(candidateValues)) return true; //$NON-NLS-1$ |
| |
| locale = locale.toUpperCase(); |
| candidateValues = candidateValues.toUpperCase(); |
| StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$ |
| while (stok.hasMoreTokens()) { |
| String candidate = stok.nextToken(); |
| if (locale.indexOf(candidate) == 0) |
| return true; |
| if (candidate.indexOf(locale) == 0) |
| return true; |
| } |
| return false; |
| } |
| |
| |
| /* |
| * |
| */ |
| private static void appendEscapedChar(StringBuffer buffer, char c) { |
| String replacement = getReplacement(c); |
| if (replacement != null) { |
| buffer.append('&'); |
| buffer.append(replacement); |
| buffer.append(';'); |
| } else { |
| if ((c >= ' ' && c <= 0x7E) || c == '\n' || c == '\r' || c == '\t') { |
| buffer.append(c); |
| } else { |
| buffer.append("&#"); //$NON-NLS-1$ |
| buffer.append(Integer.toString(c)); |
| buffer.append(';'); |
| } |
| } |
| } |
| |
| /* |
| * |
| */ |
| public static String xmlSafe(String s) { |
| StringBuffer result = new StringBuffer(s.length() + 10); |
| for (int i = 0; i < s.length(); ++i) |
| appendEscapedChar(result, s.charAt(i)); |
| return result.toString(); |
| } |
| |
| /* |
| * |
| */ |
| private static String getReplacement(char c) { |
| // Encode special XML characters into the equivalent character references. |
| // These five are defined by default for all XML documents. |
| switch (c) { |
| case '<' : |
| return "lt"; //$NON-NLS-1$ |
| case '>' : |
| return "gt"; //$NON-NLS-1$ |
| case '"' : |
| return "quot"; //$NON-NLS-1$ |
| case '\'' : |
| return "apos"; //$NON-NLS-1$ |
| case '&' : |
| return "amp"; //$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| public static boolean isSameTimestamp(URL url, long timestamp) { |
| try { |
| if (UpdateCore.getPlugin().getUpdateSession().isVisited(url)) { |
| return true; |
| } |
| URL resolvedURL = URLEncoder.encode(url); |
| IResponse response = ConnectionFactory.get(resolvedURL); |
| long remoteLastModified = response.getLastModified(); |
| // 2 seconds tolerance, as some OS's may round up the time stamp |
| // to the closest second. For safety, we make it 2 seconds. |
| return Math.abs(remoteLastModified - timestamp)/1000 <= 2; |
| } catch (MalformedURLException e) { |
| return false; |
| } catch (IOException e) { |
| return false; |
| } |
| } |
| /** |
| * The file is associated with a lookup key. |
| * @param key optional lookup key, or <code>null</code>. |
| * @param temp the local working file |
| */ |
| public synchronized static void mapLocalFileFragment(String key, FileFragment temp) { |
| // create file association |
| if (key != null) { |
| if (localFileFragmentMap == null) |
| localFileFragmentMap = new HashMap(); |
| localFileFragmentMap.put(key, temp); |
| } |
| } |
| |
| /** |
| * The file is associated with a lookup key. |
| * @param key optional lookup key, or <code>null</code>. |
| */ |
| public synchronized static void unMapLocalFileFragment(String key) { |
| // remove file association |
| if (key != null && localFileFragmentMap !=null) { |
| localFileFragmentMap.remove(key); |
| } |
| } |
| |
| /** |
| * Returns a previously cached local file (in temporary area) matching the |
| * specified key. |
| * |
| * @param key lookup key |
| * @return cached file, or <code>null</code>. |
| */ |
| public static synchronized FileFragment lookupLocalFileFragment(String key) { |
| if (localFileFragmentMap == null) |
| return null; |
| return (FileFragment) localFileFragmentMap.get(key); |
| } |
| |
| /** |
| * Copies specified input stream to the output stream. Neither stream |
| * is closed as part of this operation. |
| * |
| * @param is input stream |
| * @param os output stream |
| * @param monitor progress monitor |
| * @param expectedLength - if > 0, the number of bytes from InputStream will be verified |
| * @@return the offset in the input stream where copying stopped. Returns -1 if end of input stream is reached. |
| * @since 2.0 |
| */ |
| public static long copy(InputStream is, OutputStream os, InstallMonitor monitor, long expectedLength) { |
| byte[] buf = getBuffer(); |
| long offset=0; |
| try { |
| int len = is.read(buf); |
| int nextIncrement = 0; |
| while (len != -1) { |
| os.write(buf, 0, len); |
| offset += len; |
| if (monitor != null) { |
| nextIncrement += len; |
| // update monitor periodically |
| if (nextIncrement >= INCREMENT_SIZE){ |
| monitor.incrementCount(nextIncrement); |
| nextIncrement = 0; |
| } |
| if (monitor.isCanceled()) { |
| return offset; |
| } |
| } |
| if (expectedLength > 0 && offset == expectedLength) { |
| // everything read do not return offset, otherwise trying |
| // to read again from this offset will result in HTTP 416 |
| break; |
| } |
| |
| len = is.read(buf); |
| } |
| if (nextIncrement > 0 && monitor != null) |
| monitor.incrementCount(nextIncrement); |
| if(expectedLength>0 && offset!=expectedLength) |
| throw new IOException(NLS.bind(Messages.UpdateManagerUtils_inputStreamEnded, (new String[] { String.valueOf(offset), String.valueOf(expectedLength) }))); |
| return -1; |
| } catch(IOException e){ |
| // Log the actual error, as this is no longer |
| // passed up the calling stack |
| UpdateCore.log(Messages.UpdateManagerUtils_copy + offset, e); |
| return offset; |
| } finally { |
| freeBuffer(buf); |
| } |
| } |
| |
| private static synchronized byte[] getBuffer() { |
| if (bufferPool == null) { |
| return new byte[BUFFER_SIZE]; |
| } |
| |
| try { |
| return (byte[]) bufferPool.pop(); |
| } catch (EmptyStackException e) { |
| return new byte[BUFFER_SIZE]; |
| } |
| } |
| |
| private static synchronized void freeBuffer(byte[] buf) { |
| if (bufferPool == null) |
| bufferPool = new Stack(); |
| bufferPool.push(buf); |
| } |
| |
| |
| /** |
| * Returns a list of fragments. Zero length if no fragments. |
| * @param bundle the bundle to get fragments for |
| */ |
| public static FragmentEntry[] getFragments(Bundle bundle) { |
| PackageAdmin pkgAdmin = UpdateCore.getPlugin().getPackageAdmin(); |
| Bundle[] fragmentBundles = pkgAdmin.getFragments(bundle); |
| if (fragmentBundles == null) |
| return noFragments; |
| |
| FragmentEntry[] fragments = new FragmentEntry[fragmentBundles.length]; |
| for (int i = 0; i < fragments.length; i++) { |
| fragments[i] = new FragmentEntry((String) fragmentBundles[i] |
| .getHeaders().get(Constants.BUNDLE_SYMBOLICNAME), |
| (String) fragmentBundles[i].getHeaders().get( |
| Constants.BUNDLE_VERSION), Platform |
| .getResourceString(fragmentBundles[i], |
| (String) fragmentBundles[i].getHeaders() |
| .get(Constants.BUNDLE_VERSION)), |
| fragmentBundles[i].getLocation()); |
| } |
| return fragments; |
| } |
| |
| public static String getWritableXMLString(String value) { |
| StringBuffer buf = new StringBuffer(); |
| if(value == null) |
| return buf.toString(); |
| for (int i = 0; i < value.length(); i++) { |
| char c = value.charAt(i); |
| switch (c) { |
| case '&' : |
| buf.append("&"); //$NON-NLS-1$ |
| break; |
| case '<' : |
| buf.append("<"); //$NON-NLS-1$ |
| break; |
| case '>' : |
| buf.append(">"); //$NON-NLS-1$ |
| break; |
| case '\'' : |
| buf.append("'"); //$NON-NLS-1$ |
| break; |
| case '\"' : |
| buf.append("""); //$NON-NLS-1$ |
| break; |
| case 0x00 : |
| buf.append(" "); //$NON-NLS-1$ |
| break; |
| default : |
| buf.append(c); |
| break; |
| } |
| } |
| return buf.toString(); |
| } |
| |
| public static LiteFeature[] getLightFeatures(ExtendedSite site) { |
| |
| URL fullDigestURL; |
| try { |
| fullDigestURL = getFullDigestURL( site, Locale.getDefault().getCountry(), Locale.getDefault().getLanguage()); |
| } catch (MalformedURLException e) { |
| UpdateCore.log("Could not access digest on the site: " + e.getMessage(), null); //$NON-NLS-1$ |
| return null; |
| } |
| |
| Digest digest = new Digest( fullDigestURL); |
| try { |
| LiteFeature[] features = (LiteFeature[])digest.parseDigest(); |
| for(int i = 0; i < features.length; i++) { |
| features[i].setSite(site); |
| } |
| return features; |
| } catch(Exception e){ |
| UpdateCore.log("Digest could not be parsed:" + e.getMessage(), null); //$NON-NLS-1$ |
| return null; |
| } |
| } |
| |
| private static URL getFullDigestURL(ExtendedSite site, String country, String language) throws MalformedURLException { |
| |
| String digestURL = (site.getDigestURL().endsWith("/")? site.getDigestURL(): site.getDigestURL() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| if (digestURL.indexOf("://") == -1) { //$NON-NLS-1$ |
| String siteURL = site.getLocationURL().toExternalForm(); |
| if (siteURL.endsWith(Site.SITE_XML)) { |
| siteURL = siteURL.substring(0, siteURL.length() - Site.SITE_XML.length()); |
| } |
| if (digestURL.equals("/")) { //$NON-NLS-1$ |
| digestURL = siteURL; |
| } else { |
| if (digestURL.startsWith("/")) { //$NON-NLS-1$ |
| digestURL = digestURL.substring(1, digestURL.length()); |
| } |
| digestURL = siteURL + digestURL; |
| } |
| } |
| |
| digestURL += "digest"; //$NON-NLS-1$ |
| |
| if ( isLocalSupported(site, country, language)) { |
| return new URL(digestURL + "_" + language + "_" + country + ".zip"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| if ( isLangaugeSupported(site, language)) { |
| return new URL(digestURL + "_" + language + ".zip"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return new URL(digestURL + ".zip"); //$NON-NLS-1$ |
| } |
| |
| private static boolean isLangaugeSupported(ExtendedSite site, String language) { |
| String[] availableLanguages = site.getAvailableLocals(); |
| if ((availableLanguages == null) || (availableLanguages.length == 0)) { |
| return false; |
| } |
| for(int i = 0; i < availableLanguages.length; i++) { |
| if (availableLanguages[i].equals(language)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static boolean isLocalSupported(ExtendedSite site, String country, String language) { |
| String localeCode = language + "_" + country; //$NON-NLS-1$ |
| String[] availableLocals = site.getAvailableLocals(); |
| if ((availableLocals == null) || (availableLocals.length == 0)) { |
| return false; |
| } |
| for(int i = 0; i < availableLocals.length; i++) { |
| if (availableLocals[i].equals(localeCode)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |