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 53898
Collapse All | Expand All

(-)src/org/netbeans/core/modules/Module.java (+34 lines)
Lines 140-145 Link Here
140
     * Files are assumed to be JARs; directories are themselves.
140
     * Files are assumed to be JARs; directories are themselves.
141
     */
141
     */
142
    private Set patches = null; // Set<File>
142
    private Set patches = null; // Set<File>
143
    /** additional classpath elements from module.xml file 
144
     */
145
    private Set extraExtensions = null;
143
146
144
    /** Use ModuleManager.create as a factory. */
147
    /** Use ModuleManager.create as a factory. */
145
    Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
148
    Module(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException {
Lines 197-202 Link Here
197
        this.enabled = enabled;
200
        this.enabled = enabled;
198
    }
201
    }
199
    
202
    
203
    /** @param arr full path to array
204
     */
205
    final void assignExtraClassPath (String[] arr) {
206
        HashSet set = new HashSet ();
207
        for (int i = 0; i < arr.length; i++) {
208
            File f = new File (arr[i]);
209
            if (f.exists ()) {
210
                set.add (f);
211
            }
212
        }
213
        extraExtensions = set;
214
    }
215
    
216
    /** Getter for the extensions - returns the list.
217
     * @return null or array of files that describe our extensions
218
     */
219
    final File[] getExtraClassPath () {
220
        if (extraExtensions == null) {
221
            return null;
222
        }
223
        return (File[])extraExtensions.toArray (new File[0]);
224
    }
225
    
226
    
