KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > settings > convertors > SerialDataConvertor


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.modules.settings.convertors;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyChangeSupport JavaDoc;
25 import java.io.BufferedOutputStream JavaDoc;
26 import java.io.ByteArrayOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.io.OutputStreamWriter JavaDoc;
30 import java.io.Serializable JavaDoc;
31 import java.io.Writer JavaDoc;
32 import java.lang.ref.SoftReference JavaDoc;
33 import java.lang.ref.WeakReference JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35 import java.util.Arrays JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.logging.Level JavaDoc;
38 import javax.swing.JComponent JavaDoc;
39 import org.netbeans.modules.settings.Env;
40 import org.netbeans.modules.settings.ScheduledRequest;
41 import org.netbeans.spi.settings.Convertor;
42 import org.netbeans.spi.settings.Saver;
43 import org.openide.cookies.InstanceCookie;
44 import org.openide.cookies.SaveCookie;
45 import org.openide.filesystems.FileChangeAdapter;
46 import org.openide.filesystems.FileEvent;
47 import org.openide.filesystems.FileLock;
48 import org.openide.filesystems.FileObject;
49 import org.openide.filesystems.FileSystem;
50 import org.openide.filesystems.FileUtil;
51 import org.openide.loaders.DataObject;
52 import org.openide.loaders.Environment;
53 import org.openide.loaders.InstanceDataObject;
54 import org.openide.modules.ModuleInfo;
55 import org.openide.nodes.Node;
56 import org.openide.util.Lookup;
57 import org.openide.util.SharedClassObject;
58 import org.openide.util.lookup.AbstractLookup;
59 import org.openide.util.lookup.InstanceContent;
60 import org.openide.windows.TopComponent;
61
62 /** Convertor handles serialdata format described in
63  * http://www.netbeans.org/dtds/sessionsettings-1_0.dtd. The convertor replaces
64  * the old org.netbeans.core.projects.SerialDataConvertor.
65  * @author Jan Pokorsky
66  */

