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

(-)core/startup/src/org/netbeans/core/startup/layers/SystemFileSystem.java (-13 / +47 lines)
Lines 29-36 Link Here
29
import java.io.ObjectStreamException;
29
import java.io.ObjectStreamException;
30
import java.io.Serializable;
30
import java.io.Serializable;
31
import java.net.URL;
31
import java.net.URL;
32
import java.util.ArrayList;
33
import java.util.Arrays;
32
import java.util.HashSet;
34
import java.util.HashSet;
33
import java.util.Iterator;
35
import java.util.Iterator;
36
import java.util.List;
34
import java.util.MissingResourceException;
37
import java.util.MissingResourceException;
35
import java.util.ResourceBundle;
38
import java.util.ResourceBundle;
36
import java.util.Set;
39
import java.util.Set;
Lines 42-54 Link Here
42
import org.openide.filesystems.LocalFileSystem;
45
import org.openide.filesystems.LocalFileSystem;
43
import org.openide.filesystems.MultiFileSystem;
46
import org.openide.filesystems.MultiFileSystem;
44
import org.openide.filesystems.Repository;
47
import org.openide.filesystems.Repository;
48
import org.openide.util.Lookup;
45
import org.openide.util.NbBundle;
49
import org.openide.util.NbBundle;
46
50
47
/** The system FileSystem - represents system files under $NETBEANS_HOME/system.
51
/** The system FileSystem - represents system files under $NETBEANS_HOME/system.
48
*
52
*
49
* @author Jan Jancura, Ian Formanek, Petr Hamernik
53
* @author Jan Jancura, Ian Formanek, Petr Hamernik
50
*/
54
*/
51
public final class SystemFileSystem extends MultiFileSystem implements FileSystem.Status {
55
public final class SystemFileSystem extends MultiFileSystem 
56
implements FileSystem.Status, org.openide.util.LookupListener {
52
    // Must be public for BeanInfo to work: #11186.
57
    // Must be public for BeanInfo to work: #11186.
53
58
54
    /** generated Serialized Version UID */
59
    /** generated Serialized Version UID */
Lines 65-70 Link Here
65
    /** name of file attribute with URL to 32x32 color icon */
70
    /** name of file attribute with URL to 32x32 color icon */
66
    private static final String ATTR_ICON_32 = "SystemFileSystem.icon32"; // NOI18N
71
    private static final String ATTR_ICON_32 = "SystemFileSystem.icon32"; // NOI18N
67
72
73
    /** lookup result we listen on */
74
    private static Lookup.Result<FileSystem> result = Lookup.getDefault().lookupResult(FileSystem.class);
75
    /** the set of layers provided by the system */
76
    private static FileSystem[] layers;
77
68
    /** user fs */
78
    /** user fs */
69
    private ModuleLayeredFileSystem user;
79
    private ModuleLayeredFileSystem user;
70
    /** home fs */
80
    /** home fs */
Lines 73-85 Link Here
73
    /** @param fss list of file systems to delegate to
83
    /** @param fss list of file systems to delegate to
74
    */
84
    */
75
    @SuppressWarnings("deprecation")
85
    @SuppressWarnings("deprecation")
76
    private SystemFileSystem (FileSystem[] fss) throws PropertyVetoException {
86
    private SystemFileSystem() throws PropertyVetoException {
77
        super (fss);
87
        super(computeLayers());
78
        user = (ModuleLayeredFileSystem) fss[0];
88
        user = (ModuleLayeredFileSystem) layers[0];
79
        home = fss.length > 2 ? (ModuleLayeredFileSystem) fss[1] : null;
89
        home = layers.length > 2 ? (ModuleLayeredFileSystem) layers[1] : null;
80
90
        
81
        setSystemName (SYSTEM_NAME);
91
        setSystemName(SYSTEM_NAME);
82
        setHidden (true);
92
        setHidden(true);
93
        
94
        result.addLookupListener(this);
95
        resultChanged(null);
83
    }
96
    }
84
97
85
98
Lines 113-120 Link Here
113
            else
126
            else
114
                s.add (arr[i]);
127
                s.add (arr[i]);
115
128
129
        layers = (FileSystem[])arr.clone();
116
        // create own internal copy of passed filesystems
130
        // create own internal copy of passed filesystems
117
        setDelegates(arr.clone());
131
        setDelegates(computeLayers());
118
        firePropertyChange ("layers", null, null); // NOI18N
132
        firePropertyChange ("layers", null, null); // NOI18N
119
    }
133
    }
120
    
134
    
Lines 127-132 Link Here
127
        // don't return reference to internal buffer
141
        // don't return reference to internal buffer
