This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 113341
Collapse All | Expand All

(-)a/autoupdate.services/src/org/netbeans/modules/autoupdate/services/InstallManager.java (+2 lines)
Lines 368-373 Link Here
368
            }
368
            }
369
        
369
        
370
    }
370
    }
371
372
    // XXX also need locateAll
371
    
373
    
372
    /** Search all top dirs for a file. */
374
    /** Search all top dirs for a file. */
373
    private static File locateExactPath(String prefix, String name) {
375
    private static File locateExactPath(String prefix, String name) {
(-)a/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java (+2 lines)
Lines 173-178 Link Here
173
        }
173
        }
174
    }
174
    }
175
    
175
    
176
    // XXX also need locateAll
177
176
    /** Search all top dirs for a file. */
178
    /** Search all top dirs for a file. */
177
    private static File locateExactPath(String prefix, String name) {
179
    private static File locateExactPath(String prefix, String name) {
178
        assert Thread.holdsLock(InstalledFileLocatorImpl.class);
180
        assert Thread.holdsLock(InstalledFileLocatorImpl.class);
(-)a/core.startup/src/org/netbeans/core/startup/ModuleHistory.java (-80 / +1 lines)
Lines 47-72 Link Here
47
// and ModuleInfo-related things). Should be possible to use without
47
// and ModuleInfo-related things). Should be possible to use without
48
// the rest of core.
48
// the rest of core.
49
49
50
import org.openide.modules.SpecificationVersion;
51
52
/** Representation of the history of the module.
50
/** Representation of the history of the module.
53
 * This includes information such as: whether the module
54
 * has been installed before and now just needs to be restored
55
 * (or in fact where it was installed); the previous version
56
 * of the module, in case it needs to be upgraded.
57
 * Used for communication
58
 * between the module lister and the module installer.
59
 * @author Jesse Glick
51
 * @author Jesse Glick
60
 */
52
 */
61
53
// XXX no longer useful, could probably delete, and deprecate Module.history
62
public final class ModuleHistory {
54
public final class ModuleHistory {
63
    
55
    
64
    private final String jar;
56
    private final String jar;
65
    private int oldMajorVers;
66
    private SpecificationVersion oldSpecVers;
67
    private boolean upgraded;
68
    private byte[] installerState;
69
    private boolean installerStateChanged = false;
70
    
57
    
71
    /** Create a module history with essential information.
58
    /** Create a module history with essential information.
72
     * You also need to specify a relative or absolute JAR name.
59
     * You also need to specify a relative or absolute JAR name.
Lines 74-83 Link Here
74
    public ModuleHistory(String jar) {
61
    public ModuleHistory(String jar) {
75
        assert jar != null;
62
        assert jar != null;
76
        this.jar = jar;
63
        this.jar = jar;
77
        upgraded = false;
78
        oldMajorVers = -1;
79
        oldSpecVers = null;
80
        installerState = null;
81
    }
64
    }
82
    
65
    
83
    /**
66
    /**
Lines 88-153 Link Here
88
        return jar;
71
        return jar;
89
    }
72
    }
90
    
73
    
91
    /** True if this module has been installed before. */
92
    boolean isPreviouslyInstalled() {
93
        return upgraded;
94
    }
95
    
96
    /** The old major version of the module,
97
     * before an upgrade.
98
     * -1 if unspecified, or it has never been installed before.
99
     */
100
    int getOldMajorVersion() {
101
        return oldMajorVers;
102
    }
103
    
104
    /** The old specification version of the module,
105
     * before an upgrade.
106
     * null if unspecified, or it has never been installed before.
107
     */
108
    SpecificationVersion getOldSpecificationVersion() {
109
        return oldSpecVers;
110
    }
111
    
112
    /** Signal that a module has been previously installed,
113
     * marking it as a possible candidate for upgrade.
114
     */
115
    void upgrade(int oldMajorVersion, SpecificationVersion oldSpecificationVersion) {
116
        upgraded = true;
117
        oldMajorVers = oldMajorVersion;
118
        oldSpecVers = oldSpecificationVersion;
119
    }
120
    
121
    /** Get the stored state of the ModuleInstall, if any.
122
     * Currently this would be a serialized bytestream.
123
     * null if unknown or there was no stored state.
124
     */
125
    byte[] getInstallerState() {
126
        return installerState;
127
    }
128
    
129
    /** Set the stored state of the ModuleInstall.
130
     * This may be null to indicate that no state
131
     * needs to be stored. Otherwise it would currently
132
     * be a serialized bytestream.
133
     */
134
    void setInstallerState(byte[] state) {
135
        if (installerState != null && state != null) {
136
            installerStateChanged = true;
137
        }
138
        installerState = state;
139
    }
140
    
141
    /** True if the state of the installer has changed dynamically. */
142
    boolean getInstallerStateChanged() {
143
        return installerStateChanged;
144
    }
145
    
146
    /** Reset history after an uninstall. */
147
    void resetHistory() {
148
        upgraded = false;
149
        installerState = null;
150
        installerStateChanged = false;
151
    }
152
    
153
}
74
}
(-)a/core.startup/src/org/netbeans/core/startup/ModuleList.java (-302 / +40 lines)
Lines 45-51 Link Here
45
import java.beans.PropertyChangeListener;
45
import java.beans.PropertyChangeListener;
46
import java.io.BufferedInputStream;
46
import java.io.BufferedInputStream;
47
import java.io.ByteArrayInputStream;
47
import java.io.ByteArrayInputStream;
48
import java.io.ByteArrayOutputStream;
49
import java.io.CharArrayWriter;
48
import java.io.CharArrayWriter;
50
import java.io.DataOutputStream;
49
import java.io.DataOutputStream;
51
import java.io.File;
50
import java.io.File;
Lines 53-66 Link Here
53
import java.io.IOException;
52
import java.io.IOException;
54
import java.io.InputStream;
53
import java.io.InputStream;
55
import java.io.ObjectInputStream;
54
import java.io.ObjectInputStream;
56
import java.io.ObjectOutput;
57
import java.io.ObjectOutputStream;
55
import java.io.ObjectOutputStream;
58
import java.io.OutputStream;
56
import java.io.OutputStream;
59
import java.io.OutputStreamWriter;
57
import java.io.OutputStreamWriter;
60
import java.io.PushbackInputStream;
58
import java.io.PushbackInputStream;
61
import java.io.Writer;
59
import java.io.Writer;
62
import java.util.ArrayList;
60
import java.util.ArrayList;
63
import java.util.Arrays;
64
import java.util.Collections;
61
import java.util.Collections;
65
import java.util.HashMap;
62
import java.util.HashMap;
66
import java.util.HashSet;
63
import java.util.HashSet;
Lines 69-74 Link Here
69
import java.util.Map;
66
import java.util.Map;
70
import java.util.Set;
67
import java.util.Set;
71
import java.util.TreeMap;
68
import java.util.TreeMap;
69
import java.util.jar.JarFile;
72
import java.util.logging.Level;
70
import java.util.logging.Level;
73
import java.util.logging.Logger;
71
import java.util.logging.Logger;
74
import org.netbeans.DuplicateException;
72
import org.netbeans.DuplicateException;
Lines 89-102 Link Here
89
import org.openide.filesystems.FileUtil;
87
import org.openide.filesystems.FileUtil;
90
import org.openide.modules.Dependency;
88
import org.openide.modules.Dependency;
91
import org.openide.modules.InstalledFileLocator;
89
import org.openide.modules.InstalledFileLocator;
92
import org.openide.modules.ModuleInstall;
93
import org.openide.modules.SpecificationVersion;
90
import org.openide.modules.SpecificationVersion;
94
import org.openide.util.Parameters;
91
import org.openide.util.Parameters;
95
import org.openide.util.RequestProcessor;
92
import org.openide.util.RequestProcessor;
96
import org.openide.util.Utilities;
93
import org.openide.util.Utilities;
97
import org.openide.util.WeakSet;
94
import org.openide.util.WeakSet;
98
import org.openide.util.io.NbObjectInputStream;
99
import org.openide.util.io.NbObjectOutputStream;
100
import org.openide.xml.EntityCatalog;
95
import org.openide.xml.EntityCatalog;
101
import org.openide.xml.XMLUtil;
96
import org.openide.xml.XMLUtil;
102
import org.xml.sax.Attributes;
97
import org.xml.sax.Attributes;
Lines 139-146 Link Here
139
    private boolean triggered = false;
134
    private boolean triggered = false;
140
    /** listener for changes in modules, etc.; see comment on class Listener */
135
    /** listener for changes in modules, etc.; see comment on class Listener */
141
    private final Listener listener = new Listener();
136
    private final Listener listener = new Listener();
142
    /** any module install sers from externalizedModules.ser, from class name to data */
143
    private final Map<String,byte[]> compatibilitySers = new HashMap<String,byte[]>(100);
144
    /** atomic actions I have used to change Modules/*.xml */
137
    /** atomic actions I have used to change Modules/*.xml */
145
    private final Set<FileSystem.AtomicAction> myAtomicActions = Collections.<FileSystem.AtomicAction>synchronizedSet(new WeakSet<FileSystem.AtomicAction>(100));
138
    private final Set<FileSystem.AtomicAction> myAtomicActions = Collections.<FileSystem.AtomicAction>synchronizedSet(new WeakSet<FileSystem.AtomicAction>(100));
146
    
139
    
Lines 189-199 Link Here
189
            if (!f.isFile()) throw new FileNotFoundException(f.getAbsolutePath());
182
            if (!f.isFile()) throw new FileNotFoundException(f.getAbsolutePath());
190
            return f;
183
            return f;
191
        } else {
184
        } else {
192
            f = InstalledFileLocator.getDefault().locate(jar, name, false);
185
            Set<File> jars = InstalledFileLocator.getDefault().locateAll(jar, name, false);
193
            if (f != null) {
186
            if (jars.isEmpty()) {
194
                return f;
187
                throw new FileNotFoundException(jar);
188
            } else if (jars.size() == 1) {
189
                return jars.iterator().next();
195
            } else {
190
            } else {
196
                throw new FileNotFoundException(jar);
191
                // Pick the newest one available.
192
                int major = -1;
193
                SpecificationVersion spec = null;
194
                File newest = null;
195
                for (File candidate : jars) {
196
                    int candidateMajor = -1;
197
                    SpecificationVersion candidateSpec = null;
198
                    JarFile jf = new JarFile(candidate);
199
                    try {
200
                        java.util.jar.Attributes attr = jf.getManifest().getMainAttributes();
201
                        String codename = attr.getValue("OpenIDE-Module");
202
                        if (codename != null) {
203
                            int slash = codename.lastIndexOf('/');
204
                            if (slash != -1) {
205
                                candidateMajor = Integer.parseInt(codename.substring(slash + 1));
206
                            }
207
                        }
208
                        String sv = attr.getValue("OpenIDE-Module-Specification-Version");
209
                        if (sv != null) {
210
                            candidateSpec = new SpecificationVersion(sv);
211
                        }
212
                    } finally {
213
                        jf.close();
214
                    }
215
                    if (newest == null || candidateMajor > major || (spec != null && candidateSpec != null && candidateSpec.compareTo(spec) > 0)) {
216
                        newest = candidate;
217
                        major = candidateMajor;
218
                        spec = candidateSpec;
219
                    }
220
                }
221
                return newest;
197
            }
222
            }
198
        }
223
        }