67 public final class SerialDataConvertor extends FileChangeAdapter
68 implements PropertyChangeListener JavaDoc, FileSystem.AtomicAction {
69     /** data object name cached in the attribute to prevent instance creation when
70      * its node is displayed.
71      * @see org.openide.loaders.InstanceDataObject#EA_NAME
72      */

73     static final String JavaDoc EA_NAME = "name"; // NOI18N
74
/** lock used to sync read/write operations for .settings file */
75     final Object JavaDoc READWRITE_LOCK = new Object JavaDoc();
76     private final InstanceContent lkpContent;
77     private final Lookup lookup;
78     private final DataObject dobj;
79     private final FileObject provider;
80     private final SerialDataConvertor.NodeConvertor node;
81     private SerialDataConvertor.SettingsInstance instance;
82     private SaveSupport saver;
83     
84     /** Creates a new instance of SDConvertor */
85     public SerialDataConvertor(DataObject dobj, FileObject provider) {
86         this.dobj = dobj;
87         this.provider = provider;
88         lkpContent = new InstanceContent();
89         
90         FileObject fo = dobj.getPrimaryFile();
91         fo.addFileChangeListener(FileUtil.weakFileChangeListener(this, fo));
92         
93         SerialDataConvertor.SettingsInstance si = createInstance(null);
94         if (isModuleEnabled(si)) {
95             instance = si;
96             lkpContent.add(instance);
97         }
98         lkpContent.add(this);
99         node = new SerialDataConvertor.NodeConvertor();
100         lkpContent.add(this, node);
101         lookup = new AbstractLookup(lkpContent);
102     }
103     
104     /** can store an object inst in the serialdata format
105      * @param w stream into which inst is written
106      * @param inst the setting object to be written
107      * @exception IOException if the object cannot be written
108      */

109     public void write(Writer JavaDoc w, Object JavaDoc inst) throws IOException JavaDoc {
110         XMLSettingsSupport.storeToXML10(inst, w, ModuleInfoManager.getDefault().getModuleInfo(inst.getClass()));
111     }
112     
113     /** delegate to SaveSupport to handle an unfired setting object change
114      * @see SerialDataNode#resolvePropertyChange
115      */

116     void handleUnfiredChange() {
117         saver.propertyChange(null);
118     }
119     
120     DataObject getDataObject() {
121         return dobj;
122     }
123     
124     FileObject getProvider() {
125         return provider;
126     }
127     
128     /** provides content like InstanceCookie, SaveCokie */
129     public final Lookup getLookup() {
130         return lookup;
131     }
132     
133     /** create own InstanceCookie implementation */
134     private SettingsInstance createInstance(Object JavaDoc inst) {
135         return new SettingsInstance(inst);
136     }
137     
138     /** method provides a support storing the setting */
139     private SaveSupport createSaveSupport(Object JavaDoc inst) {
140         return new SaveSupport(inst);
141     }
142     
143     /** allow to listen on changes of the object inst; should be called when
144      * new instance is created */

145     private void attachToInstance(Object JavaDoc inst) {
146         SerialDataConvertor.SaveSupport _saver = null;
147         synchronized (this) {
148             if (saver != null) {
149                 saver.removePropertyChangeListener(this);
150                 _saver = saver;
151             }
152         }
153         
154         if (_saver != null) {
155             /** creates new Thread and waits for finish - danger of deadlock,
156              * then called outside of lock*/

157             _saver.flush();
158         }
159
160         synchronized (this) {
161             saver = createSaveSupport(inst);
162             saver.addPropertyChangeListener(this);
163         }
164     }
165     
166     private void provideSaveCookie() {
167         if (saver.isChanged()) {
168             lkpContent.add(saver);
169         } else {
170             lkpContent.remove(saver);
171         }
172     }
173     
174     private void instanceCookieChanged(Object JavaDoc inst) {
175         if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("instanceCookieChanged: " + this.dobj); // NOI18N
176
if (saver != null) {
177             if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("canceling saver: " + this.dobj); // NOI18N
178
saver.removePropertyChangeListener(this);
179             getScheduledRequest().cancel();
180             saver = null;
181         }
182
183         SerialDataConvertor.SettingsInstance si = createInstance(inst);
184
185         //#34155 - is this already instantiated SystemOption?
186
boolean recreate = false;
187         if (instance != null && instance.getCachedInstance() != null) {
188             if (isSystemOption(instance.getCachedInstance())) {
189                 recreate = true;
190             }
191         }
192         if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("need recreate: " + recreate + " for " + this.dobj); // NOI18N
193
if (isModuleEnabled(si)) {
194             instance = si;
195             lkpContent.set(Arrays.asList(new Object JavaDoc [] { this, si }), null);
196             if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("module enabled: " + this.dobj); // NOI18N
197
} else {
198             lkpContent.set(Collections.singleton(this), null);
199             instance = null;
200             if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("module disabled: " + this.dobj); // NOI18N
201
}
202         
203         lkpContent.add(this, node);
204         
205         //#34155 - if it was instantiated SystemOptions then force its recreation
206
// See issue for more details.
207
if (isModuleEnabled(si) && recreate) {
208             if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("recreating: " + this.dobj); // NOI18N
209
try {
210                 instance.instanceCreate();
211             } catch (Exception JavaDoc ex) {
212                 XMLSettingsSupport.err.log(Level.WARNING, null, ex);
213             }
214         }
215         if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("done: " + this.dobj); // NOI18N
216
}
217     
218     private static boolean isSystemOption(final Object JavaDoc obj) {
219         boolean b = false;
220         if (obj != null && obj instanceof SharedClassObject){
221             for(Class JavaDoc c = obj.getClass(); !b && c != null; c = c.getSuperclass()) {
222                 b = "org.openide.options.SystemOption".equals(c.getName());//NOI18N
223
}
224         }
225         return b;
226     }
227     
228     public void propertyChange(PropertyChangeEvent JavaDoc evt) {
229         if (evt == null) return;
230
231         String JavaDoc name = evt.getPropertyName();
232         if (name == null)
233             return;
234         // setting was changed
235
else if (name == SaveSupport.PROP_SAVE)
236             provideSaveCookie();
237         // .settings file was changed
238
else if (name == SaveSupport.PROP_FILE_CHANGED) {
239             miUnInitialized = true;
240             if (moduleCodeBase != null) {
241                 ModuleInfo mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
242                 ModuleInfoManager.getDefault().
243                     unregisterPropertyChangeListener(this, mi);
244             }
245             instanceCookieChanged(null);
246         } else if(ModuleInfo.PROP_ENABLED.equals(evt.getPropertyName())) {
247             instanceCookieChanged(null);
248         }
249     }
250
251     /** process events coming from the file object*/
252     public void fileChanged(FileEvent fe) {
253         if (saver != null && fe.firedFrom(saver)) return;
254         propertyChange(new PropertyChangeEvent JavaDoc(this, SaveSupport.PROP_FILE_CHANGED, null, null));
255     }
256     
257     public void fileDeleted(FileEvent fe) {
258         if (saver != null && fe.firedFrom(saver)) return;
259         if (saver != null) {
260             saver.removePropertyChangeListener(this);
261             getScheduledRequest().cancel();
262             saver = null;
263         }
264     }
265     
266     private String JavaDoc moduleCodeBase = null;
267     private boolean miUnInitialized = true;
268     private boolean moduleMissing;
269     
270     private boolean isModuleEnabled(SerialDataConvertor.SettingsInstance si) {
271         ModuleInfo mi = null;
272         if (miUnInitialized) {
273             moduleCodeBase = getModuleCodeNameBase(si);
274             miUnInitialized = false;
275             if (moduleCodeBase != null) {
276                 mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
277                 moduleMissing = (mi == null);
278                 if (mi != null) {
279                     ModuleInfoManager.getDefault().
280                         registerPropertyChangeListener(this, mi);
281                 } else {
282                     XMLSettingsSupport.err.warning(
283                         "Warning: unknown module code base: " + // NOI18N
284
moduleCodeBase + " in " + // NOI18N
285
getDataObject().getPrimaryFile());
286                 }
287             } else {
288                 moduleMissing = false;
289             }
290         } else {
291             mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
292         }
293         
294         return !moduleMissing && (mi == null || mi.isEnabled());
295     }
296     
297     private String JavaDoc getModuleCodeNameBase(SerialDataConvertor.SettingsInstance si) {
298         try {
299             String JavaDoc module = si.getSettings(true).getCodeNameBase();
300             return module;
301         } catch (IOException JavaDoc ex) {
302             XMLSettingsSupport.err.log(Level.WARNING, null, ex);
303         }
304         return null;
305     }
306     
307     /** Little utility method for posting an exception
308      * to the default <CODE>ErrorManager</CODE> with severity
309      * <CODE>ErrorManager.INFORMATIONAL</CODE>
310      */

311     static void inform(Throwable JavaDoc t) {
312         XMLSettingsSupport.err.log(Level.WARNING, null, t);
313     }
314     
315     /** called by ScheduledRequest in order to perform the request */
316     public void run() throws IOException JavaDoc {
317         saver.writeDown();
318     }
319     
320     /** scheduled request to store setting */
321     private ScheduledRequest request;
322     
323     /** get the scheduled request to store setting */
324     private synchronized ScheduledRequest getScheduledRequest() {
325         if (request == null) {
326             request = new ScheduledRequest(this.getDataObject().getPrimaryFile(), this);
327         }
328         return request;
329     }
330     
331     //////////////////////////////////////////////////////////////////////////
332
// SettingsInstance
333
//////////////////////////////////////////////////////////////////////////
334

335     /** InstanceCookie implementation */
336     private final class SettingsInstance implements InstanceCookie.Of {
337         
338         /** created instance */
339         private SoftReference JavaDoc<Object JavaDoc> inst;
340         
341         /* Lifecycle of SettingsRecognizer:
342          * Initially: settings = null
343          * Parsed header: settings created, light object (no byte[], no char[])
344          * Full parsing: Create char[], convert it to byte[] and release char[]
345          * create instance, throw away settings
346          *
347          */

348         /** holder of parsed settings */
349         private XMLSettingsSupport.SettingsRecognizer settings = null;
350         
351         /** Creates new SettingsInstance */
352         public SettingsInstance(Object JavaDoc instance) {
353             setCachedInstance(instance);
354         }
355         
356         /** Getter for parsed settings
357          * @param header if <code>true</code> parse just header(instanceof, module, classname)
358          */

359         private XMLSettingsSupport.SettingsRecognizer getSettings(boolean header) throws IOException JavaDoc {
360             synchronized (this) {
361                 if (settings == null) {
362                     synchronized (READWRITE_LOCK) {
363                         settings = new XMLSettingsSupport.SettingsRecognizer(
364                             header, getDataObject().getPrimaryFile());
365                         settings.parse();
366                     }
367                     return settings;
368                 }
369                 if (!header) {
370                     if (!settings.isAllRead()) {
371                         settings.setAllRead(false);
372                         settings.parse();
373                     }
374                 }
375
376                 return settings;
377             }
378         }
379         
380         public Object JavaDoc instanceCreate() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
381             Object JavaDoc inst;
382             XMLSettingsSupport.SettingsRecognizer recog;
383             
384             synchronized (this) {
385                 inst = getCachedInstance();
386                 if (inst != null) {
387                     if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("Cached instance1: " + inst); // NOI18N
388
return inst;
389                 }
390             }
391             
392             recog = getSettings(false);
393             inst = recog.instanceCreate();
394             
395             
396             synchronized (this) {
397                 Object JavaDoc existing = getCachedInstance();
398                 if (existing != null) {
399                     if (XMLSettingsSupport.err.isLoggable(Level.FINER)) XMLSettingsSupport.err.finer("Cached instance2: " + existing); // NOI18N
400
return existing;
401                 }
402                 setCachedInstance(inst);
403             }
404             if (XMLSettingsSupport.err.isLoggable(Level.FINER)) XMLSettingsSupport.err.finer("Attached to instance: " + inst); // NOI18N
405
attachToInstance(inst);
406             
407             return inst;
408         }
409         
410         public Class JavaDoc instanceClass() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
411             // cached
412
Object JavaDoc inst = getCachedInstance();
413             if (inst != null) {
414                 return inst.getClass();
415             }
416             
417             XMLSettingsSupport.SettingsRecognizer recog = getSettings(false);
418             return recog.instanceClass();
419         }
420         
421         public boolean instanceOf(Class JavaDoc<?> type) {
422             try {
423                 if (
424                     moduleCodeBase != null &&
425                     ModuleInfoManager.getDefault().isReloaded(moduleCodeBase) &&
426                     type.getClassLoader () != ClassLoader.getSystemClassLoader () &&
427                     type.getClassLoader() != null
428                 ) {
429                     // special treatment for classes that could be reloaded
430
ModuleInfo info = ModuleInfoManager.getDefault().getModule (moduleCodeBase);
431                     if (info == null || !info.isEnabled ()) {
432                         // false to disabled modules
433
return false;
434                     }
435                     // otherwise really try to load
436
Class JavaDoc<?> instanceType = instanceClass ();
437                     return type.isAssignableFrom (instanceType);
438                 }
439                 
440                 // check existing instance first:
441
Object JavaDoc inst = getCachedInstance();
442                 if (inst != null) {
443                     return type.isInstance(inst);
444                 }
445                 
446                 // check the settings cache/file
447
return getSettings(true).getInstanceOf().contains(type.getName());
448             } catch (ClassNotFoundException JavaDoc ex) {
449                 XMLSettingsSupport.err.log(Level.WARNING, getDataObject().getPrimaryFile().toString());
450                 inform(ex);
451             } catch (IOException JavaDoc ex) {
452                 XMLSettingsSupport.err.log(Level.WARNING, getDataObject().getPrimaryFile().toString());
453                 inform(ex);
454             }
455             return false;
456         }
457         
458         public String JavaDoc instanceName() {
459             // try cached instance
460
Object JavaDoc inst = getCachedInstance();
461             if (inst != null) {
462                 return inst.getClass().getName();
463             }
464             
465             try {
466                 return getSettings(true).instanceName();
467             } catch (IOException JavaDoc ex) {
468                 XMLSettingsSupport.err.warning(getDataObject().getPrimaryFile().toString());
469                 inform(ex);
470                 return ""; // NOI18N
471
}
472         }
473         
474         private Object JavaDoc getCachedInstance() {
475             return inst.get();
476         }
477         
478         private void setCachedInstance(Object JavaDoc o) {
479             inst = new SoftReference JavaDoc<Object JavaDoc>(o);
480             settings = null; // clear reference to settings
481
}
482         // called by InstanceDataObject to set new object
483
public void setInstance(Object JavaDoc inst, boolean save) throws IOException JavaDoc {
484             instanceCookieChanged(inst);
485             if (inst != null) {
486                 attachToInstance(inst);
487                 if (save) getScheduledRequest().runAndWait();
488             }
489         }
490         
491     }
492     
493     /** Support handles automatic setting objects storing and allows to identify
494      * the origin of file events fired as a consequence of this storing
495      */