128
        return getDelegates().clone();
142
        return getDelegates().clone();
129
    }
143
    }
144
    
145
    private synchronized static FileSystem[] computeLayers () {
146
        FileSystem[] fromLookup = result.allInstances ().toArray (new FileSystem[0]);
147
        
148
        if (fromLookup.length > 0) {
149
            ArrayList<FileSystem> arr = new ArrayList<FileSystem>(layers.length + fromLookup.length);
150
            arr.addAll (Arrays.asList (layers));
151
            List<FileSystem> lkpBased = Arrays.asList(fromLookup);
152
            arr.addAll(lkpBased);
153
            return arr.toArray (new FileSystem[0]);
154
        }
155
        
156
        return layers;
157
    }
130
158
131
    protected FileSystem createWritableOnForRename (String oldName, String newName) throws IOException {        
159
    protected FileSystem createWritableOnForRename (String oldName, String newName) throws IOException {        
132
        return createWritableOn (oldName);
160
        return createWritableOn (oldName);
Lines 280-286 Link Here
280
            ("org.netbeans.core.projects.FixedFileSystem", "Automatic Manifest Installation"); // NOI18N
308
            ("org.netbeans.core.projects.FixedFileSystem", "Automatic Manifest Installation"); // NOI18N
281
        arr[home == null ? 1 : 2] = FixedFileSystem.deflt;
309
        arr[home == null ? 1 : 2] = FixedFileSystem.deflt;
282
310
283
        return new SystemFileSystem (arr);
311
        layers = arr;
312
        return new SystemFileSystem ();
284
    }
313
    }
285
314
286
    /** Notification that a file has migrated from one file system
315
    /** Notification that a file has migrated from one file system
Lines 297-305 Link Here
297
    }
326
    }
298
327
299
    // --- SAFETY ---
328
    // --- SAFETY ---
300
    private Object writeReplace () throws ObjectStreamException {
329
    private Object writeReplace() throws ObjectStreamException {
301
        new NotSerializableException ("WARNING - SystemFileSystem is not designed to be serialized").printStackTrace (); // NOI18N
330
        new NotSerializableException("WARNING - SystemFileSystem is not designed to be serialized").printStackTrace(); // NOI18N
302
        return new SingletonSerializer ();
331
        return new SingletonSerializer();
332
    }
333
    
334
    /** Refresh layers */
335
    public synchronized void resultChanged(org.openide.util.LookupEvent ev) {
336
        setDelegates(computeLayers());
303
    }
337
    }
304
    
338
    