199
    }
224
    }
Lines 301-497 Link Here
301
        ev.log(Events.PERF_END, "ModuleList.installNew"); // NOI18N
326
        ev.log(Events.PERF_END, "ModuleList.installNew"); // NOI18N
302
    }
327
    }
303
    
328
    
304
    /** Record initial condition of a module installer.
305
     * First, if any stored state of the installer was found on disk,
306
     * that is if it is kept in the ModuleHistory, then deserialize
307
     * it (to the found installer). If there are deserialization errors,
308
     * this step is simply skipped. Or, if there was no prerecorded state,
309
     * and the ModuleInstall class overrides writeExternal or a similar
310
     * serialization-related method, thus indicating that it wishes to
311
     * serialize state, then this initial object is serialized to the
312
     * history's state for comparison with the later value. If there are
313
     * problems with this serialization, the history receives a dummy state
314
     * (empty bytestream) to indicate that something should be saved later.
315
     * If there is no prerecorded state and no writeExternal method, it is
316
     * assumed that serialization is irrelevant to this installer and so the
317
     * state is left null and nothing will be done here or in the postpare method.
318
     * If this installer was mentioned in externalizedModules.ser, also try to
319
     * handle the situation (determine if the state was useful or not etc.).
320
     * Access from NbInstaller.
321
     */