496     private final class SaveSupport implements FileSystem.AtomicAction,
497     SaveCookie, PropertyChangeListener JavaDoc, Saver {
498         /** property means setting is changed and should be changed */
499         public static final String JavaDoc PROP_SAVE = "savecookie"; //NOI18N
500
/** property means setting file content is changed */
501         public static final String JavaDoc PROP_FILE_CHANGED = "fileChanged"; //NOI18N
502

503         /** support for PropertyChangeListeners */
504         private PropertyChangeSupport JavaDoc changeSupport;
505         /** the number of registered PropertyChangeListeners */
506         private int propertyChangeListenerCount = 0;
507         
508         /** setting is already changed */
509         private boolean isChanged = false;
510         /** file containing persisted setting */
511         private final FileObject file;
512         /** weak reference to setting object */
513         private final WeakReference JavaDoc<Object JavaDoc> instance;
514         /** remember whether the DataObject is a template or not; calling isTemplate() is slow */
515         private Boolean JavaDoc knownToBeTemplate = null;
516         /** the setting object is serialized, if true ignore prop. change
517          * notifications
518          */

519         private boolean isWriting = false;
520         /** convertor for possible format upgrade */
521         private Convertor convertor;
522         
523         /** Creates a new instance of SaveSupport */
524         public SaveSupport(Object JavaDoc inst) {
525             this.instance = new WeakReference JavaDoc<Object JavaDoc>(inst);
526             file = getDataObject().getPrimaryFile();
527         }
528         
529         /** is setting object changed? */
530         public final boolean isChanged() {
531             return isChanged;
532         }
533         
534         /** store setting or provide just SaveCookie? */
535         private boolean acceptSave() {
536             Object JavaDoc inst = instance.get();
537             if (inst == null || !(inst instanceof Serializable JavaDoc) ||
538                 // XXX bad dep; should perhaps have some marker in the .settings file for this??
539
inst instanceof TopComponent) return false;
540             
541             return true;
542         }
543         
544         /** place where to filter events comming from setting object */
545         private boolean ignoreChange(PropertyChangeEvent JavaDoc pce) {
546             if (isChanged || isWriting || !getDataObject().isValid()) return true;
547             
548             // undocumented workaround used in 3.3; since 3.4 convertors make
549
// possible to customize the setting change notification filtering
550
if (pce != null && Boolean.FALSE.equals(pce.getPropagationId())) return true;
551             
552             if (knownToBeTemplate == null) knownToBeTemplate = getDataObject().isTemplate() ? Boolean.TRUE : Boolean.FALSE;
553             return knownToBeTemplate.booleanValue();
554         }
555         
556         /** get convertor for possible upgrade; can be null */
557         private Convertor getConvertor() {
558             return convertor;
559         }
560
561         /** try to find out convertor for possible upgrade and cache it; can be null */
562         private Convertor initConvertor() {
563             Object JavaDoc inst = instance.get();
564             if (inst == null) {
565                 throw new IllegalStateException JavaDoc(
566                     "setting object cannot be null: " + getDataObject());// NOI18N
567
}
568
569             try {
570                 FileObject newProviderFO = Env.findProvider(inst.getClass());
571                 if (newProviderFO != null) {
572                     FileObject foEntity = Env.findEntityRegistration(newProviderFO);
573                     if (foEntity == null) foEntity = newProviderFO;
574                     Object JavaDoc attrb = foEntity.getAttribute(Env.EA_PUBLICID);
575                     if (attrb == null || !(attrb instanceof String JavaDoc)) {
576                         throw new IOException JavaDoc("missing or invalid attribute: " + //NOI18N
577
Env.EA_PUBLICID + ", provider: " + foEntity); //NOI18N
578
}
579                     if (XMLSettingsSupport.INSTANCE_DTD_ID.equals(attrb)) {
580                         convertor = null;
581                         return convertor;
582                     }
583                     
584                     attrb = newProviderFO.getAttribute(Env.EA_CONVERTOR);
585                     if (attrb == null || !(attrb instanceof Convertor)) {
586                         throw new IOException JavaDoc("cannot create convertor: " + //NOI18N
587
attrb + ", provider: " + newProviderFO); //NOI18N
588
} else {
589                         convertor = (Convertor) attrb;
590                         return convertor;
591                     }
592                 }
593             } catch (IOException JavaDoc ex) {
594                 inform(ex);
595             }
596             return convertor;
597         }
598         
599         /** Registers PropertyChangeListener to receive events and initialize
600          * listening to events comming from the setting object and file object.
601          * @param listener The listener to register.
602          */

603         public synchronized void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
604             if (changeSupport == null || propertyChangeListenerCount <= 0) {
605                 Object JavaDoc inst = instance.get();
606                 if (inst == null) return;
607                 if (changeSupport == null) {
608                     changeSupport = new PropertyChangeSupport JavaDoc(this);
609                     propertyChangeListenerCount = 0;
610                 }
611                 Convertor conv = initConvertor();
612                 if (conv != null) {
613                     conv.registerSaver(inst, this);
614                 } else {
615                     registerPropertyChangeListener(inst);
616                 }
617             }
618             propertyChangeListenerCount++;
619             changeSupport.addPropertyChangeListener(listener);
620         }
621         
622         /** Removes PropertyChangeListener from the list of listeners.
623          * @param listener The listener to remove.
624          */

