Merge with more modern (and hopefully deadlock prone) version of default branch CacheModuleState204513
authorJaroslav Tulach <jtulach@netbeans.org>
Fri, 16 Mar 2012 08:17:35 +0100
branchCacheModuleState204513
changeset 223367879820a7bc7e
parent 222014 6892e1e02b9b
parent 223366 3ded471c0cd5
child 223379 b0118b3609f0
child 224445 94ac8a6ab650
Merge with more modern (and hopefully deadlock prone) version of default branch
core.startup/nbproject/project.xml
core.startup/src/org/netbeans/core/startup/NbInstaller.java
netbinox/test/unit/src/org/netbeans/modules/netbinox/CachingPreventsFileTouchesTest.java
     1.1 --- a/autoupdate.services/nbproject/project.xml	Thu Mar 15 16:10:40 2012 +0100
     1.2 +++ b/autoupdate.services/nbproject/project.xml	Fri Mar 16 08:17:35 2012 +0100
     1.3 @@ -29,7 +29,7 @@
     1.4                      <compile-dependency/>
     1.5                      <run-dependency>
     1.6                          <release-version>1</release-version>
     1.7 -                        <specification-version>1.28</specification-version>
     1.8 +                        <specification-version>1.38</specification-version>
     1.9                      </run-dependency>
    1.10                  </dependency>
    1.11                  <dependency>
     2.1 --- a/autoupdate.services/src/org/netbeans/modules/autoupdate/services/Utilities.java	Thu Mar 15 16:10:40 2012 +0100
     2.2 +++ b/autoupdate.services/src/org/netbeans/modules/autoupdate/services/Utilities.java	Fri Mar 16 08:17:35 2012 +0100
     2.3 @@ -63,6 +63,7 @@
     2.4  import org.netbeans.api.autoupdate.UpdateElement;
     2.5  import org.netbeans.api.autoupdate.UpdateManager;
     2.6  import org.netbeans.api.autoupdate.UpdateUnit;
     2.7 +import org.netbeans.core.startup.Main;
     2.8  import org.netbeans.core.startup.TopLogging;
     2.9  import org.netbeans.modules.autoupdate.updateprovider.DummyModuleInfo;
    2.10  import org.netbeans.modules.autoupdate.updateprovider.InstalledModuleProvider;
    2.11 @@ -102,7 +103,6 @@
    2.12      public static final String NBM_EXTENTSION = ".nbm";
    2.13      public static final String JAR_EXTENSION = ".jar"; //OSGi bundle
    2.14      private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat ("yyyy/MM/dd"); // NOI18N
    2.15 -    public static final String ATTR_VISIBLE = "AutoUpdate-Show-In-Client";
    2.16      public static final String ATTR_ESSENTIAL = "AutoUpdate-Essential-Module";
    2.17  
    2.18      private static final String[] FIRST_CLASS_MODULES = new String [] {
    2.19 @@ -1049,15 +1049,7 @@
    2.20      }
    2.21      
    2.22      public static boolean isKitModule (ModuleInfo mi) {
    2.23 -        // XXX: it test can break simple modules mode
    2.24 -        // should find corresponing UpdateElement and check its type
    2.25 -        Object o = mi.getAttribute (ATTR_VISIBLE);
    2.26 -        if (o != null) {
    2.27 -            return Boolean.parseBoolean(o.toString());
    2.28 -        }
    2.29 -        // OSGi bundles should be considered invisible by default since they are typically autoloads.
    2.30 -        // (NB modules get AutoUpdate-Show-In-Client inserted into the JAR by the build process.)
    2.31 -        return mi.getAttribute("Bundle-SymbolicName") == null;
    2.32 +        return Main.getModuleSystem().isShowInAutoUpdateClient(mi);
    2.33      }
    2.34      
    2.35      public static boolean isEssentialModule (ModuleInfo mi) {
     3.1 --- a/core.startup/apichanges.xml	Thu Mar 15 16:10:40 2012 +0100
     3.2 +++ b/core.startup/apichanges.xml	Fri Mar 16 08:17:35 2012 +0100
     3.3 @@ -56,6 +56,21 @@
     3.4  <!-- ACTUAL CHANGES BEGIN HERE: -->
     3.5  
     3.6    <changes>
     3.7 +     <change id="is.au.visible">
     3.8 +        <api name="bridge"/>
     3.9 +        <summary>isShowInAutoUpdateClient</summary>
    3.10 +        <version major="1" minor="38"/>
    3.11 +        <date day="21" month="3" year="2012"/>
    3.12 +        <author login="jtulach"/>
    3.13 +        <compatibility addition="yes" binary="compatible" semantic="compatible" />
    3.14 +        <description>
    3.15 +        <p>
    3.16 +            Method to allow ergonomics and autoupdate to check if a module
    3.17 +            is visible in the autoupdate client.
    3.18 +        </p>
    3.19 +        </description>
    3.20 +        <class package="org.netbeans.core.startup" name="ModuleSystem"/>
    3.21 +    </change>
    3.22       <change id="netbeans.productversion">
    3.23          <api name="exec-property"/>
    3.24          <summary>netbeans.productversion property</summary>
     4.1 --- a/core.startup/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
     4.2 +++ b/core.startup/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
     4.3 @@ -3,5 +3,5 @@
     4.4  OpenIDE-Module-Localizing-Bundle: org/netbeans/core/startup/Bundle.properties
     4.5  OpenIDE-Module-Layer: org/netbeans/core/startup/layer.xml
     4.6  OpenIDE-Module-Provides: org.openide.modules.InstalledFileLocator
     4.7 -OpenIDE-Module-Specification-Version: 1.37
     4.8 +OpenIDE-Module-Specification-Version: 1.38
     4.9  
     5.1 --- a/core.startup/nbproject/project.xml	Thu Mar 15 16:10:40 2012 +0100
     5.2 +++ b/core.startup/nbproject/project.xml	Fri Mar 16 08:17:35 2012 +0100
     5.3 @@ -55,7 +55,7 @@
     5.4                      <compile-dependency/>
     5.5                      <run-dependency>
     5.6                          <release-version>1</release-version>
     5.7 -                        <specification-version>2.49</specification-version>
     5.8 +                        <specification-version>2.51</specification-version>
     5.9                      </run-dependency>
    5.10                  </dependency>
    5.11                  <dependency>
     6.1 --- a/core.startup/src/org/netbeans/core/startup/ModuleList.java	Thu Mar 15 16:10:40 2012 +0100
     6.2 +++ b/core.startup/src/org/netbeans/core/startup/ModuleList.java	Fri Mar 16 08:17:35 2012 +0100
     6.3 @@ -880,7 +880,7 @@
     6.4              }
     6.5              // Newly added modules first.
     6.6              for (Module m : mgr.getModules()) {
     6.7 -                if (m.isFixed() || m.getAllJars().isEmpty()) {
     6.8 +                if (m.isFixed() || m.getJarFile() == null) {
     6.9                      // No way, we don't manage these.
    6.10                      continue;
    6.11                  }
     7.1 --- a/core.startup/src/org/netbeans/core/startup/ModuleSystem.java	Thu Mar 15 16:10:40 2012 +0100
     7.2 +++ b/core.startup/src/org/netbeans/core/startup/ModuleSystem.java	Fri Mar 16 08:17:35 2012 +0100
     7.3 @@ -70,6 +70,7 @@
     7.4  import org.openide.filesystems.FileObject;
     7.5  import org.openide.filesystems.FileSystem;
     7.6  import org.openide.filesystems.FileUtil;
     7.7 +import org.openide.modules.ModuleInfo;
     7.8  import org.openide.util.Exceptions;
     7.9  
    7.10  /** Controller of the IDE's whole module system.
    7.11 @@ -459,6 +460,20 @@
    7.12      public String getEffectiveClasspath(Module m) {
    7.13          return installer.getEffectiveClasspath(m);
    7.14      }
    7.15 +
    7.16 +    /** Checks whether the provided module will be visible in autoupdate client.
    7.17 +     * Seeks for AutoUpdate-Show-In-Client attribute in manifest. The module
    7.18 +     * is visible if the attribute is missing or if it is set to <code>true</code>.
    7.19 +     * Uses caches to remember the value between restarts.
    7.20 +     * 
    7.21 +     * @since 1.38
    7.22 +     * @param mi the module to test
    7.23 +     * @return <code>true</code> if the module is supposed to be visible in 
    7.24 +     *   autoupdate client
    7.25 +     */
    7.26 +    public boolean isShowInAutoUpdateClient(ModuleInfo mi) {
    7.27 +        return this.installer.isShowInAutoUpdateClient(mi);
    7.28 +    }
    7.29      
    7.30      /** Dummy event handler that does not print anything.
    7.31       * Useful for test scripts where you do not really want to see
     8.1 --- a/core.startup/src/org/netbeans/core/startup/NbInstaller.java	Thu Mar 15 16:10:40 2012 +0100
     8.2 +++ b/core.startup/src/org/netbeans/core/startup/NbInstaller.java	Fri Mar 16 08:17:35 2012 +0100
     8.3 @@ -44,16 +44,14 @@
     8.4  
     8.5  package org.netbeans.core.startup;
     8.6  
     8.7 -import java.io.ByteArrayInputStream;
     8.8  import java.io.DataOutputStream;
     8.9  import java.io.File;
    8.10  import java.io.IOException;
    8.11 +import java.io.InputStream;
    8.12  import java.net.URL;
    8.13 -import java.nio.ByteBuffer;
    8.14  import java.util.ArrayList;
    8.15  import java.util.Collection;
    8.16  import java.util.Collections;
    8.17 -import java.util.Date;
    8.18  import java.util.Enumeration;
    8.19  import java.util.HashMap;
    8.20  import java.util.HashSet;
    8.21 @@ -62,6 +60,7 @@
    8.22  import java.util.List;
    8.23  import java.util.Locale;
    8.24  import java.util.Map;
    8.25 +import java.util.Properties;
    8.26  import java.util.Set;
    8.27  import java.util.StringTokenizer;
    8.28  import java.util.TreeMap;
    8.29 @@ -69,7 +68,6 @@
    8.30  import java.util.jar.Attributes;
    8.31  import java.util.jar.JarEntry;
    8.32  import java.util.jar.JarFile;
    8.33 -import java.util.jar.Manifest;
    8.34  import java.util.logging.Level;
    8.35  import java.util.logging.Logger;
    8.36  import org.netbeans.Events;
    8.37 @@ -80,16 +78,16 @@
    8.38  import org.netbeans.Stamps;
    8.39  import org.netbeans.Util;
    8.40  import org.netbeans.core.startup.layers.ModuleLayeredFileSystem;
    8.41 -import org.netbeans.core.startup.preferences.RelPaths;
    8.42  import org.openide.filesystems.FileObject;
    8.43  import org.openide.filesystems.FileUtil;
    8.44  import org.openide.modules.Dependency;
    8.45 +import org.openide.modules.ModuleInfo;
    8.46  import org.openide.modules.ModuleInstall;
    8.47  import org.openide.modules.SpecificationVersion;
    8.48 -import org.openide.util.Exceptions;
    8.49  import org.openide.util.NbCollections;
    8.50  import org.openide.util.SharedClassObject;
    8.51  import org.openide.util.NbBundle;
    8.52 +import org.openide.util.Utilities;
    8.53  import org.openide.util.lookup.InstanceContent;
    8.54  import org.xml.sax.SAXException;
    8.55  
    8.56 @@ -124,6 +122,8 @@
    8.57      private final Map<Module,List<Module.PackageExport>> hiddenClasspathPackages = new  HashMap<Module,List<Module.PackageExport>>();
    8.58      /** #164510: similar to {@link #hiddenClasspathPackages} but backwards for efficiency */
    8.59      private final Map<Module.PackageExport,List<Module>> hiddenClasspathPackagesReverse = new HashMap<Module.PackageExport,List<Module>>();
    8.60 +    /** caches important values from module manifests */
    8.61 +    private final Cache cache = new Cache();
    8.62          
    8.63      /** Create an NbInstaller.
    8.64       * You should also call {@link #registerManager} and if applicable
    8.65 @@ -145,12 +145,15 @@
    8.66      }
    8.67  
    8.68      // @SuppressWarnings("unchecked")
    8.69 +    @Override
    8.70      public void prepare(Module m) throws InvalidException {
    8.71          ev.log(Events.PREPARE, m);
    8.72          checkForHiddenPackages(m);
    8.73          Set<ManifestSection> mysections = null;
    8.74          Class<?> clazz = null;
    8.75 -        {
    8.76 +        
    8.77 +        String processSections = cache.findGlobalProperty("processSections", null, "false"); // NOI18N
    8.78 +        if (!"false".equals(processSections)) { // NOI18N
    8.79              // Find and load manifest sections.
    8.80              for (Map.Entry<String,Attributes> entry : m.getManifest().getEntries().entrySet()) {
    8.81                  ManifestSection section = ManifestSection.create(entry.getKey(), entry.getValue(), m);
    8.82 @@ -161,8 +164,11 @@
    8.83                      mysections.add(section);
    8.84                  }
    8.85              }
    8.86 +            if (mysections != null) {
    8.87 +                cache.findGlobalProperty("processSections", "false", "true"); // NOI18N
    8.88 +            }
    8.89          }
    8.90 -        String installClass = m.getManifest().getMainAttributes().getValue("OpenIDE-Module-Install"); // NOI18N
    8.91 +        String installClass = cache.findProperty(m, "OpenIDE-Module-Install", false); // NOI18N
    8.92          if (installClass != null) {
    8.93              String installClassName;
    8.94              try {
    8.95 @@ -216,15 +222,14 @@
    8.96          }
    8.97          // For layer & help set, validate only that the base-locale resource
    8.98          // exists, not its contents or anything.
    8.99 -        String layerResource = m.getManifest().getMainAttributes().getValue("OpenIDE-Module-Layer"); // NOI18N
   8.100 -        String osgi = m.getManifest().getMainAttributes().getValue("Bundle-SymbolicName"); // NOI18N
   8.101 -        if (layerResource != null && osgi == null) {
   8.102 +        String layerResource = cache.findProperty(m, "OpenIDE-Module-Layer", false); // NOI18N
   8.103 +        if (layerResource != null && !m.isNetigso()) {
   8.104              URL layer = m.getClassLoader().getResource(layerResource);
   8.105              if (layer == null) throw new InvalidException(m, "Layer not found: " + layerResource); // NOI18N
   8.106          }
   8.107 -        String helpSetName = m.getManifest().getMainAttributes().getValue("OpenIDE-Module-Description"); // NOI18N
   8.108 +        String helpSetName = cache.findProperty(m, "OpenIDE-Module-Description", false); // NOI18N
   8.109          if (helpSetName != null) {
   8.110 -            Util.err.warning("Use of OpenIDE-Module-Description in " + m.getCodeNameBase() + " is deprecated.");
   8.111 +            Util.err.log(Level.WARNING, "Use of OpenIDE-Module-Description in {0} is deprecated.", m.getCodeNameBase());
   8.112              Util.err.warning("(Please install help using an XML layer instead.)");
   8.113          }
   8.114          // We are OK, commit everything to our cache.
   8.115 @@ -236,7 +241,7 @@
   8.116          }
   8.117          if (layerResource != null) {
   8.118              layers.put(m, layerResource);
   8.119 -        }
   8.120 +        }   
   8.121      }
   8.122  
   8.123      private void checkForHiddenPackages(Module m) throws InvalidException {
   8.124 @@ -251,7 +256,7 @@
   8.125              }
   8.126          }
   8.127          for (Module _m : mWithDeps) {
   8.128 -            String hidden = (String) _m.getAttribute("OpenIDE-Module-Hide-Classpath-Packages"); // NOI18N
   8.129 +            String hidden = cache.findProperty(_m, "OpenIDE-Module-Hide-Classpath-Packages", false); // NOI18N
   8.130              if (hidden != null) {
   8.131                  for (String piece : hidden.trim().split("[ ,]+")) { // NOI18N
   8.132                      try {
   8.133 @@ -610,7 +615,8 @@
   8.134      private void checkForDeprecations(List<Module> modules) {
   8.135          Map<String,Set<String>> depToUsers = new TreeMap<String,Set<String>>();
   8.136          for (Module m : modules) {
   8.137 -            if (!Boolean.parseBoolean((String) m.getAttribute("OpenIDE-Module-Deprecated"))) { // NOI18N
   8.138 +            String depr = cache.findProperty(m, "OpenIDE-Module-Deprecated", false); // NOI18N
   8.139 +            if (!Boolean.parseBoolean(depr)) { 
   8.140                  for (Dependency dep : m.getDependencies()) {
   8.141                      if (dep.getType() == Dependency.TYPE_MODULE) {
   8.142                          String cnb = (String) Util.parseCodeName(dep.getName())[0];
   8.143 @@ -628,8 +634,9 @@
   8.144              String dep = entry.getKey();
   8.145              Module o = mgr.get(dep);
   8.146              assert o != null : "No such module: " + dep;
   8.147 -            if (Boolean.parseBoolean((String) o.getAttribute("OpenIDE-Module-Deprecated"))) { // NOI18N
   8.148 -                String message = (String) o.getLocalizedAttribute("OpenIDE-Module-Deprecation-Message"); // NOI18N
   8.149 +            String depr = cache.findProperty(o, "OpenIDE-Module-Deprecated", false); // NOI18N
   8.150 +            if (Boolean.parseBoolean(depr)) {
   8.151 +                String message = cache.findProperty(o, "OpenIDE-Module-Deprecation-Message", true); // NOI18N
   8.152                  // XXX use NbEvents? I18N?
   8.153                  // For now, assume this is a developer-oriented message that need not be localized or displayed in a pretty fashion.
   8.154                  Set<String> users = entry.getValue();
   8.155 @@ -1125,186 +1132,6 @@
   8.156          }
   8.157      }
   8.158      
   8.159 -    // Manifest caching: #26786.
   8.160 -
   8.161 -    private static final Logger MANIFEST_LOG = Logger.getLogger(NbInstaller.class.getName() + ".manifestCache");
   8.162 -
   8.163 -    /** While true, try to use the manifest cache.
   8.164 -     * So (non-reloadable) JARs scanned during startup will have their manifests cached.
   8.165 -     * After the primary set of modules has been scanned, this will be set to false.
   8.166 -     * Initially true, unless -J-Dnetbeans.cache.manifests=false is specified,
   8.167 -     * or there is no available cache directory.
   8.168 -     */
   8.169 -    private boolean usingManifestCache;
   8.170 -    private final Object MANIFEST_CACHE = new Object();
   8.171 -
   8.172 -    {
   8.173 -        usingManifestCache = Boolean.valueOf(System.getProperty("netbeans.cache.manifests", "true")).booleanValue();
   8.174 -        if (!usingManifestCache) {
   8.175 -            MANIFEST_LOG.fine("Manifest cache disabled");
   8.176 -        }
   8.177 -    }
   8.178 -    
   8.179 -    /** Cache of known JAR manifests.
   8.180 -     * Initially null. If the cache is read, it may be used to quickly serve JAR manifests.
   8.181 -     */
   8.182 -    private Map<File,DateAndManifest> manifestCache;
   8.183 -    private static final class DateAndManifest {
   8.184 -        /** modification date when last read */
   8.185 -        public final long date;
   8.186 -        public final Manifest manifest;
   8.187 -        public DateAndManifest(long date, Manifest manifest) {
   8.188 -            this.date = date;
   8.189 -            this.manifest = manifest;
   8.190 -        }
   8.191 -    }
   8.192 -    
   8.193 -    /** Overrides superclass method to keep a cache of module manifests,
   8.194 -     * so that their JARs do not have to be opened twice during startup.
   8.195 -     */
   8.196 -    public @Override Manifest loadManifest(File jar) throws IOException {
   8.197 -        if (!usingManifestCache) {
   8.198 -            return super.loadManifest(jar);
   8.199 -        }
   8.200 -        Map<File, DateAndManifest> cache;
   8.201 -        synchronized (MANIFEST_CACHE) {
   8.202 -            if (manifestCache == null) {
   8.203 -                manifestCache = Collections.synchronizedMap(loadManifestCache());
   8.204 -            }
   8.205 -            cache = manifestCache;
   8.206 -        }
   8.207 -        DateAndManifest entry = cache.get(jar);
   8.208 -        if (entry != null) {
   8.209 -            // Cache hit.
   8.210 -            MANIFEST_LOG.fine("Found manifest for " + jar + " in cache");
   8.211 -            return entry.manifest;
   8.212 -        } else {
   8.213 -            MANIFEST_LOG.fine("No entry for " + jar + " in manifest cache");
   8.214 -        }
   8.215 -        // Cache miss.
   8.216 -        Manifest m = super.loadManifest(jar);
   8.217 -        // (If that threw IOException, we leave it out of the cache.)
   8.218 -        cache.put(jar, new DateAndManifest(jar.lastModified(), m));
   8.219 -        saveManifestCache();
   8.220 -        return m;
   8.221 -    }
   8.222 -
   8.223 -    class CacheFlusher implements Stamps.Updater {
   8.224 -        public void flushCaches(DataOutputStream os) throws IOException {
   8.225 -            updater = new CacheFlusher();
   8.226 -            
   8.227 -            MANIFEST_LOG.fine("Saving manifest cache");
   8.228 -            HashMap<File, DateAndManifest> m;
   8.229 -            synchronized (MANIFEST_CACHE) {
   8.230 -                m = new HashMap<File, DateAndManifest>(manifestCache);
   8.231 -            }
   8.232 -            for (Map.Entry<File, DateAndManifest> entry : m.entrySet()) {
   8.233 -                File jar = entry.getKey();
   8.234 -                String[] relPath = RelPaths.findRelativePath(jar.getAbsolutePath());
   8.235 -                assert relPath != null : "Cannot find relative path for " + jar;
   8.236 -                os.writeUTF(relPath[0]);
   8.237 -                os.writeUTF(relPath[1]);
   8.238 -                long time = entry.getValue().date;
   8.239 -                for (int i = 7; i >= 0; i--) {
   8.240 -                    os.write((int) ((time >> (i * 8)) & 0xFF));
   8.241 -                }
   8.242 -                entry.getValue().manifest.write(os);
   8.243 -                os.write(0);
   8.244 -            }
   8.245 -            os.close();
   8.246 -            MANIFEST_LOG.fine("Saving manifest cache - done");
   8.247 -        }
   8.248 -
   8.249 -        public void cacheReady() {
   8.250 -        }
   8.251 -    }
   8.252 -    CacheFlusher updater = new CacheFlusher();
   8.253 -    
   8.254 -    /** Really save the cache.
   8.255 -     * @see #manifestCacheFile
   8.256 -     */
   8.257 -    private void saveManifestCache() throws IOException {
   8.258 -        MANIFEST_LOG.fine("Schedule saving manifest cache");
   8.259 -        Stamps.getModulesJARs().scheduleSave(updater, "all-manifest.dat", false);
   8.260 -    }
   8.261 -    
   8.262 -    /** Load the cache if present.
   8.263 -     * If not present, or there are problems with it,
   8.264 -     * just create an empty cache.
   8.265 -     * @see #manifestCacheFile
   8.266 -     */
   8.267 -    private Map<File,DateAndManifest> loadManifestCache() {
   8.268 -        ev.log(Events.PERF_START, "NbInstaller - loadManifestCache"); // NOI18N
   8.269 -        ByteBuffer bis = Stamps.getModulesJARs().asByteBuffer("all-manifest.dat");  // NOI18N
   8.270 -        Map<File,DateAndManifest> m = new HashMap<File,DateAndManifest>(200);
   8.271 -        try {
   8.272 -            readManifestCacheEntries(bis, m);
   8.273 -        } catch (IOException ex) {
   8.274 -            MANIFEST_LOG.log(Level.WARNING, "Cannot read cache", ex); // NOI18N
   8.275 -        } finally {
   8.276 -            ev.log(Events.PERF_END, "NbInstaller - loadManifestCache"); // NOI18N
   8.277 -        }
   8.278 -        return m;
   8.279 -    }
   8.280 -    
   8.281 -    private static int findNullByte(ByteBuffer data, int start) {
   8.282 -        int len = data.limit();
   8.283 -        for (int i = start; i < len; i++) {
   8.284 -            if (data.get(i) == 0) {
   8.285 -                return i;
   8.286 -            }
   8.287 -        }
   8.288 -        return -1;
   8.289 -    }
   8.290 -    
   8.291 -    private static void readManifestCacheEntries(ByteBuffer data, Map<File,DateAndManifest> m) throws IOException {
   8.292 -        if (data == null) {
   8.293 -            return;
   8.294 -        }
   8.295 -        
   8.296 -        int pos = 0;
   8.297 -        while (true) {
   8.298 -            if (pos == data.limit()) {
   8.299 -                return;
   8.300 -            }
   8.301 -            data.position(pos);
   8.302 -            File jar = new File(RelPaths.readRelativePath(data)); // NOI18N
   8.303 -            int end = data.position();
   8.304 -            long time = 0L;
   8.305 -            if (end + 8 >= data.limit()) throw new IOException("Ran out of space for timestamp for " + jar); // NOI18N
   8.306 -            for (int i = 0; i < 8; i++) {
   8.307 -                long b = data.get(end + i + 1);
   8.308 -                if (b < 0) b += 256;
   8.309 -                int exponent = 7 - i;
   8.310 -                long addin = b << (exponent * 8);
   8.311 -                time |= addin;
   8.312 -                //System.err.println("i=" + i + " b=0x" + Long.toHexString(b) + " exponent=" + exponent + " addin=0x" + Long.toHexString(addin) + " time=0x" + Long.toHexString(time));
   8.313 -            }
   8.314 -            pos = end + 9;
   8.315 -            end = findNullByte(data, pos);
   8.316 -            if (end == -1) throw new IOException("Could not find manifest body for " + jar); // NOI18N
   8.317 -            Manifest mani;
   8.318 -            try {
   8.319 -                mani = new Manifest(new ByteArrayInputStream(toArray(data, pos, end - pos)));
   8.320 -            } catch (IOException ioe) {
   8.321 -                Exceptions.attachMessage(ioe, "While in entry for " + jar);
   8.322 -                throw ioe;
   8.323 -            }
   8.324 -            m.put(jar, new DateAndManifest(time, mani));
   8.325 -            if (MANIFEST_LOG.isLoggable(Level.FINE)) {
   8.326 -                MANIFEST_LOG.fine("Manifest cache entry: jar=" + jar + " date=" + new Date(time) + " codename=" + mani.getMainAttributes().getValue("OpenIDE-Module"));
   8.327 -            }
   8.328 -            pos = end + 1;
   8.329 -        }
   8.330 -    }
   8.331 -    
   8.332 -    private static byte[] toArray(ByteBuffer bb, int pos, int len) {
   8.333 -        byte[] manarr = new byte[len];
   8.334 -        bb.position(pos);
   8.335 -        bb.get(manarr, 0, len);
   8.336 -        return manarr;
   8.337 -    }
   8.338 -    
   8.339      /** Check all module classes to make sure there are no unresolvable compile-time
   8.340       * dependencies. Turn on this mode with
   8.341       * <code>-J-Dnetbeans.preresolve.classes=true</code>
   8.342 @@ -1349,5 +1176,83 @@
   8.343              }
   8.344          }
   8.345      }
   8.346 +    
   8.347 +    final boolean isShowInAutoUpdateClient(ModuleInfo m) {
   8.348 +        String show = cache.findProperty(m, "AutoUpdate-Show-In-Client", false); // NOI18N
   8.349 +        if (show != null) {
   8.350 +            return Boolean.parseBoolean(show);
   8.351 +        }
   8.352 +        // OSGi bundles should be considered invisible by default since they are typically autoloads.
   8.353 +        // (NB modules get AutoUpdate-Show-In-Client inserted into the JAR by the build process.)
   8.354 +        if (m instanceof Module) {
   8.355 +            return !((Module)m).isNetigso();
   8.356 +        }
   8.357 +        return true;
   8.358 +    }
   8.359 +    
   8.360 +    /** Cache important attributes from module manifests */
   8.361 +    private static class Cache implements Stamps.Updater {
   8.362 +        private static final String CACHE = "all-installer.dat"; // NOI18N
   8.363 +        private final boolean modulePropertiesCached;
   8.364 +        private final Properties moduleProperties;
   8.365  
   8.366 +        public Cache() {
   8.367 +            InputStream is = Stamps.getModulesJARs().asStream(CACHE);
   8.368 +            IF:
   8.369 +            if (is != null) {
   8.370 +                Properties p = new Properties();
   8.371 +                try {
   8.372 +                    p.load(is);
   8.373 +                    is.close();
   8.374 +                } catch (IOException ex) {
   8.375 +                    LOG.log(Level.INFO, "Can't load all-installer.dat", ex);
   8.376 +                    break IF;
   8.377 +                }
   8.378 +                moduleProperties = p;
   8.379 +                modulePropertiesCached = true;
   8.380 +                return;
   8.381 +            }
   8.382 +            moduleProperties = new Properties();
   8.383 +            modulePropertiesCached = false;
   8.384 +        }
   8.385 +
   8.386 +        final String findProperty(ModuleInfo m, String name, boolean localized) {
   8.387 +            final String fullName = m.getCodeNameBase() + '.' + name;
   8.388 +            if (modulePropertiesCached) {
   8.389 +                return moduleProperties.getProperty(fullName);
   8.390 +            } else {
   8.391 +                Object p = localized ? m.getLocalizedAttribute(name) : m.getAttribute(name);
   8.392 +                String prop = p instanceof String ? (String)p : null;
   8.393 +                if (prop != null) {
   8.394 +                    moduleProperties.setProperty(fullName, prop);
   8.395 +                    Stamps.getModulesJARs().scheduleSave(this, CACHE, false);
   8.396 +                }
   8.397 +                return prop;
   8.398 +            }
   8.399 +        }
   8.400 +
   8.401 +        final String findGlobalProperty(String name, String expValue, String replaceValue) {
   8.402 +            assert name != null;
   8.403 +            assert replaceValue != null;
   8.404 +            if (modulePropertiesCached) {
   8.405 +                return moduleProperties.getProperty(name);
   8.406 +            } else {
   8.407 +                final Object prevValue = moduleProperties.get(name);
   8.408 +                if (Utilities.compareObjects(expValue, prevValue)) {
   8.409 +                    moduleProperties.put(name, replaceValue);
   8.410 +                }
   8.411 +                Stamps.getModulesJARs().scheduleSave(this, CACHE, false);
   8.412 +                return null;
   8.413 +            }
   8.414 +        }
   8.415 +
   8.416 +        @Override
   8.417 +        public void flushCaches(DataOutputStream os) throws IOException {
   8.418 +            moduleProperties.store(os, null);
   8.419 +        }
   8.420 +
   8.421 +        @Override
   8.422 +        public void cacheReady() {
   8.423 +        }
   8.424 +    } // end of Cache
   8.425  }
     9.1 --- a/core.startup/test/unit/src/org/netbeans/core/startup/layers/CachingPreventsFileTouchesTest.java	Thu Mar 15 16:10:40 2012 +0100
     9.2 +++ b/core.startup/test/unit/src/org/netbeans/core/startup/layers/CachingPreventsFileTouchesTest.java	Fri Mar 16 08:17:35 2012 +0100
     9.3 @@ -51,7 +51,9 @@
     9.4  import java.util.Collections;
     9.5  import java.util.HashSet;
     9.6  import java.util.Set;
     9.7 +import java.util.logging.Handler;
     9.8  import java.util.logging.Level;
     9.9 +import java.util.logging.LogRecord;
    9.10  import java.util.logging.Logger;
    9.11  import junit.framework.Test;
    9.12  import org.netbeans.junit.NbModuleSuite;
    9.13 @@ -61,6 +63,7 @@
    9.14  import org.openide.filesystems.FileUtil;
    9.15  import org.openide.filesystems.LocalFileSystem;
    9.16  import org.openide.modules.InstalledFileLocator;
    9.17 +import org.openide.modules.ModuleInfo;
    9.18  import org.openide.modules.Places;
    9.19  import org.openide.util.Lookup;
    9.20  
    9.21 @@ -69,7 +72,14 @@
    9.22   * see details on http://wiki.netbeans.org/FitnessViaWhiteAndBlackList
    9.23   */
    9.24  public class CachingPreventsFileTouchesTest extends NbTestCase {
    9.25 -    private static final Logger LOG = Logger.getLogger(CachingPreventsFileTouchesTest.class.getName());
    9.26 +    static {
    9.27 +        System.setProperty("java.util.logging.config.class", CaptureLog.class.getName());
    9.28 +    }
    9.29 +    private static final Logger LOG;
    9.30 +    static {
    9.31 +        LOG = Logger.getLogger(CachingPreventsFileTouchesTest.class.getName());
    9.32 +        CaptureLog.assertCalled();
    9.33 +    }
    9.34  
    9.35      private static void initCheckReadAccess() throws IOException {
    9.36          Set<String> allowedFiles = new HashSet<String>();
    9.37 @@ -82,7 +92,6 @@
    9.38      
    9.39      public static Test suite() throws IOException {
    9.40          CountingSecurityManager.initialize("none", CountingSecurityManager.Mode.CHECK_READ, null);
    9.41 -        System.setProperty("org.netbeans.Stamps.level", "ALL");
    9.42  
    9.43          NbTestSuite suite = new NbTestSuite();
    9.44          {
    9.45 @@ -106,6 +115,7 @@
    9.46          }
    9.47          
    9.48          suite.addTest(new CachingPreventsFileTouchesTest("testCachesDontUseAbsolutePaths"));
    9.49 +        suite.addTest(new CachingPreventsFileTouchesTest("testDontLoadManifests"));
    9.50          
    9.51          return suite;
    9.52      }
    9.53 @@ -118,14 +128,19 @@
    9.54              LOG.log(Level.FINE, "Can't pre-load JavaHelp", ex);
    9.55          }
    9.56          FileObject fo = FileUtil.getConfigFile("Services/Browsers");
    9.57 -        fo.delete();
    9.58 -        // initializes counting, but waits till netbeans.dirs are provided
    9.59 -        // by NbModuleSuite
    9.60 +        if (fo != null) {
    9.61 +            fo.delete();
    9.62 +        }
    9.63 +        assertEnabled("org.netbeans.core.windows");
    9.64 +        System.setProperty("counting.off", "true");
    9.65          initCheckReadAccess();
    9.66      }
    9.67  
    9.68 -    public void testInMiddle() {
    9.69 -        LOG.info("First run finished, starting another one");
    9.70 +    public void testInMiddle() throws IOException {
    9.71 +        String p = System.getProperty("manifestParsing");
    9.72 +        assertNotNull("Parsing of manifests during first run is natural", p);
    9.73 +        System.getProperties().remove("manifestParsing");
    9.74 +        System.setProperty("counting.off", "false");
    9.75      }
    9.76  
    9.77      public void testReadAccess() throws Exception {
    9.78 @@ -145,6 +160,7 @@
    9.79              e.printStackTrace(getLog("file-reads-report.txt"));
    9.80              throw e;
    9.81          }
    9.82 +        assertEnabled("org.netbeans.core.windows");
    9.83      }
    9.84      
    9.85      public void testRememberCacheDir() {
    9.86 @@ -177,6 +193,13 @@
    9.87          }
    9.88          assertTrue("Some cache files found", cnt > 4);
    9.89      }
    9.90 +    
    9.91 +    public void testDontLoadManifests() {
    9.92 +        String p = System.getProperty("manifestParsing");
    9.93 +        if (p != null) {
    9.94 +            fail("No manifest parsing should happen:\n" + p);
    9.95 +        }
    9.96 +    }
    9.97  
    9.98      private static void assertFileDoesNotContain(File file, String text) throws IOException, PropertyVetoException {
    9.99          LocalFileSystem lfs = new LocalFileSystem();
   9.100 @@ -188,4 +211,53 @@
   9.101              fail("File " + file + " seems to contain '" + text + "'!");
   9.102          }
   9.103      }
   9.104 +
   9.105 +    private static void assertEnabled(String cnb) {
   9.106 +        for (ModuleInfo mi : Lookup.getDefault().lookupAll(ModuleInfo.class)) {
   9.107 +            if (mi.getCodeNameBase().equals(cnb)) {
   9.108 +                assertTrue("Is enabled", mi.isEnabled());
   9.109 +                return;
   9.110 +            }
   9.111 +        }
   9.112 +        fail("Not found " + cnb);
   9.113 +    }
   9.114 +    
   9.115 +    public static final class CaptureLog extends Handler {
   9.116 +        private static Logger watchOver = Logger.getLogger("org.netbeans.core.modules");
   9.117 +        private static void assertCalled() {
   9.118 +            assertEquals("OK", System.getProperty("CaptureLog"));
   9.119 +        }
   9.120 +
   9.121 +        public CaptureLog() {
   9.122 +            System.setProperty("CaptureLog", "OK");
   9.123 +            close();
   9.124 +        }
   9.125 +        
   9.126 +        @Override
   9.127 +        public void publish(LogRecord record) {
   9.128 +            final String m = record.getMessage();
   9.129 +            if (m != null && m.contains("loading manifest")) {
   9.130 +                String prev = System.getProperty("manifestParsing");
   9.131 +                if (prev == null) {
   9.132 +                    prev = m;
   9.133 +                } else {
   9.134 +                    prev = prev + "\n" + m;
   9.135 +                }
   9.136 +                System.setProperty("manifestParsing", prev);
   9.137 +            }
   9.138 +        }
   9.139 +
   9.140 +        @Override
   9.141 +        public void flush() {
   9.142 +        }
   9.143 +
   9.144 +        @Override
   9.145 +        public void close() throws SecurityException {
   9.146 +            watchOver.addHandler(this);
   9.147 +            setLevel(Level.FINE);
   9.148 +            watchOver.setLevel(Level.FINE);
   9.149 +            
   9.150 +            Logger.getLogger("org.netbeans.Stamps").setLevel(Level.ALL);
   9.151 +        }
   9.152 +    }
   9.153  }
    10.1 --- a/core.startup/test/unit/src/org/netbeans/core/startup/layers/CountingSecurityManager.java	Thu Mar 15 16:10:40 2012 +0100
    10.2 +++ b/core.startup/test/unit/src/org/netbeans/core/startup/layers/CountingSecurityManager.java	Fri Mar 16 08:17:35 2012 +0100
    10.3 @@ -170,6 +170,11 @@
    10.4      @Override
    10.5      public void checkRead(String file) {
    10.6          if (mode == Mode.CHECK_READ && acceptFileRead(file)) {
    10.7 +            String off = System.getProperty("counting.off");
    10.8 +            if ("true".equals(off)) {
    10.9 +                return;
   10.10 +            }
   10.11 +            
   10.12              String dirs = System.getProperty("netbeans.dirs");
   10.13              if (dirs == null && !acceptAll) {
   10.14                  // not initialized yet
    11.1 --- a/dlight.remote/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
    11.2 +++ b/dlight.remote/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
    11.3 @@ -4,3 +4,4 @@
    11.4  OpenIDE-Module-Implementation-Version: 1
    11.5  OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/remote/resources/Bundle.properties
    11.6  OpenIDE-Module-Needs: org.netbeans.modules.dlight.remote.spi.RemoteProviderToken
    11.7 +OpenIDE-Module-Recommends: org.netbeans.modules.remotefs.versioning
    12.1 --- a/hudson.php/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
    12.2 +++ b/hudson.php/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
    12.3 @@ -3,3 +3,4 @@
    12.4  OpenIDE-Module-Layer: org/netbeans/modules/hudson/php/resources/layer.xml
    12.5  OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/hudson/php/resources/Bundle.properties
    12.6  OpenIDE-Module-Specification-Version: 1.1
    12.7 +OpenIDE-Module-Provides: org.netbeans.modules.hudson.php
    13.1 --- a/hudson.php/nbproject/project.properties	Thu Mar 15 16:10:40 2012 +0100
    13.2 +++ b/hudson.php/nbproject/project.properties	Fri Mar 16 08:17:35 2012 +0100
    13.3 @@ -1,4 +1,4 @@
    13.4 -is.eager=true
    13.5 +is.autoload=true
    13.6  javac.source=1.6
    13.7  javac.compilerargs=-Xlint -Xlint:-serial
    13.8  release.external/config-4f37f781e487dc957ff09359d8a5cb51e6588ff9.xml=hudson/config.xml
    14.1 --- a/ide.ergonomics/nbproject/project.properties	Thu Mar 15 16:10:40 2012 +0100
    14.2 +++ b/ide.ergonomics/nbproject/project.properties	Fri Mar 16 08:17:35 2012 +0100
    14.3 @@ -8,7 +8,8 @@
    14.4  src-ant.cp=${ant.core.lib}
    14.5  
    14.6  test.config.commit.includes=\
    14.7 -    org/netbeans/modules/ide/ergonomics/DynamicVerifyTest.class
    14.8 +    org/netbeans/modules/ide/ergonomics/DynamicVerifyTest.class,\
    14.9 +    org/netbeans/modules/ide/ergonomics/CachingPreventsLoadingOfModuleManifestsTest.class
   14.10  
   14.11  test.config.stableBTD.includes=**/*Test.class
   14.12  test.config.stableBTD.excludes=\
    15.1 --- a/ide.ergonomics/nbproject/project.xml	Thu Mar 15 16:10:40 2012 +0100
    15.2 +++ b/ide.ergonomics/nbproject/project.xml	Fri Mar 16 08:17:35 2012 +0100
    15.3 @@ -38,7 +38,7 @@
    15.4                      <compile-dependency/>
    15.5                      <run-dependency>
    15.6                          <release-version>1</release-version>
    15.7 -                        <specification-version>1.30</specification-version>
    15.8 +                        <specification-version>1.38</specification-version>
    15.9                      </run-dependency>
   15.10                  </dependency>
   15.11                  <dependency>
    16.1 --- a/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FeatureManager.java	Thu Mar 15 16:10:40 2012 +0100
    16.2 +++ b/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FeatureManager.java	Fri Mar 16 08:17:35 2012 +0100
    16.3 @@ -62,6 +62,8 @@
    16.4  import javax.swing.event.ChangeListener;
    16.5  import org.netbeans.Module;
    16.6  import org.netbeans.api.project.Project;
    16.7 +import org.netbeans.core.startup.Main;
    16.8 +import org.netbeans.core.startup.ModuleSystem;
    16.9  import org.openide.filesystems.FileObject;
   16.10  import org.openide.filesystems.FileUtil;
   16.11  import org.openide.modules.Dependency;
   16.12 @@ -122,8 +124,7 @@
   16.13      }
   16.14  
   16.15      static boolean showInAU(ModuleInfo mi) {
   16.16 -        final Object show = mi.getAttribute("AutoUpdate-Show-In-Client"); // NOI18N
   16.17 -        return show == null || "true".equals(show); // NOI18N
   16.18 +        return Main.getModuleSystem().isShowInAutoUpdateClient(mi);
   16.19      }
   16.20  
   16.21  
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/ide.ergonomics/test/unit/src/org/netbeans/modules/ide/ergonomics/CachingPreventsLoadingOfModuleManifestsTest.java	Fri Mar 16 08:17:35 2012 +0100
    17.3 @@ -0,0 +1,249 @@
    17.4 +/*
    17.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    17.6 + *
    17.7 + * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
    17.8 + *
    17.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   17.10 + * Other names may be trademarks of their respective owners.
   17.11 + *
   17.12 + * The contents of this file are subject to the terms of either the GNU
   17.13 + * General Public License Version 2 only ("GPL") or the Common
   17.14 + * Development and Distribution License("CDDL") (collectively, the
   17.15 + * "License"). You may not use this file except in compliance with the
   17.16 + * License. You can obtain a copy of the License at
   17.17 + * http://www.netbeans.org/cddl-gplv2.html
   17.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   17.19 + * specific language governing permissions and limitations under the
   17.20 + * License.  When distributing the software, include this License Header
   17.21 + * Notice in each file and include the License file at
   17.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   17.23 + * particular file as subject to the "Classpath" exception as provided
   17.24 + * by Oracle in the GPL Version 2 section of the License file that
   17.25 + * accompanied this code. If applicable, add the following below the
   17.26 + * License Header, with the fields enclosed by brackets [] replaced by
   17.27 + * your own identifying information:
   17.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   17.29 + *
   17.30 + * Contributor(s):
   17.31 + *
   17.32 + * The Original Software is NetBeans. The Initial Developer of the Original
   17.33 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
   17.34 + * Microsystems, Inc. All Rights Reserved.
   17.35 + *
   17.36 + * If you wish your version of this file to be governed by only the CDDL
   17.37 + * or only the GPL Version 2, indicate your decision by adding
   17.38 + * "[Contributor] elects to include this software in this distribution
   17.39 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   17.40 + * single choice of license, a recipient has the option to distribute
   17.41 + * your version of this file under either the CDDL, the GPL Version 2 or
   17.42 + * to extend the choice of license to its licensees as provided above.
   17.43 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   17.44 + * Version 2 license, then the option applies only if the new code is
   17.45 + * made subject to such option by the copyright holder.
   17.46 + */
   17.47 +
   17.48 +package org.netbeans.modules.ide.ergonomics;
   17.49 +
   17.50 +import java.io.File;
   17.51 +import java.io.IOException;
   17.52 +import java.io.PrintWriter;
   17.53 +import java.io.StringWriter;
   17.54 +import java.util.Arrays;
   17.55 +import java.util.logging.Handler;
   17.56 +import java.util.logging.Level;
   17.57 +import java.util.logging.LogRecord;
   17.58 +import java.util.logging.Logger;
   17.59 +import junit.framework.Test;
   17.60 +import org.netbeans.junit.NbModuleSuite;
   17.61 +import org.netbeans.junit.NbTestCase;
   17.62 +import org.netbeans.junit.NbTestSuite;
   17.63 +import org.openide.filesystems.FileObject;
   17.64 +import org.openide.filesystems.FileUtil;
   17.65 +import org.openide.modules.ModuleInfo;
   17.66 +import org.openide.util.Lookup;
   17.67 +
   17.68 +/**
   17.69 + * Verifies that modules outside of platform,ide,nb and ergonomics clusters
   17.70 + * are not initialized - e.g. their manifests are not parsed. This is done
   17.71 + * by a "logging" contract from ModuleManager caches. As soon as module
   17.72 + * manifest is loaded, the test verifies that the file is in one of 
   17.73 + * allowed clusters.
   17.74 + */
   17.75 +public class CachingPreventsLoadingOfModuleManifestsTest extends NbTestCase {
   17.76 +    static {
   17.77 +        System.setProperty("java.util.logging.config.class", CaptureLog.class.getName());
   17.78 +    }
   17.79 +    private static final Logger LOG;
   17.80 +    static {
   17.81 +        LOG = Logger.getLogger(CachingPreventsLoadingOfModuleManifestsTest.class.getName());
   17.82 +        CaptureLog.assertCalled();
   17.83 +    }
   17.84 +
   17.85 +    public CachingPreventsLoadingOfModuleManifestsTest(String name) {
   17.86 +        super(name);
   17.87 +    }
   17.88 +    
   17.89 +    public static Test suite() throws IOException {
   17.90 +        NbModuleSuite.Configuration base = NbModuleSuite.createConfiguration(
   17.91 +                CachingPreventsLoadingOfModuleManifestsTest.class
   17.92 +            ).
   17.93 +            gui(false).
   17.94 +            clusters("ergonomics.*").
   17.95 +            clusters(".*").
   17.96 +            enableModules("ide[0-9]*", ".*").
   17.97 +            enableClasspathModules(false).
   17.98 +            honorAutoloadEager(true);
   17.99 +        
  17.100 +        System.setProperty("counting.off", "false");
  17.101 +        System.setProperty("no.stacks", "true");
  17.102 +        NbTestSuite suite = new NbTestSuite();
  17.103 +        suite.addTest(base.reuseUserDir(false).addTest("testInitUserDir").suite());
  17.104 +
  17.105 +        suite.addTest(new CachingPreventsLoadingOfModuleManifestsTest("testInMiddle"));
  17.106 +
  17.107 +        suite.addTest(
  17.108 +            base.reuseUserDir(true).addTest("testEnabledWindows").suite()
  17.109 +        );
  17.110 +        suite.addTest(new CachingPreventsLoadingOfModuleManifestsTest("testDontLoadManifests"));
  17.111 +        
  17.112 +        return suite;
  17.113 +    }
  17.114 +
  17.115 +    public void testInitUserDir() throws Exception {
  17.116 +        ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
  17.117 +        try {
  17.118 +            Class<?> c = Class.forName("javax.help.HelpSet", true, l);
  17.119 +        } catch (ClassNotFoundException ex) {
  17.120 +            LOG.log(Level.FINE, "Can't pre-load JavaHelp", ex);
  17.121 +        }
  17.122 +        FileObject fo = FileUtil.getConfigFile("Services/Browsers");
  17.123 +        if (fo != null) {
  17.124 +            fo.delete();
  17.125 +        }
  17.126 +        assertEnabled("org.netbeans.core.windows");
  17.127 +        System.setProperty("counting.off", "true");
  17.128 +    }
  17.129 +
  17.130 +    public void testInMiddle() throws IOException {
  17.131 +        String p = System.getProperty("manifestParsing");
  17.132 +        assertNotNull("Parsing of manifests during first run is natural", p);
  17.133 +        System.getProperties().remove("manifestParsing");
  17.134 +        System.setProperty("no.stacks", "false");
  17.135 +        System.setProperty("counting.off", "false");
  17.136 +    }
  17.137 +
  17.138 +    public void testEnabledWindows() throws Exception {
  17.139 +        assertEnabled("org.netbeans.core.windows");
  17.140 +    }
  17.141 +    
  17.142 +    public void testDontLoadManifests() {
  17.143 +        String p = System.getProperty("manifestParsing");
  17.144 +        if (p != null) {
  17.145 +            fail("No manifest parsing should happen:\n" + p);
  17.146 +        }
  17.147 +    }
  17.148 +
  17.149 +    private static void assertEnabled(String cnb) {
  17.150 +        for (ModuleInfo mi : Lookup.getDefault().lookupAll(ModuleInfo.class)) {
  17.151 +            if (mi.getCodeNameBase().equals(cnb)) {
  17.152 +                assertTrue("Is enabled", mi.isEnabled());
  17.153 +                return;
  17.154 +            }
  17.155 +        }
  17.156 +        fail("Not found " + cnb);
  17.157 +    }
  17.158 +    
  17.159 +    public static final class CaptureLog extends Handler {
  17.160 +        private static Logger watchOver = Logger.getLogger("org.netbeans.core.modules");
  17.161 +        private static void assertCalled() {
  17.162 +            assertEquals("OK", System.getProperty("CaptureLog"));
  17.163 +        }
  17.164 +
  17.165 +        public CaptureLog() {
  17.166 +            System.setProperty("CaptureLog", "OK");
  17.167 +            close();
  17.168 +        }
  17.169 +        
  17.170 +        @Override
  17.171 +        public void publish(LogRecord record) {
  17.172 +            if (Boolean.getBoolean("counting.off")) {
  17.173 +                return;
  17.174 +            }
  17.175 +            final String m = record.getMessage();
  17.176 +            if (m != null && m.startsWith("Initialize data")) {
  17.177 +                Object[] params = record.getParameters();
  17.178 +                assertNotNull("There are parameters", params);
  17.179 +                assertEquals("There is just one parameter: " + Arrays.toString(params), 1, params.length);
  17.180 +                if (params[0] == null) {
  17.181 +                    // fixed modules are OK
  17.182 +                    return;
  17.183 +                }
  17.184 +                if (isPlatformOrIde((File)params[0])) {
  17.185 +                    return;
  17.186 +                }
  17.187 +                
  17.188 +                String prev = System.getProperty("manifestParsing");
  17.189 +                StringWriter sw = new StringWriter();
  17.190 +                PrintWriter pw = new PrintWriter(sw);
  17.191 +                if (prev != null) {
  17.192 +                    pw.append(prev).append("\n");
  17.193 +                }
  17.194 +                final String msg = m + ": " + params[0];
  17.195 +                if (Boolean.getBoolean("no.stacks")) {
  17.196 +                    pw.print(msg);
  17.197 +                } else { 
  17.198 +                    new Exception(msg).printStackTrace(pw);
  17.199 +                }
  17.200 +                pw.flush();
  17.201 +                System.setProperty("manifestParsing", sw.toString());
  17.202 +            }
  17.203 +        }
  17.204 +
  17.205 +        @Override
  17.206 +        public void flush() {
  17.207 +        }
  17.208 +
  17.209 +        @Override
  17.210 +        public void close() throws SecurityException {
  17.211 +            watchOver.addHandler(this);
  17.212 +            setLevel(Level.FINE);
  17.213 +            watchOver.setLevel(Level.FINE);
  17.214 +            
  17.215 +            Logger.getLogger("org.netbeans.core.modules").setLevel(Level.ALL);
  17.216 +        }
  17.217 +
  17.218 +        private boolean isPlatformOrIde(File file) {
  17.219 +            String path = file.getPath();
  17.220 +            final String platform = System.getProperty("netbeans.home");
  17.221 +            if (platform != null && path.startsWith(platform)) {
  17.222 +                return true;
  17.223 +            }
  17.224 +            final String dirs = System.getProperty("netbeans.dirs");
  17.225 +            if (dirs != null) {
  17.226 +                for (String s : dirs.split(File.pathSeparator)) {
  17.227 +                    if (s.endsWith(File.separator + "ide")) {
  17.228 +                        if (path.startsWith(s)) {
  17.229 +                            return true;
  17.230 +                        }
  17.231 +                    }
  17.232 +                    if (s.endsWith(File.separator + "ergonomics")) {
  17.233 +                        if (path.startsWith(s)) {
  17.234 +                            return true;
  17.235 +                        }
  17.236 +                    }
  17.237 +                    if (s.endsWith(File.separator + "nb")) {
  17.238 +                        if (path.startsWith(s)) {
  17.239 +                            return true;
  17.240 +                        }
  17.241 +                    }
  17.242 +                    if (s.endsWith(File.separator + "webcommon")) {
  17.243 +                        if (path.startsWith(s)) {
  17.244 +                            return true;
  17.245 +                        }
  17.246 +                    }
  17.247 +                }
  17.248 +            }
  17.249 +            return false;
  17.250 +        }
  17.251 +    }
  17.252 +}
    18.1 --- a/netbinox/test/unit/src/org/netbeans/modules/netbinox/CachingPreventsFileTouchesTest.java	Thu Mar 15 16:10:40 2012 +0100
    18.2 +++ b/netbinox/test/unit/src/org/netbeans/modules/netbinox/CachingPreventsFileTouchesTest.java	Fri Mar 16 08:17:35 2012 +0100
    18.3 @@ -89,7 +89,7 @@
    18.4          NbTestSuite suite = new NbTestSuite();
    18.5          Compile compile = new Compile("testCompile");
    18.6          suite.addTest(compile);
    18.7 -        NbModuleSuite.Configuration common = NbModuleSuite.emptyConfiguration().clusters(".*").enableClasspathModules(false)
    18.8 +        NbModuleSuite.Configuration common = NbModuleSuite.emptyConfiguration().clusters("(?!ergonomics).*").enableClasspathModules(false)
    18.9                  .gui(false).honorAutoloadEager(true);
   18.10          {
   18.11              NbModuleSuite.Configuration conf = common.reuseUserDir(false).addTest(CachingPreventsFileTouchesTest.class, "testInitUserDir");
   18.12 @@ -175,6 +175,13 @@
   18.13  
   18.14      public void testStartAgain() throws Exception {
   18.15          CachingAndExternalPathsTest.doNecessarySetup();
   18.16 +        final String dirs = System.getProperty("netbeans.dirs");
   18.17 +        for (String s : dirs.split(File.pathSeparator)) {
   18.18 +            if (s.endsWith("ergonomics")) {
   18.19 +                fail("There should be no ergonomics cluster in netbeans.dirs: " + dirs);
   18.20 +            }
   18.21 +        }
   18.22 +        
   18.23          // will be reset next time the system starts
   18.24          System.getProperties().remove("netbeans.dirs");
   18.25          // initializes counting, but waits till netbeans.dirs are provided
    19.1 --- a/o.n.bootstrap/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
    19.2 +++ b/o.n.bootstrap/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
    19.3 @@ -1,6 +1,6 @@
    19.4  Manifest-Version: 1.0
    19.5  OpenIDE-Module: org.netbeans.bootstrap/1
    19.6 -OpenIDE-Module-Specification-Version: 2.50
    19.7 +OpenIDE-Module-Specification-Version: 2.51
    19.8  OpenIDE-Module-Localizing-Bundle: org/netbeans/Bundle.properties
    19.9  OpenIDE-Module-Recommends: org.netbeans.NetigsoFramework
   19.10  
    20.1 --- a/o.n.bootstrap/src/org/netbeans/JarClassLoader.java	Thu Mar 15 16:10:40 2012 +0100
    20.2 +++ b/o.n.bootstrap/src/org/netbeans/JarClassLoader.java	Fri Mar 16 08:17:35 2012 +0100
    20.3 @@ -82,7 +82,6 @@
    20.4  import java.util.concurrent.Future;
    20.5  import java.util.concurrent.FutureTask;
    20.6  import java.util.jar.Attributes;
    20.7 -import java.util.jar.Attributes.Name;
    20.8  import java.util.jar.JarEntry;
    20.9  import java.util.jar.JarFile;
   20.10  import java.util.jar.Manifest;
   20.11 @@ -104,6 +103,7 @@
   20.12      static void initializeCache() {
   20.13          cache = Stamps.getModulesJARs();
   20.14          archive = new Archive(cache);
   20.15 +        PackageAttrsCache.initialize();
   20.16      }
   20.17      
   20.18      /**
   20.19 @@ -186,36 +186,18 @@
   20.20      
   20.21      
   20.22      protected Package definePackage(String name, Manifest man, URL url)
   20.23 -	throws IllegalArgumentException
   20.24 -    {
   20.25 -        if (man == null ) {
   20.26 +    throws IllegalArgumentException {
   20.27 +        if (man == null) {
   20.28              return definePackage(name, null, null, null, null, null, null, null);
   20.29          }
   20.30 -        
   20.31 -	String path = name.replace('.', '/').concat("/"); // NOI18N
   20.32 -	Attributes spec = man.getAttributes(path);
   20.33 -        Attributes main = man.getMainAttributes();
   20.34 -	
   20.35 -        String specTitle = getAttr(spec, main, Name.SPECIFICATION_TITLE);
   20.36 -        String implTitle = getAttr(spec, main, Name.IMPLEMENTATION_TITLE);
   20.37 -        String specVersion = getAttr(spec, main, Name.SPECIFICATION_VERSION);
   20.38 -        String implVersion = getAttr(spec, main, Name.IMPLEMENTATION_VERSION);
   20.39 -        String specVendor = getAttr(spec, main, Name.SPECIFICATION_VENDOR);
   20.40 -        String implVendor = getAttr(spec, main, Name.IMPLEMENTATION_VENDOR);
   20.41 -        String sealed      = getAttr(spec, main, Name.SEALED);
   20.42  
   20.43 -        URL sealBase = "true".equalsIgnoreCase(sealed) ? url : null; // NOI18N
   20.44 -	return definePackage(name, specTitle, specVersion, specVendor,
   20.45 -			     implTitle, implVersion, implVendor, sealBase);
   20.46 +        String path = name.replace('.', '/').concat("/"); // NOI18N
   20.47 +        String[] arr = PackageAttrsCache.findPackageAttrs(url, man, path);
   20.48 +        URL sealBase = "true".equalsIgnoreCase(arr[6]) ? url : null; // NOI18N
   20.49 +        return definePackage(name, arr[0], arr[1], arr[2],
   20.50 +            arr[3], arr[4], arr[5], sealBase);
   20.51      }
   20.52 -
   20.53 -    private static String getAttr(Attributes spec, Attributes main, Name name) {
   20.54 -        String val = null;
   20.55 -        if (spec != null) val = spec.getValue (name);
   20.56 -        if (val == null && main != null) val = main.getValue (name);
   20.57 -        return val;
   20.58 -    }
   20.59 -
   20.60 +    
   20.61      private Boolean patchingBytecode;
   20.62      @Override
   20.63      protected Class doLoadClass(String pkgName, String name) {
   20.64 @@ -223,7 +205,7 @@
   20.65          
   20.66          // look up the Sources and return a class based on their content
   20.67          for( int i=0; i<sources.length; i++ ) {
   20.68 -            Source src = sources[i];
   20.69 +            final Source src = sources[i];
   20.70              byte[] data = src.getClassData(path);
   20.71              if (data == null) continue;
   20.72  
   20.73 @@ -254,7 +236,32 @@
   20.74                  // XXX full sealing check, URLClassLoader does something more
   20.75                  if (pkg.isSealed() && !pkg.isSealed(src.getURL())) throw new SecurityException("sealing violation"); // NOI18N
   20.76              } else {
   20.77 -                Manifest man = module == null || src != sources[0] ? src.getManifest() : module.getManifest();
   20.78 +                class DelayedManifest extends Manifest {
   20.79 +                    private Manifest delegate;
   20.80 +                    
   20.81 +                    private Manifest delegate() {
   20.82 +                        if (delegate == null) {
   20.83 +                            delegate = module == null || src != sources[0] ? src.getManifest() : module.getManifest();
   20.84 +                        }
   20.85 +                        return delegate;
   20.86 +                    }
   20.87 +                    
   20.88 +                    @Override
   20.89 +                    public Attributes getMainAttributes() {
   20.90 +                        return delegate().getMainAttributes();
   20.91 +                    }
   20.92 +
   20.93 +                    @Override
   20.94 +                    public Attributes getAttributes(String name) {
   20.95 +                        return delegate().getAttributes(name);
   20.96 +                    }
   20.97 +
   20.98 +                    @Override
   20.99 +                    public Map<String, Attributes> getEntries() {
  20.100 +                        return delegate().getEntries();
  20.101 +                    }
  20.102 +                }
  20.103 +                Manifest man = new DelayedManifest();
  20.104                  try {
  20.105                      definePackage(pkgName, man, src.getURL());
  20.106                  } catch (IllegalArgumentException x) {
  20.107 @@ -863,13 +870,21 @@
  20.108      }
  20.109      
  20.110      private static Iterable<String> getCoveredPackages(Module mod, Source[] sources) {
  20.111 +        if (mod != null) {
  20.112 +            Set<String> ret = mod.getCoveredPackages();
  20.113 +            if (ret != null) {
  20.114 +                return ret;
  20.115 +            }
  20.116 +        }
  20.117 +        
  20.118          Set<String> known = new HashSet<String>();
  20.119          Manifest m = mod == null ? null : mod.getManifest();
  20.120          if (m != null) {
  20.121              Attributes attr = m.getMainAttributes();
  20.122 -            String pack = attr.getValue("Covered-Packages");
  20.123 +            String pack = attr.getValue("Covered-Packages"); // NOI18N
  20.124              if (pack != null) {
  20.125                  known.addAll(Arrays.asList(pack.split(",", -1)));
  20.126 +                mod.registerCoveredPackages(known);
  20.127                  return known;
  20.128              }
  20.129          }
  20.130 @@ -879,9 +894,8 @@
  20.131          for (Source s : sources) s.listCoveredPackages(known, save);
  20.132  
  20.133          if (save.length() > 0) save.setLength(save.length()-1);
  20.134 -        if (m != null) {
  20.135 -            Attributes attr = m.getMainAttributes();
  20.136 -            attr.putValue("Covered-Packages", save.toString());
  20.137 +        if (mod != null) {
  20.138 +            mod.registerCoveredPackages(known);
  20.139          }
  20.140          return known;
  20.141      }
    21.1 --- a/o.n.bootstrap/src/org/netbeans/Module.java	Thu Mar 15 16:10:40 2012 +0100
    21.2 +++ b/o.n.bootstrap/src/org/netbeans/Module.java	Fri Mar 16 08:17:35 2012 +0100
    21.3 @@ -44,14 +44,18 @@
    21.4  
    21.5  package org.netbeans;
    21.6  
    21.7 +import java.io.DataInput;
    21.8 +import java.io.DataOutput;
    21.9  import java.io.File;
   21.10  import java.io.IOException;
   21.11  import java.io.InputStream;
   21.12 +import java.io.ObjectInput;
   21.13 +import java.io.ObjectInputStream;
   21.14 +import java.io.ObjectOutput;
   21.15  import java.lang.reflect.Method;
   21.16  import java.net.URL;
   21.17  import java.security.CodeSource;
   21.18  import java.util.*;
   21.19 -import java.util.jar.Attributes;
   21.20  import java.util.jar.Manifest;
   21.21  import java.util.logging.Level;
   21.22  import java.util.logging.Logger;
   21.23 @@ -60,7 +64,6 @@
   21.24  import org.openide.modules.SpecificationVersion;
   21.25  import org.openide.util.Enumerations;
   21.26  import org.openide.util.Exceptions;
   21.27 -import org.openide.util.NbBundle;
   21.28  import org.openide.util.Union2;
   21.29  
   21.30  /** Object representing one module, possibly installed.
   21.31 @@ -96,28 +99,13 @@
   21.32      protected boolean reloadable;
   21.33      /** if true, this module is eagerly turned on whenever it can be */
   21.34      private final boolean eager;
   21.35 -    /** code name base (no slash) */
   21.36 -    private String codeNameBase;
   21.37 -    /** code name release, or -1 if undefined */
   21.38 -    private int codeNameRelease;
   21.39 -    /** full code name */
   21.40 -    private String codeName;
   21.41 -    /** provided tokens */
   21.42 -    private String[] provides;
   21.43 -    /** set of dependencies parsed from manifest */
   21.44 -    private Dependency[] dependenciesA;
   21.45 -    /** specification version parsed from manifest, or null */
   21.46 -    private SpecificationVersion specVers;
   21.47      /** currently active module classloader */
   21.48 -    protected ClassLoader classloader = null;
   21.49 -    /** public packages, may be null */
   21.50 -    private PackageExport[] publicPackages;
   21.51 -    /** Set<String> of CNBs of friend modules or null */
   21.52 -    private Set/*<String>*/ friendNames;
   21.53 +    protected ClassLoader classloader;
   21.54  
   21.55 -    private final static PackageExport[] ZERO_PACKAGE_ARRAY = new PackageExport[0];
   21.56 -    private final static String[] ZERO_STRING_ARRAY = new String[0];
   21.57 +    private ModuleData data;
   21.58 +    
   21.59      private static Method findResources;
   21.60 +    private static final Object DATA_LOCK = new Object();
   21.61  
   21.62      /** Use ModuleManager.create as a factory. */
   21.63      protected Module(ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
   21.64 @@ -128,14 +116,14 @@
   21.65          this.reloadable = reloadable;
   21.66          this.autoload = autoload;
   21.67          this.eager = eager;
   21.68 -        enabled = false;
   21.69 +        this.enabled = false;
   21.70      }
   21.71      
   21.72      /** Create a special-purpose "fixed" JAR. */
   21.73      protected Module(ModuleManager mgr, Events ev, Object history, ClassLoader classloader) throws InvalidException {
   21.74          this(mgr, ev, history, classloader, false, false);
   21.75      }
   21.76 -
   21.77 +    
   21.78      /**
   21.79       * Create a special-purpose "fixed" JAR which may nonetheless be marked eager or autoload.
   21.80       * @since 2.7
   21.81 @@ -152,6 +140,63 @@
   21.82          enabled = false;
   21.83      }
   21.84      
   21.85 +    ModuleData createData(ObjectInput in, Manifest mf) throws IOException {
   21.86 +        if (in != null) {
   21.87 +            return new ModuleData(in);
   21.88 +        } else {
   21.89 +            return new ModuleData(mf, this);
   21.90 +        }
   21.91 +    }
   21.92 +    
   21.93 +    final void writeData(ObjectOutput out) throws IOException {
   21.94 +        data().write(out);
   21.95 +    }
   21.96 +    
   21.97 +    final ModuleData data() {
   21.98 +        try {
   21.99 +            return dataWithCheck();
  21.100 +        } catch (InvalidException ex) {
  21.101 +            throw new IllegalStateException(ex);
  21.102 +        }
  21.103 +    }
  21.104 +    
  21.105 +    final ModuleData dataWithCheck() throws InvalidException {
  21.106 +        synchronized (DATA_LOCK) {
  21.107 +            if (data != null) {
  21.108 +                return data;
  21.109 +            }
  21.110 +            Util.err.log(Level.FINE, "Initialize data {0}", getJarFile()); // NOI18N
  21.111 +            InputStream is = mgr.dataFor(getJarFile());
  21.112 +            if (is != null) {
  21.113 +                try {
  21.114 +                    ObjectInputStream ois = new ObjectInputStream(is);
  21.115 +                    ModuleData mine = createData(ois, null);
  21.116 +                    ois.close();
  21.117 +                    assert data == null;
  21.118 +                    data = mine;
  21.119 +                    return mine;
  21.120 +                } catch (IOException ex) {
  21.121 +                    Util.err.log(Level.INFO, "Cannot read cache for " + getJarFile(), ex); // NOI18N
  21.122 +                }
  21.123 +            }
  21.124 +            try {
  21.125 +                ModuleData mine = createData(null, getManifest());
  21.126 +                assert mine == data;
  21.127 +                return mine;
  21.128 +            } catch (InvalidException ex) {
  21.129 +                throw ex;
  21.130 +            } catch (IOException ex) {
  21.131 +                // no I/O needed when reading from manifest
  21.132 +                throw new IllegalStateException(ex);
  21.133 +            }
  21.134 +        }
  21.135 +    }
  21.136 +    
  21.137 +    final void assignData(ModuleData data) {
  21.138 +        assert Thread.holdsLock(DATA_LOCK);
  21.139 +        this.data = data;
  21.140 +    }
  21.141 +    
  21.142      /** Get the associated module manager. */
  21.143      public ModuleManager getManager() {
  21.144          return mgr;
  21.145 @@ -215,26 +260,31 @@
  21.146      
  21.147      @Override
  21.148      public String getCodeName() {
  21.149 -        return codeName;
  21.150 +        return data().getCodeName();
  21.151      }
  21.152      
  21.153      @Override
  21.154      public String getCodeNameBase() {
  21.155 -        return codeNameBase;
  21.156 +        String cnb = mgr.cnbFor(getJarFile());
  21.157 +        if (cnb != null) {
  21.158 +            return cnb;
  21.159 +        }
  21.160 +        return data().getCodeNameBase();
  21.161      }
  21.162      
  21.163      @Override
  21.164      public int getCodeNameRelease() {
  21.165 -        return codeNameRelease;
  21.166 +        return data().getCodeNameRelease();
  21.167      }
  21.168      
  21.169      public @Override String[] getProvides() {
  21.170 -        return provides;
  21.171 +        return data().getProvides();
  21.172      }
  21.173      /** Test whether the module provides a given token or not. 
  21.174       * @since JST-PENDING again used from NbProblemDisplayer
  21.175       */
  21.176      public final boolean provides(String token) {
  21.177 +        String[] provides = getProvides();
  21.178          if (provides == null) {
  21.179              return false;
  21.180          }
  21.181 @@ -250,14 +300,32 @@
  21.182      public Set<Dependency> getDependencies() {
  21.183          return new HashSet<Dependency>(Arrays.asList(getDependenciesArray()));
  21.184      }
  21.185 -    public final Dependency[]  getDependenciesArray() {
  21.186 +    public final Dependency[] getDependenciesArray() {
  21.187 +        Dependency[] dependenciesA;
  21.188 +        try {
  21.189 +            dependenciesA = data().getDependencies();
  21.190 +        } catch (IllegalStateException ex) {
  21.191 +            dependenciesA = null;
  21.192 +        }
  21.193          return dependenciesA == null ? new Dependency[0] : dependenciesA;
  21.194      }
  21.195      
  21.196      @Override
  21.197      public SpecificationVersion getSpecificationVersion() {
  21.198 -        return specVers;
  21.199 +        return data().getSpecificationVersion();
  21.200      }
  21.201 +
  21.202 +    @Override
  21.203 +    public String getImplementationVersion() {
  21.204 +        return data.getImplementationVersion();
  21.205 +    }
  21.206 +
  21.207 +    @Override
  21.208 +    public String getBuildVersion() {
  21.209 +        return data.getBuildVersion();
  21.210 +    }
  21.211 +    
  21.212 +    
  21.213      
  21.214      public @Override boolean owns(Class<?> clazz) {
  21.215          ClassLoader cl = clazz.getClassLoader();
  21.216 @@ -269,7 +337,7 @@
  21.217          }
  21.218          String _codeName = findClasspathModuleCodeName(clazz);
  21.219          if (_codeName != null) {
  21.220 -            return _codeName.equals(codeName);
  21.221 +            return _codeName.equals(getCodeName());
  21.222          }
  21.223          return true; // not sure...
  21.224      }
  21.225 @@ -304,13 +372,14 @@
  21.226       * @see "#19621"
  21.227       */
  21.228      public PackageExport[] getPublicPackages() {
  21.229 -        return publicPackages;
  21.230 +        return data().getPublicPackages();
  21.231      }
  21.232      
  21.233      /** Checks whether we use friends attribute and if so, then
  21.234       * whether the name of module is listed there.
  21.235       */
  21.236      boolean isDeclaredAsFriend (Module module) {
  21.237 +        Set<String> friendNames = data().getFriendNames();
  21.238          if (friendNames == null) {
  21.239              return true;
  21.240          }
  21.241 @@ -323,151 +392,9 @@
  21.242       * some kind of description of the problem.
  21.243       */
  21.244      protected void parseManifest() throws InvalidException {
  21.245 -        Attributes attr = getManifest().getMainAttributes();
  21.246 -
  21.247 -        // Code name
  21.248 -        codeName = attr.getValue("OpenIDE-Module"); // NOI18N
  21.249 -        if (codeName == null) {
  21.250 -            InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */this, getManifest()); // NOI18N
  21.251 -            // #29393: plausible user mistake, deal with it politely.
  21.252 -            Exceptions.attachLocalizedMessage(e,
  21.253 -                                              NbBundle.getMessage(Module.class,
  21.254 -                                                                  "EXC_not_a_module",
  21.255 -                                                                  this.toString()));
  21.256 -            throw e;
  21.257 -        }
  21.258 -        try {
  21.259 -            // This has the side effect of checking syntax:
  21.260 -            if (codeName.indexOf(',') != -1) {
  21.261 -                throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); // NOI18N
  21.262 -            }
  21.263 -            Object[] cnParse = Util.parseCodeName(codeName);
  21.264 -            codeNameBase = (String)cnParse[0];
  21.265 -            Set<?> deps = mgr.loadDependencies(codeNameBase);
  21.266 -            boolean verifyCNBs = deps == null;
  21.267 -            if (verifyCNBs) {
  21.268 -                Dependency.create(Dependency.TYPE_MODULE, codeName);
  21.269 -            }
  21.270 -            codeNameRelease = (cnParse[1] != null) ? ((Integer)cnParse[1]).intValue() : -1;
  21.271 -            if (cnParse[2] != null) throw new NumberFormatException(codeName);
  21.272 -            // Spec vers
  21.273 -            String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N
  21.274 -            if (specVersS != null) {
  21.275 -                try {
  21.276 -                    specVers = new SpecificationVersion(specVersS);
  21.277 -                } catch (NumberFormatException nfe) {
  21.278 -                    throw (InvalidException)new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()).initCause(nfe); // NOI18N
  21.279 -                }
  21.280 -            } else {
  21.281 -                specVers = null;
  21.282 -            }
  21.283 -            computeProvides(attr, verifyCNBs);
  21.284 -            
  21.285 -            // Exports
  21.286 -            String exportsS = attr.getValue("OpenIDE-Module-Public-Packages"); // NOI18N
  21.287 -            if (exportsS != null) {
  21.288 -                if (exportsS.trim().equals("-")) { // NOI18N
  21.289 -                    publicPackages = ZERO_PACKAGE_ARRAY;
  21.290 -                } else {
  21.291 -                    StringTokenizer tok = new StringTokenizer(exportsS, ", "); // NOI18N
  21.292 -                    List<PackageExport> exports = new ArrayList<PackageExport>(Math.max(tok.countTokens(), 1));
  21.293 -                    while (tok.hasMoreTokens()) {
  21.294 -                        String piece = tok.nextToken();
  21.295 -                        if (piece.endsWith(".*")) { // NOI18N
  21.296 -                            String pkg = piece.substring(0, piece.length() - 2);
  21.297 -                            if (verifyCNBs) {
  21.298 -                                Dependency.create(Dependency.TYPE_MODULE, pkg);
  21.299 -                            }
  21.300 -                            if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  21.301 -                            exports.add(new PackageExport(pkg.replace('.', '/') + '/', false));
  21.302 -                        } else if (piece.endsWith(".**")) { // NOI18N
  21.303 -                            String pkg = piece.substring(0, piece.length() - 3);
  21.304 -                            if (verifyCNBs) {
  21.305 -                                Dependency.create(Dependency.TYPE_MODULE, pkg);
  21.306 -                            }
  21.307 -                            if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  21.308 -                            exports.add(new PackageExport(pkg.replace('.', '/') + '/', true));
  21.309 -                        } else {
  21.310 -                            throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  21.311 -                        }
  21.312 -                    }
  21.313 -                    if (exports.isEmpty()) throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  21.314 -                    publicPackages = exports.toArray(new PackageExport[exports.size()]);
  21.315 -                }
  21.316 -            } else {
  21.317 -                // XXX new link?
  21.318 -                Util.err.log(Level.WARNING, "module {0} does not declare OpenIDE-Module-Public-Packages in its manifest, so all packages are considered public by default: http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/doc-files/upgrade.html#3.4-public-packages", codeNameBase);
  21.319 -                publicPackages = null;
  21.320 -            }
  21.321 -            
  21.322 -            {
  21.323 -                // friends 
  21.324 -                String friends = attr.getValue("OpenIDE-Module-Friends"); // NOI18N
  21.325 -                if (friends != null) {
  21.326 -                    StringTokenizer tok = new StringTokenizer(friends, ", "); // NOI18N
  21.327 -                    HashSet<String> set = new HashSet<String> ();
  21.328 -                    while (tok.hasMoreTokens()) {
  21.329 -                        String piece = tok.nextToken();
  21.330 -                        if (piece.indexOf('/') != -1) {
  21.331 -                            throw new IllegalArgumentException("May specify only module code name bases in OpenIDE-Module-Friends, not major release versions: " + piece); // NOI18N
  21.332 -                        }
  21.333 -                        if (verifyCNBs) {
  21.334 -                            // Indirect way of checking syntax:
  21.335 -                            Dependency.create(Dependency.TYPE_MODULE, piece);
  21.336 -                        }
  21.337 -                        // OK, add it.
  21.338 -                        set.add(piece);
  21.339 -                    }
  21.340 -                    if (set.isEmpty()) {
  21.341 -                        throw new IllegalArgumentException("Empty OpenIDE-Module-Friends: " + friends); // NOI18N
  21.342 -                    }
  21.343 -                    if (publicPackages == null || publicPackages.length == 0) {
  21.344 -                        throw new IllegalArgumentException("No use specifying OpenIDE-Module-Friends without any public packages: " + friends); // NOI18N
  21.345 -                    }
  21.346 -                    this.friendNames = set;
  21.347 -                }
  21.348 -            }
  21.349 -            initDeps(deps, attr);
  21.350 -        } catch (IllegalArgumentException iae) {
  21.351 -            throw (InvalidException) new InvalidException("While parsing " + codeName + " a dependency attribute: " + iae.toString()).initCause(iae); // NOI18N
  21.352 -        }
  21.353 +        data();
  21.354      }
  21.355  
  21.356 -    final void computeProvides(Attributes attr, boolean verifyCNBs) throws InvalidException, IllegalArgumentException {
  21.357 -        // Token provides
  21.358 -        String providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N
  21.359 -        if (providesS == null) {
  21.360 -            provides = ZERO_STRING_ARRAY;
  21.361 -        } else {
  21.362 -            StringTokenizer tok = new StringTokenizer(providesS, ", "); // NOI18N
  21.363 -            provides = new String[tok.countTokens()];
  21.364 -            for (int i = 0; i < provides.length; i++) {
  21.365 -                String provide = tok.nextToken();
  21.366 -                if (provide.indexOf(',') != -1) {
  21.367 -                    throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N
  21.368 -                }
  21.369 -                if (verifyCNBs) {
  21.370 -                    Dependency.create(Dependency.TYPE_MODULE, provide);
  21.371 -                }
  21.372 -                if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Provides: " + provide); // NOI18N
  21.373 -                provides[i] = provide;
  21.374 -            }
  21.375 -            if (new HashSet<String>(Arrays.asList(provides)).size() < provides.length) {
  21.376 -                throw new IllegalArgumentException("Duplicate entries in OpenIDE-Module-Provides: " + providesS); // NOI18N
  21.377 -            }
  21.378 -        }
  21.379 -        String[] additionalProvides = mgr.refineProvides (this);
  21.380 -        if (additionalProvides != null) {
  21.381 -            if (provides == null) {
  21.382 -                provides = additionalProvides;
  21.383 -            } else {
  21.384 -                ArrayList<String> l = new ArrayList<String> ();
  21.385 -                l.addAll (Arrays.asList (provides));
  21.386 -                l.addAll (Arrays.asList (additionalProvides));
  21.387 -                provides = l.toArray (provides);
  21.388 -            }
  21.389 -        }
  21.390 -    }
  21.391  
  21.392      /** Get all JARs loaded by this module.
  21.393       * Includes the module itself, any locale variants of the module,
  21.394 @@ -511,7 +438,7 @@
  21.395      // impl of ModuleInfo method
  21.396      public @Override ClassLoader getClassLoader() throws IllegalArgumentException {
  21.397          if (!enabled) {
  21.398 -            throw new IllegalArgumentException("Not enabled: " + codeNameBase); // NOI18N
  21.399 +            throw new IllegalArgumentException("Not enabled: " + getCodeNameBase()); // NOI18N
  21.400          }
  21.401          assert classloader != null : "Should have had a non-null loader for " + this;
  21.402          return classloader;
  21.403 @@ -658,6 +585,32 @@
  21.404          }
  21.405      }
  21.406  
  21.407 +    /** To be overriden to empty in FixedModule & co. */
  21.408 +    void refineDependencies(Set<Dependency> dependencies) {
  21.409 +        // Permit the concrete installer to make some changes:
  21.410 +        mgr.refineDependencies(this, dependencies);
  21.411 +    }
  21.412 +
  21.413 +    void registerCoveredPackages(Set<String> known) {
  21.414 +        data().registerCoveredPackages(known);
  21.415 +    }
  21.416 +
  21.417 +    Set<String> getCoveredPackages() {
  21.418 +        return data().getCoveredPackages();
  21.419 +    }
  21.420 +
  21.421 +    /** Is this module a wrapper around OSGi?
  21.422 +     * @return true, if the module is build around OSGi
  21.423 +     * @since 2.51
  21.424 +     */
  21.425 +    public final boolean isNetigso() {
  21.426 +        return isNetigsoImpl();
  21.427 +    }
  21.428 +    
  21.429 +    boolean isNetigsoImpl() {
  21.430 +        return false;
  21.431 +    }
  21.432 +
  21.433      /** Struct representing a package exported from a module.
  21.434       * @since org.netbeans.core/1 > 1.4
  21.435       * @see Module#getPublicPackages
  21.436 @@ -685,58 +638,31 @@
  21.437          public @Override int hashCode() {
  21.438              return pkg.hashCode();
  21.439          }
  21.440 +        
  21.441 +        static void write(DataOutput dos, PackageExport[] arr) throws IOException {
  21.442 +            if (arr == null) {
  21.443 +                dos.writeInt(0);
  21.444 +                return;
  21.445 +            }
  21.446 +            dos.writeInt(arr.length);
  21.447 +            for (PackageExport pe : arr) {
  21.448 +                dos.writeUTF(pe.pkg);
  21.449 +                dos.writeBoolean(pe.recursive);
  21.450 +            }
  21.451 +        }
  21.452 +        
  21.453 +        static PackageExport[] read(DataInput is) throws IOException {
  21.454 +            int cnt = is.readInt();
  21.455 +            if (cnt == 0) {
  21.456 +                return null;
  21.457 +            }
  21.458 +            PackageExport[] arr = new PackageExport[cnt];
  21.459 +            for (int i = 0; i < cnt; i++) {
  21.460 +                String pkg = is.readUTF();
  21.461 +                boolean recursive = is.readBoolean();
  21.462 +                arr[i] = new PackageExport(pkg, recursive);
  21.463 +            }
  21.464 +            return arr;
  21.465 +        }
  21.466      }
  21.467 -
  21.468 -    /** Initializes dependencies of this module
  21.469 -     *
  21.470 -     * @param knownDeps Set<Dependency> of this module known from different source,
  21.471 -     *    can be null
  21.472 -     * @param attr attributes in manifest to parse if knownDeps is null
  21.473 -     */
  21.474 -    private void initDeps(Set<?> knownDeps, Attributes attr)
  21.475 -    throws IllegalStateException, IllegalArgumentException {
  21.476 -        if (knownDeps != null) {
  21.477 -            dependenciesA = knownDeps.toArray(new Dependency[knownDeps.size()]);
  21.478 -            knownDeps = null;
  21.479 -            return;
  21.480 -        }
  21.481 -
  21.482 -        // Dependencies
  21.483 -        Set<Dependency> dependencies = new HashSet<Dependency>(20);
  21.484 -        // First convert IDE/1 -> org.openide/1, so we never have to deal with
  21.485 -        // "IDE deps" internally:
  21.486 -        @SuppressWarnings(value = "deprecation")
  21.487 -        Set<Dependency> openideDeps = Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies")); // NOI18N
  21.488 -        if (!openideDeps.isEmpty()) {
  21.489 -            // If empty, leave it that way; NbInstaller will add it anyway.
  21.490 -            Dependency d = openideDeps.iterator().next();
  21.491 -            String name = d.getName();
  21.492 -            if (!name.startsWith("IDE/")) {
  21.493 -                throw new IllegalStateException("Weird IDE dep: " + name); // NOI18N
  21.494 -            }
  21.495 -            dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, "org.openide/" + name.substring(4) + " > " + d.getVersion())); // NOI18N
  21.496 -            if (dependencies.size() != 1) {
  21.497 -                throw new IllegalStateException("Should be singleton: " + dependencies); // NOI18N
  21.498 -            }
  21.499 -            Util.err.log(Level.WARNING, "the module {0} uses OpenIDE-Module-IDE-Dependencies which is deprecated. See http://openide.netbeans.org/proposals/arch/modularize.html", codeNameBase); // NOI18N
  21.500 -        }
  21.501 -        dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N
  21.502 -        dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N
  21.503 -        String pkgdeps = attr.getValue("OpenIDE-Module-Package-Dependencies"); // NOI18N
  21.504 -        if (pkgdeps != null) {
  21.505 -            // XXX: Util.err.log(ErrorManager.WARNING, "Warning: module " + codeNameBase + " uses the OpenIDE-Module-Package-Dependencies manifest attribute, which is now deprecated: XXX URL TBD");
  21.506 -            dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, pkgdeps)); // NOI18N
  21.507 -        }
  21.508 -        dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); // NOI18N
  21.509 -        dependencies.addAll(Dependency.create(Dependency.TYPE_NEEDS, attr.getValue("OpenIDE-Module-Needs"))); // NOI18N
  21.510 -        dependencies.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, attr.getValue("OpenIDE-Module-Recommends"))); // NOI18N
  21.511 -        refineDependencies(dependencies);
  21.512 -        dependenciesA = dependencies.toArray(new Dependency[dependencies.size()]);
  21.513 -    }
  21.514 -
  21.515 -    void refineDependencies(Set<Dependency> dependencies) {
  21.516 -        // Permit the concrete installer to make some changes:
  21.517 -        mgr.refineDependencies(this, dependencies);
  21.518 -    }
  21.519 -
  21.520  }
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/o.n.bootstrap/src/org/netbeans/ModuleData.java	Fri Mar 16 08:17:35 2012 +0100
    22.3 @@ -0,0 +1,466 @@
    22.4 +/*
    22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    22.6 + *
    22.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    22.8 + *
    22.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   22.10 + * Other names may be trademarks of their respective owners.
   22.11 + *
   22.12 + * The contents of this file are subject to the terms of either the GNU
   22.13 + * General Public License Version 2 only ("GPL") or the Common
   22.14 + * Development and Distribution License("CDDL") (collectively, the
   22.15 + * "License"). You may not use this file except in compliance with the
   22.16 + * License. You can obtain a copy of the License at
   22.17 + * http://www.netbeans.org/cddl-gplv2.html
   22.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   22.19 + * specific language governing permissions and limitations under the
   22.20 + * License.  When distributing the software, include this License Header
   22.21 + * Notice in each file and include the License file at
   22.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   22.23 + * particular file as subject to the "Classpath" exception as provided
   22.24 + * by Oracle in the GPL Version 2 section of the License file that
   22.25 + * accompanied this code. If applicable, add the following below the
   22.26 + * License Header, with the fields enclosed by brackets [] replaced by
   22.27 + * your own identifying information:
   22.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   22.29 + *
   22.30 + * If you wish your version of this file to be governed by only the CDDL
   22.31 + * or only the GPL Version 2, indicate your decision by adding
   22.32 + * "[Contributor] elects to include this software in this distribution
   22.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   22.34 + * single choice of license, a recipient has the option to distribute
   22.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   22.36 + * to extend the choice of license to its licensees as provided above.
   22.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   22.38 + * Version 2 license, then the option applies only if the new code is
   22.39 + * made subject to such option by the copyright holder.
   22.40 + *
   22.41 + * Contributor(s):
   22.42 + *
   22.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   22.44 + */
   22.45 +package org.netbeans;
   22.46 +
   22.47 +import java.io.DataInput;
   22.48 +import java.io.DataOutput;
   22.49 +import java.io.IOException;
   22.50 +import java.io.ObjectInput;
   22.51 +import java.io.ObjectOutput;
   22.52 +import java.util.ArrayList;
   22.53 +import java.util.Arrays;
   22.54 +import java.util.Collection;
   22.55 +import java.util.Collections;
   22.56 +import java.util.HashSet;
   22.57 +import java.util.List;
   22.58 +import java.util.Set;
   22.59 +import java.util.StringTokenizer;
   22.60 +import java.util.jar.Attributes;
   22.61 +import java.util.jar.Manifest;
   22.62 +import java.util.logging.Level;
   22.63 +import org.netbeans.Module.PackageExport;
   22.64 +import org.openide.modules.Dependency;
   22.65 +import org.openide.modules.SpecificationVersion;
   22.66 +import org.openide.util.Exceptions;
   22.67 +import org.openide.util.NbBundle;
   22.68 +
   22.69 +/** Information about essential properties of a module.
   22.70 + *
   22.71 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   22.72 + */
   22.73 +class ModuleData {
   22.74 +    private final static PackageExport[] ZERO_PACKAGE_ARRAY = new PackageExport[0];
   22.75 +    private final static String[] ZERO_STRING_ARRAY = new String[0];
   22.76 +
   22.77 +    private final String codeName;
   22.78 +    private final String codeNameBase;
   22.79 +    private final int codeNameRelease;
   22.80 +    private final String implVersion;
   22.81 +    private final String buildVersion;
   22.82 +    private final Set<String> friendNames;
   22.83 +    private final SpecificationVersion specVers;
   22.84 +    private final PackageExport[] publicPackages;
   22.85 +    private final String[] provides;
   22.86 +    private final Dependency[] dependencies;
   22.87 +    private final Set<String> coveredPackages;
   22.88 +    
   22.89 +    
   22.90 +    ModuleData(Manifest mf, Module forModule) throws InvalidException {
   22.91 +        Attributes attr = mf.getMainAttributes();
   22.92 +        // Code name
   22.93 +        codeName = attr.getValue("OpenIDE-Module"); // NOI18N
   22.94 +        if (codeName == null) {
   22.95 +            InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */ this, mf); // NOI18N
   22.96 +            // #29393: plausible user mistake, deal with it politely.
   22.97 +            Exceptions.attachLocalizedMessage(e,
   22.98 +                NbBundle.getMessage(Module.class,
   22.99 +                "EXC_not_a_module",
  22.100 +                this.toString()));
  22.101 +            throw e;
  22.102 +        }
  22.103 +        forModule.assignData(this);
  22.104 +        try {
  22.105 +            // This has the side effect of checking syntax:
  22.106 +            if (codeName.indexOf(',') != -1) {
  22.107 +                throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); // NOI18N
  22.108 +            }
  22.109 +            Object[] cnParse = Util.parseCodeName(codeName);
  22.110 +            codeNameBase = (String) cnParse[0];
  22.111 +            Set<?> deps = forModule.getManager().loadDependencies(codeNameBase);
  22.112 +            boolean verifyCNBs = deps == null;
  22.113 +            if (verifyCNBs) {
  22.114 +                Dependency.create(Dependency.TYPE_MODULE, codeName);
  22.115 +            }
  22.116 +            codeNameRelease = (cnParse[1] != null) ? ((Integer) cnParse[1]).intValue() : -1;
  22.117 +            if (cnParse[2] != null) {
  22.118 +                throw new NumberFormatException(codeName);
  22.119 +            }
  22.120 +            // Spec vers
  22.121 +            String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N
  22.122 +            if (specVersS != null) {
  22.123 +                try {
  22.124 +                    specVers = new SpecificationVersion(specVersS);
  22.125 +                } catch (NumberFormatException nfe) {
  22.126 +                    throw (InvalidException) new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()).initCause(nfe); // NOI18N
  22.127 +                }
  22.128 +            } else {
  22.129 +                specVers = null;
  22.130 +            }
  22.131 +            String iv = attr.getValue("OpenIDE-Module-Implementation-Version"); // NOI18N
  22.132 +            implVersion = iv == null ? "" : iv;
  22.133 +            String bld = attr.getValue("OpenIDE-Module-Build-Version"); // NOI18N
  22.134 +            buildVersion = bld == null ? implVersion : bld;
  22.135 +            
  22.136 +            this.provides = computeProvides(forModule, attr, verifyCNBs);
  22.137 +
  22.138 +            // Exports
  22.139 +            String exportsS = attr.getValue("OpenIDE-Module-Public-Packages"); // NOI18N
  22.140 +            if (exportsS != null) {
  22.141 +                if (exportsS.trim().equals("-")) { // NOI18N
  22.142 +                    publicPackages = ZERO_PACKAGE_ARRAY;
  22.143 +                } else {
  22.144 +                    StringTokenizer tok = new StringTokenizer(exportsS, ", "); // NOI18N
  22.145 +                    List<Module.PackageExport> exports = new ArrayList<Module.PackageExport>(Math.max(tok.countTokens(), 1));
  22.146 +                    while (tok.hasMoreTokens()) {
  22.147 +                        String piece = tok.nextToken();
  22.148 +                        if (piece.endsWith(".*")) { // NOI18N
  22.149 +                            String pkg = piece.substring(0, piece.length() - 2);
  22.150 +                            if (verifyCNBs) {
  22.151 +                                Dependency.create(Dependency.TYPE_MODULE, pkg);
  22.152 +                            }
  22.153 +                            if (pkg.lastIndexOf('/') != -1) {
  22.154 +                                throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  22.155 +                            }
  22.156 +                            exports.add(new Module.PackageExport(pkg.replace('.', '/') + '/', false));
  22.157 +                        } else if (piece.endsWith(".**")) { // NOI18N
  22.158 +                            String pkg = piece.substring(0, piece.length() - 3);
  22.159 +                            if (verifyCNBs) {
  22.160 +                                Dependency.create(Dependency.TYPE_MODULE, pkg);
  22.161 +                            }
  22.162 +                            if (pkg.lastIndexOf('/') != -1) {
  22.163 +                                throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  22.164 +                            }
  22.165 +                            exports.add(new Module.PackageExport(pkg.replace('.', '/') + '/', true));
  22.166 +                        } else {
  22.167 +                            throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  22.168 +                        }
  22.169 +                    }
  22.170 +                    if (exports.isEmpty()) {
  22.171 +                        throw new IllegalArgumentException("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
  22.172 +                    }
  22.173 +                    publicPackages = exports.toArray(new Module.PackageExport[exports.size()]);
  22.174 +                }
  22.175 +            } else {
  22.176 +                // XXX new link?
  22.177 +                Util.err.log(Level.WARNING, "module {0} does not declare OpenIDE-Module-Public-Packages in its manifest, so all packages are considered public by default: http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/doc-files/upgrade.html#3.4-public-packages", codeNameBase);
  22.178 +                publicPackages = null;
  22.179 +            }
  22.180 +
  22.181 +            {
  22.182 +                HashSet<String> set = null;
  22.183 +                // friends 
  22.184 +                String friends = attr.getValue("OpenIDE-Module-Friends"); // NOI18N
  22.185 +                if (friends != null) {
  22.186 +                    StringTokenizer tok = new StringTokenizer(friends, ", "); // NOI18N
  22.187 +                    set = new HashSet<String>();
  22.188 +                    while (tok.hasMoreTokens()) {
  22.189 +                        String piece = tok.nextToken();
  22.190 +                        if (piece.indexOf('/') != -1) {
  22.191 +                            throw new IllegalArgumentException("May specify only module code name bases in OpenIDE-Module-Friends, not major release versions: " + piece); // NOI18N
  22.192 +                        }
  22.193 +                        if (verifyCNBs) {
  22.194 +                            // Indirect way of checking syntax:
  22.195 +                            Dependency.create(Dependency.TYPE_MODULE, piece);
  22.196 +                        }
  22.197 +                        // OK, add it.
  22.198 +                        set.add(piece);
  22.199 +                    }
  22.200 +                    if (set.isEmpty()) {
  22.201 +                        throw new IllegalArgumentException("Empty OpenIDE-Module-Friends: " + friends); // NOI18N
  22.202 +                    }
  22.203 +                    if (publicPackages == null || publicPackages.length == 0) {
  22.204 +                        throw new IllegalArgumentException("No use specifying OpenIDE-Module-Friends without any public packages: " + friends); // NOI18N
  22.205 +                    }
  22.206 +                }
  22.207 +                this.friendNames = set;
  22.208 +            }
  22.209 +            this.dependencies = initDeps(forModule, deps, attr);
  22.210 +        } catch (IllegalArgumentException iae) {
  22.211 +            throw (InvalidException) new InvalidException("While parsing " + codeName + " a dependency attribute: " + iae.toString()).initCause(iae); // NOI18N
  22.212 +        }
  22.213 +        this.coveredPackages = new HashSet<String>();
  22.214 +    }
  22.215 +    
  22.216 +    ModuleData(Manifest mf, NetigsoModule m) throws InvalidException {
  22.217 +        final String symbName = getMainAttribute(mf, "Bundle-SymbolicName"); // NOI18N
  22.218 +        if (symbName == null) {
  22.219 +            throw new InvalidException("Not an OSGi bundle: " + m);
  22.220 +        }
  22.221 +        m.assignData(this);
  22.222 +        this.codeName = symbName.replace('-', '_');
  22.223 +        int slash = codeName.lastIndexOf('/');
  22.224 +        if (slash != -1) {
  22.225 +            this.codeNameRelease = Integer.parseInt(symbName.substring(slash + 1));
  22.226 +        } else {
  22.227 +            this.codeNameRelease = -1;
  22.228 +        }
  22.229 +        String v = getMainAttribute(mf, "Bundle-Version"); // NOI18N
  22.230 +        if (v == null) {
  22.231 +            NetigsoModule.LOG.log(Level.WARNING, "No Bundle-Version for {0}", m);
  22.232 +            this.specVers = new SpecificationVersion(v = "0.0");
  22.233 +        } else {
  22.234 +            this.specVers = computeVersion(v);
  22.235 +        }
  22.236 +        this.codeNameBase = codeName;
  22.237 +        String iv = getMainAttribute(mf, "OpenIDE-Module-Implementation-Version"); // NOI18N
  22.238 +        this.implVersion = iv == null ? v : iv;
  22.239 +        String bld = getMainAttribute(mf, "OpenIDE-Module-Build-Version"); // NOI18N
  22.240 +        this.buildVersion = bld == null ? implVersion : bld;
  22.241 +        this.friendNames = Collections.emptySet();
  22.242 +        this.publicPackages = null;
  22.243 +        this.provides = computeProvides(m, mf.getMainAttributes(), false);
  22.244 +        this.dependencies = null;
  22.245 +        this.coveredPackages = new HashSet<String>();
  22.246 +    }
  22.247 +    
  22.248 +    ModuleData(ObjectInput dis) throws IOException {
  22.249 +        try {
  22.250 +            this.codeName = dis.readUTF();
  22.251 +            this.codeNameBase = dis.readUTF();
  22.252 +            this.codeNameRelease = dis.readInt();
  22.253 +            this.coveredPackages = readStrings(dis, new HashSet<String>(), true);
  22.254 +            this.dependencies = (Dependency[]) dis.readObject();
  22.255 +            this.implVersion = dis.readUTF();
  22.256 +            this.buildVersion = dis.readUTF();
  22.257 +            this.provides = readStrings(dis);
  22.258 +            this.friendNames = readStrings(dis, new HashSet<String>(), false);
  22.259 +            this.specVers = new SpecificationVersion(dis.readUTF());
  22.260 +            this.publicPackages = Module.PackageExport.read(dis);
  22.261 +        } catch (ClassNotFoundException cnfe) {
  22.262 +            throw new IOException(cnfe);
  22.263 +        }
  22.264 +    }
  22.265 +    
  22.266 +    void write(ObjectOutput dos) throws IOException {
  22.267 +        dos.writeUTF(codeName);
  22.268 +        dos.writeUTF(codeNameBase);
  22.269 +        dos.writeInt(codeNameRelease);
  22.270 +        writeStrings(dos, coveredPackages);
  22.271 +        dos.writeObject(dependencies);
  22.272 +        dos.writeUTF(implVersion);
  22.273 +        dos.writeUTF(buildVersion);
  22.274 +        writeStrings(dos, provides);
  22.275 +        writeStrings(dos, friendNames);
  22.276 +        dos.writeUTF(specVers.toString());
  22.277 +        Module.PackageExport.write(dos, publicPackages);
  22.278 +    }
  22.279 +
  22.280 +    private String[] computeProvides(Module forModule, Attributes attr, boolean verifyCNBs) throws InvalidException, IllegalArgumentException {
  22.281 +        String[] arr;
  22.282 +        // Token provides
  22.283 +        String providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N
  22.284 +        if (providesS == null) {
  22.285 +            arr = ZERO_STRING_ARRAY;
  22.286 +        } else {
  22.287 +            StringTokenizer tok = new StringTokenizer(providesS, ", "); // NOI18N
  22.288 +            arr = new String[tok.countTokens()];
  22.289 +            for (int i = 0; i < arr.length; i++) {
  22.290 +                String provide = tok.nextToken();
  22.291 +                if (provide.indexOf(',') != -1) {
  22.292 +                    throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N
  22.293 +                }
  22.294 +                if (verifyCNBs) {
  22.295 +                    Dependency.create(Dependency.TYPE_MODULE, provide);
  22.296 +                }
  22.297 +                if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException("Illegal OpenIDE-Module-Provides: " + provide); // NOI18N
  22.298 +                arr[i] = provide;
  22.299 +            }
  22.300 +            if (new HashSet<String>(Arrays.asList(arr)).size() < arr.length) {
  22.301 +                throw new IllegalArgumentException("Duplicate entries in OpenIDE-Module-Provides: " + providesS); // NOI18N
  22.302 +            }
  22.303 +        }
  22.304 +        String[] additionalProvides = forModule.getManager().refineProvides (forModule);
  22.305 +        if (additionalProvides != null) {
  22.306 +            if (arr == null) {
  22.307 +                arr = additionalProvides;
  22.308 +            } else {
  22.309 +                ArrayList<String> l = new ArrayList<String> ();
  22.310 +                l.addAll (Arrays.asList (arr));
  22.311 +                l.addAll (Arrays.asList (additionalProvides));
  22.312 +                arr = l.toArray (arr);
  22.313 +            }
  22.314 +        }
  22.315 +        return arr;
  22.316 +    }
  22.317 +    
  22.318 +    /**
  22.319 +     * Initializes dependencies of this module
  22.320 +     *
  22.321 +     * @param knownDeps Set<Dependency> of this module known from different
  22.322 +     * source, can be null
  22.323 +     * @param attr attributes in manifest to parse if knownDeps is null
  22.324 +     */
  22.325 +    private Dependency[] initDeps(Module forModule, Set<?> knownDeps, Attributes attr)
  22.326 +        throws IllegalStateException, IllegalArgumentException {
  22.327 +        if (knownDeps != null) {
  22.328 +            return knownDeps.toArray(new Dependency[knownDeps.size()]);
  22.329 +        }
  22.330 +
  22.331 +        // deps
  22.332 +        Set<Dependency> deps = new HashSet<Dependency>(20);
  22.333 +        // First convert IDE/1 -> org.openide/1, so we never have to deal with
  22.334 +        // "IDE deps" internally:
  22.335 +        @SuppressWarnings(value = "deprecation")
  22.336 +        Set<Dependency> openideDeps = Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies")); // NOI18N
  22.337 +        if (!openideDeps.isEmpty()) {
  22.338 +            // If empty, leave it that way; NbInstaller will add it anyway.
  22.339 +            Dependency d = openideDeps.iterator().next();
  22.340 +            String name = d.getName();
  22.341 +            if (!name.startsWith("IDE/")) {
  22.342 +                throw new IllegalStateException("Weird IDE dep: " + name); // NOI18N
  22.343 +            }
  22.344 +            deps.addAll(Dependency.create(Dependency.TYPE_MODULE, "org.openide/" + name.substring(4) + " > " + d.getVersion())); // NOI18N
  22.345 +            if (deps.size() != 1) {
  22.346 +                throw new IllegalStateException("Should be singleton: " + deps); // NOI18N
  22.347 +            }
  22.348 +            Util.err.log(Level.WARNING, "the module {0} uses OpenIDE-Module-IDE-Dependencies which is deprecated. See http://openide.netbeans.org/proposals/arch/modularize.html", codeNameBase); // NOI18N
  22.349 +        }
  22.350 +        deps.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N
  22.351 +        deps.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N
  22.352 +        String pkgdeps = attr.getValue("OpenIDE-Module-Package-Dependencies"); // NOI18N
  22.353 +        if (pkgdeps != null) {
  22.354 +            // XXX: Util.err.log(ErrorManager.WARNING, "Warning: module " + codeNameBase + " uses the OpenIDE-Module-Package-Dependencies 
  22.355 +            // manifest attribute, which is now deprecated: XXX URL TBD");
  22.356 +            deps.addAll(Dependency.create(Dependency.TYPE_PACKAGE, pkgdeps)); // NOI18N
  22.357 +        }
  22.358 +        deps.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); // NOI18N
  22.359 +        deps.addAll(Dependency.create(Dependency.TYPE_NEEDS, attr.getValue("OpenIDE-Module-Needs"))); // NOI18N
  22.360 +        deps.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, attr.getValue("OpenIDE-Module-Recommends"))); // NOI18N
  22.361 +        forModule.refineDependencies(deps);
  22.362 +        return deps.toArray(new Dependency[0]);
  22.363 +    }
  22.364 +
  22.365 +    final String getCodeName() {
  22.366 +        return codeName;
  22.367 +    }
  22.368 +    
  22.369 +    final String getCodeNameBase() {
  22.370 +        return codeNameBase;
  22.371 +    }
  22.372 +
  22.373 +    final int getCodeNameRelease() {
  22.374 +        return codeNameRelease;
  22.375 +    }
  22.376 +
  22.377 +    final String[] getProvides() {
  22.378 +        return provides;
  22.379 +    }
  22.380 +
  22.381 +    final SpecificationVersion getSpecificationVersion() {
  22.382 +        return specVers;
  22.383 +    }
  22.384 +
  22.385 +    final PackageExport[] getPublicPackages() {
  22.386 +        return publicPackages;
  22.387 +    }
  22.388 +
  22.389 +    final Set<String> getFriendNames() {
  22.390 +        return friendNames;
  22.391 +    }
  22.392 +
  22.393 +    final Dependency[] getDependencies() {
  22.394 +        return dependencies;
  22.395 +    }
  22.396 +
  22.397 +    final String getBuildVersion() {
  22.398 +        return buildVersion.isEmpty() ? null : buildVersion;
  22.399 +    }
  22.400 +
  22.401 +    final String getImplementationVersion() {
  22.402 +        return implVersion.isEmpty() ? null : implVersion;
  22.403 +    }
  22.404 +    
  22.405 +    void registerCoveredPackages(Set<String> known) {
  22.406 +        assert coveredPackages.isEmpty();
  22.407 +        coveredPackages.addAll(known);
  22.408 +    }
  22.409 +
  22.410 +    Set<String> getCoveredPackages() {
  22.411 +        return coveredPackages.isEmpty() ? null : coveredPackages;
  22.412 +    }
  22.413 +
  22.414 +    private <T extends Collection<String>> T readStrings(
  22.415 +        DataInput dis, T set, boolean returnEmpty
  22.416 +    ) throws IOException {
  22.417 +        int cnt = dis.readInt();
  22.418 +        if (!returnEmpty && cnt == 0) {
  22.419 +            return null;
  22.420 +        }
  22.421 +        while (cnt-- > 0) {
  22.422 +            set.add(dis.readUTF());
  22.423 +        }
  22.424 +        return set;
  22.425 +    }
  22.426 +    private String[] readStrings(ObjectInput dis) throws IOException {
  22.427 +        List<String> arr = new ArrayList<String>();
  22.428 +        readStrings(dis, arr, false);
  22.429 +        return arr.toArray(new String[0]);
  22.430 +    }
  22.431 +    private void writeStrings(DataOutput dos, Collection<String> set) 
  22.432 +    throws IOException {
  22.433 +        if (set == null) {
  22.434 +            dos.writeInt(0);
  22.435 +            return;
  22.436 +        }
  22.437 +        dos.writeInt(set.size());
  22.438 +        for (String s : set) {
  22.439 +            dos.writeUTF(s);
  22.440 +        }
  22.441 +    }
  22.442 +    private void writeStrings(ObjectOutput dos, String[] provides) throws IOException {
  22.443 +        writeStrings(dos, Arrays.asList(provides));
  22.444 +    }
  22.445 +    
  22.446 +    private static String getMainAttribute(Manifest manifest, String attr) {
  22.447 +        String s = manifest.getMainAttributes().getValue(attr);
  22.448 +        if (s == null) {
  22.449 +            return null;
  22.450 +        }
  22.451 +        int semicolon = s.indexOf(';');
  22.452 +        if (semicolon == -1) {
  22.453 +            return s;
  22.454 +        } else {
  22.455 +            return s.substring(0, semicolon);
  22.456 +        }
  22.457 +    }
  22.458 +    private static SpecificationVersion computeVersion(String v) {
  22.459 +        int pos = -1;
  22.460 +        for (int i = 0; i < 3; i++) {
  22.461 +            pos = v.indexOf('.', pos + 1);
  22.462 +            if (pos == -1) {
  22.463 +                return new SpecificationVersion(v);
  22.464 +            }
  22.465 +        }
  22.466 +        return new SpecificationVersion(v.substring(0, pos));
  22.467 +    }
  22.468 +
  22.469 +}
    23.1 --- a/o.n.bootstrap/src/org/netbeans/ModuleFactory.java	Thu Mar 15 16:10:40 2012 +0100
    23.2 +++ b/o.n.bootstrap/src/org/netbeans/ModuleFactory.java	Fri Mar 16 08:17:35 2012 +0100
    23.3 @@ -65,9 +65,16 @@
    23.4      public Module create(File jar, Object history, boolean reloadable,
    23.5              boolean autoload, boolean eager, ModuleManager mgr, Events ev)
    23.6      throws IOException {
    23.7 +        final Boolean osgiStatus = mgr.isOSGi(jar);
    23.8 +        if (Boolean.TRUE.equals(osgiStatus)) {
    23.9 +            return new NetigsoModule(null, jar, mgr, ev, history, reloadable, autoload, eager);
   23.10 +        }
   23.11 +        Module m;
   23.12          try {
   23.13 -            StandardModule m = new StandardModule(mgr, ev, jar, history, reloadable, autoload, eager);
   23.14 -            return m;
   23.15 +            m = new StandardModule(mgr, ev, jar, history, reloadable, autoload, eager);
   23.16 +            if (osgiStatus == null) {
   23.17 +                m.dataWithCheck();
   23.18 +            }
   23.19          } catch (InvalidException ex) {
   23.20              Manifest mani = ex.getManifest();
   23.21              if (mani != null) {
   23.22 @@ -75,10 +82,15 @@
   23.23                  if (name == null) {
   23.24                      throw ex;
   23.25                  }
   23.26 -                return new NetigsoModule(mani, jar, mgr, ev, history, reloadable, autoload, eager);
   23.27 +                m = new NetigsoModule(mani, jar, mgr, ev, history, reloadable, autoload, eager);
   23.28 +                if (osgiStatus == null) {
   23.29 +                    m.dataWithCheck();
   23.30 +                }
   23.31 +            } else {
   23.32 +                throw ex;
   23.33              }
   23.34 -            throw ex;
   23.35          }
   23.36 +        return m;
   23.37      }
   23.38      
   23.39      /**
    24.1 --- a/o.n.bootstrap/src/org/netbeans/ModuleManager.java	Thu Mar 15 16:10:40 2012 +0100
    24.2 +++ b/o.n.bootstrap/src/org/netbeans/ModuleManager.java	Fri Mar 16 08:17:35 2012 +0100
    24.3 @@ -47,9 +47,13 @@
    24.4  import java.beans.PropertyChangeListener;
    24.5  import java.beans.PropertyChangeSupport;
    24.6  import java.io.ByteArrayInputStream;
    24.7 +import java.io.ByteArrayOutputStream;
    24.8 +import java.io.DataInputStream;
    24.9 +import java.io.DataOutputStream;
   24.10  import java.io.File;
   24.11  import java.io.IOException;
   24.12  import java.io.InputStream;
   24.13 +import java.io.ObjectOutputStream;
   24.14  import java.net.URL;
   24.15  import java.security.AllPermission;
   24.16  import java.security.CodeSource;
   24.17 @@ -57,6 +61,7 @@
   24.18  import java.security.Permissions;
   24.19  import java.util.ArrayList;
   24.20  import java.util.Arrays;
   24.21 +import java.util.Collection;
   24.22  import java.util.Collections;
   24.23  import java.util.Comparator;
   24.24  import java.util.Enumeration;
   24.25 @@ -112,7 +117,7 @@
   24.26      private static final Set<Union2<Dependency,InvalidException>> EMPTY_COLLECTION = Collections.<Union2<Dependency, InvalidException>>emptySet();
   24.27  
   24.28      // modules providing a given requires token; set may never be empty
   24.29 -    private final Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>(25);
   24.30 +    private final ProvidersOf providersOf = new ProvidersOf();
   24.31  
   24.32      private final ModuleInstaller installer;
   24.33      private ModuleFactory moduleFactory;
   24.34 @@ -122,6 +127,7 @@
   24.35      private final Object classLoaderLock = new String("ModuleManager.classLoaderLock"); // NOI18N
   24.36  
   24.37      private final Events ev;
   24.38 +    private final ModuleDataCache mdc = new ModuleDataCache();
   24.39  
   24.40      /** Create a manager, initially with no managed modules.
   24.41       * The handler for installing modules is given.
   24.42 @@ -308,6 +314,10 @@
   24.43          return new HashSet<Module>(modules);
   24.44      }
   24.45  
   24.46 +    final int getModuleCount() {
   24.47 +        return modules.size();
   24.48 +    }
   24.49 +
   24.50      /** Get a set of modules managed which are currently enabled.
   24.51       * Convenience method only.
   24.52       * @see #PROP_ENABLED_MODULES
   24.53 @@ -348,7 +358,7 @@
   24.54       */
   24.55      @Deprecated
   24.56      public Set<Module> getModuleInterdependencies(Module m, boolean reverse, boolean transitive) {
   24.57 -        return Util.moduleInterdependencies(m, reverse, transitive, true, modules, modulesByName, providersOf);
   24.58 +        return Util.moduleInterdependencies(m, reverse, transitive, true, modules, modulesByName, getProvidersOf());
   24.59      }
   24.60  
   24.61      /**
   24.62 @@ -367,7 +377,7 @@
   24.63       * @since org.netbeans.bootstrap/1 > 2.48
   24.64       */
   24.65      public Set<Module> getModuleInterdependencies(Module m, boolean reverse, boolean transitive, boolean considerNeeds) {
   24.66 -        return Util.moduleInterdependencies(m, reverse, transitive, considerNeeds, modules, modulesByName, providersOf);
   24.67 +        return Util.moduleInterdependencies(m, reverse, transitive, considerNeeds, modules, modulesByName, getProvidersOf());
   24.68      }
   24.69  
   24.70      /** Get a classloader capable of loading from any
   24.71 @@ -499,6 +509,91 @@
   24.72          return cnt;
   24.73      }
   24.74  
   24.75 +    /** Checks whether the module is supposed be OSGi or not 
   24.76 +     * @return null if it is not known
   24.77 +     */
   24.78 +    final Boolean isOSGi(File jar) {
   24.79 +        return mdc.isOSGi(jar.getPath());
   24.80 +    }
   24.81 +    
   24.82 +    /** Obtains (and destroys) data for given JAR file.
   24.83 +     * @return stream with data or null if not found in cache
   24.84 +     */
   24.85 +    final InputStream dataFor(File jar) {
   24.86 +        if (jar == null) {
   24.87 +            return null;
   24.88 +        }
   24.89 +        byte[] arr = mdc.getModuleState(jar.getPath());
   24.90 +        return arr == null ? null : new ByteArrayInputStream(arr);
   24.91 +    }
   24.92 +    /** Obtains cnb for given JAR file.
   24.93 +     * @return stream with data or null if not found in cache
   24.94 +     */
   24.95 +    final String cnbFor(File jar) {
   24.96 +        if (jar == null) {
   24.97 +            return null;
   24.98 +        }
   24.99 +        return mdc.getCnb(jar.getPath());
  24.100 +    }
  24.101 +
  24.102 +    private Map<String, Set<Module>> getProvidersOf() {
  24.103 +        return providersOf.getProvidersOf();
  24.104 +    }
  24.105 +
  24.106 +    static void registerProviders(Module m, Map<String, Set<Module>> po) {
  24.107 +        String[] provides = m.getProvides();
  24.108 +        for (int i = 0; i < provides.length; i++) {
  24.109 +            Set<Module> providing = po.get(provides[i]);
  24.110 +            if (providing == null) {
  24.111 +                providing = new HashSet<Module>(16);
  24.112 +                po.put(provides[i], providing);
  24.113 +            }
  24.114 +            providing.add(m);
  24.115 +        }
  24.116 +    }
  24.117 +
  24.118 +    private class ProvidersOf {
  24.119 +        private Map<String,Set<Module>> providersOf;
  24.120 +        
  24.121 +        public ProvidersOf() {
  24.122 +        }
  24.123 +        
  24.124 +        final synchronized Map<String, Set<Module>> getProvidersOf() {
  24.125 +            if (providersOf == null) {
  24.126 +                providersOf = new HashMap<String, Set<Module>>();
  24.127 +                for (Module m : modules) {
  24.128 +                    possibleProviderAdded(m);
  24.129 +                }
  24.130 +            }
  24.131 +            return providersOf;
  24.132 +        }
  24.133 +
  24.134 +        final synchronized void possibleProviderAdded(Module m) {
  24.135 +            if (providersOf == null) {
  24.136 +                return;
  24.137 +            }
  24.138 +            registerProviders(m, providersOf);
  24.139 +        }
  24.140 +
  24.141 +        final synchronized void possibleProviderRemoved(Module m) {
  24.142 +            if (providersOf == null) {
  24.143 +                return;
  24.144 +            }
  24.145 +            for (String token : m.getProvides()) {
  24.146 +                Set<Module> providing = providersOf.get(token);
  24.147 +                if (providing != null) {
  24.148 +                    providing.remove(m);
  24.149 +                    if (providing.isEmpty()) {
  24.150 +                        providersOf.remove(token);
  24.151 +                    }
  24.152 +                } else {
  24.153 +                    // Else we called reload and m.reload threw IOException, so
  24.154 +                    // it has already removed its provider list
  24.155 +                }
  24.156 +            }
  24.157 +        }
  24.158 +    }
  24.159 +
  24.160      /** A classloader giving access to all the module classloaders at once. */
  24.161      private final class SystemClassLoader extends JarClassLoader {
  24.162  
  24.163 @@ -769,14 +864,13 @@
  24.164      }
  24.165  
  24.166      private void subCreate(Module m) throws DuplicateException {
  24.167 -        Util.err.log(Level.FINE, "created: {0}", m);
  24.168          Module old = get(m.getCodeNameBase());
  24.169          if (old != null) {
  24.170              throw new DuplicateException(old, m);
  24.171          }
  24.172          modules.add(m);
  24.173          modulesByName.put(m.getCodeNameBase(), m);
  24.174 -        possibleProviderAdded(m);
  24.175 +        providersOf.possibleProviderAdded(m);
  24.176          lookup.add(m);
  24.177          firer.created(m);
  24.178          firer.change(new ChangeFirer.Change(this, PROP_MODULES, null, null));
  24.179 @@ -787,17 +881,6 @@
  24.180          clearProblemCache();
  24.181          firer.fire();
  24.182      }
  24.183 -    private void possibleProviderAdded(Module m) {
  24.184 -        String[] provides = m.getProvides();
  24.185 -        for (int i = 0; i < provides.length; i++) {
  24.186 -            Set<Module> providing = providersOf.get(provides[i]);
  24.187 -            if (providing == null) {
  24.188 -                providing = new HashSet<Module>(16);
  24.189 -                providersOf.put(provides[i], providing);
  24.190 -            }
  24.191 -            providing.add(m);
  24.192 -        }
  24.193 -    }
  24.194  
  24.195      /** Remove a module from the managed set.
  24.196       * Must be disabled first.
  24.197 @@ -810,7 +893,7 @@
  24.198          ev.log(Events.DELETE_MODULE, m);
  24.199          modules.remove(m);
  24.200          modulesByName.remove(m.getCodeNameBase());
  24.201 -        possibleProviderRemoved(m);
  24.202 +        providersOf.possibleProviderRemoved(m);
  24.203          lookup.remove(m);
  24.204          firer.deleted(m);
  24.205          firer.change(new ChangeFirer.Change(this, PROP_MODULES, null, null));
  24.206 @@ -820,20 +903,6 @@
  24.207          m.destroy();
  24.208          firer.fire();
  24.209      }
  24.210 -    private void possibleProviderRemoved(Module m) {
  24.211 -        for (String token : m.getProvides()) {
  24.212 -            Set<Module> providing = providersOf.get(token);
  24.213 -            if (providing != null) {
  24.214 -                providing.remove(m);
  24.215 -                if (providing.isEmpty()) {
  24.216 -                    providersOf.remove(token);
  24.217 -                }
  24.218 -            } else {
  24.219 -                // Else we called reload and m.reload threw IOException, so
  24.220 -                // it has already removed its provider list
  24.221 -            }
  24.222 -        }
  24.223 -    }
  24.224  
  24.225      /** Reload a module.
  24.226       * This could make a fresh copy of its JAR file preparing
  24.227 @@ -854,7 +923,7 @@
  24.228          Util.err.fine("reload: " + m);
  24.229          if (m.isFixed()) throw new IllegalArgumentException("reload fixed module: " + m); // NOI18N
  24.230          if (m.isEnabled()) throw new IllegalArgumentException("reload enabled module: " + m); // NOI18N
  24.231 -        possibleProviderRemoved(m);
  24.232 +        providersOf.possibleProviderRemoved(m);
  24.233          try {
  24.234              m.reload();
  24.235          } catch (IOException ioe) {
  24.236 @@ -862,7 +931,7 @@
  24.237              delete(m);
  24.238              throw ioe;
  24.239          }
  24.240 -        possibleProviderAdded(m);
  24.241 +        providersOf.possibleProviderAdded(m);
  24.242          firer.change(new ChangeFirer.Change(m, Module.PROP_MANIFEST, null, null));
  24.243          // Some problem with this module may now have gone away. In turn, some
  24.244          // other modules may now no longer have problems. So clear the cache
  24.245 @@ -966,25 +1035,9 @@
  24.246                      }
  24.247                      fallback.addFirst(m);
  24.248                      Util.err.fine("enable: bringing up: " + m);
  24.249 -                    ev.log(Events.PERF_START, "bringing up classloader on " + m.getCodeName() ); // NOI18N
  24.250 +                    ev.log(Events.PERF_START, "bringing up classloader on " + m.getCodeNameBase()); // NOI18N
  24.251                      try {
  24.252 -                        // Calculate the parents to initialize the classloader with.
  24.253 -                        Dependency[] dependencies = m.getDependenciesArray();
  24.254 -                        Set<Module> parents = new HashSet<Module>(dependencies.length * 4 / 3 + 1);
  24.255 -                        for (int i = 0; i < dependencies.length; i++) {
  24.256 -                            Dependency dep = dependencies[i];
  24.257 -                            if (dep.getType() != Dependency.TYPE_MODULE) {
  24.258 -                                // Token providers do *not* go into the parent classloader
  24.259 -                                // list. The providing module must have been turned on first.
  24.260 -                                // But you cannot automatically access classes from it.
  24.261 -                                continue;
  24.262 -                            }
  24.263 -                            String name = (String)Util.parseCodeName(dep.getName())[0];
  24.264 -                            Module parent = get(name);
  24.265 -                            // Should not happen:
  24.266 -                            if (parent == null) throw new IOException("Parent " + name + " not found!"); // NOI18N
  24.267 -                            parents.add(parent);
  24.268 -                        }
  24.269 +                        Set<Module> parents = calculateParents(m);
  24.270                          m.classLoaderUp(parents);
  24.271                      } catch (IOException ioe) {
  24.272                          tryingClassLoaderUp = true;
  24.273 @@ -993,7 +1046,7 @@
  24.274                          throw ie;
  24.275                      }
  24.276                      m.setEnabled(true);
  24.277 -                    ev.log(Events.PERF_END, "bringing up classloader on " + m.getCodeName() ); // NOI18N
  24.278 +                    ev.log(Events.PERF_END, "bringing up classloader on " + m.getCodeNameBase() ); // NOI18N
  24.279                      // Check package dependencies.
  24.280  //                    ev.log(Events.PERF_START, "package dependency check on " + m.getCodeName() ); // NOI18N
  24.281                      Util.err.fine("enable: checking package dependencies for " + m);
  24.282 @@ -1187,6 +1240,30 @@
  24.283              return m1.getCodeNameBase().compareTo(m2.getCodeNameBase());
  24.284          }
  24.285      }
  24.286 +    
  24.287 +    private final Set<Module> calculateParents(Module m) throws NumberFormatException, IOException {
  24.288 +        // Calculate the parents to initialize the classloader with.
  24.289 +        Dependency[] dependencies = m.getDependenciesArray();
  24.290 +        Set<Module> res = new HashSet<Module>(dependencies.length * 4 / 3 + 1);
  24.291 +        for (int i = 0; i < dependencies.length; i++) {
  24.292 +            Dependency dep = dependencies[i];
  24.293 +            if (dep.getType() != Dependency.TYPE_MODULE) {
  24.294 +                // Token providers do *not* go into the parent classloader
  24.295 +                // list. The providing module must have been turned on first.
  24.296 +                // But you cannot automatically access classes from it.
  24.297 +                continue;
  24.298 +            }
  24.299 +            String name = (String) Util.parseCodeName(dep.getName())[0];
  24.300 +            Module parent = get(name);
  24.301 +            // Should not happen:
  24.302 +            if (parent == null) {
  24.303 +                throw new IOException("Parent " + name + " not found!"); // NOI18N
  24.304 +            }
  24.305 +            res.add(parent);
  24.306 +        }
  24.307 +        return res;
  24.308 +    }
  24.309 +
  24.310  
  24.311      /** Simulate what would happen if a set of modules were to be enabled.
  24.312       * None of the listed modules may be autoload modules, nor eager, nor currently enabled,
  24.313 @@ -1221,6 +1298,15 @@
  24.314          return simulateEnable(modules, true);
  24.315      }
  24.316      final List<Module> simulateEnable(Set<Module> modules, boolean honorAutoloadEager) throws IllegalArgumentException {
  24.317 +        List<String> cnbs = mdc.simulateEnable(modules);
  24.318 +        if (cnbs != null) {
  24.319 +            List<Module> arr = new ArrayList<Module>(cnbs.size());
  24.320 +            for (String cnb : cnbs) {
  24.321 +                arr.add(get(cnb));
  24.322 +            }
  24.323 +            assert !arr.contains(null) : arr;
  24.324 +            return arr;
  24.325 +        }
  24.326          /* Not quite, eager modules may change this:
  24.327          if (modules.isEmpty()) {
  24.328              return Collections.EMPTY_LIST;
  24.329 @@ -1247,10 +1333,11 @@
  24.330              }
  24.331          }
  24.332          while (searchForPossibleEager(willEnable, stillDisabled, modules)) {/* search again */}
  24.333 -        Map<Module,List<Module>> deps = Util.moduleDependencies(willEnable, modulesByName, providersOf);
  24.334 +        Map<Module,List<Module>> deps = Util.moduleDependencies(willEnable, modulesByName, getProvidersOf());
  24.335          try {
  24.336              List<Module> l = Utilities.topologicalSort(willEnable, deps);
  24.337              Collections.reverse(l);
  24.338 +            mdc.registerEnable(modules, l);
  24.339              return l;
  24.340          } catch (TopologicalSortException ex) {
  24.341              // Some kind of cycle involving prov-req deps. Should be extremely rare.
  24.342 @@ -1297,7 +1384,7 @@
  24.343                  dep.getType() == Dependency.TYPE_NEEDS ||
  24.344                  dep.getType() == Dependency.TYPE_RECOMMENDS
  24.345              ) {
  24.346 -                Set<Module> providers = providersOf.get(dep.getName());
  24.347 +                Set<Module> providers = getProvidersOf().get(dep.getName());
  24.348                  if (providers == null) {
  24.349                      assert dep.getType() == Dependency.TYPE_RECOMMENDS : "Should have found a provider of " + dep;
  24.350                      continue;
  24.351 @@ -1382,7 +1469,7 @@
  24.352                  if (other == null) throw new IllegalStateException("Should have found module: " + codeNameBase); // NOI18N
  24.353                  if (!couldBeEnabledWithEagers(other, willEnable, recursion)) return false;
  24.354              } else if (dep.getType() == Dependency.TYPE_REQUIRES || dep.getType() == Dependency.TYPE_NEEDS) {
  24.355 -                Set<Module> providers = providersOf.get(dep.getName());
  24.356 +                Set<Module> providers = getProvidersOf().get(dep.getName());
  24.357                  if (providers == null) throw new IllegalStateException("Should have found a provider of: " + dep.getName()); // NOI18N
  24.358                  // Just need *one* to match.
  24.359                  boolean foundOne = false;
  24.360 @@ -1403,7 +1490,7 @@
  24.361      public List<Module> simulateJaveleonReload(Module moduleToReload) throws IllegalArgumentException {
  24.362          Set<Module> transitiveDependents = new HashSet<Module>(20);
  24.363          addToJaveleonDisableList(transitiveDependents, moduleToReload);
  24.364 -        Map<Module,List<Module>> deps = Util.moduleDependencies(transitiveDependents, modulesByName, providersOf);
  24.365 +        Map<Module,List<Module>> deps = Util.moduleDependencies(transitiveDependents, modulesByName, getProvidersOf());
  24.366          try {
  24.367              LinkedList<Module> orderedForEnabling = new LinkedList<Module>();
  24.368              for (Module m : Utilities.topologicalSort(transitiveDependents, deps)) {
  24.369 @@ -1468,7 +1555,7 @@
  24.370          Set<Module> stillEnabled = new HashSet<Module>(getEnabledModules());
  24.371          stillEnabled.removeAll(willDisable);
  24.372          while (searchForUnusedAutoloads(willDisable, stillEnabled)) {/* search again */}
  24.373 -        Map<Module,List<Module>> deps = Util.moduleDependencies(willDisable, modulesByName, providersOf);
  24.374 +        Map<Module,List<Module>> deps = Util.moduleDependencies(willDisable, modulesByName, getProvidersOf());
  24.375          try {
  24.376              return Utilities.topologicalSort(willDisable, deps);
  24.377          } catch (TopologicalSortException ex) {
  24.378 @@ -1688,7 +1775,7 @@
  24.379                          // Works much like a regular module dependency. However it only
  24.380                          // fails if there are no satisfying modules with no problems.
  24.381                          String token = dep.getName();
  24.382 -                        Set<Module> providers = providersOf.get(token);
  24.383 +                        Set<Module> providers = getProvidersOf().get(token);
  24.384                          if (providers == null) {
  24.385                              // Nobody provides it. This dep failed.
  24.386                              probs.add(Union2.<Dependency,InvalidException>createFirst(dep));
  24.387 @@ -1811,7 +1898,11 @@
  24.388      public boolean shutDown(Runnable midHook) {
  24.389          assertWritable();
  24.390          Set<Module> unorderedModules = getEnabledModules();
  24.391 -        Map<Module,List<Module>> deps = Util.moduleDependencies(unorderedModules, modulesByName, providersOf);
  24.392 +        Map<String, Set<Module>> providersMap = new HashMap<String, Set<Module>>();
  24.393 +        for (Module m : unorderedModules) {
  24.394 +            registerProviders(m, providersMap);
  24.395 +        }
  24.396 +        Map<Module,List<Module>> deps = Util.moduleDependencies(unorderedModules, modulesByName, providersMap);
  24.397          List<Module> sortedModules;
  24.398          try {
  24.399              sortedModules = Utilities.topologicalSort(unorderedModules, deps);
  24.400 @@ -1849,4 +1940,177 @@
  24.401              }
  24.402          });
  24.403      }
  24.404 +    private class ModuleDataCache implements Stamps.Updater {
  24.405 +        private static final String CACHE = "all-manifests.dat";
  24.406 +        private final Map<String,byte[]> path2Data;
  24.407 +        private final Map<String,Boolean> path2OSGi;
  24.408 +        private final Map<String,String> path2Cnb;
  24.409 +        private final int moduleCount;
  24.410 +        private Set<String> toEnable;
  24.411 +        private List<String> willEnable;
  24.412 +        
  24.413 +        public ModuleDataCache() {
  24.414 +            InputStream is = Stamps.getModulesJARs().asStream(CACHE);
  24.415 +            Map<String,byte[]> map = null;
  24.416 +            Map<String,Boolean> osgi = null;
  24.417 +            Map<String,String> cnbs = null;
  24.418 +            Set<String> toEn = null;
  24.419 +            List<String> toWi = null;
  24.420 +            int cnt = -1;
  24.421 +            if (is != null) try {
  24.422 +                DataInputStream dis = new DataInputStream(is);
  24.423 +                map = new HashMap<String, byte[]>();
  24.424 +                osgi = new HashMap<String, Boolean>();
  24.425 +                cnbs = new HashMap<String, String>();
  24.426 +                cnt = dis.readInt();
  24.427 +                for (;;) {
  24.428 +                    String path = Stamps.readRelativePath(dis);
  24.429 +                    if (path.isEmpty()) {
  24.430 +                        break;
  24.431 +                    }
  24.432 +                    boolean isOSGi = dis.readBoolean();
  24.433 +                    osgi.put(path, isOSGi);
  24.434 +                    cnbs.put(path, dis.readUTF());
  24.435 +                    int len = dis.readInt();
  24.436 +                    byte[] data = new byte[len];
  24.437 +                    dis.readFully(data);
  24.438 +                    map.put(path, data);
  24.439 +                }
  24.440 +                toEn = readCnbs(dis, new HashSet<String>());
  24.441 +                toWi = readCnbs(dis, new ArrayList<String>());
  24.442 +                dis.close();
  24.443 +            } catch (IOException ex) {
  24.444 +                Util.err.log(Level.INFO, "Cannot read all-modules.dat", ex);
  24.445 +                map = null;
  24.446 +                osgi = null;
  24.447 +                cnbs = null;
  24.448 +                toEn = null;
  24.449 +                toWi = null;
  24.450 +            }
  24.451 +            path2Data = map;
  24.452 +            path2OSGi = osgi;
  24.453 +            path2Cnb = cnbs;
  24.454 +            toEnable = toEn;
  24.455 +            willEnable = toWi;
  24.456 +            moduleCount = cnt;
  24.457 +            if (map == null) {
  24.458 +                reset();
  24.459 +            }
  24.460 +        }
  24.461 +        
  24.462 +        public Boolean isOSGi(String path) {
  24.463 +            if (path2OSGi == null) {
  24.464 +                return null;
  24.465 +            }
  24.466 +            return path2OSGi.get(path);
  24.467 +        }
  24.468 +        
  24.469 +        public synchronized byte[] getModuleState(String path) {
  24.470 +            byte[] res = null;
  24.471 +            if (path2Data != null) {
  24.472 +                res = path2Data.remove(path);
  24.473 +            }
  24.474 +            if (res == null) {
  24.475 +                reset();
  24.476 +            }
  24.477 +            return res;
  24.478 +        }
  24.479 +        final String getCnb(String path) {
  24.480 +            return path2Cnb == null ? null : path2Cnb.get(path);
  24.481 +        }
  24.482 +        
  24.483 +        @Override
  24.484 +        public void flushCaches(DataOutputStream os) throws IOException {
  24.485 +            Set<Module> store = getModules();
  24.486 +            os.writeInt(store.size());
  24.487 +            for (Module m : store) {
  24.488 +                final File path = m.getJarFile();
  24.489 +                if (path == null) {
  24.490 +                    assert m instanceof FixedModule : "Only fixed modules are excluded from caches " + m;
  24.491 +                    continue;
  24.492 +                }
  24.493 +                Stamps.writeRelativePath(path.getPath(), os);
  24.494 +                os.writeBoolean(m.isNetigso());
  24.495 +                os.writeUTF(m.getCodeNameBase());
  24.496 +                
  24.497 +                ByteArrayOutputStream data = new ByteArrayOutputStream();
  24.498 +                ObjectOutputStream dos = new ObjectOutputStream(data);
  24.499 +                m.writeData(dos);
  24.500 +                dos.close();
  24.501 +                
  24.502 +                byte[] arr = data.toByteArray();
  24.503 +                os.writeInt(arr.length);
  24.504 +                os.write(arr);
  24.505 +            }
  24.506 +            Stamps.writeRelativePath("", os);
  24.507 +            synchronized (this) {
  24.508 +                writeCnbs(os, toEnable);
  24.509 +                writeCnbs(os, willEnable);
  24.510 +            }
  24.511 +        }
  24.512 +        @Override
  24.513 +        public void cacheReady() {
  24.514 +        }
  24.515 +        
  24.516 +        private synchronized void reset() {
  24.517 +            toEnable = null;
  24.518 +            willEnable = null;
  24.519 +        }
  24.520 +
  24.521 +        synchronized final void registerEnable(Set<Module> modules, List<Module> l) {
  24.522 +            toEnable = new HashSet<String>();
  24.523 +            for (Module m : modules) {
  24.524 +                toEnable.add(m.getCodeNameBase());
  24.525 +            }
  24.526 +            List<String> arr = new ArrayList<String>(l.size());
  24.527 +            for (Module m : l) {
  24.528 +                arr.add(m.getCodeNameBase());
  24.529 +            }
  24.530 +            willEnable = Collections.unmodifiableList(arr);
  24.531 +            Stamps.getModulesJARs().scheduleSave(this, CACHE, false);
  24.532 +        }
  24.533 +
  24.534 +        synchronized final List<String> simulateEnable(Set<Module> modules) {
  24.535 +            if (
  24.536 +                toEnable != null &&
  24.537 +                modules.size() == toEnable.size() &&
  24.538 +                moduleCount == getModuleCount()
  24.539 +            ) {
  24.540 +                Set<String> clone = new HashSet<String>(toEnable);
  24.541 +                for (Module m : modules) {
  24.542 +                    if (!clone.remove(m.getCodeNameBase())) {
  24.543 +                        return null;
  24.544 +                    }
  24.545 +                }
  24.546 +                if (clone.isEmpty()) {
  24.547 +                    return willEnable;
  24.548 +                }
  24.549 +            }
  24.550 +            return null;
  24.551 +        }
  24.552 +
  24.553 +        private <T extends Collection<String>> T readCnbs(DataInputStream dis, T fill) throws IOException {
  24.554 +            int size = dis.readInt();
  24.555 +            if (size == -1) {
  24.556 +                return null;
  24.557 +            }
  24.558 +            
  24.559 +            while (size-- > 0) {
  24.560 +                fill.add(dis.readUTF());
  24.561 +            }
  24.562 +            return fill;
  24.563 +        }
  24.564 +
  24.565 +        private void writeCnbs(DataOutputStream os, Collection<String> cnbs) throws IOException {
  24.566 +            if (cnbs == null) {
  24.567 +                os.writeInt(-1);
  24.568 +                return;
  24.569 +            }
  24.570 +            
  24.571 +            os.writeInt(cnbs.size());
  24.572 +            for (String s : cnbs) {
  24.573 +                os.writeUTF(s);
  24.574 +            }
  24.575 +        }
  24.576 +    }
  24.577  }
    25.1 --- a/o.n.bootstrap/src/org/netbeans/NetigsoModule.java	Thu Mar 15 16:10:40 2012 +0100
    25.2 +++ b/o.n.bootstrap/src/org/netbeans/NetigsoModule.java	Fri Mar 16 08:17:35 2012 +0100
    25.3 @@ -46,6 +46,7 @@
    25.4  
    25.5  import java.io.File;
    25.6  import java.io.IOException;
    25.7 +import java.io.ObjectInput;
    25.8  import java.net.URL;
    25.9  import java.util.Collections;
   25.10  import java.util.Enumeration;
   25.11 @@ -54,7 +55,6 @@
   25.12  import java.util.jar.Manifest;
   25.13  import java.util.logging.Level;
   25.14  import java.util.logging.Logger;
   25.15 -import org.openide.modules.SpecificationVersion;
   25.16  import org.openide.util.Exceptions;
   25.17  
   25.18  /** Special module for representing OSGi bundles 
   25.19 @@ -66,58 +66,26 @@
   25.20      private final File jar;
   25.21      private final Manifest manifest;
   25.22      private int startLevel = -1;
   25.23 -    private final String codeName;
   25.24 -    private final int release;
   25.25 -    private final SpecificationVersion version;
   25.26      private InvalidException problem;
   25.27  
   25.28      public NetigsoModule(Manifest mani, File jar, ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
   25.29          super(mgr, ev, history, reloadable, autoload, eager);
   25.30          this.jar = jar;
   25.31          this.manifest = mani;
   25.32 -        final String symbName = getMainAttribute("Bundle-SymbolicName");
   25.33 -        this.codeName = symbName.replace('-', '_');
   25.34 -        int slash = codeName.lastIndexOf('/');
   25.35 -        if (slash != -1) {
   25.36 -            this.release = Integer.parseInt(symbName.substring(slash + 1));
   25.37 -        } else {
   25.38 -            this.release = -1;
   25.39 -        }
   25.40 -        String v = getMainAttribute("Bundle-Version"); // NOI18N
   25.41 -        if (v == null) {
   25.42 -            NetigsoModule.LOG.log(Level.WARNING, "No Bundle-Version for {0}", jar);
   25.43 -            this.version = new SpecificationVersion("0.0");
   25.44 -        } else {
   25.45 -            this.version = computeVersion(v);
   25.46 -        }
   25.47 -        
   25.48 -        computeProvides(mani.getMainAttributes(), false);
   25.49      }
   25.50  
   25.51      @Override
   25.52 -    public String getCodeName() {
   25.53 -        return getCodeNameBase();
   25.54 +    ModuleData createData(ObjectInput in, Manifest mf) throws IOException {
   25.55 +        if (in != null) {
   25.56 +            return new ModuleData(in);
   25.57 +        } else {
   25.58 +            return new ModuleData(mf, this);
   25.59 +        }
   25.60      }
   25.61  
   25.62      @Override
   25.63 -    public String getCodeNameBase() {
   25.64 -        return codeName;
   25.65 -    }
   25.66 -
   25.67 -    @Override
   25.68 -    public int getCodeNameRelease() {
   25.69 -        return release;
   25.70 -    }
   25.71 -
   25.72 -    @Override
   25.73 -    public SpecificationVersion getSpecificationVersion() {
   25.74 -        return version;
   25.75 -    }
   25.76 -
   25.77 -    @Override
   25.78 -    public String getImplementationVersion() {
   25.79 -        String explicit = super.getImplementationVersion(); // OIDE-M-I-V/-B-V added by NB build harness
   25.80 -        return explicit != null ? explicit : getMainAttribute("Bundle-Version"); // NOI18N
   25.81 +    boolean isNetigsoImpl() {
   25.82 +        return true;
   25.83      }
   25.84  
   25.85      @Override
   25.86 @@ -236,19 +204,6 @@
   25.87          return "Netigso: " + jar;
   25.88      }
   25.89  
   25.90 -    private String getMainAttribute(String attr) {
   25.91 -        String s = manifest.getMainAttributes().getValue(attr);
   25.92 -        if (s == null) {
   25.93 -            return null;
   25.94 -        }
   25.95 -        int semicolon = s.indexOf(';');
   25.96 -        if (semicolon == -1) {
   25.97 -            return s;
   25.98 -        } else {
   25.99 -            return s.substring(0, semicolon);
  25.100 -        }
  25.101 -    }
  25.102 -
  25.103      @Override
  25.104      final int getStartLevelImpl() {
  25.105          return startLevel;
  25.106 @@ -258,17 +213,6 @@
  25.107          this.startLevel = startLevel;
  25.108      }
  25.109      
  25.110 -    private static SpecificationVersion computeVersion(String v) {
  25.111 -        int pos = -1;
  25.112 -        for (int i = 0; i < 3; i++) {
  25.113 -            pos = v.indexOf('.', pos + 1);
  25.114 -            if (pos == -1) {
  25.115 -                return new SpecificationVersion(v);
  25.116 -            }
  25.117 -        }
  25.118 -        return new SpecificationVersion(v.substring(0, pos));
  25.119 -    }
  25.120 -
  25.121      private final class DelegateCL extends ProxyClassLoader 
  25.122      implements Util.ModuleProvider {
  25.123          public DelegateCL() {
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/o.n.bootstrap/src/org/netbeans/PackageAttrsCache.java	Fri Mar 16 08:17:35 2012 +0100
    26.3 @@ -0,0 +1,176 @@
    26.4 +/*
    26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    26.6 + *
    26.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    26.8 + *
    26.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   26.10 + * Other names may be trademarks of their respective owners.
   26.11 + *
   26.12 + * The contents of this file are subject to the terms of either the GNU
   26.13 + * General Public License Version 2 only ("GPL") or the Common
   26.14 + * Development and Distribution License("CDDL") (collectively, the
   26.15 + * "License"). You may not use this file except in compliance with the
   26.16 + * License. You can obtain a copy of the License at
   26.17 + * http://www.netbeans.org/cddl-gplv2.html
   26.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   26.19 + * specific language governing permissions and limitations under the
   26.20 + * License.  When distributing the software, include this License Header
   26.21 + * Notice in each file and include the License file at
   26.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   26.23 + * particular file as subject to the "Classpath" exception as provided
   26.24 + * by Oracle in the GPL Version 2 section of the License file that
   26.25 + * accompanied this code. If applicable, add the following below the
   26.26 + * License Header, with the fields enclosed by brackets [] replaced by
   26.27 + * your own identifying information:
   26.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   26.29 + *
   26.30 + * If you wish your version of this file to be governed by only the CDDL
   26.31 + * or only the GPL Version 2, indicate your decision by adding
   26.32 + * "[Contributor] elects to include this software in this distribution
   26.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   26.34 + * single choice of license, a recipient has the option to distribute
   26.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   26.36 + * to extend the choice of license to its licensees as provided above.
   26.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   26.38 + * Version 2 license, then the option applies only if the new code is
   26.39 + * made subject to such option by the copyright holder.
   26.40 + *
   26.41 + * Contributor(s):
   26.42 + *
   26.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   26.44 + */
   26.45 +package org.netbeans;
   26.46 +
   26.47 +import java.io.DataInputStream;
   26.48 +import java.io.DataOutputStream;
   26.49 +import java.io.IOException;
   26.50 +import java.io.InputStream;
   26.51 +import java.net.URL;
   26.52 +import java.util.Collections;
   26.53 +import java.util.HashMap;
   26.54 +import java.util.HashSet;
   26.55 +import java.util.Map;
   26.56 +import java.util.jar.Attributes;
   26.57 +import java.util.jar.Manifest;
   26.58 +import java.util.logging.Level;
   26.59 +import java.util.logging.Logger;
   26.60 +
   26.61 +/** Cache of various attributes of packages (vendor, spec & impl version, etc.)
   26.62 + *
   26.63 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   26.64 + */
   26.65 +final class PackageAttrsCache implements Stamps.Updater {
   26.66 +    private static final String CACHE = "package-attrs.dat"; // NOI18N
   26.67 +    private static final String[] EMPTY = new String[7];
   26.68 +    private static final Logger LOG = Logger.getLogger(PackageAttrsCache.class.getName());
   26.69 +    private static PackageAttrsCache packages;
   26.70 +    
   26.71 +    static void initialize() {
   26.72 +        packages = new PackageAttrsCache();
   26.73 +    }
   26.74 +    
   26.75 +    private final Map<String,String[]> cache;
   26.76 +    PackageAttrsCache() {
   26.77 +        InputStream is = Stamps.getModulesJARs().asStream(CACHE);
   26.78 +        Map<String,String[]> tmp = null;
   26.79 +        if (is != null) {
   26.80 +            try {
   26.81 +                tmp = new HashMap<String, String[]>();
   26.82 +                DataInputStream dis = new DataInputStream(is);
   26.83 +                for (;;) {
   26.84 +                    String key = Stamps.readRelativePath(dis);
   26.85 +                    if (key.isEmpty()) {
   26.86 +                        break;
   26.87 +                    }
   26.88 +                    String[] arr = new String[7];
   26.89 +                    for (int i = 0; i < 7; i++) {
   26.90 +                        arr[i] = dis.readUTF();
   26.91 +                    }
   26.92 +                    tmp.put(key, arr);
   26.93 +                }
   26.94 +            } catch (IOException ex) {
   26.95 +                LOG.log(Level.INFO, "Cannot read " + CACHE, ex);
   26.96 +                tmp = null;
   26.97 +            }
   26.98 +        }
   26.99 +        if (tmp == null) {
  26.100 +            cache = new HashMap<String,String[]>();
  26.101 +            Stamps.getModulesJARs().scheduleSave(this, CACHE, false);
  26.102 +        } else {
  26.103 +            cache = Collections.unmodifiableMap(tmp);
  26.104 +        }
  26.105 +    }
  26.106 +
  26.107 +    static String[] findPackageAttrs(URL src, Manifest man, String path) {
  26.108 +        PackageAttrsCache p = packages;
  26.109 +        return p == null ? extractFromManifest(man, path) : p.findImpl(src, man, path);
  26.110 +    }
  26.111 +    
  26.112 +    final String[] findImpl(URL src, Manifest man, String path) {
  26.113 +        String key = src.toExternalForm() + "!/" + path;
  26.114 +        String[] arr;
  26.115 +        if (cache instanceof HashSet) {
  26.116 +            arr = extractFromManifest(man, path);
  26.117 +            if (isEmpty(arr)) {
  26.118 +                arr = EMPTY;
  26.119 +            } else {
  26.120 +                cache.put(key, arr);
  26.121 +            }
  26.122 +        } else {
  26.123 +            arr = cache.get(key);
  26.124 +            if (arr == null) {
  26.125 +                arr = EMPTY;
  26.126 +            }
  26.127 +        }
  26.128 +        return arr;
  26.129 +    }
  26.130 +
  26.131 +    
  26.132 +    @Override
  26.133 +    public void flushCaches(DataOutputStream os) throws IOException {
  26.134 +        for (Map.Entry<String, String[]> entry : cache.entrySet()) {
  26.135 +            Stamps.writeRelativePath(entry.getKey(), os);
  26.136 +            for (String s : entry.getValue()) {
  26.137 +                os.writeUTF(s);
  26.138 +            }
  26.139 +        }
  26.140 +        Stamps.writeRelativePath("", os);
  26.141 +    }
  26.142 +
  26.143 +    @Override
  26.144 +    public void cacheReady() {
  26.145 +    }
  26.146 +
  26.147 +    private static String getAttr(Attributes spec, Attributes main, Attributes.Name name) {
  26.148 +        String val = null;
  26.149 +        if (spec != null) val = spec.getValue (name);
  26.150 +        if (val == null && main != null) val = main.getValue (name);
  26.151 +        return val;
  26.152 +    }
  26.153 +
  26.154 +    private static String[] extractFromManifest(Manifest man, String path) {
  26.155 +        Attributes spec = man.getAttributes(path);
  26.156 +        Attributes main = man.getMainAttributes();
  26.157 +        String[] arr = new String[7];
  26.158 +        arr[0] = getAttr(spec, main, Attributes.Name.SPECIFICATION_TITLE);
  26.159 +        arr[1] = getAttr(spec, main, Attributes.Name.SPECIFICATION_VERSION);
  26.160 +        arr[2] = getAttr(spec, main, Attributes.Name.SPECIFICATION_VENDOR);
  26.161 +        arr[3] = getAttr(spec, main, Attributes.Name.IMPLEMENTATION_TITLE);
  26.162 +        arr[4] = getAttr(spec, main, Attributes.Name.IMPLEMENTATION_VERSION);
  26.163 +        arr[5] = getAttr(spec, main, Attributes.Name.IMPLEMENTATION_VENDOR);
  26.164 +        arr[6] = getAttr(spec, main, Attributes.Name.SEALED);
  26.165 +        return arr;
  26.166 +    }
  26.167 +
  26.168 +    private static boolean isEmpty(String[] arr) {
  26.169 +        if (arr == EMPTY) {
  26.170 +            return true;
  26.171 +        }
  26.172 +        for (String s : arr) {
  26.173 +            if (s != null) {
  26.174 +                return false;
  26.175 +            }
  26.176 +        }
  26.177 +        return true;
  26.178 +    }
  26.179 +}
    27.1 --- a/o.n.bootstrap/src/org/netbeans/Stamps.java	Thu Mar 15 16:10:40 2012 +0100
    27.2 +++ b/o.n.bootstrap/src/org/netbeans/Stamps.java	Fri Mar 16 08:17:35 2012 +0100
    27.3 @@ -44,7 +44,7 @@
    27.4  
    27.5  import java.io.BufferedOutputStream;
    27.6  import java.io.ByteArrayInputStream;
    27.7 -import java.io.DataInputStream;
    27.8 +import java.io.DataInput;
    27.9  import java.io.DataOutput;
   27.10  import java.io.DataOutputStream;
   27.11  import java.io.File;
   27.12 @@ -810,7 +810,7 @@
   27.13          return cluster.getName().replaceAll("\\.\\.", "__");
   27.14      }
   27.15      
   27.16 -    static String readRelativePath(DataInputStream dis) throws IOException {
   27.17 +    static String readRelativePath(DataInput dis) throws IOException {
   27.18          String index = dis.readUTF();
   27.19          if (index.isEmpty()) {
   27.20              return index;
    28.1 --- a/o.n.bootstrap/src/org/netbeans/StandardModule.java	Thu Mar 15 16:10:40 2012 +0100
    28.2 +++ b/o.n.bootstrap/src/org/netbeans/StandardModule.java	Fri Mar 16 08:17:35 2012 +0100
    28.3 @@ -52,17 +52,16 @@
    28.4  import java.io.File;
    28.5  import java.io.IOException;
    28.6  import java.io.InputStream;
    28.7 +import java.io.ObjectInput;
    28.8  import java.security.AllPermission;
    28.9  import java.security.CodeSource;
   28.10  import java.security.PermissionCollection;
   28.11  import java.security.Permissions;
   28.12  import java.util.ArrayList;
   28.13  import java.util.Collections;
   28.14 -import java.util.HashMap;
   28.15  import java.util.HashSet;
   28.16  import java.util.List;
   28.17  import java.util.Locale;
   28.18 -import java.util.Map;
   28.19  import java.util.MissingResourceException;
   28.20  import java.util.Properties;
   28.21  import java.util.ResourceBundle;
   28.22 @@ -92,38 +91,19 @@
   28.23      /** JAR file holding the module */
   28.24      private final File jar;
   28.25      /** if reloadable, temporary JAR file actually loaded from */
   28.26 -    private File physicalJar = null;
   28.27 +    private File physicalJar;
   28.28      private Manifest manifest;
   28.29      
   28.30 -    /** Map from extension JARs to sets of JAR that load them via Class-Path.
   28.31 -     * Used only for debugging purposes, so that a warning is printed if two
   28.32 -     * different modules try to load the same extension (which would cause them
   28.33 -     * to both load their own private copy, which may not be intended).
   28.34 -     */
   28.35 -    private static final Map<File,Set<File>> extensionOwners = new HashMap<File,Set<File>>();
   28.36      /** Simple registry of JAR files used as modules.
   28.37       * Used only for debugging purposes, so that we can be sure
   28.38       * that no one is using Class-Path to refer to other modules.
   28.39       */
   28.40      private static final Set<File> moduleJARs = new HashSet<File>();
   28.41  
   28.42 -    /** Set of locale-variants JARs for this module (or null).
   28.43 -     * Added explicitly to classloader, and can be used by execution engine.
   28.44 -     */
   28.45 -    private Set<File> localeVariants = null;
   28.46 -    /** Set of extension JARs that this module loads via Class-Path (or null).
   28.47 -     * Can be used e.g. by execution engine. (#9617)
   28.48 -     */
   28.49 -    private Set<File> plainExtensions = null;
   28.50 -    /** Set of localized extension JARs derived from plainExtensions (or null).
   28.51 -     * Used to add these to the classloader. (#9348)
   28.52 -     * Can be used e.g. by execution engine.
   28.53 -     */
   28.54 -    private Set<File> localeExtensions = null;
   28.55      /** Patches added at the front of the classloader (or null).
   28.56       * Files are assumed to be JARs; directories are themselves.
   28.57       */
   28.58 -    private Set<File> patches = null;
   28.59 +    private Set<File> patches;
   28.60      
   28.61      /** localized properties, only non-null if requested from disabled module */
   28.62      private Properties localizedProps;
   28.63 @@ -132,16 +112,16 @@
   28.64      public StandardModule(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
   28.65          super(mgr, ev, history, JaveleonModule.isJaveleonPresent || reloadable, autoload, eager);
   28.66          this.jar = jar;
   28.67 -        loadManifest();
   28.68 -        parseManifest();
   28.69 -        findExtensionsAndVariants(manifest);
   28.70 -        // Check if some other module already listed this one in Class-Path.
   28.71 -        // For the chronologically reverse case, see findExtensionsAndVariants().
   28.72 -        Set<File> bogoOwners = extensionOwners.get(jar);
   28.73 -        if (bogoOwners != null) {
   28.74 -            Util.err.warning("module " + jar + " was incorrectly placed in the Class-Path of other JARs " + bogoOwners + "; please use OpenIDE-Module-Module-Dependencies instead");
   28.75 +        moduleJARs.add(jar);
   28.76 +    }
   28.77 +
   28.78 +    @Override
   28.79 +    ModuleData createData(ObjectInput in, Manifest mf) throws IOException {
   28.80 +        if (in != null) {
   28.81 +            return new StandardModuleData(in);
   28.82 +        } else {
   28.83 +            return new StandardModuleData(mf, this);
   28.84          }
   28.85 -        moduleJARs.add(jar);
   28.86      }
   28.87  
   28.88      public @Override Manifest getManifest() {
   28.89 @@ -315,109 +295,57 @@
   28.90          }
   28.91      }
   28.92      
   28.93 -    /** Find any extensions loaded by the module, as well as any localized
   28.94 -     * variants of the module or its extensions.
   28.95 -     */
   28.96 -    private void findExtensionsAndVariants(Manifest m) {
   28.97 -        assert jar != null : "Cannot load extensions from classpath module " + getCodeNameBase();
   28.98 -        localeVariants = null;
   28.99 -        List<File> l = LocaleVariants.findLocaleVariantsOf(jar, getCodeNameBase());
  28.100 -        if (!l.isEmpty()) {
  28.101 -            localeVariants = new HashSet<File>(l);
  28.102 -        }
  28.103 -        plainExtensions = null;
  28.104 -        localeExtensions = null;
  28.105 -        String classPath = m.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
  28.106 -        if (classPath != null) {
  28.107 -            StringTokenizer tok = new StringTokenizer(classPath);
  28.108 -            while (tok.hasMoreTokens()) {
  28.109 -                String ext = tok.nextToken();
  28.110 -                if (new File(ext).isAbsolute()) { // NOI18N
  28.111 -                    Util.err.log(Level.WARNING, "Class-Path value {0} from {1} is illegal according to the Java Extension Mechanism: must be relative", new Object[] {ext, jar});
  28.112 -                }
  28.113 -                File base = jar.getParentFile();
  28.114 -                while (ext.startsWith("../")) {
  28.115 -                    // cannot access FileUtil.normalizeFile from here, and URI.normalize might be unsafe for UNC paths
  28.116 -                    ext = ext.substring(3);
  28.117 -                    base = base.getParentFile();
  28.118 -                }
  28.119 -                File extfile = new File(base, ext.replace('/', File.separatorChar));
  28.120 -                //No need to sync on extensionOwners - we are in write mutex
  28.121 -                Set<File> owners = extensionOwners.get(extfile);
  28.122 -                if (owners == null) {
  28.123 -                    owners = new HashSet<File>(2);
  28.124 -                    owners.add(jar);
  28.125 -                    extensionOwners.put(extfile, owners);
  28.126 -                } else if (! owners.contains(jar)) {
  28.127 -                    owners.add(jar);
  28.128 -                    events.log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
  28.129 -                } // else already know about it (OK or warned)
  28.130 -                // Also check to make sure it is not a module JAR! See constructor for the reverse case.
  28.131 -                if (moduleJARs.contains(extfile)) {
  28.132 -                    Util.err.warning("Class-Path value " + ext + " from " + jar + " illegally refers to another module; use OpenIDE-Module-Module-Dependencies instead");
  28.133 -                }
  28.134 -                if (plainExtensions == null) plainExtensions = new HashSet<File>();
  28.135 -                plainExtensions.add(extfile);
  28.136 -                l = LocaleVariants.findLocaleVariantsOf(extfile, getCodeNameBase());
  28.137 -                if (!l.isEmpty()) {
  28.138 -                    if (localeExtensions == null) {
  28.139 -                        localeExtensions = new HashSet<File>();
  28.140 +    private Set<File> findPatches() {
  28.141 +        if (patches == null) {
  28.142 +            // #9273: load any modules/patches/this-code-name/*.jar files first:
  28.143 +            File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
  28.144 +                getCodeNameBase().replace('.', '-')); // NOI18N
  28.145 +            if (patchdir.isDirectory()) {
  28.146 +                File[] jars = patchdir.listFiles(Util.jarFilter());
  28.147 +                if (jars != null) {
  28.148 +                    for (File patchJar : jars) {
  28.149 +                        if (patches == null) {
  28.150 +                            patches = new HashSet<File>(5);
  28.151 +                        }
  28.152 +                        patches.add(patchJar);
  28.153                      }
  28.154 -                    localeExtensions.addAll(l);
  28.155 +                } else {
  28.156 +                    Util.err.warning("Could not search for patches in " + patchdir);
  28.157                  }
  28.158              }
  28.159 -        }
  28.160 -        // #9273: load any modules/patches/this-code-name/*.jar files first:
  28.161 -        File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N
  28.162 -                                 getCodeNameBase().replace('.', '-')); // NOI18N
  28.163 -        scanForPatches(patchdir);
  28.164 -        // Use of the following system property is not supported, but is used
  28.165 -        // by e.g. XTest to influence installed modules without changing the build.
  28.166 -        // Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir
  28.167 -        String patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N
  28.168 -        if (patchesClassPath != null) {
  28.169 -            StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
  28.170 -            while (tokenizer.hasMoreTokens()) {
  28.171 -                String element = tokenizer.nextToken();
  28.172 -                File fileElement = new File(element);
  28.173 -                if (fileElement.exists()) {
  28.174 -                    if (patches == null) {
  28.175 -                        patches = new HashSet<File>(15);
  28.176 +            // Use of the following system property is not supported, but is used
  28.177 +            // by e.g. XTest to influence installed modules without changing the build.
  28.178 +            // Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir
  28.179 +            String patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N
  28.180 +            if (patchesClassPath != null) {
  28.181 +                StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator);
  28.182 +                while (tokenizer.hasMoreTokens()) {
  28.183 +                    String element = tokenizer.nextToken();
  28.184 +                    File fileElement = new File(element);
  28.185 +                    if (fileElement.exists()) {
  28.186 +                        if (patches == null) {
  28.187 +                            patches = new HashSet<File>(15);
  28.188 +                        }
  28.189 +                        patches.add(fileElement);
  28.190                      }
  28.191 -                    patches.add(fileElement);
  28.192                  }
  28.193              }
  28.194 -        }
  28.195 -        if (Util.err.isLoggable(Level.FINE)) {
  28.196 -            Util.err.fine("localeVariants of " + jar + ": " + localeVariants);
  28.197 -            Util.err.fine("plainExtensions of " + jar + ": " + plainExtensions);
  28.198 -            Util.err.fine("localeExtensions of " + jar + ": " + localeExtensions);
  28.199 -            Util.err.fine("patches of " + jar + ": " + patches);
  28.200 -        }
  28.201 -        if (patches != null) {
  28.202 -            for (File patch : patches) {
  28.203 -                events.log(Events.PATCH, patch);
  28.204 +            if (Util.err.isLoggable(Level.FINE)) {
  28.205 +                Util.err.log(Level.FINE, "patches of {0}: {1}", new Object[]{jar, patches});
  28.206 +            }
  28.207 +            if (patches != null) {
  28.208 +                for (File patch : patches) {
  28.209 +                    events.log(Events.PATCH, patch);
  28.210 +                }
  28.211 +            }
  28.212 +            if (patches == null) {
  28.213 +                patches = Collections.emptySet();
  28.214              }
  28.215          }
  28.216 +        
  28.217 +        return patches;
  28.218      }
  28.219      
  28.220 -    /** Scans a directory for possible patch JARs. */
  28.221 -    private void scanForPatches(File patchdir) {
  28.222 -        if (!patchdir.isDirectory()) {
  28.223 -            return;
  28.224 -        }
  28.225 -        File[] jars = patchdir.listFiles(Util.jarFilter());
  28.226 -        if (jars != null) {
  28.227 -            for (File patchJar : jars) {
  28.228 -                if (patches == null) {
  28.229 -                    patches = new HashSet<File>(5);
  28.230 -                }
  28.231 -                patches.add(patchJar);
  28.232 -            }
  28.233 -        } else {
  28.234 -            Util.err.warning("Could not search for patches in " + patchdir);
  28.235 -        }
  28.236 -    }
  28.237      
  28.238      /** Check if there is any need to load localized properties.
  28.239       * If so, try to load them. Throw an exception if they cannot
  28.240 @@ -508,17 +436,17 @@
  28.241       * JARs already present in the classpath are <em>not</em> listed.
  28.242       * @return a <code>List&lt;File&gt;</code> of JARs
  28.243       */
  28.244 +    @Override
  28.245      public List<File> getAllJars() {
  28.246          List<File> l = new ArrayList<File>();
  28.247 -        if (patches != null) l.addAll(patches);
  28.248 +        Set<File> ptchs = findPatches();
  28.249 +        if (ptchs != null) l.addAll(ptchs);
  28.250          if (physicalJar != null) {
  28.251              l.add(physicalJar);
  28.252          } else if (jar != null) {
  28.253              l.add(jar);
  28.254          }
  28.255 -        if (plainExtensions != null) l.addAll (plainExtensions);
  28.256 -        if (localeVariants != null) l.addAll (localeVariants);
  28.257 -        if (localeExtensions != null) l.addAll (localeExtensions);
  28.258 +        ((StandardModuleData)data()).addCp(l);
  28.259          return l;
  28.260      }
  28.261  
  28.262 @@ -548,7 +476,8 @@
  28.263          localizedProps = null;
  28.264          loadManifest();
  28.265          parseManifest();
  28.266 -        findExtensionsAndVariants(manifest);
  28.267 +    // JST:  reload not solved yet
  28.268 +    // JST   findExtensionsAndVariants(manifest);
  28.269          String codeNameBase2 = getCodeNameBase();
  28.270          if (! codeNameBase1.equals(codeNameBase2)) {
  28.271              throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N
  28.272 @@ -596,7 +525,8 @@
  28.273              loaders.add(l);
  28.274          }
  28.275          List<File> classp = new ArrayList<File>(3);
  28.276 -        if (patches != null) classp.addAll(patches);
  28.277 +        Set<File> ptchs = findPatches();
  28.278 +        if (ptchs != null) classp.addAll(ptchs);
  28.279  
  28.280          if (reloadable) {
  28.281              ensurePhysicalJar();
  28.282 @@ -607,12 +537,8 @@
  28.283          } else {
  28.284              classp.add(jar);
  28.285          }
  28.286 -        // URLClassLoader would not otherwise find these, so:
  28.287 -        if (localeVariants != null) classp.addAll(localeVariants);
  28.288 -
  28.289 -        if (localeExtensions != null) classp.addAll(localeExtensions);
  28.290 -
  28.291 -        if (plainExtensions != null) classp.addAll(plainExtensions);
  28.292 +        
  28.293 +        ((StandardModuleData)data()).addCp(classp);
  28.294          
  28.295          // #27853:
  28.296          getManager().refineClassLoader(this, loaders);
  28.297 @@ -675,6 +601,10 @@
  28.298          }
  28.299          return modulePermissions;
  28.300      }
  28.301 +    
  28.302 +    static boolean isModuleJar(File f) {
  28.303 +        return moduleJARs.contains(f);
  28.304 +    }
  28.305  
  28.306      /** Class loader to load a single module.
  28.307       * Auto-localizing, multi-parented, permission-granting, the works.
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/o.n.bootstrap/src/org/netbeans/StandardModuleData.java	Fri Mar 16 08:17:35 2012 +0100
    29.3 @@ -0,0 +1,215 @@
    29.4 +/*
    29.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    29.6 + *
    29.7 + * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
    29.8 + *
    29.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
   29.10 + * Other names may be trademarks of their respective owners.
   29.11 + *
   29.12 + * The contents of this file are subject to the terms of either the GNU
   29.13 + * General Public License Version 2 only ("GPL") or the Common
   29.14 + * Development and Distribution License("CDDL") (collectively, the
   29.15 + * "License"). You may not use this file except in compliance with the
   29.16 + * License. You can obtain a copy of the License at
   29.17 + * http://www.netbeans.org/cddl-gplv2.html
   29.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
   29.19 + * specific language governing permissions and limitations under the
   29.20 + * License.  When distributing the software, include this License Header
   29.21 + * Notice in each file and include the License file at
   29.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
   29.23 + * particular file as subject to the "Classpath" exception as provided
   29.24 + * by Oracle in the GPL Version 2 section of the License file that
   29.25 + * accompanied this code. If applicable, add the following below the
   29.26 + * License Header, with the fields enclosed by brackets [] replaced by
   29.27 + * your own identifying information:
   29.28 + * "Portions Copyrighted [year] [name of copyright owner]"
   29.29 + *
   29.30 + * If you wish your version of this file to be governed by only the CDDL
   29.31 + * or only the GPL Version 2, indicate your decision by adding
   29.32 + * "[Contributor] elects to include this software in this distribution
   29.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
   29.34 + * single choice of license, a recipient has the option to distribute
   29.35 + * your version of this file under either the CDDL, the GPL Version 2 or
   29.36 + * to extend the choice of license to its licensees as provided above.
   29.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
   29.38 + * Version 2 license, then the option applies only if the new code is
   29.39 + * made subject to such option by the copyright holder.
   29.40 + *
   29.41 + * Contributor(s):
   29.42 + *
   29.43 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
   29.44 + */
   29.45 +package org.netbeans;
   29.46 +
   29.47 +import java.io.DataInput;
   29.48 +import java.io.DataOutput;
   29.49 +import java.io.File;
   29.50 +import java.io.IOException;
   29.51 +import java.io.ObjectInput;
   29.52 +import java.io.ObjectOutput;
   29.53 +import java.util.HashMap;
   29.54 +import java.util.HashSet;
   29.55 +import java.util.List;
   29.56 +import java.util.Map;
   29.57 +import java.util.Set;
   29.58 +import java.util.StringTokenizer;
   29.59 +import java.util.jar.Attributes;
   29.60 +import java.util.jar.Manifest;
   29.61 +import java.util.logging.Level;
   29.62 +
   29.63 +/**
   29.64 + *
   29.65 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   29.66 + */
   29.67 +final class StandardModuleData extends ModuleData {
   29.68 +    /**
   29.69 +     * Map from extension JARs to sets of JAR that load them via Class-Path.
   29.70 +     * Used only for debugging purposes, so that a warning is printed if two
   29.71 +     * different modules try to load the same extension (which would cause them
   29.72 +     * to both load their own private copy, which may not be intended).
   29.73 +     */
   29.74 +    private static final Map<File, Set<File>> extensionOwners = new HashMap<File, Set<File>>();
   29.75 +    /** Set of locale-variants JARs for this module (or null).
   29.76 +     * Added explicitly to classloader, and can be used by execution engine.
   29.77 +     */
   29.78 +    private final Set<File> localeVariants;
   29.79 +    /** Set of extension JARs that this module loads via Class-Path (or null).
   29.80 +     * Can be used e.g. by execution engine. (#9617)
   29.81 +     */
   29.82 +    private final Set<File> plainExtensions;
   29.83 +    /** Set of localized extension JARs derived from plainExtensions (or null).
   29.84 +     * Used to add these to the classloader. (#9348)
   29.85 +     * Can be used e.g. by execution engine.
   29.86 +     */
   29.87 +    private final Set<File> localeExtensions;
   29.88 +    
   29.89 +    
   29.90 +    public StandardModuleData(Manifest mf, StandardModule forModule) throws InvalidException {
   29.91 +        super(mf, forModule);
   29.92 +        assert forModule instanceof StandardModule;
   29.93 +        final File jar = forModule.getJarFile();
   29.94 +        assert jar != null : "Cannot load extensions from classpath module " + getCodeNameBase();
   29.95 +        List<File> l = LocaleVariants.findLocaleVariantsOf(jar, getCodeNameBase());
   29.96 +        if (!l.isEmpty()) {
   29.97 +            localeVariants = new HashSet<File>(l);
   29.98 +        } else {
   29.99 +            localeVariants = null;
  29.100 +        }
  29.101 +        Set<File> pe = null;
  29.102 +        Set<File> le = null;
  29.103 +        String classPath = mf.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
  29.104 +        if (classPath != null) {
  29.105 +            StringTokenizer tok = new StringTokenizer(classPath);
  29.106 +            while (tok.hasMoreTokens()) {
  29.107 +                String ext = tok.nextToken();
  29.108 +                if (new File(ext).isAbsolute()) { // NOI18N
  29.109 +                    Util.err.log(Level.WARNING, "Class-Path value {0} from {1} is illegal according to the Java Extension Mechanism: must be relative", new Object[]{ext, jar});
  29.110 +                }
  29.111 +                File base = jar.getParentFile();
  29.112 +                while (ext.startsWith("../")) {
  29.113 +                    // cannot access FileUtil.normalizeFile from here, and URI.normalize might be unsafe for UNC paths
  29.114 +                    ext = ext.substring(3);
  29.115 +                    base = base.getParentFile();
  29.116 +                }
  29.117 +                File extfile = new File(base, ext.replace('/', File.separatorChar));
  29.118 +                //No need to sync on extensionOwners - we are in write mutex
  29.119 +                Set<File> owners = extensionOwners.get(extfile);
  29.120 +                if (owners == null) {
  29.121 +                    owners = new HashSet<File>(2);
  29.122 +                    owners.add(jar);
  29.123 +                    extensionOwners.put(extfile, owners);
  29.124 +                } else if (!owners.contains(jar)) {
  29.125 +                    owners.add(jar);
  29.126 +                    forModule.getManager().getEvents().log(Events.EXTENSION_MULTIPLY_LOADED, extfile, owners);
  29.127 +                } // else already know about it (OK or warned)
  29.128 +                // Also check to make sure it is not a module JAR! See constructor for the reverse case.
  29.129 +                if (StandardModule.isModuleJar(extfile)) {
  29.130 +                    Util.err.log(Level.WARNING, 
  29.131 +                        "Class-Path value {0} from {1} illegally refers to another module; use OpenIDE-Module-Module-Dependencies instead", 
  29.132 +                        new Object[]{ext, jar}
  29.133 +                    );
  29.134 +                }
  29.135 +                if (pe == null) {
  29.136 +                    pe = new HashSet<File>();
  29.137 +                }
  29.138 +                pe.add(extfile);
  29.139 +                l = LocaleVariants.findLocaleVariantsOf(extfile, getCodeNameBase());
  29.140 +                if (!l.isEmpty()) {
  29.141 +                    if (le == null) {
  29.142 +                        le = new HashSet<File>();
  29.143 +                    }
  29.144 +                    le.addAll(l);
  29.145 +                }
  29.146 +            }
  29.147 +        }
  29.148 +        localeExtensions = le;
  29.149 +        plainExtensions = pe;
  29.150 +        
  29.151 +        
  29.152 +        if (Util.err.isLoggable(Level.FINE)) {
  29.153 +            Util.err.log(Level.FINE, "localeVariants of {0}: {1}", new Object[]{jar, localeVariants});
  29.154 +            Util.err.log(Level.FINE, "plainExtensions of {0}: {1}", new Object[]{jar, plainExtensions});
  29.155 +            Util.err.log(Level.FINE, "localeExtensions of {0}: {1}", new Object[]{jar, localeExtensions});
  29.156 +        }
  29.157 +        // For the chronologically reverse case, see findExtensionsAndVariants().
  29.158 +        Set<File> bogoOwners = extensionOwners.get(jar);
  29.159 +        if (bogoOwners != null) {
  29.160 +            Util.err.log(Level.WARNING, 
  29.161 +                "module {0} was incorrectly placed in the Class-Path of other JARs {1}; please use OpenIDE-Module-Module-Dependencies instead", 
  29.162 +                new Object[]{jar, bogoOwners}
  29.163 +            );
  29.164 +        }
  29.165 +    }
  29.166 +
  29.167 +    public StandardModuleData(ObjectInput dis) throws IOException {
  29.168 +        super(dis);
  29.169 +        localeVariants = readFiles(dis);
  29.170 +        localeExtensions = readFiles(dis);
  29.171 +        plainExtensions = readFiles(dis);
  29.172 +    }
  29.173 +
  29.174 +    @Override
  29.175 +    void write(ObjectOutput dos) throws IOException {
  29.176 +        super.write(dos);
  29.177 +        writeFiles(dos, localeVariants);
  29.178 +        writeFiles(dos, localeExtensions);
  29.179 +        writeFiles(dos, plainExtensions);
  29.180 +    }
  29.181 +    
  29.182 +    private static Set<File> readFiles(DataInput is) throws IOException {
  29.183 +        int size = is.readInt();
  29.184 +        Set<File> set = new HashSet<File>();
  29.185 +        while (size-- > 0) {
  29.186 +            set.add(new File(Stamps.readRelativePath(is)));
  29.187 +        }
  29.188 +        return set;
  29.189 +    }
  29.190 +    
  29.191 +    private static void writeFiles(DataOutput os, Set<File> files) throws IOException {
  29.192 +        if (files == null) {
  29.193 +            os.writeInt(0);
  29.194 +            return;
  29.195 +        }
  29.196 +        os.writeInt(files.size());
  29.197 +        for (File f : files) {
  29.198 +            Stamps.writeRelativePath(f.getPath(), os);
  29.199 +        }
  29.200 +    }
  29.201 +    
  29.202 +    final void addCp(List<File> classp) {
  29.203 +        // URLClassLoader would not otherwise find these, so:
  29.204 +        if (localeVariants != null) {
  29.205 +            classp.addAll(localeVariants);
  29.206 +        }
  29.207 +
  29.208 +        if (localeExtensions != null) {
  29.209 +            classp.addAll(localeExtensions);
  29.210 +        }
  29.211 +
  29.212 +        if (plainExtensions != null) {
  29.213 +            classp.addAll(plainExtensions);
  29.214 +        }
  29.215 +        
  29.216 +    }
  29.217 +    
  29.218 +}
    30.1 --- a/o.n.bootstrap/test/unit/src/org/netbeans/JarClassLoaderTest.java	Thu Mar 15 16:10:40 2012 +0100
    30.2 +++ b/o.n.bootstrap/test/unit/src/org/netbeans/JarClassLoaderTest.java	Fri Mar 16 08:17:35 2012 +0100
    30.3 @@ -170,9 +170,15 @@
    30.4      
    30.5      private void doCanLoadCached(String covPkg) throws Exception {
    30.6          final File jar = new File(getWorkDir(), "default-package-resource-cached.jar");
    30.7 -        TestFileUtils.writeZipFile(jar, "resource.txt:content", "package/resource.txt:content", "META-INF/MANIFEST.MF:Covered-Packages: " + covPkg + ",\n");
    30.8 +        TestFileUtils.writeZipFile(jar, "resource.txt:content", "package/resource.txt:content", 
    30.9 +            "META-INF/MANIFEST.MF:OpenIDE-Module: x.y.z\nCovered-Packages: " + covPkg + ",\n"
   30.10 +        );
   30.11  
   30.12 -        Module fake = new Module(null, null, null, null) {
   30.13 +        MockModuleInstaller inst = new MockModuleInstaller();
   30.14 +        MockEvents ev = new MockEvents();
   30.15 +        ModuleManager mm = new ModuleManager(inst, ev);
   30.16 +        
   30.17 +        Module fake = new Module(mm, null, null, null) {
   30.18  	    public List<File> getAllJars() {throw new UnsupportedOperationException();}
   30.19              public void setReloadable(boolean r) { throw new UnsupportedOperationException();}
   30.20              public void reload() throws IOException { throw new UnsupportedOperationException();}
    31.1 --- a/php.kit/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
    31.2 +++ b/php.kit/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
    31.3 @@ -2,4 +2,4 @@
    31.4  OpenIDE-Module: org.netbeans.modules.php.kit
    31.5  OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/php/kit/Bundle.properties
    31.6  OpenIDE-Module-Specification-Version: 1.36
    31.7 -OpenIDE-Module-Recommends: org.netbeans.modules.web.client.tools.kit
    31.8 +OpenIDE-Module-Recommends: org.netbeans.modules.web.client.tools.kit,org.netbeans.modules.hudson.php
    32.1 --- a/remotefs.versioning/manifest.mf	Thu Mar 15 16:10:40 2012 +0100
    32.2 +++ b/remotefs.versioning/manifest.mf	Fri Mar 16 08:17:35 2012 +0100
    32.3 @@ -2,4 +2,5 @@
    32.4  OpenIDE-Module: org.netbeans.modules.remotefs.versioning
    32.5  OpenIDE-Module-Implementation-Version: 1
    32.6  OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/remotefs/versioning/Bundle.properties
    32.7 +OpenIDE-Module-Provides: org.netbeans.modules.remotefs.versioning
    32.8  
    33.1 --- a/remotefs.versioning/nbproject/project.properties	Thu Mar 15 16:10:40 2012 +0100
    33.2 +++ b/remotefs.versioning/nbproject/project.properties	Fri Mar 16 08:17:35 2012 +0100
    33.3 @@ -1,4 +1,4 @@
    33.4 -is.eager=true
    33.5 +is.autoload=true
    33.6  javac.source=1.6
    33.7  javac.compilerargs=-Xlint -Xlint:-serial
    33.8  spec.version.base=1.0