322
    void installPrepare(Module m, ModuleInstall inst) {
323
        if (! (m.getHistory() instanceof ModuleHistory)) {
324
            LOG.fine(m + " had strange history " + m.getHistory() + ", ignoring...");
325
            return;
326
        }
327
        ModuleHistory hist = (ModuleHistory)m.getHistory();
328
        // We might have loaded something from externalizedModules.ser before.
329
        byte[] compatSer = compatibilitySers.get(inst.getClass().getName());
330
        if (compatSer != null) {
331
            LOG.fine("Had some old-style state for " + m);
332
            if (isReallyExternalizable(inst.getClass())) {
333
                // OK, maybe it was not useless, let's see...
334
                // Compare virgin state to what we had; if different, load
335
                // the old state and record that we want to track state.
336
                try {
337
                    ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
338
                    new NbObjectOutputStream(baos).writeObject(inst);
339
                    baos.close();
340
                    if (Utilities.compareObjects(compatSer, baos.toByteArray())) {
341
                        LOG.fine("Old-style state for " + m + " was gratuitous");
342
                        // leave hist.installerState null
343
                    } else {
344
                        LOG.fine("Old-style state for " + m + " was useful, loading it...");
345
                        // Make sure it is recorded as "changed" in history by writing something
346
                        // fake now. In installPostpare, we will load the new installer state
347
                        // and call setInstallerState again, so the result will be written to disk.
348
                        hist.setInstallerState(new byte[0]);
349
                        // And also load it into the actual installer.
350
                        InputStream is = new ByteArrayInputStream(compatSer);
351
                        Object o = new NbObjectInputStream(is).readObject();
352
                        if (o != inst) throw new ClassCastException("Stored " + o + " but expecting " + inst); // NOI18N
353
                    }
354
                } catch (Exception e) {
355
                    LOG.log(Level.WARNING, null, e);
356
                    // Try later to continue.
357
                    hist.setInstallerState(new byte[0]);
358
                } catch (LinkageError le) {
359
                    LOG.log(Level.WARNING, null, le);
360
                    // Try later to continue.
361
                    hist.setInstallerState(new byte[0]);
362
                }
363
            } else {
364
                LOG.fine(m + " did not want to store install state");
365
                // leave hist.installerState null
366
            }
367
        } else if (hist.getInstallerState() != null) {
368
            // We already have some state, load it now.
369
            LOG.fine("Loading install state for " + m);
370
            try {
371
                InputStream is = new ByteArrayInputStream(hist.getInstallerState());
372
                // Note: NBOOS requires the system class loader to be in order.
373
                // Technically we have not yet fired any changes in it. However,
374
                // assuming that we are not in the first block of modules to be
375
                // loaded (that is, core = bootstraps) this will work because the
376
                // available systemClassLoader is just appended to. Better would
377
                // probably be to use a special ObjectInputStream resolving
378
                // specifically to the module's classloader, as this is far more
379
                // direct and possibly more reliable.
380
                Object o = new NbObjectInputStream(is).readObject();
381
                // The joys of SharedClassObject. The deserialization itself actually
382
                // is assumed to overwrite the state of the install singleton. We
383
                // can only confirm that we actually deserialized the same thing we
384
                // were expecting too (it is too late to revert anything of course).
385
                if (o != inst) throw new ClassCastException("Stored " + o + " but expecting " + inst); // NOI18N
386
            } catch (Exception e) {
387
                // IOException, ClassNotFoundException, and maybe unchecked stuff
388
                LOG.log(Level.WARNING, null, e);
389
                // Nothing else to do, hope that the install object was not corrupted
390
                // by the failed deserialization! If it was, it cannot be saved now.
391
            } catch (LinkageError le) {
392
                LOG.log(Level.WARNING, null, le);
393
            }
394
        } else {
395
            // Virgin installer. First we check if it really cares about serialization
396
            // at all, because it not we do not want to waste time forcing it.
397
            if (isReallyExternalizable(inst.getClass())) {
398
                LOG.fine("Checking pre-install state of " + m);
399
                LOG.warning("Warning: use of writeExternal (or writeReplace) in " + inst.getClass().getName() + " is deprecated; use normal settings instead");
400
                try {
401
                    ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
402
                    new NbObjectOutputStream(baos).writeObject(inst);
403
                    baos.close();
404
                    // Keep track of the installer's state before we installed it.
405
                    // This will be compared to its state afterwards so we can
406
                    // avoid writing anything if nothing changed, thus avoid
407
                    // polluting the disk.
408
                    hist.setInstallerState(baos.toByteArray());
409
                } catch (Exception e) {
410
                    LOG.log(Level.WARNING, null, e);
411
                    // Remember that it is *supposed* to be serializable to something.
412
                    hist.setInstallerState(new byte[0]);
413
                } catch (LinkageError le) {
414
                    LOG.log(Level.WARNING, null, le);
415
                    hist.setInstallerState(new byte[0]);
416
                }
417
            } else {
418
                // It does not want to store anything. Leave the installer state null
419
                // and continue.
420
                LOG.fine(m + " did not want to store install state");
421
            }
422
        }
423
    }
