diff options
20 files changed, 232 insertions, 200 deletions
diff --git a/bundles/org.eclipse.osgi.compatibility.plugins/src/org/eclipse/osgi/compatibility/plugins/PluginConverterHook.java b/bundles/org.eclipse.osgi.compatibility.plugins/src/org/eclipse/osgi/compatibility/plugins/PluginConverterHook.java index 392155ee3..b7fd91719 100644 --- a/bundles/org.eclipse.osgi.compatibility.plugins/src/org/eclipse/osgi/compatibility/plugins/PluginConverterHook.java +++ b/bundles/org.eclipse.osgi.compatibility.plugins/src/org/eclipse/osgi/compatibility/plugins/PluginConverterHook.java @@ -12,14 +12,23 @@ package org.eclipse.osgi.compatibility.plugins; import java.io.File; import java.io.IOException; -import java.util.Enumeration; + import org.eclipse.osgi.framework.util.Headers; -import org.eclipse.osgi.internal.hookregistry.*; +import org.eclipse.osgi.internal.hookregistry.ActivatorHookFactory; +import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook; +import org.eclipse.osgi.internal.hookregistry.HookConfigurator; +import org.eclipse.osgi.internal.hookregistry.HookRegistry; import org.eclipse.osgi.service.pluginconversion.PluginConversionException; import org.eclipse.osgi.service.pluginconversion.PluginConverter; import org.eclipse.osgi.storage.BundleInfo.Generation; -import org.eclipse.osgi.storage.bundlefile.*; -import org.osgi.framework.*; +import org.eclipse.osgi.storage.bundlefile.BundleEntry; +import org.eclipse.osgi.storage.bundlefile.BundleFile; +import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper; +import org.eclipse.osgi.storage.bundlefile.FileBundleEntry; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; public class PluginConverterHook implements HookConfigurator { @Override @@ -34,26 +43,11 @@ public class PluginConverterHook implements HookConfigurator { hookRegistry.addBundleFileWrapperFactoryHook(new BundleFileWrapperFactoryHook() { @Override - public BundleFile wrapBundleFile(final BundleFile bundleFile, Generation generation, boolean base) { + public BundleFileWrapper wrapBundleFile(final BundleFile bundleFile, Generation generation, boolean base) { if (!base) { return null; } - return new BundleFile(bundleFile.getBaseFile()) { - - @Override - public void open() throws IOException { - bundleFile.open(); - } - - @Override - public File getFile(String path, boolean nativeCode) { - return bundleFile.getFile(path, nativeCode); - } - - @Override - public Enumeration<String> getEntryPaths(String path) { - return bundleFile.getEntryPaths(path); - } + return new BundleFileWrapper(bundleFile) { @Override public BundleEntry getEntry(String path) { @@ -85,16 +79,6 @@ public class PluginConverterHook implements HookConfigurator { throw new RuntimeException(e); } } - - @Override - public boolean containsDir(String dir) { - return bundleFile.containsDir(dir); - } - - @Override - public void close() throws IOException { - bundleFile.close(); - } }; } }); diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java index 77adecca1..c519ad8b1 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java @@ -145,6 +145,10 @@ public class DiscardBundleTests extends AbstractBundleTests { try { equinox = restart(equinox, configuration); assertNotDiscarded(location, equinox); + // Attempting to touch the file with equinox still running + // will sometimes result in failure presumably due to a locked + // file. + stop(equinox); touchFile(bundleFile); equinox = restart(equinox, configuration); if (discard) diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/BundleFileWrapperFactoryHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/BundleFileWrapperFactoryHook.java index d2e4e55d6..cfcfc492c 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/BundleFileWrapperFactoryHook.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/BundleFileWrapperFactoryHook.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 IBM Corporation and others. + * Copyright (c) 2012, 2013 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 @@ -13,6 +13,7 @@ package org.eclipse.osgi.internal.hookregistry; import org.eclipse.osgi.storage.BundleInfo.Generation; import org.eclipse.osgi.storage.bundlefile.BundleFile; +import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper; /** * A factory that wraps bundle file objects. @@ -27,6 +28,6 @@ public interface BundleFileWrapperFactoryHook { * @return a wrapped bundle file for the specified content, or null if the bundle content * is not wrapped. */ - BundleFile wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base); + BundleFileWrapper wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base); } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java index b1d50d316..ddda31ffd 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/loader/BundleLoader.java @@ -213,10 +213,11 @@ public class BundleLoader implements ModuleLoader { if (System.getSecurityManager() == null) { classloader = createClassLoaderPrivledged(parent, generation.getBundleInfo().getStorage().getConfiguration(), this, generation, hooks); } else { + final ClassLoader cl = parent; classloader = AccessController.doPrivileged(new PrivilegedAction<ModuleClassLoader>() { @Override public ModuleClassLoader run() { - return createClassLoaderPrivledged(parent, generation.getBundleInfo().getStorage().getConfiguration(), BundleLoader.this, generation, hooks); + return createClassLoaderPrivledged(cl, generation.getBundleInfo().getStorage().getConfiguration(), BundleLoader.this, generation, hooks); } }); } @@ -678,7 +679,9 @@ public class BundleLoader implements ModuleLoader { } boolean localSearch = (options & BundleWiring.LISTRESOURCES_LOCAL) != 0; - List<String> result = new ArrayList<String>(); + // Use LinkedHashSet for optimized performance of contains() plus + // ordering guarantees. + LinkedHashSet<String> result = new LinkedHashSet<String>(); Set<String> importedPackages = new HashSet<String>(0); for (String name : packages) { // look for import source diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java index dc20915ba..f1763777f 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 IBM Corporation and others. All rights reserved. + * Copyright (c) 2007, 2013 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 @@ -36,7 +36,7 @@ public class SignatureBlockProcessor implements SignedContentConstants { } public SignedContentImpl process() throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException { - BundleFile wrappedBundleFile = signedBundle.getWrappedBundleFile(); + BundleFile wrappedBundleFile = signedBundle.getBundleFile(); BundleEntry be = wrappedBundleFile.getEntry(META_INF_MANIFEST_MF); if (be == null) return createUnsignedContent(); diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java index ab610f238..e9127878a 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 IBM Corporation and others. + * Copyright (c) 2006, 2013 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 @@ -11,15 +11,14 @@ package org.eclipse.osgi.internal.signedcontent; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.security.*; import java.security.cert.*; import java.util.Date; -import java.util.Enumeration; import org.eclipse.osgi.signedcontent.*; -import org.eclipse.osgi.storage.bundlefile.BundleEntry; -import org.eclipse.osgi.storage.bundlefile.BundleFile; +import org.eclipse.osgi.storage.bundlefile.*; import org.eclipse.osgi.util.NLS; /** @@ -27,21 +26,19 @@ import org.eclipse.osgi.util.NLS; * signatures. It requires full signing of the manifest by all signers. If no * signatures are found, the classes and resources are retrieved without checks. */ -public class SignedBundleFile extends BundleFile implements SignedContentConstants, SignedContent { - private BundleFile wrappedBundleFile; +public class SignedBundleFile extends BundleFileWrapper implements SignedContentConstants, SignedContent { SignedContentImpl signedContent; private final int supportFlags; private final SignedBundleHook signedBundleHook; - SignedBundleFile(SignedContentImpl signedContent, int supportFlags, SignedBundleHook signedBundleHook) { - super(null); + SignedBundleFile(BundleFile bundleFile, SignedContentImpl signedContent, int supportFlags, SignedBundleHook signedBundleHook) { + super(bundleFile); this.signedContent = signedContent; this.supportFlags = supportFlags; this.signedBundleHook = signedBundleHook; } - void setBundleFile(BundleFile bundleFile) throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException { - wrappedBundleFile = bundleFile; + void initializeSignedContent() throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException { if (signedContent == null) { SignatureBlockProcessor signatureProcessor = new SignatureBlockProcessor(this, supportFlags, signedBundleHook); signedContent = signatureProcessor.process(); @@ -50,15 +47,11 @@ public class SignedBundleFile extends BundleFile implements SignedContentConstan } } - public File getFile(String path, boolean nativeCode) { - return wrappedBundleFile.getFile(path, nativeCode); - } - public BundleEntry getEntry(String path) { // strip off leading slashes so we can ensure the path matches the one provided in the manifest. if (path.length() > 0 && path.charAt(0) == '/') path = path.substring(1); - BundleEntry be = wrappedBundleFile.getEntry(path); + BundleEntry be = getBundleFile().getEntry(path); if ((supportFlags & SignedBundleHook.VERIFY_RUNTIME) == 0 || signedContent == null) return be; if (path.startsWith(META_INF)) { @@ -82,26 +75,6 @@ public class SignedBundleFile extends BundleFile implements SignedContentConstan return new SignedBundleEntry(be); } - public Enumeration<String> getEntryPaths(String path) { - return wrappedBundleFile.getEntryPaths(path); - } - - public void close() throws IOException { - wrappedBundleFile.close(); - } - - public void open() throws IOException { - wrappedBundleFile.open(); - } - - public boolean containsDir(String dir) { - return wrappedBundleFile.containsDir(dir); - } - - public File getBaseFile() { - return wrappedBundleFile.getBaseFile(); - } - class SignedBundleEntry extends BundleEntry { BundleEntry nestedEntry; @@ -138,10 +111,6 @@ public class SignedBundleFile extends BundleFile implements SignedContentConstan } - BundleFile getWrappedBundleFile() { - return wrappedBundleFile; - } - SignedContentImpl getSignedContent() { return signedContent; } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java index fe0fcebb3..45ea87b0d 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java @@ -146,26 +146,26 @@ public class SignedBundleHook implements ActivatorHookFactory, BundleFileWrapper } } - public BundleFile wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base) { + public BundleFileWrapper wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base) { try { if (bundleFile != null) { StorageHookImpl hook = generation.getStorageHook(SignedStorageHook.class); SignedBundleFile signedBaseFile; if (base && hook != null) { - signedBaseFile = new SignedBundleFile(hook.signedContent, supportSignedBundles, this); + signedBaseFile = new SignedBundleFile(bundleFile, hook.signedContent, supportSignedBundles, this); if (hook.signedContent == null) { - signedBaseFile.setBundleFile(bundleFile); + signedBaseFile.initializeSignedContent(); SignedContentImpl signedContent = signedBaseFile.getSignedContent(); hook.signedContent = signedContent != null && signedContent.isSigned() ? signedContent : null; } } else - signedBaseFile = new SignedBundleFile(null, supportSignedBundles, this); - signedBaseFile.setBundleFile(bundleFile); + signedBaseFile = new SignedBundleFile(bundleFile, null, supportSignedBundles, this); + signedBaseFile.initializeSignedContent(); SignedContentImpl signedContent = signedBaseFile.getSignedContent(); if (signedContent != null && signedContent.isSigned()) { // only use the signed file if there are certs signedContent.setContent(signedBaseFile); - bundleFile = signedBaseFile; + return new BundleFileWrapper(signedBaseFile); } } } catch (IOException e) { @@ -173,7 +173,7 @@ public class SignedBundleHook implements ActivatorHookFactory, BundleFileWrapper } catch (GeneralSecurityException e) { log("Bad bundle file: " + bundleFile.getBaseFile(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ } - return bundleFile; + return null; } public void addHooks(HookRegistry hookRegistry) { @@ -210,9 +210,9 @@ public class SignedBundleHook implements ActivatorHookFactory, BundleFileWrapper temp.close(); contentBundleFile = new ZipBundleFile(content, null, null, container.getConfiguration().getDebug()); } - SignedBundleFile result = new SignedBundleFile(null, VERIFY_ALL, this); + SignedBundleFile result = new SignedBundleFile(contentBundleFile, null, VERIFY_ALL, this); try { - result.setBundleFile(contentBundleFile); + result.initializeSignedContent(); } catch (InvalidKeyException e) { throw (InvalidKeyException) new InvalidKeyException(NLS.bind(SignedContentMessages.Factory_SignedContent_Error, content)).initCause(e); } catch (SignatureException e) { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java index fe4d81c69..318f78bc0 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/Storage.java @@ -864,7 +864,7 @@ public class Storage { List<BundleFileWrapperFactoryHook> wrapperFactories = getConfiguration().getHookRegistry().getBundleFileWrapperFactoryHooks(); BundleFileWrapperChain wrapped = wrapperFactories.isEmpty() ? null : new BundleFileWrapperChain(bundleFile, null); for (BundleFileWrapperFactoryHook wrapperFactory : wrapperFactories) { - BundleFile wrapperBundle = wrapperFactory.wrapBundleFile(bundleFile, generation, isBase); + BundleFileWrapper wrapperBundle = wrapperFactory.wrapBundleFile(bundleFile, generation, isBase); if (wrapperBundle != null && wrapperBundle != bundleFile) bundleFile = wrapped = new BundleFileWrapperChain(wrapperBundle, wrapped); } @@ -1473,12 +1473,13 @@ public class Storage { * @see BundleWiring#listResources(String, String, int) */ public static List<String> listEntryPaths(List<BundleFile> bundleFiles, String path, String filePattern, int options) { - // a list used to store the results of the search - List<String> pathList = new ArrayList<String>(); + // Use LinkedHashSet for optimized performance of contains() plus + // ordering guarantees. + LinkedHashSet<String> pathList = new LinkedHashSet<String>(); Filter patternFilter = null; Hashtable<String, String> patternProps = null; if (filePattern != null) { - // Optimization: If the file pattern does not include a wildcard or escape char then it must represent a single file. + // Optimization: If the file pattern does not include a wildcard or escape char then it must represent a single file. // Avoid pattern matching and use BundleFile.getEntry() if recursion was not requested. if ((options & BundleWiring.FINDENTRIES_RECURSE) == 0 && filePattern.indexOf('*') == -1 && filePattern.indexOf('\\') == -1) { if (path.length() == 0) @@ -1489,7 +1490,7 @@ public class Storage { if (bundleFile.getEntry(path) != null && !pathList.contains(path)) pathList.add(path); } - return pathList; + return new ArrayList<String>(pathList); } // For when the file pattern includes a wildcard. try { @@ -1501,14 +1502,14 @@ public class Storage { // TODO something unexpected happened; log error and return nothing // Bundle b = context == null ? null : context.getBundle(); // eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, b, e); - return pathList; + return new ArrayList<String>(pathList); } } // find the entry paths for the datas for (BundleFile bundleFile : bundleFiles) { listEntryPaths(bundleFile, path, patternFilter, patternProps, options, pathList); } - return pathList; + return new ArrayList<String>(pathList); } public static String sanitizeFilterInput(String filePattern) throws InvalidSyntaxException { @@ -1551,10 +1552,16 @@ public class Storage { return buffer == null ? filePattern : buffer.toString(); } - private static List<String> listEntryPaths(BundleFile bundleFile, String path, Filter patternFilter, Hashtable<String, String> patternProps, int options, List<String> pathList) { + // Use LinkedHashSet for optimized performance of contains() plus ordering + // guarantees. + private static LinkedHashSet<String> listEntryPaths(BundleFile bundleFile, String path, Filter patternFilter, Hashtable<String, String> patternProps, int options, LinkedHashSet<String> pathList) { if (pathList == null) - pathList = new ArrayList<String>(); - Enumeration<String> entryPaths = bundleFile.getEntryPaths(path); + pathList = new LinkedHashSet<String>(); + Enumeration<String> entryPaths; + if ((options & BundleWiring.FINDENTRIES_RECURSE) != 0) + entryPaths = bundleFile.getEntryPaths(path, true); + else + entryPaths = bundleFile.getEntryPaths(path); if (entryPaths == null) return pathList; while (entryPaths.hasMoreElements()) { @@ -1582,9 +1589,6 @@ public class Storage { // prevent duplicates and match on the patternFilter if (!pathList.contains(entry) && (patternFilter == null || patternFilter.matchCase(patternProps))) pathList.add(entry); - // recurse only into entries that are directories - if (((options & BundleWiring.FINDENTRIES_RECURSE) != 0) && !entry.equals(path) && entry.length() > 0 && lastSlash == (entry.length() - 1)) - listEntryPaths(bundleFile, entry, patternFilter, patternProps, options, pathList); } return pathList; } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java index c75524400..002ab3739 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/SystemBundleFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 IBM Corporation and others. + * Copyright (c) 2013 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 @@ -63,7 +63,7 @@ public class SystemBundleFile extends BundleFile { } @Override - public Enumeration<String> getEntryPaths(String path) { + public Enumeration<String> getEntryPaths(String path, boolean recurse) { return null; } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java index 7930b869a..735a6b2c6 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleEntry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2013 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 @@ -21,7 +21,6 @@ import org.eclipse.osgi.storage.StorageUtil; * <p> * Clients may extend this class. * </p> - * @since 3.2 */ public abstract class BundleEntry { protected static final int BUF_SIZE = 8 * 1024; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java index 69d27fa32..e4ddde7fc 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2013 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 @@ -25,10 +25,10 @@ import org.eclipse.osgi.storage.url.bundleresource.Handler; /** * The BundleFile API is used by Adaptors to read resources out of an * installed Bundle in the Framework. - * <p> - * Clients may extend this class. - * </p> - * @since 3.2 + * <p/> + * Clients wishing to modify or extend the functionality of this class at + * runtime should extend the associated {@link BundleFileWrapper decorator} + * instead. */ abstract public class BundleFile { static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction()); @@ -67,6 +67,18 @@ abstract public class BundleFile { abstract public BundleEntry getEntry(String path); /** + * Performs the same function as calling + * {@link #getEntryPaths(String, boolean)} with <code>recurse</code> equal + * to <code>false</code>. + * @param path path of the entry to locate in the bundle + * @return an Enumeration of Strings that indicate the paths found or + * null if the path does not exist. + */ + public Enumeration<String> getEntryPaths(String path) { + return getEntryPaths(path, false); + } + + /** * Allows to access the entries of the bundle. * Since the bundle content is usually a jar, this * allows to access the jar contents. @@ -77,10 +89,14 @@ abstract public class BundleFile { * themselves. If a returned name is a directory, it finishes with a * slash. If a returned name is a file, it does not finish with a slash. * @param path path of the entry to locate in the bundle + * @param recurse - If <code>true</code>, provide entries for the files and + * directories within the directory denoted by <code>path</code> plus + * all sub-directories and files; otherwise, provide only the entries + * within the immediate directory. * @return an Enumeration of Strings that indicate the paths found or * null if the path does not exist. */ - abstract public Enumeration<String> getEntryPaths(String path); + abstract public Enumeration<String> getEntryPaths(String path, boolean recurse); /** * Closes the BundleFile. diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java new file mode 100755 index 000000000..33f59380e --- /dev/null +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapper.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2013 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.osgi.storage.bundlefile; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook; +import org.eclipse.osgi.storage.BundleInfo; + +/** + * A {@link BundleFile bundle file} decorator. + * <p/> + * Clients wishing to modify or extend the behavior of a bundle file at runtime + * should extend this class instead. A hook is provided by the related {@link + * BundleFileWrapperFactoryHook abstract factory} class in response to a + * {@link BundleFileWrapperFactoryHook#wrapBundleFile(BundleFile, + * BundleInfo.Generation, boolean) call} from the framework. + */ +public class BundleFileWrapper extends BundleFile { + private final BundleFile bundleFile; + + /** + * Creates a new <code>BundleFileWrapper</code> instance wrapping the + * given {@link BundleFile bundle file}. + * + * @param bundleFile - The bundle file to wrap. + * @throws NullPointerException - If the bundle file is <code>null</code>. + */ + public BundleFileWrapper(BundleFile bundleFile) { + super(bundleFile.getBaseFile()); + this.bundleFile = bundleFile; + } + + @Override + public File getFile(String path, boolean nativeCode) { + return bundleFile.getFile(path, nativeCode); + } + + @Override + public BundleEntry getEntry(String path) { + return bundleFile.getEntry(path); + } + + @Override + public Enumeration<String> getEntryPaths(String path) { + return bundleFile.getEntryPaths(path); + } + + @Override + public Enumeration<String> getEntryPaths(String path, boolean recurse) { + return bundleFile.getEntryPaths(path, recurse); + } + + /** + * Get the wrapped bundle file. + * + * @return The wrapped bundle file. + */ + public BundleFile getBundleFile() { + return bundleFile; + } + + @Override + public void close() throws IOException { + bundleFile.close(); + } + + @Override + public void open() throws IOException { + bundleFile.open(); + } + + @Override + public boolean containsDir(String dir) { + return bundleFile.containsDir(dir); + } +} diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java index 3edf2eae0..6ad57ade2 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/BundleFileWrapperChain.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2012 IBM Corporation and others. + * Copyright (c) 2008, 2013 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 @@ -11,59 +11,23 @@ package org.eclipse.osgi.storage.bundlefile; -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import org.eclipse.osgi.container.Module; import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook; /** * Used to chain the BundleFile objects returned from {@link BundleFileWrapperFactoryHook}. * This class is useful for traversing the chain of wrapped bundle files. */ -public class BundleFileWrapperChain extends BundleFile { +public class BundleFileWrapperChain extends BundleFileWrapper { private final BundleFile wrapped; private final BundleFileWrapperChain next; public BundleFileWrapperChain(BundleFile wrapped, BundleFileWrapperChain next) { - super(null); + super(wrapped); this.wrapped = wrapped; this.next = next; } - public void close() throws IOException { - wrapped.close(); - } - - public boolean containsDir(String dir) { - return wrapped.containsDir(dir); - } - - public BundleEntry getEntry(String path) { - return wrapped.getEntry(path); - } - - public Enumeration<String> getEntryPaths(String path) { - return wrapped.getEntryPaths(path); - } - - public File getFile(String path, boolean nativeCode) { - return wrapped.getFile(path, nativeCode); - } - - public void open() throws IOException { - wrapped.open(); - } - - public File getBaseFile() { - return wrapped.getBaseFile(); - } - - public URL getResourceURL(String path, Module hostModule, int index) { - return wrapped.getResourceURL(path, hostModule, index); - } - + @Override public String toString() { return wrapped.toString(); } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirBundleFile.java index da8c15109..462892cd7 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirBundleFile.java @@ -13,14 +13,12 @@ package org.eclipse.osgi.storage.bundlefile; import java.io.File; import java.io.IOException; -import java.util.Enumeration; -import java.util.NoSuchElementException; +import java.util.*; import org.eclipse.osgi.storage.StorageMsg; import org.eclipse.osgi.util.NLS; /** * A BundleFile that uses a directory as its base file. - * @since 3.2 */ public class DirBundleFile extends BundleFile { @@ -116,35 +114,29 @@ public class DirBundleFile extends BundleFile { return dirPath != null && BundleFile.secureAction.isDirectory(dirPath); } - public Enumeration<String> getEntryPaths(String path) { + public Enumeration<String> getEntryPaths(String path, boolean recurse) { if (path.length() > 0 && path.charAt(0) == '/') path = path.substring(1); - final File pathFile = getFile(path, false); + File pathFile = getFile(path, false); if (pathFile == null || !BundleFile.secureAction.isDirectory(pathFile)) return null; - final String[] fileList = BundleFile.secureAction.list(pathFile); + String[] fileList = BundleFile.secureAction.list(pathFile); if (fileList == null || fileList.length == 0) return null; - final String dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/'; - return new Enumeration<String>() { - int cur = 0; - - public boolean hasMoreElements() { - return fileList != null && cur < fileList.length; - } - - public String nextElement() { - if (!hasMoreElements()) { - throw new NoSuchElementException(); - } - java.io.File childFile = new java.io.File(pathFile, fileList[cur]); - StringBuffer sb = new StringBuffer(dirPath).append(fileList[cur++]); - if (BundleFile.secureAction.isDirectory(childFile)) { - sb.append("/"); //$NON-NLS-1$ - } - return sb.toString(); + String dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/'; + + LinkedHashSet<String> entries = new LinkedHashSet<String>(); + for (String s : fileList) { + java.io.File childFile = new java.io.File(pathFile, s); + StringBuilder sb = new StringBuilder(dirPath).append(s); + if (BundleFile.secureAction.isDirectory(childFile)) { + sb.append("/"); //$NON-NLS-1$ + if (recurse) + entries.addAll(Collections.list(getEntryPaths(sb.toString(), true))); } - }; + entries.add(sb.toString()); + } + return Collections.enumeration(entries); } public void close() { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirZipBundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirZipBundleEntry.java index 0bb1cee5c..a4a7d261c 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirZipBundleEntry.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/DirZipBundleEntry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -19,7 +19,6 @@ import java.net.URL; * Represents a directory entry in a ZipBundleFile. This object is used to * reference a directory entry in a ZipBundleFile when the directory entries are * not included in the zip file. - * @since 3.2 */ public class DirZipBundleEntry extends BundleEntry { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/FileBundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/FileBundleEntry.java index 94bc8ee90..8a4f00a07 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/FileBundleEntry.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/FileBundleEntry.java @@ -18,7 +18,6 @@ import java.net.URL; /** * A BundleEntry represented by a File object. The FileBundleEntry class is * used for bundles that are installed as extracted zips on a file system. - * @since 3.2 */ public class FileBundleEntry extends BundleEntry { /** diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/MRUBundleFileList.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/MRUBundleFileList.java index fcf148f75..06885d5e9 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/MRUBundleFileList.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/MRUBundleFileList.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -20,7 +20,6 @@ import org.eclipse.osgi.framework.eventmgr.*; * track of open BundleFiles. The MRU will use the file limit specified by the property * "osgi.bundlefile.limit" by default unless the MRU is constructed with a specific * file limit. - * @since 3.2 */ public class MRUBundleFileList implements EventDispatcher<Object, Object, BundleFile> { private static final int MIN = 10; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/NestedDirBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/NestedDirBundleFile.java index dea0669ce..718441417 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/NestedDirBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/NestedDirBundleFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -25,7 +25,6 @@ import java.util.Enumeration; * <pre> * Bundle-ClassPath: nested.jar,nesteddir/ * </pre> - * @since 3.2 */ public class NestedDirBundleFile extends BundleFile { private final BundleFile baseBundleFile; @@ -66,8 +65,8 @@ public class NestedDirBundleFile extends BundleFile { return new StringBuffer(cp).append(path).toString(); } - public Enumeration<String> getEntryPaths(String path) { - final Enumeration<String> basePaths = baseBundleFile.getEntryPaths(prependNestedDir(path)); + public Enumeration<String> getEntryPaths(String path, boolean recurse) { + final Enumeration<String> basePaths = baseBundleFile.getEntryPaths(prependNestedDir(path), recurse); final int cpLength = cp.length(); if (basePaths == null) return null; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleEntry.java index 727e59d43..2c8671a4d 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleEntry.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleEntry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2013 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 @@ -19,7 +19,6 @@ import java.util.zip.ZipEntry; /** * A BundleEntry represented by a ZipEntry in a ZipFile. The ZipBundleEntry * class is used for bundles that are installed as a ZipFile on a file system. - * @since 3.2 */ public class ZipBundleEntry extends BundleEntry { /** diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java index d8f796a48..eb291d8bc 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/storage/bundlefile/ZipBundleFile.java @@ -24,7 +24,6 @@ import org.eclipse.osgi.util.NLS; /** * A BundleFile that uses a ZipFile as it base file. - * @since 3.2 */ public class ZipBundleFile extends BundleFile { @@ -255,39 +254,55 @@ public class ZipBundleFile extends BundleFile { } - public synchronized Enumeration<String> getEntryPaths(String path) { - if (!checkedOpen()) - return null; + @Override + public synchronized Enumeration<String> getEntryPaths(String path, boolean recurse) { if (path == null) throw new NullPointerException(); + // Is the zip file already open or, if not, can it be opened? + if (!checkedOpen()) + return null; + // Strip any leading '/' off of path. if (path.length() > 0 && path.charAt(0) == '/') path = path.substring(1); + // Append a '/', if not already there, to path if not an empty string. if (path.length() > 0 && path.charAt(path.length() - 1) != '/') - path = new StringBuffer(path).append("/").toString(); //$NON-NLS-1$ + path = new StringBuilder(path).append("/").toString(); //$NON-NLS-1$ - List<String> vEntries = new ArrayList<String>(); + Set<String> vEntries = new HashSet<String>(); + // Get all zip file entries and add the ones of interest. Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); String entryPath = zipEntry.getName(); + // Is the entry of possible interest? Note that + // string.startsWith("") == true. if (entryPath.startsWith(path)) { + // If we get here, we know that the entry is either (1) equal to + // path, (2) a file under path, or (3) a subdirectory of path. if (path.length() < entryPath.length()) { - if (entryPath.lastIndexOf('/') < path.length()) { - vEntries.add(entryPath); - } else { - entryPath = entryPath.substring(path.length()); - int slash = entryPath.indexOf('/'); - entryPath = path + entryPath.substring(0, slash + 1); - if (!vEntries.contains(entryPath)) - vEntries.add(entryPath); - } + // If we get here, we know that entry is not equal to path. + getEntryPaths(path, entryPath.substring(path.length()), recurse, vEntries); } } } return vEntries.size() == 0 ? null : Collections.enumeration(vEntries); } + private void getEntryPaths(String path, String entry, boolean recurse, Set<String> entries) { + if (entry.length() == 0) + return; + int slash = entry.indexOf('/'); + if (slash == -1) + entries.add(path + entry); + else { + path = path + entry.substring(0, slash + 1); + entries.add(path); + if (recurse) + getEntryPaths(path, entry.substring(slash + 1), true, entries); + } + } + public synchronized void close() throws IOException { if (!closed) { if (referenceCount > 0 && isMruListClosing()) { |