| /******************************************************************************* |
| * Copyright (c) 2000, 2008 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 org.eclipse.update.core.FeatureContentProvider; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.signedcontent.SignedContentFactory; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.update.core.*; |
| import org.eclipse.update.internal.jarprocessor.JarProcessor; |
| import org.eclipse.update.internal.jarprocessor.Utils; |
| import org.eclipse.update.internal.security.JarVerifier; |
| import org.eclipse.update.internal.verifier.CertVerifier; |
| |
| /** |
| * Content Provider of a Feature Package |
| */ |
| public class FeaturePackagedContentProvider extends FeatureContentProvider { |
| |
| private ContentReference localManifest = null; |
| private ContentReference[] localFeatureFiles = new ContentReference[0]; |
| private IVerifier jarVerifier = null; |
| private ExtendedSite siteModel = null; |
| private boolean continueOnError; |
| /* |
| * filter for file with .jar |
| */ |
| public static final FilenameFilter filter = new FilenameFilter() { |
| public boolean accept(File dir, String name) { |
| return name.endsWith(FeatureContentProvider.JAR_EXTENSION); |
| } |
| }; |
| |
| /* |
| * Constructor |
| */ |
| public FeaturePackagedContentProvider(URL url, ISite site) { |
| super(url); |
| if (site instanceof ExtendedSite) { |
| this.siteModel = (ExtendedSite) site; |
| } |
| } |
| |
| /* |
| * Returns a new verifier for each top-level install |
| * (if the verifier has a parent, return the verifier |
| * otherwise reinitialize) |
| */ |
| public IVerifier getVerifier() throws CoreException { |
| SignedContentFactory factory = UpdateCore.getPlugin().getSignedContentFactory(); |
| if (jarVerifier == null || jarVerifier.getParent() == null) { |
| if (factory != null) |
| jarVerifier = new CertVerifier(UpdateCore.getPlugin().getSignedContentFactory()); |
| else |
| jarVerifier = new JarVerifier(); |
| return jarVerifier; |
| } |
| |
| // re-init will be done if the parent changes |
| return jarVerifier; |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getFeatureManifestReference() |
| */ |
| public ContentReference getFeatureManifestReference(InstallMonitor monitor) throws CoreException { |
| |
| // check to see if we already have local copy of the manifest |
| if (localManifest != null) |
| return localManifest; |
| ContentReference[] featureArchiveReference = getFeatureEntryArchiveReferences(monitor); |
| JarContentReference featureJarReference = null; |
| try { |
| |
| // force feature archive to local. |
| // This content provider always assumes exactly 1 archive file (index [0]) |
| featureJarReference = (JarContentReference) asLocalReference(featureArchiveReference[0], null); |
| // we need to unpack archive locally for UI browser references to be resolved correctly |
| localFeatureFiles = featureJarReference.unpack(getWorkingDirectory(), null, monitor); |
| } catch (IOException e) { |
| throw errorRetrieving(Feature.FEATURE_XML, featureJarReference, e); |
| } |
| |
| // find the manifest in the unpacked feature files |
| for (int i = 0; i < localFeatureFiles.length; i++) { |
| if (localFeatureFiles[i].getIdentifier().equals(Feature.FEATURE_XML)) { |
| localManifest = localFeatureFiles[i]; |
| // cache reference to manifest |
| return localManifest; |
| } |
| } |
| |
| // the manifest has not been found |
| String[] values = new String[] { Feature.FEATURE_XML, getURL().toExternalForm()}; |
| throw Utilities.newCoreException(NLS.bind(Messages.FeaturePackagedContentProvider_NoManifestFile, values), new Exception()); |
| |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getArchiveReferences() |
| */ |
| public ContentReference[] getArchiveReferences(InstallMonitor monitor) throws CoreException { |
| |
| IPluginEntry[] entries = getFeature().getPluginEntries(); |
| INonPluginEntry[] nonEntries = getFeature().getNonPluginEntries(); |
| List listAllContentRef = new ArrayList(); |
| ContentReference[] allContentRef = new ContentReference[0]; |
| |
| // feature |
| listAllContentRef.addAll(Arrays.asList(getFeatureEntryArchiveReferences(monitor))); |
| |
| // plugins |
| for (int i = 0; i < entries.length; i++) { |
| listAllContentRef.addAll(Arrays.asList(getPluginEntryArchiveReferences(entries[i], monitor))); |
| } |
| |
| // non plugins |
| for (int i = 0; i < nonEntries.length; i++) { |
| listAllContentRef.addAll(Arrays.asList(getNonPluginEntryArchiveReferences(nonEntries[i], monitor))); |
| } |
| |
| // transform List in Array |
| if (listAllContentRef.size() > 0) { |
| allContentRef = new ContentReference[listAllContentRef.size()]; |
| listAllContentRef.toArray(allContentRef); |
| } |
| |
| return allContentRef; |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getFeatureEntryArchiveReferences() |
| */ |
| public ContentReference[] getFeatureEntryArchiveReferences(InstallMonitor monitor) throws CoreException { |
| |
| //1 jar file <-> 1 feature |
| // we will return the JAR file |
| ContentReference[] references = new ContentReference[1]; |
| ContentReference currentReference = null; |
| String archiveID = null; |
| |
| try { |
| archiveID = (getFeature() != null) ? getFeature().getVersionedIdentifier().toString() : ""; //$NON-NLS-1$ |
| currentReference = new JarContentReference(archiveID, getURL()); |
| currentReference = asLocalReference(currentReference, monitor); |
| references[0] = currentReference; |
| } catch (IOException e) { |
| references[0] = continueOnErrorOrRethrow(archiveID, e); |
| } |
| return references; |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getPluginEntryArchiveReferences(IPluginEntry) |
| */ |
| public ContentReference[] getPluginEntryArchiveReferences(IPluginEntry pluginEntry, InstallMonitor monitor) throws CoreException { |
| |
| // 1 plugin <-> 1 jar |
| // we return the JAR file |
| ContentReference[] references = new ContentReference[1]; |
| String archiveID = getPathID(pluginEntry); |
| ISite site = (getFeature() == null) ? null : getFeature().getSite(); |
| ISiteContentProvider siteContentProvider = (site == null) ? null : site.getSiteContentProvider(); |
| URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID); |
| |
| try { |
| references[0] = retrieveLocalJar(new JarContentReference(archiveID, url), monitor); |
| } catch (IOException e) { |
| references[0] = continueOnErrorOrRethrow(archiveID, e); |
| } |
| return references; |
| } |
| |
| private ContentReference retrieveLocalJar(JarContentReference reference, InstallMonitor monitor) throws IOException, CoreException { |
| //If the site does not support pack200, just get the jar as normal |
| if(siteModel == null || !siteModel.supportsPack200() || !JarProcessor.canPerformUnpack()) { |
| ContentReference contentReference = null; |
| try { |
| contentReference = asLocalReference(reference, monitor); |
| } |
| catch (FileNotFoundException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (IOException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (CoreException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| return contentReference; |
| } |
| |
| ContentReference packedRef = null; |
| String key = reference.toString(); |
| Object jarLock = LockManager.getLock(key); |
| synchronized (jarLock) { |
| //do we have this jar already? |
| File localFile = Utilities.lookupLocalFile(key); |
| if (localFile != null) { |
| // check if the cached file is still valid (no newer version on server) |
| if (UpdateManagerUtils.isSameTimestamp(reference.asURL(), localFile.lastModified())) { |
| LockManager.returnLock(key); |
| return reference.createContentReference(reference.getIdentifier(), localFile); |
| } |
| } |
| |
| try { |
| //don't have jar, check for pack.gz |
| URL packGZURL = new URL(reference.asURL().toExternalForm() + ".pack.gz"); //$NON-NLS-1$ |
| packedRef = asLocalReference(new JarContentReference(reference.getIdentifier(), packGZURL), monitor); |
| } catch (IOException e) { |
| //no pack.gz |
| } catch (CoreException e){ |
| //no pack.gz |
| } |
| } |
| |
| if (packedRef == null) { |
| //no pack.gz on server, get normal jar |
| ContentReference contentReference = null; |
| try { |
| contentReference = asLocalReference(reference, monitor); |
| } |
| catch (FileNotFoundException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (IOException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (CoreException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| return contentReference; |
| } |
| |
| boolean success = false; |
| synchronized (jarLock) { |
| String packed = packedRef.toString(); |
| Object packedLock = LockManager.getLock(packed); |
| synchronized (packedLock) { |
| try { |
| File tempFile = packedRef.asFile(); |
| long timeStamp = tempFile.lastModified(); |
| |
| JarProcessor processor = JarProcessor.getUnpackProcessor(null); |
| processor.setWorkingDirectory(tempFile.getParent()); |
| |
| File packedFile = new File(tempFile.toString() + Utils.PACKED_SUFFIX); |
| tempFile.renameTo(packedFile); |
| |
| if (monitor != null) { |
| monitor.saveState(); |
| monitor.subTask(Messages.JarContentReference_Unpacking + " " + reference.getIdentifier() + Utils.PACKED_SUFFIX); //$NON-NLS-1$ |
| monitor.showCopyDetails(false); |
| } |
| //unpacking the jar will strip the ".pack.gz" and leave us back with the original filename |
| try { |
| processor.processJar(packedFile); |
| } catch (Throwable e) { |
| //something is wrong unpacking |
| } |
| |
| if(tempFile.exists() && tempFile.length() > 0){ |
| success = true; |
| tempFile.setLastModified(timeStamp); |
| Utilities.mapLocalFile(key, tempFile); |
| UpdateCore.getPlugin().getUpdateSession().markVisited(reference.asURL()); |
| } |
| } finally { |
| LockManager.returnLock(packed); |
| LockManager.returnLock(key); |
| if(monitor != null) |
| monitor.restoreState(); |
| } |
| } |
| } |
| if(!success){ |
| //Something went wrong with the unpack, get the normal jar. |
| ContentReference contentReference = null; |
| try { |
| contentReference = asLocalReference(reference, monitor); |
| } |
| catch (FileNotFoundException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (IOException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| catch (CoreException e) { |
| contentReference = continueOnErrorOrRethrow(reference.getIdentifier(), e); |
| } |
| return contentReference; |
| } |
| return packedRef; |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getNonPluginEntryArchiveReferences(INonPluginEntry) |
| */ |
| public ContentReference[] getNonPluginEntryArchiveReferences(INonPluginEntry nonPluginEntry, InstallMonitor monitor) throws CoreException { |
| |
| // archive = feature/<id>_<ver>/<file> |
| String archiveID = Site.DEFAULT_FEATURE_PATH + ((getFeature() != null) ? getFeature().getVersionedIdentifier().toString() : ""); //$NON-NLS-1$ |
| archiveID += "/" + nonPluginEntry.getIdentifier(); //$NON-NLS-1$ |
| |
| ContentReference[] references = new ContentReference[1]; |
| ContentReference currentReference = null; |
| |
| try { |
| ISite site = (getFeature() == null) ? null : getFeature().getSite(); |
| ISiteContentProvider siteContentProvider = (site == null) ? null : site.getSiteContentProvider(); |
| URL url = (siteContentProvider == null) ? null : siteContentProvider.getArchiveReference(archiveID); |
| |
| currentReference = new ContentReference(nonPluginEntry.getIdentifier(), url); |
| currentReference = asLocalReference(currentReference, monitor); |
| references[0] = currentReference; |
| |
| } catch (IOException e) { |
| references[0] = continueOnErrorOrRethrow(archiveID, e); |
| } |
| |
| return references; |
| } |
| |
| |
| /* |
| * @see IFeatureContentProvider#getFeatureEntryContentReferences() |
| */ |
| public ContentReference[] getFeatureEntryContentReferences(InstallMonitor monitor) throws CoreException { |
| |
| return localFeatureFiles; // return cached feature references |
| // Note: assumes this content provider is always called first to |
| // get the feature manifest. This forces the feature files |
| // to be unpacked and caches the references |
| } |
| |
| /* |
| * @see IFeatureContentProvider#getPluginEntryContentReferences(IPluginEntry) |
| */ |
| public ContentReference[] getPluginEntryContentReferences(IPluginEntry pluginEntry, InstallMonitor monitor) throws CoreException { |
| |
| ContentReference[] references = getPluginEntryArchiveReferences(pluginEntry, monitor); |
| ContentReference[] pluginReferences = new ContentReference[0]; |
| |
| try { |
| if (references[0] instanceof JarContentReference) { |
| JarContentReference localRef = (JarContentReference) asLocalReference(references[0], monitor); |
| pluginReferences = localRef.peek(null, monitor); |
| } else { |
| // return the list of all subdirectories |
| List files = getFiles(references[0].asFile()); |
| pluginReferences = new ContentReference[files.size()]; |
| for (int i = 0; i < pluginReferences.length; i++) { |
| File currentFile = (File) files.get(i); |
| pluginReferences[i] = new ContentReference(null, currentFile.toURL()); |
| } |
| } |
| |
| //[20866] we did not preserve executable bit |
| validatePermissions(pluginReferences); |
| |
| } catch (IOException e) { |
| throw errorRetrieving(pluginEntry.getVersionedIdentifier().toString(), references[0], e); |
| } |
| return pluginReferences; |
| } |
| |
| /* |
| * return all the files under the directory |
| */ |
| private List getFiles(File dir) throws IOException { |
| List result = new ArrayList(); |
| |
| if (!dir.isDirectory()) |
| throw new IOException(NLS.bind(Messages.FeaturePackagedContentProvider_InvalidDirectory, (new String[] { dir.getPath() }))); |
| |
| File[] files = dir.listFiles(); |
| if (files != null) // be careful since it can be null |
| for (int i = 0; i < files.length; ++i) { |
| if (files[i].isDirectory()) { |
| result.addAll(getFiles(files[i])); |
| } else { |
| result.add(files[i]); |
| } |
| } |
| return result; |
| } |
| |
| /* |
| * |
| */ |
| private CoreException errorRetrieving(String obj, ContentReference archive, Exception e) { |
| |
| String[] values = new String[] { obj }; |
| |
| return Utilities.newCoreException(NLS.bind(Messages.FeaturePackagedContentProvider_ErrorRetrieving, values), e); |
| |
| } |
| |
| |
| public void setContinueOnError(boolean continueOnError) { |
| this.continueOnError = continueOnError; |
| } |
| |
| /** |
| * This method is used for when a core exception is detected, so, if its decided to rethrow, then |
| * a core exception odes not have to be recreated. |
| * |
| * @param archiveID id of the archive file |
| * @param CoreException |
| * @return NullReference if its decided not to continue |
| * @throws CoreException |
| */ |
| /*private ContentReference continueOrErrorOrRethrow(String archiveID, CoreException coreException) throws CoreException { |
| ContentReference reference = null; |
| |
| if (continueOnError) { |
| // this ContentReference without a file or URL is purely a |
| // "missing jar" reference. |
| reference = new NullContentReference(archiveID); |
| |
| String msg = " ContinueOnError: The following ID was not found, so was skipped, and is not on miror site: " + archiveID; //$NON-NLS-1$ |
| String id = UpdateCore.getPlugin().getBundle().getSymbolicName(); |
| IStatus status = new Status(IStatus.WARNING, id , 0, msg, null); |
| UpdateCore.log(status); |
| |
| } |
| else { |
| throw coreException; |
| } |
| return reference; |
| }*/ |
| |
| private ContentReference continueOnErrorOrRethrow(String archiveID, Exception e) throws CoreException { |
| ContentReference reference = null; |
| |
| if (continueOnError) { |
| // this ContentReference without a file or URL is purely a |
| // "missing jar" reference. |
| reference = new NullContentReference(archiveID); |
| |
| String msg = " ContinueOnError: The following ID was not found, so was skipped, and is not on miror site: " + archiveID; //$NON-NLS-1$ |
| String id = UpdateCore.getPlugin().getBundle().getSymbolicName(); |
| IStatus status = new Status(IStatus.WARNING, id , 0, msg, null); |
| UpdateCore.log(status); |
| |
| } |
| else { |
| throw errorRetrieving(archiveID, reference, e); |
| } |
| return reference; |
| } |
| |
| } |