424
    /** Check if a class (extends ModuleInstall) is truly externalizable,
425
     * e.g. overrides writeExternal.
426
     */
427
    private static boolean isReallyExternalizable(Class clazz) {
428
        Class<?> c;
429
        for (c = clazz; c != ModuleInstall.class && c != Object.class; c = c.getSuperclass()) {
430
            try {
431
                c.getDeclaredMethod("writeExternal", ObjectOutput.class); // NOI18N
432
                // [PENDING] check that m is public, nonstatic, returns Void.TYPE and includes at most
433
                // IOException and unchecked exceptions in its clauses, else die
434
                // OK, it does something nontrivial.
435
                return true;
436
            } catch (NoSuchMethodException nsme) {
437
                // Didn't find it at this level, continue.
438
            }
439
            try {
440
                c.getDeclaredMethod("writeReplace"); // NOI18N
441
                // [PENDING] check that m is nonstatic, returns Object, throws ObjectStreamException
442
                // Designates a serializable replacer, this is special.
443
                return true;
444
            } catch (NoSuchMethodException nsme) {
445
                // Again keep on looking.
446
            }
447
        }
448
        // Hit a superclass.
449
        if (c == Object.class) throw new IllegalArgumentException("Class " + clazz + " was not a ModuleInstall"); // NOI18N
450
        // Hit ModuleInstall. Did not find anything. Assumed to not do anything during externalization.
451
        return false;
452
    }
453
    
454
    /** Acknowledge later conditions of a module installer.
455
     * If the module history indicates a nonnull installer state, then we
456
     * try to serialize the current state to a temporary buffer and compare
457
     * to the previous state. If the serialization succeeds, and they differ,
458
     * then the new state is recorded in the history and will later be written to disk.
459
     * Access from NbInstaller.
460
     */
461
    void installPostpare(Module m, ModuleInstall inst) {
462
        if (! (m.getHistory() instanceof ModuleHistory)) {
463
            LOG.fine(m + " had strange history " + m.getHistory() + ", ignoring...");
464
            return;
465
        }
466
        ModuleHistory hist = (ModuleHistory)m.getHistory();
467
        if (hist.getInstallerState() != null) {
468
            try {
469
                ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
470
                new NbObjectOutputStream(baos).writeObject(inst);
471
                baos.close();
472
                byte[] old = hist.getInstallerState();
473
                byte[] nue = baos.toByteArray();
474
                if (Utilities.compareObjects(old, nue)) {
475
                    // State has not changed.
476
                    LOG.fine(m + " did not change installer state (" + old.length + " bytes), not writing anything");
477
                } else {
478
                    // It did change. Store new version.
479
                    LOG.fine(m + " changed installer state after loading");
480
                    hist.setInstallerState(nue);
481
                }
482
            } catch (Exception e) {
483
                LOG.log(Level.WARNING, null, e);
484
                // We could not compare, so don't bother writing out any old state.
485
                //hist.setInstallerState(null);
486
            } catch (LinkageError le) {
487
                LOG.log(Level.WARNING, null, le);
488
            }
489
        } else {
490
            // Nothing stored (does not writeExternal), do nothing.
491
            LOG.fine(m + " has no saved state");
492
        }
493
    }
494
    
495
    /** Read an XML file using an XMLReader and parse into a map of properties.
329
    /** Read an XML file using an XMLReader and parse into a map of properties.
496
     * One distinguished property 'name' is the code name base
330
     * One distinguished property 'name' is the code name base
497
     * and is taken from the root element. Others are taken
331
     * and is taken from the root element. Others are taken
Lines 579-594 Link Here
579
     * @return some parsed value suitable for the status map
413
     * @return some parsed value suitable for the status map
580
     */