200
    /** Normally a module once created and managed is valid
227
    /** Normally a module once created and managed is valid
201
     * (that is, either installed or not, but at least managed).
228
     * (that is, either installed or not, but at least managed).
202
     * If it is deleted any remaining references to it become
229
     * If it is deleted any remaining references to it become
Lines 843-848 Link Here
843
        if (plainExtensions != null) l.addAll (plainExtensions);
870
        if (plainExtensions != null) l.addAll (plainExtensions);
844
        if (localeVariants != null) l.addAll (localeVariants);
871
        if (localeVariants != null) l.addAll (localeVariants);
845
        if (localeExtensions != null) l.addAll (localeExtensions);
872
        if (localeExtensions != null) l.addAll (localeExtensions);
873
        if (extraExtensions != null) l.addAll (extraExtensions);
846
        return l;
874
        return l;
847
    }
875
    }
848
876
Lines 984-989 Link Here
984
        }
1012
        }
985
        if (plainExtensions != null) {
1013
        if (plainExtensions != null) {
986
        for( it = plainExtensions.iterator(); it.hasNext(); ) {
1014
        for( it = plainExtensions.iterator(); it.hasNext(); ) {
1015
            File act = (File)it.next();
1016
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
1017
        }
1018
        }
1019
        if (extraExtensions != null) {
1020
        for( it = extraExtensions.iterator(); it.hasNext(); ) {
987
            File act = (File)it.next();
1021
            File act = (File)it.next();
988
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
1022
            classp.add(act.isDirectory() ? (Object)act : new JarFile(act, false));
989
        }
1023
        }
(-)src/org/netbeans/core/modules/ModuleList.java (+96 lines)
Lines 199-204 Link Here
199
                        props.put("installerState", buf); // NOI18N
199
                        props.put("installerState", buf); // NOI18N
200
                    }
200
                    }
201
                    Module m = mgr.create(jarFile, history, reloadable, autoload, eager);
201
                    Module m = mgr.create(jarFile, history, reloadable, autoload, eager);
202
                    
203
                    List l = (List)props.get ("extra-cp"); // NOI18N
204
                    if (l != null) {
205
                        m.assignExtraClassPath ((String[])l.toArray (new String[0]));
206
                    }
207
                    
202
                    read.add(m);
208
                    read.add(m);
203
                    DiskStatus status = new DiskStatus();
209
                    DiskStatus status = new DiskStatus();
204
                    status.module = m;
210
                    status.module = m;
Lines 573-578 Link Here
573
            private String modName;
579
            private String modName;
574
            private String paramName;
580
            private String paramName;
575
            private StringBuffer data = new StringBuffer();
581
            private StringBuffer data = new StringBuffer();
582
            private List extraClassPath;
576
	    
583
	    
577
            public void startElement(String uri,
584
            public void startElement(String uri,
578
                                     String localname,
585
                                     String localname,
Lines 592-597 Link Here
592
                    paramName = paramName.intern();
599
                    paramName = paramName.intern();
593
                    data.setLength(0);
600
                    data.setLength(0);
594
                }
601
                }
602
                else if ("extra-cp".equals (qname)) { // NOI18N
603
                    if (extraClassPath != null) {
604
                        throw new SAXException("extra-cp can be there just once"); // NOI18N
605
                    }
606
                    extraClassPath = new ArrayList ();
607
                    m.put ("extra-cp", extraClassPath); // NOI18N
608
                }
609
                else if ("path".equals (qname)) { // NOI18N
610
                    if (! (extraClassPath instanceof ArrayList)) {
611
                        throw new SAXException ("path can be just inside extra-cp"); // NOI18N
612
                    }
613
                    String location = attrs.getValue ("location"); // NOI18N
614
                    if (location == null) {
615
                        throw new SAXException ("attribute location must be present when specifying path"); // NOI18N
616
                    }
617
                    extraClassPath.add (location);
618
                }
595
            }
619
            }
596
	    
620
	    
597
            public void characters(char[] ch, int start, int len) {
621
            public void characters(char[] ch, int start, int len) {
Lines 623-628 Link Here
623
                else if ("module".equals(qname)) { // NOI18N
647
                else if ("module".equals(qname)) { // NOI18N
624
                    modName = null;
648
                    modName = null;
625
                }
649
                }
650
                else if ("extra-cp".equals (qname)) { // NOI18N
651
                    extraClassPath = java.util.Collections.unmodifiableList (extraClassPath);
652
                }
626
            }
653
            }
627
        };
654
        };
628
        
655
        
Lines 698-703 Link Here
698
//    private static final byte[] MODULE_XML_DIV1 = ">\n    <param name=\"".getBytes(); // NOI18N
725
//    private static final byte[] MODULE_XML_DIV1 = ">\n    <param name=\"".getBytes(); // NOI18N
699
    private static final byte[] MODULE_XML_INTRO_END = ">\n".getBytes(); // NOI18N
726
    private static final byte[] MODULE_XML_INTRO_END = ">\n".getBytes(); // NOI18N
700
    private static final byte[] MODULE_XML_DIV2 = "   <param name=\"".getBytes(); // NOI18N
727
    private static final byte[] MODULE_XML_DIV2 = "   <param name=\"".getBytes(); // NOI18N
728
    private static final byte[] MODULE_EXTRA_CP = "   <extra-cp>\n".getBytes(); // NOI18N
729
    private static final byte[] MODULE_SPACES = "    ".getBytes(); // NOI18N
730
    private static final byte[] MODULE_PATH = "   <path location=\"".getBytes(); // NOI18N
731
    private static final byte[] MODULE_PATH_END = "/>\n".getBytes(); // NOI18N
732
    private static final byte[] MODULE_EXTRA_CP_END = "/extra-cp>\n".getBytes(); // NOI18N
701
    private static final byte[] MODULE_XML_DIV3 = "/param>\n".getBytes(); // NOI18N
733
    private static final byte[] MODULE_XML_DIV3 = "/param>\n".getBytes(); // NOI18N
702
    private static final byte[] MODULE_XML_END = "/module>\n".getBytes(); // NOI18N
734
    private static final byte[] MODULE_XML_END = "/module>\n".getBytes(); // NOI18N
703
    /** Just like {@link #readStatus(InputSource,XMLReader} but avoids using an XML parser.
735
    /** Just like {@link #readStatus(InputSource,XMLReader} but avoids using an XML parser.
Lines 721-726 Link Here
721
            Util.err.log("Could not read stuff after cnb");
753
            Util.err.log("Could not read stuff after cnb");
722
            return null;
754
            return null;
723
        }
755
        }
756
        
757
        ArrayList extraClassPath = new ArrayList ();
758
        
724
        // Now we have <param>s some number of times, finally </module>.
759
        // Now we have <param>s some number of times, finally </module>.
725
    PARSE:
760
    PARSE:
726
        while (true) {
761
        while (true) {
Lines 729-734 Link Here
729
            case ' ':
764
            case ' ':
730
                // <param>
765
                // <param>
731
                if (!expect(is, MODULE_XML_DIV2)) {
766
                if (!expect(is, MODULE_XML_DIV2)) {
767
                    if (expect (is, MODULE_EXTRA_CP)) {
768
                        // do extra cp loading, if possible
769
                        for (;;) {
770
                            if (!expect (is, MODULE_SPACES)) {
771
                                return null;
772
                            }
773
                            int x = is.read ();
774
                            if (x == ' ') {
775
                                // path element
776
                                if (!expect (is, MODULE_PATH)) {
777
                                    Util.err.log("No path");
778
                                    return null;
779
                                }
780
                                String k = readTo(is, '"');
781
                                if (k == null) {
782
                                    Util.err.log("Could not read path");
783
                                    return null;
784
                                }
785
                                extraClassPath.add (k.intern ());
786
                                if (!expect (is, MODULE_PATH_END)) {
787
                                    Util.err.log("Could not read path end");
788
                                    return null;
789
                                }                                
790
                            } else if (x == '<') {
791
                                // </extra-cp>
792
                                if (!expect (is, MODULE_EXTRA_CP_END)) {
793
                                    return null;
794
                                } else {
795
                                    break;
796
                                }
797
                            } else {
798
                                return null;
799
                            }
800
                        }
801
                        continue;
802
                    }
732
                    Util.err.log("Could not read up to param");
803
                    Util.err.log("Could not read up to param");
733
                    return null;
804
                    return null;
734
                }
805
                }
Lines 775-780 Link Here
775
                return null;
846
                return null;
776
            }
847
            }
777
        }
848
        }
849
        
850
        if (!extraClassPath.isEmpty ()) {
851
            m.put ("extra-cp", extraClassPath); // NOI18N
852
        }
778
        sanityCheckStatus(m);
853
        sanityCheckStatus(m);
779
        return m;
854
        return m;
780
    }
855
    }
Lines 786-791 Link Here
786
    private boolean expect(InputStream is, byte[] stuff) throws IOException {
861
    private boolean expect(InputStream is, byte[] stuff) throws IOException {
787
        int len = stuff.length;
862
        int len = stuff.length;
788
        boolean inNewline = false;
863
        boolean inNewline = false;
864
        // mark the possition so we can reset on failure
865
        is.mark (stuff.length);
789
        for (int i = 0; i < len; ) {
866
        for (int i = 0; i < len; ) {
790
            int c = is.read();
867
            int c = is.read();
791
            if (c == 10 || c == 13) {
868
            if (c == 10 || c == 13) {
Lines 800-805 Link Here
800
                inNewline = false;
877
                inNewline = false;
801
            }
878
            }
802
            if (c != stuff[i++]) {
879
            if (c != stuff[i++]) {
880
                is.reset ();
803
                return false;
881
                return false;
804
            }
882
            }
805
        }
883
        }
Lines 874-879 Link Here
874
        w.write("<module name=\""); // NOI18N
952
        w.write("<module name=\""); // NOI18N
875
        w.write(XMLUtil.toAttributeValue(codeName)); // NOI18N
953
        w.write(XMLUtil.toAttributeValue(codeName)); // NOI18N
876
        w.write("\">\n");       // NOI18N
954
        w.write("\">\n");       // NOI18N
955
        
956
        File[] extraClassPath = null;
877
957
878
        // Use TreeMap to sort the keys by name; since the module status files might
958
        // Use TreeMap to sort the keys by name; since the module status files might
879
        // be version-controlled we want to avoid gratuitous format changes.
959
        // be version-controlled we want to avoid gratuitous format changes.
Lines 887-892 Link Here
887
            }
967
            }
888
            
968
            
889
            Object val = entry.getValue();
969
            Object val = entry.getValue();
970
            
971
            if (name.equals ("extra-cp")) { // NOI18N
972
                extraClassPath = (File[])val;
973
                continue;
974
            }
890
975
891
            w.write("    <param name=\""); // NOI18N
976
            w.write("    <param name=\""); // NOI18N
892
            w.write(XMLUtil.toAttributeValue(name)); // NOI18N
977
            w.write(XMLUtil.toAttributeValue(name)); // NOI18N
Lines 895-900 Link Here
895
            w.write("</param>\n"); // NOI18N
980
            w.write("</param>\n"); // NOI18N
896
        }
981
        }
897
982
983
        if (extraClassPath != null) {
984
            w.write ("    <extra-cp>\n");
985
            for (int i = 0; i < extraClassPath.length; i++) {
986
                w.write ("        <path location=\"");
987
                w.write (extraClassPath[i].toString ());
988
                w.write ("\"/>\n");
989
            }
990
            w.write ("    </extra-cp>\n");
991
        }
992
        
898
        w.write("</module>\n"); // NOI18N
993
        w.write("</module>\n"); // NOI18N
899
        w.flush();
994
        w.flush();
900
    }
995
    }
Lines 1184-1189 Link Here
1184
            p.put("installer", m.getCodeNameBase().replace('.', '-') + ".ser"); // NOI18N
1279
            p.put("installer", m.getCodeNameBase().replace('.', '-') + ".ser"); // NOI18N
1185
            p.put("installerState", hist.getInstallerState()); // NOI18N
1280
            p.put("installerState", hist.getInstallerState()); // NOI18N
1186
        }
1281
        }
1282
        p.put("extra-cp", m.getExtraClassPath ()); // NOI18N
1187
        return p;
1283
        return p;
1188
    }
1284
    }
1189
    
1285
    
(-)src/org/netbeans/core/modules/module-status-1_0.dtd (-1 / +8 lines)
Lines 29-41 Link Here
29
    <param name="release">1</param>
29
    <param name="release">1</param>
30
    <param name="reloadable">false</param>
30
    <param name="reloadable">false</param>
31
    <param name="specversion">1.6</param>
31
    <param name="specversion">1.6</param>
32
    <extra-cp>
33
        <path location="path/to/file1" />
34
        <path location="path/to/file2" />
35
    </extra-cp>
32
</module>
36
</module>
33
37
34
Such a module status would canonically be stored in the
38
Such a module status would canonically be stored in the
35
system file system with the name Modules/org-netbeans-modules-foo.xml.
39
system file system with the name Modules/org-netbeans-modules-foo.xml.
36
-->
40
-->
37
41
38
<!ELEMENT module (param)*>
42
<!ELEMENT module (param*, extra-cp?) >
39
<!ATTLIST module name CDATA #REQUIRED>
43
<!ATTLIST module name CDATA #REQUIRED>
40
<!ELEMENT param (#PCDATA)>
44
<!ELEMENT param (#PCDATA)>
41
<!ATTLIST param name CDATA #REQUIRED>
45
<!ATTLIST param name CDATA #REQUIRED>
46
<!ELEMENT extra-cp (path)* >
47
<!ELEMENT path EMPTY >
48
<!ATTLIST path location CDATA #REQUIRED>
(-)test/unit/src/org/netbeans/core/modules/ModuleListTest.java (-1 / +150 lines)
Lines 38-44 Link Here
38
    public static final class L extends ProxyLookup {
38
    public static final class L extends ProxyLookup {
39
        public L() {
39
        public L() {
40
            super(new Lookup[] {
40
            super(new Lookup[] {
41
                Lookups.singleton(new IFL()),
41
                Lookups.singleton(new IFL()), Lookups.singleton (new ErrManager ()),
42
            });
42
            });
43
        }
43
        }
44
    }
44
    }
Lines 58-63 Link Here
58
            return null;
58
            return null;
59
        }
59
        }
60
    }
60
    }
61
    private static final class ErrManager extends org.openide.ErrorManager {
62
        public static final StringBuffer messages = new StringBuffer ();
63
        
64
        public Throwable annotate (Throwable t, int severity, String message, String localizedMessage, Throwable stackTrace, java.util.Date date) {
65
            return t;
66
        }
67
        
68
        public Throwable attachAnnotations (Throwable t, org.openide.ErrorManager.Annotation[] arr) {
69
            return t;
70
        }
71
        
72
        public org.openide.ErrorManager.Annotation[] findAnnotations (Throwable t) {
73
            return null;
74
        }
75
        
76
        public org.openide.ErrorManager getInstance (String name) {
77
            return this;
78
        }
79
        
80
        public void log (int severity, String s) {
81
            messages.append (s);
82
            messages.append ('\n');
83
        }
84
        
85
        public void notify (int severity, Throwable t) {
86
            junit.framework.AssertionFailedError err = new junit.framework.AssertionFailedError (t.getMessage ());
87
            err.initCause (t);
88
            throw err;
89
        }
90
        
91
    } 
61
    
92
    
62
    public ModuleListTest(String name) {
93
    public ModuleListTest(String name) {
63
        super(name);
94
        super(name);
Lines 80-85 Link Here
80
        modulesfolder = fs.findResource("Modules");
111
        modulesfolder = fs.findResource("Modules");
81
        assertNotNull(modulesfolder);
112
        assertNotNull(modulesfolder);
82
        list = new ModuleList(mgr, modulesfolder, ev);
113
        list = new ModuleList(mgr, modulesfolder, ev);
114
        
115
        ErrManager.messages.setLength (0);
83
    }
116
    }
84
    
117
    
85
    private Module makeModule(String jarName) throws Exception {
118
    private Module makeModule(String jarName) throws Exception {
Lines 186-191 Link Here
186
        } finally {
219
        } finally {
187
            mgr.mutexPrivileged().exitReadAccess();
220
            mgr.mutexPrivileged().exitReadAccess();
188
        }
221
        }
222
    }
223
224
    /** Checks that extra-cp element is honored.
225
     */