305
    private static final class SingletonSerializer extends Object implements Serializable {
339
    private static final class SingletonSerializer extends Object implements Serializable {
(-)core/startup/test/unit/src/org/netbeans/core/startup/layers/SystemFileSystemTest.java (+276 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.netbeans.core.startup.layers;
21
22
import java.io.File;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.io.OutputStream;
26
import java.util.Collections;
27
import java.util.Enumeration;
28
import java.util.Iterator;
29
import java.util.LinkedList;
30
import java.util.List;
31
import java.util.TreeSet;
32
import junit.framework.TestCase;
33
import org.netbeans.Module;
34
import org.netbeans.ModuleManager;
35
import org.netbeans.core.startup.Main;
36
import org.netbeans.core.startup.MainLookup;
37
import org.netbeans.core.startup.ModuleManagerTest;
38
import org.netbeans.junit.NbTestCase;
39
import org.openide.filesystems.FileAttributeEvent;
40
import org.openide.filesystems.FileChangeListener;
41
import org.openide.filesystems.FileEvent;
42
import org.openide.filesystems.FileObject;
43
import org.openide.filesystems.FileRenameEvent;
44
import org.openide.filesystems.FileSystem;
45
import org.openide.filesystems.FileUtil;
46
import org.openide.filesystems.Repository;
47
import org.openide.modules.ModuleInfo;
48
import org.openide.util.Lookup;
49
import org.openide.util.lookup.InstanceContent;
50
51
/** Test layering of filesystems installed via lookup.
52
 *
53
 * @author Jaroslav Tulach
54
 */
55
public class SystemFileSystemTest extends NbTestCase 
56
implements InstanceContent.Convertor<FileSystem,FileSystem>, FileChangeListener {
57
    FileSystem fs;
58
    FileSystem fs1 = FileUtil.createMemoryFileSystem();
59
    FileSystem fs2 = FileUtil.createMemoryFileSystem();
60
    private List<FileEvent> events;
61
    private File jars;
62
    
63
    public SystemFileSystemTest(String testName) {
64
        super(testName);
65
    }
66
    
67
    @Override
68
    protected void setUp() throws Exception {
69
        fs = Repository.getDefault().getDefaultFileSystem();
70
        Lookup.getDefault().lookup(ModuleInfo.class);
71
        
72
        for (FileObject fo : fs.getRoot().getChildren()) {
73
            fo.delete();
74
        }
75
        events = new LinkedList<FileEvent>();
76
        
77
        fs.addFileChangeListener(this);
78
        jars = new File(ModuleManagerTest.class.getResource("jars").getFile());
79
        clearWorkDir();
80
    }
81
    
82
    @Override
83
    protected void tearDown() throws Exception {
84
        MainLookup.unregister(fs1, this);
85
        MainLookup.unregister(fs2, this);
86
    }
87
88
    
89
90
    public void testUserHasPreferenceOverFSs() throws Exception {
91
        FileObject global = FileUtil.createData(fs.getRoot(), "dir/file.txt");
92
        global.setAttribute("global", 3);
93
        write(global, "global");
94
        
95
        FileObject fo1 = FileUtil.createData(fs1.getRoot(), "dir/file.txt");
96
        fo1.setAttribute("one", 1);
97
        write(fo1, "fileone");
98
        
99
        FileObject fo2 = FileUtil.createData(fs2.getRoot(), "dir/file.txt");
100
        fo2.setAttribute("two", 2);
101
        write(fo2, "two");
102
103
        events.clear();
104
        
105
        MainLookup.register(fs1, this);
106
        MainLookup.register(fs2, this);
107
        
108
        Enumeration<String> en = global.getAttributes();
109
        TreeSet<String> t = new TreeSet<String>();
110
        while (en.hasMoreElements()) {
111
            t.add(en.nextElement());
112
        }
113
        
114
        assertEquals("three elements: " + t, 3, t.size());
115
        assertTrue(t.contains("two"));
116
        assertTrue(t.contains("one"));
117
        assertTrue(t.contains("global"));
118
        
119
        assertEquals(1, global.getAttribute("one"));
120
        assertEquals(2, global.getAttribute("two"));
121
        assertEquals(3, global.getAttribute("global"));
122
123
        assertEquals("contains global", 6, global.getSize());
124
        assertEquals("global", read(global));
125
        
126
        
127
        assertTrue("no events: " + events, events.isEmpty());
128
    }
129
130
    public void testUserHasPreferenceOverFSsButGeneratesAnEvent() throws Exception {
131
        FileObject fo1 = FileUtil.createData(fs1.getRoot(), "dir/file.txt");
132
        fo1.setAttribute("one", 1);
133
        write(fo1, "fileone");
134
        
135
        FileObject fo2 = FileUtil.createData(fs2.getRoot(), "dir/file.txt");
136
        fo2.setAttribute("two", 2);
137
        write(fo2, "two");
138
139
        events.clear();
140
        
141
        MainLookup.register(fs1, this);
142
        MainLookup.register(fs2, this);
143
144
        assertFalse("not empty", events.isEmpty());
145
        events.clear();
146
        
147
        FileObject global = FileUtil.createData(fs.getRoot(), "dir/file.txt");
148
        global.setAttribute("global", 3);
149
        write(global, "global");
150
        
151
        assertFalse("yet another set", events.isEmpty());
152
        
153
        Enumeration<String> en = global.getAttributes();
154
        TreeSet<String> t = new TreeSet<String>();
155
        while (en.hasMoreElements()) {
156
            t.add(en.nextElement());
157
        }
158
159
        
160
        
161
        assertEquals("three elements: " + t, 3, t.size());
162
        assertTrue(t.contains("two"));
163
        assertTrue(t.contains("one"));
164
        assertTrue(t.contains("global"));
165
        
166
        assertEquals(1, global.getAttribute("one"));
167
        assertEquals(2, global.getAttribute("two"));
168
        assertEquals(3, global.getAttribute("global"));
169
170
        assertEquals("contains global", 6, global.getSize());
171
        assertEquals("global", read(global));
172
    }
173
    
174
    public void testPreferenceOfLayers() throws Exception {
175
        ModuleManager mgr = Main.getModuleSystem ().getManager();
176
        mgr.mutexPrivileged().enterWriteAccess();
177
        try {
178
            Module m1 = mgr.create(new File(jars, "base-layer-mod.jar"), null, false, false, false);
179
            assertEquals(Collections.EMPTY_SET, m1.getProblems());
180
            mgr.enable(m1);
181
            FileObject global = fs.findResource("foo/file2.txt");
182
            assertNotNull("File Object installed: " + global, global);
183
            assertEquals("base contents", read(global));
184
            
185
            
186
            FileObject fo1 = FileUtil.createData(fs1.getRoot(), global.getPath());
187
            fo1.setAttribute("one", 1);
188
            write(fo1, "fileone");
189
190
            FileObject fo2 = FileUtil.createData(fs2.getRoot(), global.getPath());
191
            fo2.setAttribute("two", 2);
192
            write(fo2, "two");
193
194
            events.clear();
195
196
            MainLookup.register(fs1, this);
197
            MainLookup.register(fs2, this);
198
            
199
            Iterator<? extends FileSystem> it = Lookup.getDefault().lookupAll(FileSystem.class).iterator();
200
            assertTrue("At least One", it.hasNext());
201
            assertEquals("first is fs1", fs1, it.next());
202
            assertTrue("At least two ", it.hasNext());
203
            assertEquals("first is fs2", fs2, it.next());
204
            
205
            
206
            
207
            assertEquals("base contents", read(global));
208
            
209
            
210
            mgr.disable(m1);
211
            mgr.delete(m1);
212
            
213
            assertTrue("Still valid", global.isValid());
214
            assertEquals("fileone", read(global));
215
            
216
            
217
        } finally {
218
            mgr.mutexPrivileged().exitWriteAccess();
219
        }
220
        
221
    }
222
    
223
    private static void write(FileObject fo, String txt) throws IOException {
224
        OutputStream os = fo.getOutputStream();
225
        os.write(txt.getBytes());
226
        os.close();
227
    }
228
    
229
    private static String read(FileObject fo) throws IOException {
230
        byte[] arr = new byte[(int)fo.getSize()];
231
        InputStream is = fo.getInputStream();
232
        int len = is.read(arr);
233
        assertEquals("Not enough read", arr.length, len);
234
        return new String(arr);
235
    }
236
237
    public FileSystem convert(FileSystem obj) {
238
        return obj;
239
    }
240
241
    public Class<? extends FileSystem> type(FileSystem obj) {
242
        return obj.getClass();
243
    }
244
245
    public String id(FileSystem obj) {
246
        return obj.getDisplayName();
247
    }
248
249
    public String displayName(FileSystem obj) {
250
        return obj.getDisplayName();
251
    }
252
253
    public void fileFolderCreated(FileEvent fe) {
254
        events.add(fe);
255
    }
256
257
    public void fileDataCreated(FileEvent fe) {
258
        events.add(fe);
259
    }
260
261
    public void fileChanged(FileEvent fe) {
262
        events.add(fe);
263
    }
264
265
    public void fileDeleted(FileEvent fe) {
266
        events.add(fe);
267
    }
268
269
    public void fileRenamed(FileRenameEvent fe) {
270
        events.add(fe);
271
    }
272
273
    public void fileAttributeChanged(FileAttributeEvent fe) {
274
        events.add(fe);
275
    }
276
}
(-)openide/arch/arch-openide-filesystems.xml (-1 / +350 lines)
Lines 22-28 Link Here
22
]>
22
]>
23
23
24
<api-answers
24
<api-answers
25
  question-version="1.12"
25
  question-version="1.29"
26
  author="rmatous@netbeans.org"
26
  author="rmatous@netbeans.org"
27
>
27
>
28
28
Lines 718-722 Link Here
718
<answer id="resources-read">
718
<answer id="resources-read">
719
No.
719
No.
720
</answer>
720
</answer>
721
722
723
724
725
<!--
726
        <question id="arch-overall" when="init">
727
            Describe the overall architecture. 
728
            <hint>
729
            What will be API for 
730
            <a href="http://openide.netbeans.org/tutorial/api-design.html#design.apiandspi" shape="rect">
731
                clients and what support API</a>? 
732
            What parts will be pluggable?
733
            How will plug-ins be registered? Please use <code>&lt;api type="export"/&gt;</code>
734
            to describe your general APIs and specify their
735
            <a href="http://openide.netbeans.org/tutorial/api-design.html#category-private" shape="rect">
736
            stability categories</a>.
737
            If possible please provide simple diagrams.
738
            </hint>
739
        </question>
740
-->
741
 <answer id="arch-overall">
742
  <p>
743
   NetBeans internally uses the concept of a virtual filesystem. This module
744
   provide APIs for accessing such virtual files as well as some support classes
745
   to make writing of custom vitual filesystems easier.
746
  </p>
747
 </answer>
748
749
750
751
<!--
752
        <question id="arch-quality" when="init">
753
            How will the <a href="http://www.netbeans.org/community/guidelines/q-evangelism.html" shape="rect">quality</a>
754
            of your code be tested and 
755
            how are future regressions going to be prevented?
756
            <hint>
757
            What kind of testing do
758
            you want to use? How much functionality, in which areas,
759
            should be covered by the tests? How you find out that your
760
            project was successful?
761
            </hint>
762
        </question>
763
-->
764
 <answer id="arch-quality">
765
  <p>
766
   XXX no answer for arch-quality
767
  </p>
768
 </answer>
769
770
771
772
<!--
773
        <question id="arch-time" when="init">
774
            What are the time estimates of the work?
775
            <hint>
776
            Please express your estimates of how long the design, implementation,
777
            stabilization are likely to last. How many people will be needed to
778
            implement this and what is the expected milestone by which the work should be 
779
            ready?
780
            </hint>
781
        </question>
782
-->
783
 <answer id="arch-time">
784
  <p>
785
   XXX no answer for arch-time
786
  </p>
787
 </answer>
788
789
790
791
<!--
792
        <question id="arch-usecases" when="init">
793
            <hint>
794
                Content of this answer will be displayed as part of page at
795
                http://www.netbeans.org/download/dev/javadoc/usecases.html 
796
                You can use tags &lt;usecase name="name&gt; regular html description &lt;/usecase&gt;
797
                and if you want to use an URL you can prefix if with @TOP@ to begin
798
                at the root of your javadoc
799
            </hint>
800
        
801
            Describe the main <a href="http://openide.netbeans.org/tutorial/api-design.html#usecase" shape="rect">
802
            use cases</a> of the new API. Who will use it under
803
            what circumstances? What kind of code would typically need to be written
804
            to use the module?
805
        </question>
806
-->
807
 <answer id="arch-usecases">
808
  <p>
809
   Many of the usecases are described at the
810
   <a href="@TOP@/org/openide/filesystems/doc-files/api.html">overall documentation</a>,
811
   in a way how to 
812
   <a href="@TOP@/org/openide/filesystems/doc-files/HOWTO-MIME.html">register a mime type</a>.
813
   Some of the additional usecases are covered here.
814
  </p>
815
  
816
  <usecase id="login-changes" name="How to change menus, etc. after login?">
817
      <p>
818
      Since version 7.1 there is a way to change the content of system file
819
      system in a dynamic way. As system file systems contains various 
820
      definitions (in NetBeans Platform menus, toolbars, layout of windows, etc.)
821
      it de-facto allows global change to these settings for example when
822
      user logs into some system.
823
      </p>
824
      
825
      <p>
826
          First thing to do is to create an implementation of filesystem.
827
          It can be created either from scratch, or by subclassing
828
          <a href="@TOP@/org/openide/filesystems/AbstractFileSystem.html">AbstractFileSystem</a>,
829
          or
830
          <a href="@TOP@/org/openide/filesystems/MultiFileSystem.html">MultiFileSystem</a>.
831
          In this example we will subclass the 
832
          <a href="@TOP@/org/openide/filesystems/MultiFileSystem.html">MultiFileSystem</a>:
833
      </p>
834
      
835
      <pre>
836
public class LoginFileSystem extends <a href="@TOP@/org/openide/filesystems/MultiFileSystem.html">MultiFileSystem</a> {
837
  public LoginFileSystem() {
838
    // let's create the filesystem empty, because the user
839
    // is not yet logged in
840
    super(new FileSystem[0]);
841
  }
842
  
843
  public static void assignURL(URL u) {
844
    LoginFileSystem lfs = <a href="@org-openide-util@/org/openide/util/Lookup.html">Lookup</a>.getDefault().lookup(LoginFileSystem.class);
845
    <a href="@TOP@/org/openide/filesystems/XMLFileSystem.html">XMLFileSystem</a> xmlFS = new <a href="@TOP@/org/openide/filesystems/XMLFileSystem.html">XMLFileSystem</a>(u);
846
    lfs.setDelegates(new FileSystem[] { xmlFS });
847
  }
848
}
849
      </pre>
850
      
851
      <p>
852
      It is necessary to register this instance in lookup by creating two files:
853
      </p>
854
      <ul>
855
          <li><code>META-INF/services/org.openide.filesystems.FileSystem</code></li>
856
          <li><code>META-INF/services/your.module.LoginFileSystem</code></li>
857
      </ul>
858
      <p>
859
          and filling these files with a single line containing the full
860
          name of your filesystem - e.g. <code>your.module.LoginFileSystem</code>.
861
          When done, the system will find out your registration of the filesystem
862
          on startup and will merge the content of the filesystem into the 
863
          default system file system. You can show a dialog letting the user
864
          to log in to some system anytime later, and when the user is successfully
865
          in, just call <code>LoginFileSystem.assignURL(url)</code> where the
866
          URL is an XML file in <a href="@TOP@/org/openide/filesystems/XMLFileSystem.html">the same format</a>
867
          as used for regular layer files inside of many NetBeans modules.
868
          The system will notice the change in the content and notify all the
869
          config file listeners accordingly.
870
      </p>
871
      
872
      <p>
873
          Of course, instead of 
874
          <a href="@TOP@/org/openide/filesystems/XMLFileSystem.html">XMLFileSystem</a>
875
          you can use for example
876
          <a href="@TOP@/org/openide/filesystems/FileUtil.html#createMemoryFileSystem()">memory file system</a>,
877
          or any other you write yourself.
878
      </p>
879
  </usecase>
880
 </answer>
881
882
883
884
<!--
885
        <question id="arch-where" when="impl">
886
            Where one can find sources for your module?
887
            <hint>
888
                Please provide link to the CVS web client at
889
                http://www.netbeans.org/download/source_browse.html
890
                or just use tag defaultanswer generate='here'
891
            </hint>
892
        </question>
893
-->
894
 <answer id="arch-where">
895
  <defaultanswer generate='here' />
896
 </answer>
897
898
899
900
<!--
901
        <question id="compat-deprecation" when="init">
902
            How the introduction of your project influences functionality
903
            provided by previous version of the product?
904
            <hint>
905
            If you are planning to deprecate/remove/change any existing APIs,
906
            list them here accompanied with the reason explaining why you
907
            are doing so.
908
            </hint>
909
        </question>
910
-->
911
 <answer id="compat-deprecation">
912
  <p>
913
   XXX no answer for compat-deprecation
914
  </p>
915
 </answer>
916
917
918
919
<!--
920
        <question id="deploy-dependencies" when="final">
921
            What do other modules need to do to declare a dependency on this one,
922
            in addition to or instead of the normal module dependency declaration
923
            (e.g. tokens to require)?
924
            <hint>
925
                Provide a sample of the actual lines you would add to a module manifest
926
                to declare a dependency, for example OpenIDE-Module-Requires: some.token.
927
                If other modules should not depend on this module, or should just use a
928
                simple regular module dependency, you can just answer "nothing". If you
929
                intentionally expose a semistable API to clients using implementation
930
                dependencies, you should mention that here (but there is no need to give
931
                an example of usage).
932
            </hint>
933
        </question>
934
-->
935
 <answer id="deploy-dependencies">
936
  <p>
937
   XXX no answer for deploy-dependencies
938
  </p>
939
 </answer>
940
941
942
943
<!--
944
        <question id="exec-ant-tasks" when="impl">
945
            Do you define or register any ant tasks that other can use?
946
            
947
            <hint>
948
            If you provide an ant task that users can use, you need to be very
949
            careful about its syntax and behaviour, as it most likely forms an
950
	          API for end users and as there is a lot of end users, their reaction
951
            when such API gets broken can be pretty strong.
952
            </hint>
953
        </question>
954
-->
955
 <answer id="exec-ant-tasks">
956
  <p>
957
   XXX no answer for exec-ant-tasks
958
  </p>
959
 </answer>
960
961
962
963
<!--
964
        <question id="exec-threading" when="init">
965
            What threading models, if any, does your module adhere to? How the
966
            project behaves with respect to threading?
967
            <hint>
968
                Is your API threadsafe? Can it be accessed from any threads or
969
                just from some dedicated ones? Any special relation to AWT and
970
                its Event Dispatch thread? Also
971
                if your module calls foreign APIs which have a specific threading model,
972
                indicate how you comply with the requirements for multithreaded access
973
                (synchronization, mutexes, etc.) applicable to those APIs.
974
                If your module defines any APIs, or has complex internal structures
975
                that might be used from multiple threads, declare how you protect
976
                data against concurrent access, race conditions, deadlocks, etc.,
977
                and whether such rules are enforced by runtime warnings, errors, assertions, etc.
978
                Examples: a class might be non-thread-safe (like Java Collections); might
979
                be fully thread-safe (internal locking); might require access through a mutex
980
                (and may or may not automatically acquire that mutex on behalf of a client method);
981
                might be able to run only in the event queue; etc.
982
                Also describe when any events are fired: synchronously, asynchronously, etc.
983
                Ideas: <a href="http://core.netbeans.org/proposals/threading/index.html#recommendations" shape="rect">Threading Recommendations</a> (in progress)
984
            </hint>
985
        </question>
986
-->
987
 <answer id="exec-threading">
988
  <p>
989
   XXX no answer for exec-threading
990
  </p>
991
 </answer>
992
993
994
995
<!--
996
        <question id="perf-spi" when="init">
997
            How the performance of the plugged in code will be enforced?
998
            <hint>
999
            If you allow foreign code to be plugged into your own module, how
1000
            do you enforce that it will behave correctly and quickly and will not
1001
            negatively influence the performance of your own module?
1002
            </hint>
1003
        </question>
1004
-->
1005
 <answer id="perf-spi">
1006
  <p>
1007
   XXX no answer for perf-spi
1008
  </p>
1009
 </answer>
1010
1011
1012
1013
<!--
1014
        <question id="resources-preferences" when="final">
1015
            Does your module uses preferences via Preferences API? Does your module use NbPreferences or
1016
            or regular JDK Preferences ? Does it read, write or both ? 
1017
            Does it share preferences with other modules ? If so, then why ?
1018
            <hint>
1019
                You may use
1020
                    &lt;api type="export" group="preferences"
1021
                    name="preference node name" category="private"&gt;
1022
                    description of individual keys, where it is used, what it
1023
                    influences, whether the module reads/write it, etc.
1024
                    &lt;/api&gt;
1025
                Due to XML ID restrictions, rather than /org/netbeans/modules/foo give the "name" as org.netbeans.modules.foo.
1026
                Note that if you use NbPreferences this name will then be the same as the code name base of the module.
1027
            </hint>
1028
        </question>
1029
-->
1030
 <answer id="resources-preferences">
1031
  <p>
1032
   XXX no answer for resources-preferences
1033
  </p>
1034
 </answer>
1035
1036
1037
1038
<!--
1039
        <question id="security-grant" when="final">
1040
            Does your code grant additional rights to some other code?
1041
            <hint>Avoid using a class loader that adds extra
1042
            permissions to loaded code unless really necessary.
1043
            Also note that your API implementation
1044
            can also expose unneeded permissions to enemy code by
1045
            calling AccessController.doPrivileged().</hint>
1046
        </question>
1047
-->
1048
 <answer id="security-grant">
1049
  <p>
1050
   XXX no answer for security-grant
1051
  </p>
1052
 </answer>
1053
1054
1055
1056
<!--
1057
        <question id="security-policy" when="final">
1058
            Does your functionality require modifications to the standard policy file?
1059
            <hint>Your code might pass control to third-party code not
1060
            coming from trusted domains. This could be code downloaded over the
1061
            network or code coming from libraries that are not bundled
1062
            with NetBeans. Which permissions need to be granted to which domains?</hint>
1063
        </question>
1064
-->
1065
 <answer id="security-policy">
1066
  <p>
1067
   XXX no answer for security-policy
1068
  </p>
1069
 </answer>
721
1070
722
</api-answers>
1071
</api-answers>
(-)openide/fs/apichanges.xml (+22 lines)
Lines 23-28 Link Here
23
        <apidef name="filesystems">Filesystems API</apidef>
23
        <apidef name="filesystems">Filesystems API</apidef>
24
    </apidefs>
24
    </apidefs>
25
    <changes>
25
    <changes>
26
        <change id="add-content-to-sfs">
27
            <api name="filesystems"/>
28
            <summary>Allow modules to dynamically add/remove layer content</summary>
29
            <version major="7" minor="1"/>
30
            <date day="12" month="3" year="2007"/>
31
            <author login="jtulach"/>
32
            <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
33
            <description>
34
                <p>
35
                    Repository.getDefaultFileSystem's content can now be 
36
                    influenced by adding own 
37
                    <a href="@TOP@/org/openide/filesystems/FileSystem.html">FileSystem</a>s
38
                    into global 
39
                    <a href="@org-openide-util@/org/openide/util/Lookup.html">Lookup.getDefault()</a>.
40
                    This is supposed to work in a standalone mode as well 
41
                    as inside NetBeans Platform. The tutorial is available
42
                    in the <a href="@TOP@/architecture-summary.html#answer-arch-usecases">usecases section</a> of achitecture description.
43
                </p>
44
            </description>
45
            <class package="org.openide.filesystems" name="Repository"/>
46
            <issue number="26338"/>
47
        </change>
26
        <change id="createData-and-createFolder-take-File-as-parameter">
48
        <change id="createData-and-createFolder-take-File-as-parameter">
27
            <api name="filesystems"/>
49
            <api name="filesystems"/>
28
            <summary>Added additional methods <code>FileUtil.createData</code>
50
            <summary>Added additional methods <code>FileUtil.createData</code>
(-)openide/fs/manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.filesystems
2
OpenIDE-Module: org.openide.filesystems
3
OpenIDE-Module-Specification-Version: 7.0
3
OpenIDE-Module-Specification-Version: 7.1
4
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties
5
5
(-)openide/fs/src/org/openide/filesystems/ExternalUtil.java (-1 / +28 lines)
Lines 18-27 Link Here
18
 */
18
 */
19
package org.openide.filesystems;
19
package org.openide.filesystems;
20
20
21
import java.util.ArrayList;
22
import java.util.List;
21
import java.util.logging.Level;
23
import java.util.logging.Level;
22
import java.util.logging.Logger;
24
import java.util.logging.Logger;
23
import org.openide.util.Exceptions;
25
import org.openide.util.Exceptions;
24
import org.openide.util.Lookup;
26
import org.openide.util.Lookup;
27
import org.openide.util.LookupEvent;
28
import org.openide.util.LookupListener;
25
29
26
30
27
/** Contains utility methods to deal with repository and error manager,
31
/** Contains utility methods to deal with repository and error manager,
Lines 120-126 Link Here
120
124
121
        if (repository == null) {
125
        if (repository == null) {
122
            // if not provided use default one
126
            // if not provided use default one
123
            repository = new Repository(FileUtil.createMemoryFileSystem());
127
            repository = new Repository(new MainFS());
124
        }
128
        }
125
    }
129
    }
130
    
131
    private static final class MainFS extends MultiFileSystem implements LookupListener {
132
        private static final Lookup.Result<FileSystem> ALL = Lookup.getDefault().lookupResult(FileSystem.class);
133
        private static final FileSystem MEMORY = FileUtil.createMemoryFileSystem();
134
        
135
        public MainFS() {
136
            super(computeDelegates());
137
            ALL.addLookupListener(this);
138
            resultChanged(null);
139
        }
140
        
141
        private static FileSystem[] computeDelegates() {
142
            List<FileSystem> arr = new ArrayList<FileSystem>();
143
            arr.add(MEMORY);
144
            arr.addAll(ALL.allInstances());
145
            return arr.toArray(new FileSystem[0]);
146
        }
147
        
148
    
149
        public void resultChanged(LookupEvent ev) {
150
            setDelegates(computeDelegates());
151
        }
152
    } // end of MainFS
126
}
153
}
(-)openide/fs/test/unit/src/org/openide/filesystems/RepositoryTest.java (+65 lines)
Added Link Here
1
/*
2
 * The contents of this file are subject to the terms of the Common Development
3
 * and Distribution License (the License). You may not use this file except in
4
 * compliance with the License.
5
 *
6
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7
 * or http://www.netbeans.org/cddl.txt.
8
 *
9
 * When distributing Covered Code, include this CDDL Header Notice in each file
10
 * and include the License file at http://www.netbeans.org/cddl.txt.
11
 * If applicable, add the following below the CDDL Header, with the fields
12
 * enclosed by brackets [] replaced by your own identifying information:
13
 * "Portions Copyrighted [year] [name of copyright owner]"
14
 *
15
 * The Original Software is NetBeans. The Initial Developer of the Original
16
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17
 * Microsystems, Inc. All Rights Reserved.
18
 */
19
20
package org.openide.filesystems;
21
22
import junit.framework.TestCase;
23
import org.openide.util.lookup.AbstractLookup;
24
import org.openide.util.lookup.InstanceContent;
25
26
/**
27
 *
28
 * @author Jaroslav Tulach
29
 */
30
public class RepositoryTest extends TestCase {
31
    static {
32
        System.setProperty("org.openide.util.Lookup", MainLookup.class.getName());
33
    }
34
    
35
    
36
    public RepositoryTest(String testName) {
37
        super(testName);
38
    }
39
40
    
41
    public void testContentOfFileSystemIsInfluencedByLookup () throws Exception {
42
        FileSystem mem = FileUtil.createMemoryFileSystem();
43
        String dir = "/yarda/own/file";
44
        org.openide.filesystems.FileUtil.createFolder (mem.getRoot (), dir);
45
        
46
        assertNull ("File is not there yet", Repository.getDefault ().getDefaultFileSystem ().findResource (dir));
47
        MainLookup.ic.add(mem);
48
        try {
49
            assertNotNull ("The file is there now", Repository.getDefault ().getDefaultFileSystem ().findResource (dir));
50
        } finally {
51
            MainLookup.ic.remove(mem);
52
        }
53
        assertNull ("File is no longer there", Repository.getDefault ().getDefaultFileSystem ().findResource (dir));
54
    }
55
    
56
    
57
    public static final class MainLookup extends AbstractLookup {
58
        static final InstanceContent ic = new InstanceContent();
59
        
60
        
61
        public MainLookup() {
62
            super(ic);
63
        }
64
    }
65
}

Return to bug 26338