414
     */
581
    private Object processStatusParam(String k, String v) throws NumberFormatException {
415
    private Object processStatusParam(String k, String v) throws NumberFormatException {
582
        if (k == "release") { // NOI18N
416
        if (k == "enabled" // NOI18N
583
            return Integer.parseInt(v);
584
        } else if (k == "enabled" // NOI18N
585
                   || k == "autoload" // NOI18N
417
                   || k == "autoload" // NOI18N
586
                   || k == "eager" // NOI18N
418
                   || k == "eager" // NOI18N
587
                   || k == "reloadable" // NOI18N
419
                   || k == "reloadable" // NOI18N
588
                   ) {
420
                   ) {
589
            return Boolean.valueOf(v);
421
            return Boolean.valueOf(v);
590
        } else if (k == "specversion") { // NOI18N
591
            return new SpecificationVersion(v);
592
        } else {
422
        } else {
593
            // Other properties are of type String.
423
            // Other properties are of type String.
594
            // Intern the smaller ones which are likely to be repeated somewhere.
424
            // Intern the smaller ones which are likely to be repeated somewhere.
Lines 610-634 Link Here
610
            && ((Boolean)m.get("eager")).booleanValue() // NOI18N
440
            && ((Boolean)m.get("eager")).booleanValue() // NOI18N
611
            && m.get("enabled") != null) // NOI18N
441
            && m.get("enabled") != null) // NOI18N
612
            throw new IOException("Eager modules cannot specify enablement"); // NOI18N
442
            throw new IOException("Eager modules cannot specify enablement"); // NOI18N
613
        // Compatibility:
614
        String origin = (String)m.remove("origin"); // NOI18N
615
        if (origin != null) {
616
            String jar = (String)m.get("jar"); // NOI18N
617
            String newjar;
618
            if (origin.equals("user") || origin.equals("installation")) { // NOI18N
619
                newjar = "modules/" + jar; // NOI18N
620
            } else if (origin.equals("user/autoload") || origin.equals("installation/autoload")) { // NOI18N
621
                newjar = "modules/autoload/" + jar; // NOI18N
622
            } else if (origin.equals("user/eager") || origin.equals("installation/eager")) { // NOI18N
623
                newjar = "modules/eager/" + jar; // NOI18N
624
            } else if (origin.equals("adhoc")) { // NOI18N
625
                newjar = jar;
626
            } else {
627
                throw new IOException("Unrecognized origin " + origin + " for " + jar); // NOI18N
628
            }
629
            LOG.warning("Upgrading 'jar' param from " + jar + " to " + newjar + " and removing 'origin' " + origin);
630
            m.put("jar", newjar); // NOI18N
631
        }
632
    }
443
    }
633
444
634
    // Encoding irrelevant for these getBytes() calls: all are ASCII...
445
    // Encoding irrelevant for these getBytes() calls: all are ASCII...
Lines 874-880 Link Here
874
        for (Map.Entry<String, Object> entry: new TreeMap<String, Object>(m).entrySet()) {
685
        for (Map.Entry<String, Object> entry: new TreeMap<String, Object>(m).entrySet()) {
875
            String name = entry.getKey();
686
            String name = entry.getKey();
876
            if (
687
            if (
877
                name.equals("installerState") || name.equals("name") || // NOI18N
688
                name.equals("name") || // NOI18N
878
                name.equals("deps") // NOI18N
689
                name.equals("deps") // NOI18N
879
            ) {
690
            ) {
880
                // Skip this one, it is a pseudo-param.
691
                // Skip this one, it is a pseudo-param.
Lines 936-971 Link Here
936
                    lock.releaseLock();
747
                    lock.releaseLock();
937
                }
748
                }
938
                //nue.lastApprovedChange = nue.file.lastModified().getTime();
749
                //nue.lastApprovedChange = nue.file.lastModified().getTime();
939
                // Now check up on the installer ser.
940
                byte[] data = (byte[])nue.diskProps.get("installerState"); // NOI18N
941
                if (data != null) {
942
                    String installerName = (String)nue.diskProps.get("installer"); // NOI18N
943
                    FileObject ser = folder.getFileObject(installerName);
944
                    if (ser == null) {
945
                        // Need to make it.
946
                        int idx = installerName.lastIndexOf('.'); // NOI18N
947
                        ser = folder.createData(installerName.substring(0, idx), installerName.substring(idx + 1));
948
                    }
949
                    // Now write it.
950
                    lock = ser.lock();
951
                    try {
952
                        OutputStream os = ser.getOutputStream(lock);
953
                        try {
954
                            os.write(data);
955
                        } finally {
956
                            os.close();
957
                        }
958
                    } finally {
959
                        lock.releaseLock();
960
                    }
961
                } else {
962
                    /* Probably not right:
963
                    // Delete any existing one.
964
                    if (ser != null) {
965
                        ser.delete();
966
                    }
967
                     */
968
                }
969
            }
750
            }
970
        };
751
        };
971
        myAtomicActions.add(aa);
752
        myAtomicActions.add(aa);
Lines 1153-1175 Link Here
1153
    
934
    
1154
    /** Compute what properties we would want to store in XML
935
    /** Compute what properties we would want to store in XML
1155
     * for this module. I.e. 'name', 'reloadable', etc.
936
     * for this module. I.e. 'name', 'reloadable', etc.
1156
     * The special property 'installerState' may be set (only
1157
     * if the normal property 'installer' is also set) and
1158
     * will be a byte[] rather than a string, which means that
1159
     * the indicated installer state should be written out.
1160
     */
