2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.settings.convertors;
44
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeListener;
46
import java.beans.PropertyChangeSupport;
47
import java.io.BufferedOutputStream;
48
import java.io.ByteArrayOutputStream;
49
import java.io.IOException;
50
import java.io.OutputStream;
51
import java.io.OutputStreamWriter;
52
import java.io.Serializable;
53
import java.io.Writer;
54
import java.lang.ref.SoftReference;
55
import java.lang.ref.WeakReference;
56
import java.lang.reflect.Method;
57
import java.util.Arrays;
58
import java.util.Collections;
59
import java.util.logging.Level;
60
import javax.swing.JComponent;
61
import org.netbeans.modules.settings.Env;
62
import org.netbeans.modules.settings.ScheduledRequest;
63
import org.netbeans.spi.settings.Convertor;
64
import org.netbeans.spi.settings.Saver;
65
import org.openide.cookies.InstanceCookie;
66
import org.openide.cookies.SaveCookie;
67
import org.openide.filesystems.FileChangeAdapter;
68
import org.openide.filesystems.FileEvent;
69
import org.openide.filesystems.FileLock;
70
import org.openide.filesystems.FileObject;
71
import org.openide.filesystems.FileSystem;
72
import org.openide.filesystems.FileUtil;
73
import org.openide.loaders.DataObject;
74
import org.openide.loaders.Environment;
75
import org.openide.loaders.InstanceDataObject;
76
import org.openide.modules.ModuleInfo;
77
import org.openide.nodes.Node;
78
import org.openide.util.Lookup;
79
import org.openide.util.SharedClassObject;
80
import org.openide.util.lookup.AbstractLookup;
81
import org.openide.util.lookup.InstanceContent;
82
import org.openide.windows.TopComponent;
84
/** Convertor handles serialdata format described in
85
* http://www.netbeans.org/dtds/sessionsettings-1_0.dtd. The convertor replaces
86
* the old org.netbeans.core.projects.SerialDataConvertor.
87
* @author Jan Pokorsky
89
public final class SerialDataConvertor extends FileChangeAdapter
90
implements PropertyChangeListener, FileSystem.AtomicAction {
91
/** data object name cached in the attribute to prevent instance creation when
92
* its node is displayed.
93
* @see org.openide.loaders.InstanceDataObject#EA_NAME
95
static final String EA_NAME = "name"; // NOI18N
96
/** lock used to sync read/write operations for .settings file */
97
final Object READWRITE_LOCK = new Object();
98
private final InstanceContent lkpContent;
99
private final Lookup lookup;
100
private final DataObject dobj;
101
private final FileObject provider;
102
private final SerialDataConvertor.NodeConvertor node;
103
private SerialDataConvertor.SettingsInstance instance;
104
private SaveSupport saver;
106
/** Creates a new instance of SDConvertor */
107
public SerialDataConvertor(DataObject dobj, FileObject provider) {
109
this.provider = provider;
110
lkpContent = new InstanceContent();
112
FileObject fo = dobj.getPrimaryFile();
113
fo.addFileChangeListener(FileUtil.weakFileChangeListener(this, fo));
115
SerialDataConvertor.SettingsInstance si = createInstance(null);
116
if (isModuleEnabled(si)) {
118
lkpContent.add(instance);
120
lkpContent.add(this);
121
node = new SerialDataConvertor.NodeConvertor();
122
lkpContent.add(this, node);
123
lookup = new AbstractLookup(lkpContent);
126
/** can store an object inst in the serialdata format
127
* @param w stream into which inst is written
128
* @param inst the setting object to be written
129
* @exception IOException if the object cannot be written
131
public void write(Writer w, Object inst) throws IOException {
132
XMLSettingsSupport.storeToXML10(inst, w, ModuleInfoManager.getDefault().getModuleInfo(inst.getClass()));
135
/** delegate to SaveSupport to handle an unfired setting object change
136
* @see SerialDataNode#resolvePropertyChange
138
void handleUnfiredChange() {
139
saver.propertyChange(null);
142
DataObject getDataObject() {
146
FileObject getProvider() {
150
/** provides content like InstanceCookie, SaveCokie */
151
public final Lookup getLookup() {
155
/** create own InstanceCookie implementation */
156
private SettingsInstance createInstance(Object inst) {
157
return new SettingsInstance(inst);
160
/** method provides a support storing the setting */
161
private SaveSupport createSaveSupport(Object inst) {
162
return new SaveSupport(inst);
165
/** allow to listen on changes of the object inst; should be called when
166
* new instance is created */
167
private void attachToInstance(Object inst) {
168
SerialDataConvertor.SaveSupport _saver = null;
169
synchronized (this) {
171
saver.removePropertyChangeListener(this);
176
if (_saver != null) {
177
/** creates new Thread and waits for finish - danger of deadlock,
178
* then called outside of lock*/
182
synchronized (this) {
183
saver = createSaveSupport(inst);
184
saver.addPropertyChangeListener(this);
188
private void provideSaveCookie() {
189
if (saver.isChanged()) {
190
lkpContent.add(saver);
192
lkpContent.remove(saver);
196
private void instanceCookieChanged(Object inst) {
197
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("instanceCookieChanged: " + this.dobj); // NOI18N
199
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("canceling saver: " + this.dobj); // NOI18N
200
saver.removePropertyChangeListener(this);
201
getScheduledRequest().cancel();
205
SerialDataConvertor.SettingsInstance si = createInstance(inst);
207
//#34155 - is this already instantiated SystemOption?
208
boolean recreate = false;
209
if (instance != null && instance.getCachedInstance() != null) {
210
if (isSystemOption(instance.getCachedInstance())) {
214
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("need recreate: " + recreate + " for " + this.dobj); // NOI18N
215
if (isModuleEnabled(si)) {
217
lkpContent.set(Arrays.asList(new Object [] { this, si }), null);
218
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("module enabled: " + this.dobj); // NOI18N
220
lkpContent.set(Collections.singleton(this), null);
222
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("module disabled: " + this.dobj); // NOI18N
225
lkpContent.add(this, node);
227
//#34155 - if it was instantiated SystemOptions then force its recreation
228
// See issue for more details.
229
if (isModuleEnabled(si) && recreate) {
230
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("recreating: " + this.dobj); // NOI18N
232
instance.instanceCreate();
233
} catch (Exception ex) {
234
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
237
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("done: " + this.dobj); // NOI18N
240
private static boolean isSystemOption(final Object obj) {
242
if (obj != null && obj instanceof SharedClassObject){
243
for(Class c = obj.getClass(); !b && c != null; c = c.getSuperclass()) {
244
b = "org.openide.options.SystemOption".equals(c.getName());//NOI18N
250
public void propertyChange(PropertyChangeEvent evt) {
251
if (evt == null) return;
253
String name = evt.getPropertyName();
256
// setting was changed
257
else if (name == SaveSupport.PROP_SAVE)
259
// .settings file was changed
260
else if (name == SaveSupport.PROP_FILE_CHANGED) {
261
miUnInitialized = true;
262
if (moduleCodeBase != null) {
263
ModuleInfo mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
264
ModuleInfoManager.getDefault().
265
unregisterPropertyChangeListener(this, mi);
267
instanceCookieChanged(null);
268
} else if(ModuleInfo.PROP_ENABLED.equals(evt.getPropertyName())) {
269
instanceCookieChanged(null);
273
/** process events coming from the file object*/
274
public void fileChanged(FileEvent fe) {
275
if (saver != null && fe.firedFrom(saver)) return;
276
propertyChange(new PropertyChangeEvent(this, SaveSupport.PROP_FILE_CHANGED, null, null));
279
public void fileDeleted(FileEvent fe) {
280
if (saver != null && fe.firedFrom(saver)) return;
282
saver.removePropertyChangeListener(this);
283
getScheduledRequest().cancel();
288
private String moduleCodeBase = null;
289
private boolean miUnInitialized = true;
290
private boolean moduleMissing;
292
private boolean isModuleEnabled(SerialDataConvertor.SettingsInstance si) {
293
ModuleInfo mi = null;
294
if (miUnInitialized) {
295
moduleCodeBase = getModuleCodeNameBase(si);
296
miUnInitialized = false;
297
if (moduleCodeBase != null) {
298
mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
299
moduleMissing = (mi == null);
301
ModuleInfoManager.getDefault().
302
registerPropertyChangeListener(this, mi);
304
XMLSettingsSupport.err.warning(
305
"Warning: unknown module code base: " + // NOI18N
306
moduleCodeBase + " in " + // NOI18N
307
getDataObject().getPrimaryFile());
310
moduleMissing = false;
313
mi = ModuleInfoManager.getDefault().getModule(moduleCodeBase);
316
return !moduleMissing && (mi == null || mi.isEnabled());
319
private String getModuleCodeNameBase(SerialDataConvertor.SettingsInstance si) {
321
String module = si.getSettings(true).getCodeNameBase();
323
} catch (IOException ex) {
324
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
329
/** Little utility method for posting an exception
330
* to the default <CODE>ErrorManager</CODE> with severity
331
* <CODE>ErrorManager.INFORMATIONAL</CODE>
333
static void inform(Throwable t) {
334
XMLSettingsSupport.err.log(Level.WARNING, null, t);
337
/** called by ScheduledRequest in order to perform the request */
338
public void run() throws IOException {
342
/** scheduled request to store setting */
343
private ScheduledRequest request;
345
/** get the scheduled request to store setting */
346
private synchronized ScheduledRequest getScheduledRequest() {
347
if (request == null) {
348
request = new ScheduledRequest(this.getDataObject().getPrimaryFile(), this);
353
//////////////////////////////////////////////////////////////////////////
355
//////////////////////////////////////////////////////////////////////////
357
/** InstanceCookie implementation */
358
private final class SettingsInstance implements InstanceCookie.Of {
360
/** created instance */
361
private SoftReference<Object> inst;
363
/* Lifecycle of SettingsRecognizer:
364
* Initially: settings = null
365
* Parsed header: settings created, light object (no byte[], no char[])
366
* Full parsing: Create char[], convert it to byte[] and release char[]
367
* create instance, throw away settings
370
/** holder of parsed settings */
371
private XMLSettingsSupport.SettingsRecognizer settings = null;
373
/** Creates new SettingsInstance */
374
public SettingsInstance(Object instance) {
375
setCachedInstance(instance);
378
/** Getter for parsed settings
379
* @param header if <code>true</code> parse just header(instanceof, module, classname)
381
private XMLSettingsSupport.SettingsRecognizer getSettings(boolean header) throws IOException {
382
synchronized (this) {
383
if (settings == null) {
384
synchronized (READWRITE_LOCK) {
385
settings = new XMLSettingsSupport.SettingsRecognizer(
386
header, getDataObject().getPrimaryFile());
392
if (!settings.isAllRead()) {
393
settings.setAllRead(false);
402
public Object instanceCreate() throws IOException, ClassNotFoundException {
404
XMLSettingsSupport.SettingsRecognizer recog;
406
synchronized (this) {
407
inst = getCachedInstance();
409
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) XMLSettingsSupport.err.fine("Cached instance1: " + inst); // NOI18N
414
recog = getSettings(false);
415
inst = recog.instanceCreate();
418
synchronized (this) {
419
Object existing = getCachedInstance();
420
if (existing != null) {
421
if (XMLSettingsSupport.err.isLoggable(Level.FINER)) XMLSettingsSupport.err.finer("Cached instance2: " + existing); // NOI18N
424
setCachedInstance(inst);
426
if (XMLSettingsSupport.err.isLoggable(Level.FINER)) XMLSettingsSupport.err.finer("Attached to instance: " + inst); // NOI18N
427
attachToInstance(inst);
432
public Class instanceClass() throws IOException, ClassNotFoundException {
434
Object inst = getCachedInstance();
436
return inst.getClass();
439
XMLSettingsSupport.SettingsRecognizer recog = getSettings(false);
440
return recog.instanceClass();
443
public boolean instanceOf(Class<?> type) {
446
moduleCodeBase != null &&
447
ModuleInfoManager.getDefault().isReloaded(moduleCodeBase) &&
448
type.getClassLoader () != ClassLoader.getSystemClassLoader () &&
449
type.getClassLoader() != null
451
// special treatment for classes that could be reloaded
452
ModuleInfo info = ModuleInfoManager.getDefault().getModule (moduleCodeBase);
453
if (info == null || !info.isEnabled ()) {
454
// false to disabled modules
457
// otherwise really try to load
458
Class<?> instanceType = instanceClass ();
459
return type.isAssignableFrom (instanceType);
462
// check existing instance first:
463
Object inst = getCachedInstance();
465
return type.isInstance(inst);
468
// check the settings cache/file
469
return getSettings(true).getInstanceOf().contains(type.getName());
470
} catch (ClassNotFoundException ex) {
471
XMLSettingsSupport.err.log(Level.WARNING, getDataObject().getPrimaryFile().toString());
473
} catch (IOException ex) {
474
XMLSettingsSupport.err.log(Level.WARNING, getDataObject().getPrimaryFile().toString());
480
public String instanceName() {
481
// try cached instance
482
Object inst = getCachedInstance();
484
return inst.getClass().getName();
488
return getSettings(true).instanceName();
489
} catch (IOException ex) {
490
XMLSettingsSupport.err.warning(getDataObject().getPrimaryFile().toString());
496
private Object getCachedInstance() {
500
private void setCachedInstance(Object o) {
501
inst = new SoftReference<Object>(o);
502
settings = null; // clear reference to settings
504
// called by InstanceDataObject to set new object
505
public void setInstance(Object inst, boolean save) throws IOException {
506
instanceCookieChanged(inst);
508
attachToInstance(inst);
509
if (save) getScheduledRequest().runAndWait();
515
/** Support handles automatic setting objects storing and allows to identify
516
* the origin of file events fired as a consequence of this storing
518
private final class SaveSupport implements FileSystem.AtomicAction,
519
SaveCookie, PropertyChangeListener, Saver {
520
/** property means setting is changed and should be changed */
521
public static final String PROP_SAVE = "savecookie"; //NOI18N
522
/** property means setting file content is changed */
523
public static final String PROP_FILE_CHANGED = "fileChanged"; //NOI18N
525
/** support for PropertyChangeListeners */
526
private PropertyChangeSupport changeSupport;
527
/** the number of registered PropertyChangeListeners */
528
private int propertyChangeListenerCount = 0;
530
/** setting is already changed */
531
private boolean isChanged = false;
532
/** file containing persisted setting */
533
private final FileObject file;
534
/** weak reference to setting object */
535
private final WeakReference<Object> instance;
536
/** remember whether the DataObject is a template or not; calling isTemplate() is slow */
537
private Boolean knownToBeTemplate = null;
538
/** the setting object is serialized, if true ignore prop. change
541
private boolean isWriting = false;
542
/** convertor for possible format upgrade */
543
private Convertor convertor;
545
/** Creates a new instance of SaveSupport */
546
public SaveSupport(Object inst) {
547
this.instance = new WeakReference<Object>(inst);
548
file = getDataObject().getPrimaryFile();
551
/** is setting object changed? */
552
public final boolean isChanged() {
556
/** store setting or provide just SaveCookie? */
557
private boolean acceptSave() {
558
Object inst = instance.get();
559
if (inst == null || !(inst instanceof Serializable) ||
560
// XXX bad dep; should perhaps have some marker in the .settings file for this??
561
inst instanceof TopComponent) return false;
566
/** place where to filter events comming from setting object */
567
private boolean ignoreChange(PropertyChangeEvent pce) {
568
if (isChanged || isWriting || !getDataObject().isValid()) return true;
570
// undocumented workaround used in 3.3; since 3.4 convertors make
571
// possible to customize the setting change notification filtering
572
if (pce != null && Boolean.FALSE.equals(pce.getPropagationId())) return true;
574
if (knownToBeTemplate == null) knownToBeTemplate = getDataObject().isTemplate() ? Boolean.TRUE : Boolean.FALSE;
575
return knownToBeTemplate.booleanValue();
578
/** get convertor for possible upgrade; can be null */
579
private Convertor getConvertor() {
583
/** try to find out convertor for possible upgrade and cache it; can be null */
584
private Convertor initConvertor() {
585
Object inst = instance.get();
587
throw new IllegalStateException(
588
"setting object cannot be null: " + getDataObject());// NOI18N
592
FileObject newProviderFO = Env.findProvider(inst.getClass());
593
if (newProviderFO != null) {
594
FileObject foEntity = Env.findEntityRegistration(newProviderFO);
595
if (foEntity == null) foEntity = newProviderFO;
596
Object attrb = foEntity.getAttribute(Env.EA_PUBLICID);
597
if (attrb == null || !(attrb instanceof String)) {
598
throw new IOException("missing or invalid attribute: " + //NOI18N
599
Env.EA_PUBLICID + ", provider: " + foEntity); //NOI18N
601
if (XMLSettingsSupport.INSTANCE_DTD_ID.equals(attrb)) {
606
attrb = newProviderFO.getAttribute(Env.EA_CONVERTOR);
607
if (attrb == null || !(attrb instanceof Convertor)) {
608
throw new IOException("cannot create convertor: " + //NOI18N
609
attrb + ", provider: " + newProviderFO); //NOI18N
611
convertor = (Convertor) attrb;
615
} catch (IOException ex) {
621
/** Registers PropertyChangeListener to receive events and initialize
622
* listening to events comming from the setting object and file object.
623
* @param listener The listener to register.
625
public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
626
if (changeSupport == null || propertyChangeListenerCount <= 0) {
627
Object inst = instance.get();
628
if (inst == null) return;
629
if (changeSupport == null) {
630
changeSupport = new PropertyChangeSupport(this);
631
propertyChangeListenerCount = 0;
633
Convertor conv = initConvertor();
635
conv.registerSaver(inst, this);
637
registerPropertyChangeListener(inst);
640
propertyChangeListenerCount++;
641
changeSupport.addPropertyChangeListener(listener);
644
/** Removes PropertyChangeListener from the list of listeners.
645
* @param listener The listener to remove.
647
public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
648
if (changeSupport == null)
651
propertyChangeListenerCount--;
652
changeSupport.removePropertyChangeListener(listener);
654
if (propertyChangeListenerCount == 0) {
655
Object inst = instance.get();
656
if (inst == null) return;
658
Convertor conv = getConvertor();
660
conv.unregisterSaver(inst, this);
662
unregisterPropertyChangeListener(inst);
667
/** try to register PropertyChangeListener to the setting object
668
* to be notified about its changes.
670
private void registerPropertyChangeListener(Object inst) {
671
if (inst instanceof SharedClassObject) {
672
((SharedClassObject)inst).addPropertyChangeListener(this);
674
else if (inst instanceof JComponent) {
675
((JComponent) inst).addPropertyChangeListener(this);
678
// add propertyChangeListener
680
Method method = inst.getClass().getMethod(
681
"addPropertyChangeListener", // NOI18N
682
new Class[] {PropertyChangeListener.class});
683
method.invoke(inst, new Object[] {this});
684
} catch (NoSuchMethodException ex) {
685
// just changes done through gui will be saved
686
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
687
XMLSettingsSupport.err.warning(
688
"NoSuchMethodException: " + // NOI18N
689
inst.getClass().getName() + ".addPropertyChangeListener"); // NOI18N
691
} catch (IllegalAccessException ex) {
692
// just changes done through gui will be saved
693
XMLSettingsSupport.err.warning("Instance: " + inst); // NOI18N
694
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
695
} catch (java.lang.reflect.InvocationTargetException ex) {
696
// just changes done through gui will be saved
697
XMLSettingsSupport.err.log(Level.WARNING, null, ex.getTargetException());
702
/** @see #registerPropertyChangeListener
704
private void unregisterPropertyChangeListener(Object inst) {
706
Method method = inst.getClass().getMethod(
707
"removePropertyChangeListener", // NOI18N
708
new Class[] {PropertyChangeListener.class});
709
method.invoke(inst, new Object[] {this});
710
} catch (NoSuchMethodException ex) {
711
// just changes done through gui will be saved
712
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
713
XMLSettingsSupport.err.log(Level.FINE,
714
"NoSuchMethodException: " + // NOI18N
715
inst.getClass().getName() + ".removePropertyChangeListener"); // NOI18N
717
} catch (IllegalAccessException ex) {
718
XMLSettingsSupport.err.log(Level.WARNING, "Instance: " + inst); // NOI18N
719
XMLSettingsSupport.err.log(Level.WARNING, null, ex);
720
} catch (java.lang.reflect.InvocationTargetException ex) {
721
XMLSettingsSupport.err.log(Level.WARNING, null, ex.getTargetException());
725
/** Notifies all registered listeners about the event.
726
* @param event The event to be fired
727
* @see #PROP_FILE_CHANGED
730
private void firePropertyChange(String name) {
731
if (changeSupport != null)
732
changeSupport.firePropertyChange(name, null, null);
735
/** force to finish scheduled request */
736
public void flush() {
737
getScheduledRequest().forceToFinish();
740
private ByteArrayOutputStream buf;
742
/** process events coming from a setting object */
743
public final void propertyChange(PropertyChangeEvent pce) {
744
if (ignoreChange(pce)) return ;
746
firePropertyChange(PROP_SAVE);
748
getScheduledRequest().schedule(instance.get());
752
public void markDirty() {
753
if (ignoreChange(null)) return;
755
firePropertyChange(PROP_SAVE);
758
public void requestSave() throws IOException {
759
if (ignoreChange(null)) return;
761
firePropertyChange(PROP_SAVE);
762
getScheduledRequest().schedule(instance.get());
765
/** store buffer to the file. */
766
public void run() throws IOException {
767
if (!getDataObject().isValid()) {
768
//invalid data object cannot be used for storing
769
if (XMLSettingsSupport.err.isLoggable(Level.FINE)) {
770
XMLSettingsSupport.err.fine("invalid data object cannot be used for storing " + getDataObject()); // NOI18N
777
} catch (IOException ex) {
778
//#25288: DO can be invalidated asynchronously (module disabling)
779
//then ignore IO exceptions
780
if (getDataObject().isValid()) {
788
/** try to perform atomic action */
789
private void try2run() throws IOException {
792
synchronized (READWRITE_LOCK) {
793
if (XMLSettingsSupport.err.isLoggable(Level.FINER)) {
794
XMLSettingsSupport.err.finer("saving " + getDataObject()); // NOI18N
796
lock = getScheduledRequest().getFileLock();
797
if (lock == null) return;
798
los = file.getOutputStream(lock);
800
OutputStream os = new BufferedOutputStream(los, 1024);
803
if (XMLSettingsSupport.err.isLoggable(Level.FINER)) {
804
XMLSettingsSupport.err.finer("saved " + dobj); // NOI18N
812
/** Implementation of SaveCookie. */
813
public void save() throws IOException {
814
if (!isChanged) return;
815
getScheduledRequest().runAndWait();
818
/** store the setting object even if was not changed */
819
private void writeDown() throws IOException {
820
Object inst = instance.get();
821
if (inst == null) return ;
823
ByteArrayOutputStream b = new ByteArrayOutputStream(1024);
824
Writer w = new OutputStreamWriter(b, "UTF-8"); // NOI18N
827
Convertor conv = getConvertor();
840
file.getFileSystem().runAtomicAction(this);
842
if (!isChanged) firePropertyChange(PROP_SAVE);
846
////////////////////////////////////////////////////////////////////////////
848
////////////////////////////////////////////////////////////////////////////
850
/** A provider for .settings files containing serial data format
853
public final static class Provider implements Environment.Provider {
854
private final FileObject providerFO;
856
public static Environment.Provider create(FileObject fo) {
857
return new Provider(fo);
860
private Provider(FileObject fo) {
864
public Lookup getEnvironment(DataObject dobj) {
865
if (!(dobj instanceof InstanceDataObject)) return Lookup.EMPTY;
866
return new SerialDataConvertor(dobj, providerFO).getLookup();
871
////////////////////////////////////////////////////////////////////////////
873
////////////////////////////////////////////////////////////////////////////
875
/** allow to postpone the node creation */
876
private static final class NodeConvertor implements InstanceContent.Convertor<SerialDataConvertor, Node> {
879
public Node convert(SerialDataConvertor o) {
880
return new SerialDataNode(o);
883
public Class<Node> type(SerialDataConvertor o) {
887
public String id(SerialDataConvertor o) {
888
// Generally irrelevant in this context.
892
public String displayName(SerialDataConvertor o) {
893
// Again, irrelevant here.