KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > catalog > settings > CatalogSettings


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 package org.netbeans.modules.xml.catalog.settings;
20
21 import java.io.*;
22 import java.util.*;
23 import java.beans.*;
24 import org.netbeans.modules.xml.catalog.lib.IteratorIterator;
25
26 import org.openide.*;
27 import org.openide.util.HelpCtx;
28 import org.openide.util.io.NbMarshalledObject;
29
30 import org.netbeans.modules.xml.catalog.spi.*;
31 import org.openide.filesystems.FileObject;
32 import org.openide.filesystems.FileSystem;
33 import org.openide.filesystems.Repository;
34 import org.openide.loaders.DataFolder;
35 import org.openide.loaders.DataObject;
36 import org.openide.loaders.DataObjectNotFoundException;
37 import org.openide.loaders.FolderLookup;
38 import org.openide.util.Lookup;
39 import org.openide.util.LookupListener;
40 import org.openide.util.LookupEvent;
41 import org.openide.util.lookup.Lookups;
42
43
44 /**
45  * The pool holding mounted catalogs both at per project basics
46  * and at at global basics. Project scope catalogs are always considered a higher
47  * priority ones.
48  * <p>
49  * Global scope catalogs are intended to be used by semantics modules for
50  * which one can assume that if an user enabled such module then the user
51  * really wants to have enabled module catalog. It can be done declarativelly
52  * at module layer as <code>InstanceCookie</code> providers of {@link CatalogReader}:
53  * <pre>
54  * <filesystem>
55  * <folder name="Plugins"><folder name="XML"><folder name="UserCatalogs">
56  * <file name="org-mycompany-mymodule-MyCatalog.instance">
57  * <attr name="instanceCreate"
58  * methodValue="org.mycompany.mymodule.MyCatalog.createSingleton"/>
59  * <attr name="instanceOf"
60  * stringValue="org.netbeans.modules.xml.catalog.spi.CatalogReader"/>
61  * </file>
62  * </folder></folder></folder>
63  * </filesystem>
64  * </pre>
65  * <p>
66  * Project scope settings are currently only accesible by this class <coda>addCatalog</code>
67  * and <code>removeCatalog</code> methods. It's persistent for <code>Serializable</code>
68  * implementations.
69  *
70  * @deprecated Modules are highly suggested to use declarative registrations
71  * of global catalogs. Project scope catalogs should be managed by user via UI only.
72  *
73  * @thread implementation is thread safe
74  *
75  * @author Petr Kuzel
76  */