937
     */
1161
    private Map<String,Object> computeProperties(Module m) {
938
    private Map<String,Object> computeProperties(Module m) {
1162
        if (m.isFixed() || ! m.isValid()) throw new IllegalArgumentException("fixed or invalid: " + m); // NOI18N
939
        if (m.isFixed() || ! m.isValid()) throw new IllegalArgumentException("fixed or invalid: " + m); // NOI18N
1163
        Map<String,Object> p = new HashMap<String,Object>();
940
        Map<String,Object> p = new HashMap<String,Object>();
1164
        p.put("name", m.getCodeNameBase()); // NOI18N
941
        p.put("name", m.getCodeNameBase()); // NOI18N
1165
        int rel = m.getCodeNameRelease();
1166
        if (rel >= 0) {
1167
            p.put("release", rel); // NOI18N
1168
        }
1169
        SpecificationVersion spec = m.getSpecificationVersion();
1170
        if (spec != null) {
1171
            p.put("specversion", spec); // NOI18N
1172
        }
1173
        if (!m.isAutoload() && !m.isEager()) {
942
        if (!m.isAutoload() && !m.isEager()) {
1174
            p.put("enabled", m.isEnabled()); // NOI18N
943
            p.put("enabled", m.isEnabled()); // NOI18N
1175
        }
944
        }
Lines 1179-1188 Link Here
1179
        if (m.getHistory() instanceof ModuleHistory) {
948
        if (m.getHistory() instanceof ModuleHistory) {
1180
            ModuleHistory hist = (ModuleHistory) m.getHistory();
949
            ModuleHistory hist = (ModuleHistory) m.getHistory();
1181
            p.put("jar", hist.getJar()); // NOI18N
950
            p.put("jar", hist.getJar()); // NOI18N
1182
            if (hist.getInstallerStateChanged()) {
1183
                p.put("installer", m.getCodeNameBase().replace('.', '-') + ".ser"); // NOI18N
1184
                p.put("installerState", hist.getInstallerState()); // NOI18N
1185
            }
1186
        }
951
        }
1187
        return p;
952
        return p;
1188
    }
953
    }
Lines 1636-1642 Link Here
1636
        }
1401
        }