625         public synchronized void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
626             if (changeSupport == null)
627                 return;
628             
629             propertyChangeListenerCount--;
630             changeSupport.removePropertyChangeListener(listener);
631
632             if (propertyChangeListenerCount == 0) {
633                 Object JavaDoc inst = instance.get();
634                 if (inst == null) return;
635                 
636                 Convertor conv = getConvertor();
637                 if (conv != null) {
638                     conv.unregisterSaver(inst, this);
639                 } else {
640                     unregisterPropertyChangeListener(inst);
641                 }
642             }
643         }
644         
645         /** try to register PropertyChangeListener to the setting object
646          * to be notified about its changes.
647          */

648         private void registerPropertyChangeListener(Object JavaDoc inst) {
649             if (inst instanceof SharedClassObject) {
650                 ((SharedClassObject)inst).addPropertyChangeListener(this);
651             }
652             else if (inst instanceof JComponent JavaDoc) {
653                 ((JComponent JavaDoc) inst).addPropertyChangeListener(this);
654             }
655             else {
656                 // add propertyChangeListener
657
try {
658                     Method JavaDoc method = inst.getClass().getMethod(
659                         "addPropertyChangeListener", // NOI18N
660
new Class JavaDoc[] {PropertyChangeListener JavaDoc.class});
661                     method.invoke(inst, new Object JavaDoc[] {this});
662                 } catch (NoSuchMethodException JavaDoc ex) {
663                     // just changes done through gui will be saved
664
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
665                         XMLSettingsSupport.err.warning(
666                         "NoSuchMethodException: " + // NOI18N
667
inst.getClass().getName() + ".addPropertyChangeListener"); // NOI18N
668
}
669                 } catch (IllegalAccessException JavaDoc ex) {
670                     // just changes done through gui will be saved
671
XMLSettingsSupport.err.warning("Instance: " + inst); // NOI18N
672
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
673                 } catch (java.lang.reflect.InvocationTargetException JavaDoc ex) {
674                     // just changes done through gui will be saved
675
XMLSettingsSupport.err.log(Level.WARNING, null, ex.getTargetException());
676                 }
677             }
678         }
679         
680         /** @see #registerPropertyChangeListener
681          */