226
    public void testExtraClassPathElementWorks () throws Exception {
227
        FileObject jar = modulesfolder.getFileSystem ().getRoot ().createData ("External.jar");
228
        File f = FileUtil.toFile (jar);
229
        assertNotNull ("File created on disk", f);
230
231
        {
232
            FileLock l = jar.lock ();
233
            java.util.jar.JarOutputStream os = new java.util.jar.JarOutputStream (jar.getOutputStream (l));
234
            os.putNextEntry (new java.util.jar.JarEntry ("external/file.txt"));
235
            os.closeEntry ();
236
            os.close ();
237
            l.releaseLock ();
238
        }
239
240
        FileObject jar2 = modulesfolder.getFileSystem ().getRoot ().createData ("External2.jar");
241
        File f2 = FileUtil.toFile (jar2);
242
        assertNotNull ("File created on disk", f2);
243
244
        {
245
            FileLock l = jar2.lock ();
246
            java.util.jar.JarOutputStream os = new java.util.jar.JarOutputStream (jar2.getOutputStream (l));
247
            os.putNextEntry (new java.util.jar.JarEntry ("external/file2.txt"));
248
            os.closeEntry ();
249
            os.close ();
250
            l.releaseLock ();
251
        }
252
253
        
254
        
255
        FileObject fooxml = modulesfolder.createData("org-foo.xml");
256
        {
257
            FileLock l = fooxml.lock ();
258
            PrintStream os = new PrintStream (fooxml.getOutputStream (l));
259
            os.println ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
260
            os.println ("<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Module Status 1.0//EN\"");
261
            os.println ("\"http://www.netbeans.org/dtds/module-status-1_0.dtd\">");
262
            os.println ("<module name=\"org.foo\">");
263
            os.println ("<param name=\"autoload\">false</param>");
264
            os.println ("<param name=\"eager\">false</param>");
265
            os.println ("<param name=\"enabled\">true</param>");
266
            os.println ("<param name=\"jar\">wherever/simple-module.jar</param>");
267
            os.println ("<param name=\"release\">1</param>");
268
            os.println ("<param name=\"reloadable\">false</param>");
269
            os.println ("<param name=\"specversion\">1.1</param>");
270
            os.println ("<extra-cp>");
271
            os.println ("  <path location=\"" + f + "\" />");
272
            os.println ("  <path location=\"" + f2 + "\" />");
273
            os.println ("</extra-cp>");
274
            os.println ("</module>");
275
            os.close ();
276
            l.releaseLock ();
277
        }
278
279
        doCheckForTestExtraClassPathElementWorks (mgr, list, false);
280
281
        assertTrue ("Shutdowning the manager, we will use another one", mgr.shutDown ());
282
        
283
        if (ErrManager.messages.indexOf ("Note - failed to parse") < 0) {
284
            fail ("We should have fallback to parsing by SAX parser as this text is not well formated: " + ErrManager.messages);
285
        }
286
        
287
        // initialize new module
288
        FakeModuleInstaller installer = new FakeModuleInstaller();
289
        FakeEvents ev = new FakeEvents();
290
        ModuleManager m = new ModuleManager(installer, ev);
291
        ErrManager.messages.setLength (0);
292
        
293
        doCheckForTestExtraClassPathElementWorks (
294
            m,
295
            new ModuleList(m, modulesfolder, ev),
296
            true
297
        );
298
        if (ErrManager.messages.indexOf ("Note - failed to parse") >= 0) {
299
            fail ("Parsing by faster method should be performed now, as the test was saved by us: " + ErrManager.messages);
300
        }
301
        
302
    }