1637
        private void stepCheckMisc(Map<String,Map<String,Object>> dirtyprops) {
1402
        private void stepCheckMisc(Map<String,Map<String,Object>> dirtyprops) {
1638
            LOG.fine("ModuleList: stepCheckMisc");
1403
            LOG.fine("ModuleList: stepCheckMisc");
1639
            String[] toCheck = {"jar", "autoload", "eager", "release", "specversion"}; // NOI18N
1404
            String[] toCheck = {"jar", "autoload", "eager"}; // NOI18N
1640
            for (Map.Entry<String,Map<String,Object>> entry : dirtyprops.entrySet()) {
1405
            for (Map.Entry<String,Map<String,Object>> entry : dirtyprops.entrySet()) {
1641
                String cnb = entry.getKey();
1406
                String cnb = entry.getKey();
1642
                Map<String,Object> props = entry.getValue();
1407
                Map<String,Object> props = entry.getValue();
Lines 1804-1813 Link Here
1804
                        continue;
1569
                        continue;
1805
                    }
1570
                    }
1806
                    ModuleHistory history = new ModuleHistory(jar); // NOI18N
1571
                    ModuleHistory history = new ModuleHistory(jar); // NOI18N
1807
                    Integer prevReleaseI = (Integer) props.get("release"); // NOI18N
1808
                    int prevRelease = prevReleaseI == null ? -1 : prevReleaseI.intValue();
1809
                    SpecificationVersion prevSpec = (SpecificationVersion) props.get("specversion"); // NOI18N
1810
                    history.upgrade(prevRelease, prevSpec);
1811
                    Boolean reloadableB = (Boolean) props.get("reloadable"); // NOI18N
1572
                    Boolean reloadableB = (Boolean) props.get("reloadable"); // NOI18N
1812
                    boolean reloadable = reloadableB != null ? reloadableB.booleanValue() : false;
1573
                    boolean reloadable = reloadableB != null ? reloadableB.booleanValue() : false;
1813
                    boolean enabled = enabledB != null ? enabledB.booleanValue() : false;
1574
                    boolean enabled = enabledB != null ? enabledB.booleanValue() : false;
Lines 1815-1843 Link Here
1815
                    boolean autoload = autoloadB != null ? autoloadB.booleanValue() : false;
1576
                    boolean autoload = autoloadB != null ? autoloadB.booleanValue() : false;
1816
                    Boolean eagerB = (Boolean) props.get("eager"); // NOI18N
1577
                    Boolean eagerB = (Boolean) props.get("eager"); // NOI18N
1817
                    boolean eager = eagerB != null ? eagerB.booleanValue() : false;
1578
                    boolean eager = eagerB != null ? eagerB.booleanValue() : false;
1818
                    String installer = (String) props.get("installer"); // NOI18N
1819
                    if (installer != null) {
1820
                        String nameDashes = name.replace('.', '-');
1821
                        if (!installer.equals(nameDashes + ".ser")) {
1822
                            throw new IOException("Incorrect installer ser name: " + installer); // NOI18N
1823
                        }
1824
                        // Load from disk in mentioned file.
1825
                        FileObject installerSer = folder.getFileObject(nameDashes, "ser"); // NOI18N
1826
                        if (installerSer == null) {
1827
                            throw new IOException("No such install ser: " + installer + "; I see only: " + Arrays.asList(folder.getChildren())); // NOI18N
1828
                        }
1829
                        // Hope the stored state is not >Integer.MAX_INT! :-)
1830
                        byte[] buf = new byte[(int) installerSer.getSize()];
1831
                        InputStream is2 = installerSer.getInputStream();
1832
                        try {
1833
                            is2.read(buf);
1834
                        } finally {
1835
                            is2.close();
1836
                        }
1837
                        history.setInstallerState(buf);
1838
                        // Quasi-prop which is stored separately.
1839
                        props.put("installerState", buf); // NOI18N
1840
                    }
1841
                    NbInstaller.register(name, props.get("deps")); // NOI18N
1579
                    NbInstaller.register(name, props.get("deps")); // NOI18N
1842
                    Module m = mgr.create(jarFile, history, reloadable, autoload, eager);
1580
                    Module m = mgr.create(jarFile, history, reloadable, autoload, eager);
1843
                    NbInstaller.register(null, null);
1581
                    NbInstaller.register(null, null);
(-)a/core.startup/src/org/netbeans/core/startup/NbInstaller.java (-38 / +2 lines)
Lines 417-463 Link Here
417
        if (instClazz != null) {
417
        if (instClazz != null) {
418
            ModuleInstall inst = SharedClassObject.findObject(instClazz, true);
418
            ModuleInstall inst = SharedClassObject.findObject(instClazz, true);
419
            if (load) {
419
            if (load) {
420
                if (moduleList != null) {
420
                ev.log(Events.RESTORE, m);
421
                    moduleList.installPrepare(m, inst);
421
                inst.restored();
422
                }
423
                // restore, install, or upgrade as appropriate
424
                Object history = m.getHistory();
425
                if (history instanceof ModuleHistory) {
426
                    ModuleHistory h = (ModuleHistory)history;
427
                    if (h.isPreviouslyInstalled()) {
428
                        // Check whether we have changed versions.
429
                        SpecificationVersion oldSpec = h.getOldSpecificationVersion();
430
                        SpecificationVersion nueSpec = m.getSpecificationVersion();
431
                        if (m.getCodeNameRelease() != h.getOldMajorVersion() ||
432
                                (oldSpec == null ^ nueSpec == null) ||
433
                                (oldSpec != null && nueSpec != null && oldSpec.compareTo(nueSpec) != 0)) {
434
                            // Yes, different version; upgrade from the old one.
435
                            ev.log(Events.UPDATE, m);
436
                            inst.updated(h.getOldMajorVersion(), oldSpec == null ? null : oldSpec.toString());
437
                        } else {
438
                            // Same version as before.
439
                            ev.log(Events.RESTORE, m);
440
                            inst.restored();
441
                        }
442
                    } else {
443
                        // First time.
444
                        ev.log(Events.INSTALL, m);
445
                        inst.installed();
446
                    }
447
                } else {
448
                    // Probably fixed module. Just restore.
449
                    ev.log(Events.RESTORE, m);
450
                    inst.restored();
451
                }
452
                if (moduleList != null) {
453
                    moduleList.installPostpare(m, inst);
454
                }
455
            } else {
422
            } else {
456
                ev.log(Events.UNINSTALL, m);
423
                ev.log(Events.UNINSTALL, m);
457
                inst.uninstalled();
424
                inst.uninstalled();
458
                if (m.getHistory() instanceof ModuleHistory) {
459
                    ((ModuleHistory)m.getHistory()).resetHistory();
460
                }
461
            }
425
            }
462
        }
426
        }
463
    }
427
    }