682         private void unregisterPropertyChangeListener(Object JavaDoc inst) {
683             try {
684                 Method JavaDoc method = inst.getClass().getMethod(
685                     "removePropertyChangeListener", // NOI18N
686
new Class JavaDoc[] {PropertyChangeListener JavaDoc.class});
687                 method.invoke(inst, new Object JavaDoc[] {this});
688             } catch (NoSuchMethodException JavaDoc ex) {
689                 // just changes done through gui will be saved
690
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
691                     XMLSettingsSupport.err.log(Level.FINE,
692                     "NoSuchMethodException: " + // NOI18N
693
inst.getClass().getName() + ".removePropertyChangeListener"); // NOI18N
694
}
695             } catch (IllegalAccessException JavaDoc ex) {
696                 XMLSettingsSupport.err.log(Level.WARNING, "Instance: " + inst); // NOI18N
697
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
698             } catch (java.lang.reflect.InvocationTargetException JavaDoc ex) {
699                 XMLSettingsSupport.err.log(Level.WARNING, null, ex.getTargetException());
700             }
701         }
702         
703         /** Notifies all registered listeners about the event.
704          * @param event The event to be fired
705          * @see #PROP_FILE_CHANGED
706          * @see #PROP_SAVE
707          */

708         private void firePropertyChange(String JavaDoc name) {
709             if (changeSupport != null)
710                 changeSupport.firePropertyChange(name, null, null);
711         }
712
713         /** force to finish scheduled request */
714         public void flush() {
715             getScheduledRequest().forceToFinish();
716         }
717         
718         private ByteArrayOutputStream JavaDoc buf;
719
720         /** process events coming from a setting object */
721         public final void propertyChange(PropertyChangeEvent JavaDoc pce) {
722             if (ignoreChange(pce)) return ;
723             isChanged = true;
724             firePropertyChange(PROP_SAVE);
725             if (acceptSave()) {
726                 getScheduledRequest().schedule(instance.get());
727             }
728         }
729         
730         public void markDirty() {
731             if (ignoreChange(null)) return;
732             isChanged = true;
733             firePropertyChange(PROP_SAVE);
734         }
735         
736         public void requestSave() throws IOException JavaDoc {
737             if (ignoreChange(null)) return;
738             isChanged = true;
739             firePropertyChange(PROP_SAVE);
740             getScheduledRequest().schedule(instance.get());
741         }
742
743         /** store buffer to the file. */
744         public void run() throws IOException JavaDoc {
745             if (!getDataObject().isValid()) {
746                 //invalid data object cannot be used for storing
747
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
748                     XMLSettingsSupport.err.fine("invalid data object cannot be used for storing " + getDataObject()); // NOI18N
749
}
750                 return;
751             }
752             
753             try {
754                 try2run();
755             } catch (IOException JavaDoc ex) {
756                 //#25288: DO can be invalidated asynchronously (module disabling)
757
//then ignore IO exceptions
758
if (getDataObject().isValid()) {
759                     throw ex;
760                 } else {
761                     return;
762                 }
763             }
764         }
765         
766         /** try to perform atomic action */
767         private void try2run() throws IOException JavaDoc {
768             FileLock lock;
769             OutputStream JavaDoc los;
770             synchronized (READWRITE_LOCK) {
771                 if (XMLSettingsSupport.err.isLoggable(Level.FINER)) {
772                     XMLSettingsSupport.err.finer("saving " + getDataObject()); // NOI18N
773
}
774                 lock = getScheduledRequest().getFileLock();
775                 if (lock == null) return;
776                 los = file.getOutputStream(lock);
777
778                 OutputStream JavaDoc os = new BufferedOutputStream JavaDoc(los, 1024);
779                 try {
780                     buf.writeTo(os);
781                     if (XMLSettingsSupport.err.isLoggable(Level.FINER)) {
782                         XMLSettingsSupport.err.finer("saved " + dobj); // NOI18N
783
}
784                 } finally {
785                     os.close();
786                 }
787             }
788         }
789
790         /** Implementation of SaveCookie. */
791         public void save() throws IOException JavaDoc {
792             if (!isChanged) return;
793             getScheduledRequest().runAndWait();
794         }
795
796         /** store the setting object even if was not changed */
797         private void writeDown() throws IOException JavaDoc {
798             Object JavaDoc inst = instance.get();
799             if (inst == null) return ;
800             
801             ByteArrayOutputStream JavaDoc b = new ByteArrayOutputStream JavaDoc(1024);
802             Writer JavaDoc w = new OutputStreamWriter JavaDoc(b, "UTF-8"); // NOI18N
803
try {
804                 isWriting = true;
805                 Convertor conv = getConvertor();
806                 if (conv != null) {
807                     conv.write(w, inst);
808                 } else {
809                     write(w, inst);
810                 }
811             } finally {
812                 w.close();
813                 isWriting = false;
814             }
815             isChanged = false;
816
817             buf = b;
818             file.getFileSystem().runAtomicAction(this);
819             buf = null;
820             if (!isChanged) firePropertyChange(PROP_SAVE);
821         }
822     }
823
824 ////////////////////////////////////////////////////////////////////////////
825
// Provider
826
////////////////////////////////////////////////////////////////////////////
827