303
    
304
    private static void doCheckForTestExtraClassPathElementWorks (ModuleManager mgr, ModuleList list, boolean enable) 
305
    throws Exception {
306
        Module m;        
307
        mgr.mutexPrivileged().enterWriteAccess();
308
        try {
309
            Set modules = list.readInitial();            
310
            assertEquals("One module", 1, modules.size ());
311
            
312
            m = (Module)modules.iterator ().next ();
313
            assertEquals ("Name is foo", "org.foo", m.getCodeNameBase ());
314
315
            assertFalse ("Is not yet enabled", m.isEnabled ());
316
            
317
            list.trigger(Collections.EMPTY_SET);
318
            
319
            assertTrue ("Is enabled", m.isEnabled ());
320
        } finally {
321
            mgr.mutexPrivileged().exitWriteAccess();
322
        }
323
        
324
        ClassLoader c = m.getClassLoader ();
325
        assertNotNull ("external.jar is in classpath", c.getResource ("external/file.txt"));
326
        assertNotNull ("external2.jar is in classpath", c.getResource ("external/file2.txt"));
327
        
328
        mgr.mutexPrivileged().enterWriteAccess();
329
        try {
330
            // and now disable the module
331
            mgr.disable (m);
332
            mgr.enable (m);
333
        } finally {
334
            mgr.mutexPrivileged().exitWriteAccess();
335
        }
336
        
337
        assertTrue ("It is ok to finish", mgr.shutDown ());
189
    }
338
    }
190
    
339
    
191
    // XXX try to read a nonempty initial list
340
    // XXX try to read a nonempty initial list

Return to bug 53898