(-)a/nbbuild/antsrc/org/netbeans/nbbuild/CreateModuleXML.java (-15 lines)
Lines 47-53 Link Here
47
import java.util.jar.*;
47
import java.util.jar.*;
48
import java.io.*;
48
import java.io.*;
49
import java.util.zip.ZipEntry;
49
import java.util.zip.ZipEntry;
50
import org.apache.tools.ant.types.Mapper;
51
50
52
/** Create XML files corresponding to the set of known modules
51
/** Create XML files corresponding to the set of known modules
53
 * without actually running the IDE.
52
 * without actually running the IDE.
Lines 206-222 Link Here
206
                }
205
                }
207
                int idx = codename.lastIndexOf('/');
206
                int idx = codename.lastIndexOf('/');
208
                String codenamebase;
207
                String codenamebase;
209
                int rel;
210
                if (idx == -1) {
208
                if (idx == -1) {
211
                    codenamebase = codename;
209
                    codenamebase = codename;
212
                    rel = -1;
213
                } else {
210
                } else {
214
                    codenamebase = codename.substring(0, idx);
211
                    codenamebase = codename.substring(0, idx);
215
                    try {
216
                        rel = Integer.parseInt(codename.substring(idx + 1));
217
                    } catch (NumberFormatException e) {
218
                        throw new BuildException("Invalid OpenIDE-Module '" + codename + "' in " + module, getLocation());
219
                    }
220
                }
212
                }
221
                File xml = new File(xmldir, codenamebase.replace('.', '-') + ".xml");
213
                File xml = new File(xmldir, codenamebase.replace('.', '-') + ".xml");
222
                if (xml.exists()) {
214
                if (xml.exists()) {
Lines 262-268 Link Here
262
                    displayname = codename;
254
                    displayname = codename;
263
                }
255
                }
264
                names.add(displayname);
256
                names.add(displayname);
265
                String spec = attr.getValue("OpenIDE-Module-Specification-Version");
266
                if (isHidden) {
257
                if (isHidden) {
267
                    File h = new File(xml.getParentFile(), xml.getName() + "_hidden");
258
                    File h = new File(xml.getParentFile(), xml.getName() + "_hidden");
268
                    h.createNewFile();
259
                    h.createNewFile();
Lines 282-294 Link Here
282
                            pw.println("    <param name=\"enabled\">" + isEnabled + "</param>");
273
                            pw.println("    <param name=\"enabled\">" + isEnabled + "</param>");
283
                        }
274
                        }
284
                        pw.println("    <param name=\"jar\">" + kid.replace(File.separatorChar, '/') + "</param>");
275
                        pw.println("    <param name=\"jar\">" + kid.replace(File.separatorChar, '/') + "</param>");
285
                        if (rel != -1) {
286
                            pw.println("    <param name=\"release\">" + rel + "</param>");
287
                        }
288
                        pw.println("    <param name=\"reloadable\">false</param>");
276
                        pw.println("    <param name=\"reloadable\">false</param>");
289
                        if (spec != null) {
290
                            pw.println("    <param name=\"specversion\">" + spec + "</param>");
291
                        }
292
                        pw.println("</module>");
277
                        pw.println("</module>");
293
                        pw.flush();
278
                        pw.flush();
294
                        pw.close();
279
                        pw.close();
(-)a/openide.modules/src/org/openide/modules/InstalledFileLocator.java (-3 / +34 lines)
Lines 43-48 Link Here
43
43
44
import java.io.File;
44
import java.io.File;
45
import java.util.Collection;
45
import java.util.Collection;
46
import java.util.Collections;
47
import java.util.LinkedHashSet;
48
import java.util.Set;
46
import org.openide.util.Lookup;
49
import org.openide.util.Lookup;
47
import org.openide.util.LookupEvent;
50
import org.openide.util.LookupEvent;
48
import org.openide.util.LookupListener;
51
import org.openide.util.LookupListener;
Lines 70-75 Link Here
70
            
73
            
71
            return null;
74
            return null;
72
        }
75
        }
76
        public @Override Set<File> locateAll(String relativePath, String codeNameBase, boolean localized) {
77
            Set<File> result = null;
78
            for (InstalledFileLocator ifl : getInstances()) {
79
                Set<File> added = ifl.locateAll(relativePath, codeNameBase, localized);
80
                // avoid allocating extra lists, under the assumption there is only one result:
81
                if (!added.isEmpty()) {
82
                    if (result == null) {
83
                        result = added;
84
                    } else {
85
                        result = new LinkedHashSet<File>(result);
86
                        result.addAll(added);
87
                    }
88
                }
89
            }
90
            return result != null ? result : Collections.<File>emptySet();
91
        }
73
    };
92
    };
74
    
93
    
75
    private static InstalledFileLocator[] instances = null;
94
    private static InstalledFileLocator[] instances = null;
Lines 108-116 Link Here
108
     * useful where a directory can contain many items that may be merged between e.g.
127
     * useful where a directory can contain many items that may be merged between e.g.
109
     * the installation and user directories. For example, the <samp>docs</samp> folder
128
     * the installation and user directories. For example, the <samp>docs</samp> folder
110
     * (used e.g. for Javadoc) might contain several ZIP files in both the installation and
129
     * (used e.g. for Javadoc) might contain several ZIP files in both the installation and
111
     * user areas. There is currently no supported way to enumerate all such files. Therefore
130
     * user areas. Use {@link #locateAll} if you need all results. The module may assume
112
     * searching for a directory should be attempted only when there is just one module which
113
     * is expected to provide that directory and all of its contents. The module may assume
114
     * that all contained files are in the same relative structure in the directory as in
131
     * that all contained files are in the same relative structure in the directory as in
115
     * the normal NBM-based installation; unusual locator implementations may need to create
132
     * the normal NBM-based installation; unusual locator implementations may need to create
116
     * temporary directories with matching structures to return from this method, in case the
133
     * temporary directories with matching structures to return from this method, in case the
Lines 182-187 Link Here
182
     * @return the requested <code>File</code>, if it can be found, else <code>null</code>
199
     * @return the requested <code>File</code>, if it can be found, else <code>null</code>
183
     */
200
     */
184
    public abstract File locate(String relativePath, String codeNameBase, boolean localized);
201
    public abstract File locate(String relativePath, String codeNameBase, boolean localized);
202
203
    /**
204
     * Similar to {@link #locate} but can return multiple results.
205
     * The default implementation returns a list with zero or one elements according to {@link #locate}.
206
     * @param relativePath a path from install root
207
     * @param codeNameBase name of the supplying module or null
208
     * @param localized true to perform a localized/branded search
209
     * @return a (possibly empty) set of files
210
     * @since XXX
211
     */
212
    public Set<File> locateAll(String relativePath, String codeNameBase, boolean localized) {
213
        File f = locate(relativePath, codeNameBase, localized);
214
        return f != null ? Collections.singleton(f) : Collections.<File>emptySet();
215
    }
185
    
216
    
186
    /**
217
    /**
187
     * Get a master locator.
218
     * Get a master locator.

Return to bug 113341