828     /** A provider for .settings files containing serial data format
829      * (hexa stream)
830      */

831     public final static class Provider implements Environment.Provider {
832         private final FileObject providerFO;
833         
834         public static Environment.Provider create(FileObject fo) {
835             return new Provider(fo);
836         }
837
838         private Provider(FileObject fo) {
839             providerFO = fo;
840         }
841
842         public Lookup getEnvironment(DataObject dobj) {
843             if (!(dobj instanceof InstanceDataObject)) return Lookup.EMPTY;
844             return new SerialDataConvertor(dobj, providerFO).getLookup();
845         }
846
847     }
848     
849 ////////////////////////////////////////////////////////////////////////////
850
// NodeConvertor
851
////////////////////////////////////////////////////////////////////////////
852

853     /** allow to postpone the node creation */
854     private static final class NodeConvertor implements InstanceContent.Convertor<SerialDataConvertor, Node> {
855         NodeConvertor() {}
856      
857         public Node convert(SerialDataConvertor o) {
858             return new SerialDataNode(o);
859         }
860      
861         public Class JavaDoc<Node> type(SerialDataConvertor o) {
862             return Node.class;
863         }
864      
865         public String JavaDoc id(SerialDataConvertor o) {
866             // Generally irrelevant in this context.
867
return o.toString();
868         }
869      
870         public String JavaDoc displayName(SerialDataConvertor o) {
871             // Again, irrelevant here.
872
return o.toString();
873         }
874      
875     }
876     
877 }
878
Popular Tags