77 public final class CatalogSettings implements Externalizable {
78
79     /** Serial Version UID */
80     private static final long serialVersionUID = 7895789034L;
81
82     public static final int VERSION_1 = 1; //my externalization protocol version
83

84     /** Identifies property holding mounted catalogs */
85     public static final String JavaDoc PROP_MOUNTED_CATALOGS = "catalogs"; // NOI18N
86

87     // folder at SFS holding global registrations
88
private static final String JavaDoc REGISTRATIONS = "Plugins/XML/UserCatalogs";
89
90     /**
91      * Project has changed. You MUST switch to new settings instance.
92      * It is fired at the old instance.
93      * @deprecated It is hack for NetBeans 3.X lacking project system
94      */

95     public static final String JavaDoc PROP_PRJ_INSTANCE = "cat-prj-in";
96     
97     // cached instance
98
private static Lookup userCatalogLookup;
99
100     // ordered set of mounted catalogs
101
private List mountedCatalogs = new ArrayList(5);
102
103     private PropertyChangeSupport listeners = null;
104
105     private final CatalogListener catalogListener = new CL();
106     
107     private static ErrorManager err = null;
108
109     // active result of lookup for this setting
110
private static Lookup.Result result = null;
111     
112     // the only active instance in current project
113
private static CatalogSettings instance = null;
114     
115     /**
116      * Just for externalization purposes.
117      * It MUST NOT be called directly by a user code.
118      */

119     public CatalogSettings() {
120         init();
121     }
122     
123
124     /**
125      * Initialized the instance from externalization.
126      */

127     private void init() {
128         listeners = new PropertyChangeSupport(this);
129     }
130     
131     
132     /**
133      * Return active settings <b>instance</b> in the only one active project.
134      * @deprecated does not allow multiple opened projects
135      */

136     public static synchronized CatalogSettings getDefault() {
137         if (result == null) {
138             result = Lookup.getDefault().lookup(new Lookup.Template(CatalogSettings.class));
139             
140             // listen at project "switch", we are project setting
141
result.addLookupListener(new LookupListener() {
142                 public void resultChanged(LookupEvent e) {
143                     CatalogSettings oldSettings = instance;
144                     synchronized (CatalogSettings.class) {
145                         instance = (CatalogSettings) Lookup.getDefault().lookup(CatalogSettings.class);
146                     }
147                     if (oldSettings != null) {
148                         oldSettings.firePropertyChange(PROP_PRJ_INSTANCE, oldSettings, instance);
149                     }
150                 }
151             });
152             
153             // start result listening
154
instance = (CatalogSettings) result.allInstances().iterator().next();
155         }
156         return instance;
157     }
158     
159     /**
160      * Register mounted catalog at project scope level.
161      * @param provider to be registered. Must not be null.
162      */

163     public final void addCatalog(CatalogReader provider) {
164         synchronized (this) {
165             if (provider == null)
166                 throw new IllegalArgumentException JavaDoc("null provider not permited"); // NOI18N
167
if (mountedCatalogs.contains(provider) == false) {
168                 mountedCatalogs.add(provider);
169             }
170         }
171         firePropertyChange(PROP_MOUNTED_CATALOGS, null, null);
172         
173         // add listener to the catalog
174
try {
175             provider.addCatalogListener(catalogListener);
176         } catch (UnsupportedOperationException JavaDoc ex) {
177             // ignore it, we just can not listen at it and save it on change
178
// it is fully OK until the catalog instance supports data source
179
// change
180
}
181     }
182     
183     /**
184      * Deregister given catalog at project scope level.
185      */

186     public final void removeCatalog(CatalogReader provider) {
187         synchronized (this) {
188             mountedCatalogs.remove(provider);
189         }
190         firePropertyChange(PROP_MOUNTED_CATALOGS, null, null);
191         
192         // remove listener to the catalog
193
try {
194             provider.removeCatalogListener(catalogListener);
195         } catch (UnsupportedOperationException JavaDoc ex) {
196             // ignore it
197
}
198         
199     }
200
201     /**
202      * Tests whether removeCatalog will actualy eliminate it.
203      * @return false for catalogs declared at layer
204      * true for catalogs added by user using Add action.
205      */

206     public final boolean isRemovable(CatalogReader provider) {
207         return mountedCatalogs.contains(provider);
208     }
209
210     /**
211      * Return iterator of providers of given class.
212      *
213      * @param providerClasses returned providers will be assignable to it
214      * e.g. <code>CatalogReader</code> class or <code>null</code>
215      * as a wildcard.
216      * @return providers of given class or all if passed <code>null/code> argument.
217      * It never returns null.
218      */

219     public final synchronized Iterator getCatalogs(Class JavaDoc[] providerClasses) {
220
221         // compose global registrations and local(project) registrations
222
IteratorIterator it = new IteratorIterator();
223         it.add(mountedCatalogs.iterator());
224         
225         Lookup.Template template = new Lookup.Template(CatalogReader.class);
226         Lookup.Result result = getUserCatalogsLookup().lookup(template);
227         it.add(result.allInstances().iterator());
228         
229         if (providerClasses == null)
230             return it;
231         
232         ArrayList list = new ArrayList();
233         
234         while (it.hasNext()) {
235             Object JavaDoc next = it.next();
236             // provider test
237
boolean add = true;
238             for (int i=0; i<providerClasses.length; i++) {
239                 if (!providerClasses[i].isAssignableFrom(next.getClass())) {
240                     add = false;
241                     break;
242                 }
243             }
244             // add passed
245
if (add) list.add(next);
246         }
247         return list.iterator();
248     }
249
250     /**
251      * Provide Lookup containing registered module catalogs.
252      */

253     private static Lookup getUserCatalogsLookup() {
254         if (userCatalogLookup == null) {
255             FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
256             FileObject folder = sfs.findResource(REGISTRATIONS);
257             // do not cache any module providing it can be enabled at any time
258
if (folder == null) return Lookups.fixed(new Object JavaDoc[0]);
259             try {
260                 DataFolder dataFolder = (DataFolder) DataObject.find(folder);
261                 userCatalogLookup = new FolderLookup(dataFolder).getLookup();
262             } catch (DataObjectNotFoundException ex) {
263                 throw new IllegalStateException JavaDoc("There must be DataFolder for " + folder + "!");
264             }
265         }
266         return userCatalogLookup;
267     }
268     
269     // ~~~~~~~~~~~~~~~~~~~~~~ listeners ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
270

271     
272     public void addPropertyChangeListener(PropertyChangeListener l){
273         listeners.addPropertyChangeListener(l);
274     }
275     
276     public void removePropertyChangeListener(PropertyChangeListener l) {
277         listeners.removePropertyChangeListener(l);
278     }
279     
280     private void firePropertyChange(String JavaDoc name, Object JavaDoc oldValue, Object JavaDoc newValue) {
281         listeners.firePropertyChange(name, oldValue, newValue);
282     }
283     
284     // ~~~~~~~~~~~~~~~~~~ Persistent state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
285

286     
287     /**
288      * Read persistent catalog settings logging diagnostics information if needed.
289      */

290     public synchronized void readExternal(ObjectInput in) throws IOException, ClassNotFoundException JavaDoc {
291         //super.readExternal(in);
292

293         if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("CatalogSettings.readExternal()"); // NOI18N
294

295         int version = in.readInt(); //IN version
296

297         // version switch
298

299         if (version != VERSION_1) throw new StreamCorruptedException("Unsupported catalog externalization protocol version (" + version + ")."); // NOI18N
300

301         int persistentCount = in.readInt(); //IN count
302

303         for (int i = 0; i<persistentCount; i++) {
304
305             String JavaDoc catalogClass = (String JavaDoc) in.readObject(); //IN class name
306
NbMarshalledObject marshaled = (NbMarshalledObject) in.readObject(); //IN marshalled object
307
try {
308                 Object JavaDoc unmarshaled = marshaled.get();
309                 if (mountedCatalogs.contains(unmarshaled) == false) {
310                     mountedCatalogs.add(unmarshaled);
311                 }
312             } catch (ClassNotFoundException JavaDoc ex) {
313                 //ignore probably missing provider class
314
emgr().annotate(ex, Util.THIS.getString("EXC_deserialization_failed", catalogClass));
315                 emgr().notify(ErrorManager.INFORMATIONAL, ex);
316             } catch (IOException ex) {
317                 //ignore incompatible classes
318
emgr().annotate(ex, Util.THIS.getString("EXC_deserialization_failed", catalogClass));
319                 emgr().notify(ErrorManager.INFORMATIONAL, ex);
320             } catch (RuntimeException JavaDoc ex) {
321                 //ignore catalog that can not deserialize itself without NPE etc.
322
emgr().annotate(ex, Util.THIS.getString("EXC_deserialization_failed", catalogClass));
323                 emgr().notify(ErrorManager.INFORMATIONAL, ex);
324             }
325         }
326     }
327     
328     /**
329      * Write persistent catalog settings as NbMarshalledObjects with some diagnostics information.
330      */

331     public synchronized void writeExternal(ObjectOutput out) throws IOException {
332         //super.writeExternal(out);
333

334         if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("CatalogSettings.writeExternal()"); // NOI18N
335

336         out.writeInt(VERSION_1); //OUT version
337

338         int persistentCount = 0;
339
340         Iterator it = mountedCatalogs.iterator();
341         
342         while (it.hasNext()) {
343             Object JavaDoc next = it.next();
344             if (next instanceof Serializable) {
345                 persistentCount++;
346             }
347         }
348         
349         it = mountedCatalogs.iterator();
350                 
351         out.writeInt(persistentCount); //OUT count
352

353         while (it.hasNext()) {
354             Object JavaDoc next = it.next();
355             if (next instanceof Serializable) {
356                 try {
357                     NbMarshalledObject marshaled = new NbMarshalledObject(next);
358                     out.writeObject(next.getClass().getName()); //OUT class name
359
out.writeObject(marshaled); //OUT marshalled object
360
} catch (IOException ex) {
361                     // catalog can not be serialized
362
emgr().annotate(ex, Util.THIS.getString("EXC_serialization_failed", next.getClass()));
363                     emgr().notify(ErrorManager.INFORMATIONAL, ex);
364                 } catch (RuntimeException JavaDoc ex) {
365                     //skip this odd catalog
366
emgr().annotate(ex, Util.THIS.getString("EXC_serialization_failed", next.getClass()));
367                     emgr().notify(ErrorManager.INFORMATIONAL, ex);
368                 }
369             }
370         }
371     }
372         
373     /** Lazy initialized error manager. */
374     private ErrorManager emgr() {
375         return ErrorManager.getDefault();
376     }
377     
378
379     /**
380      * For debugging purposes only.
381      */

382     public String JavaDoc toString() {
383         Lookup.Template template = new Lookup.Template(CatalogReader.class);
384         Lookup.Result result = getUserCatalogsLookup().lookup(template);
385         return "CatalogSettings[ global-scope: " + result.allInstances() +
386             ", project-scope: " + mountedCatalogs + " ]";
387     }
388     
389     
390     /**
391      * Private catalog listener exposing all changes at catalogs
392      * as a change at this bean, so it get saved later.
393      */

394     private class CL implements CatalogListener {
395     
396         /** Given public ID has changed - disappeared. */
397         public void notifyRemoved(String JavaDoc publicID) {
398         }
399
400         /** Given public ID has changed - created. */
401         public void notifyNew(String JavaDoc publicID) {
402         }
403
404         /** Given public ID has changed. */
405         public void notifyUpdate(String JavaDoc publicID) {
406         }
407
408         /*
409          * It is typical data source change.
410          */

411         public void notifyInvalidate() {
412             firePropertyChange("settings changed!", null, CatalogSettings.this);
413         }
414     }
415     
416 }
417
Popular Tags