--- a/core.startup/test/unit/src/org/netbeans/core/startup/preferences/TestPropertiesStorage.java +++ a/core.startup/test/unit/src/org/netbeans/core/startup/preferences/TestPropertiesStorage.java @@ -50,7 +50,12 @@ import java.util.Collections; import java.util.TreeSet; import java.util.prefs.BackingStoreException; +import java.util.prefs.NodeChangeEvent; +import java.util.prefs.NodeChangeListener; +import java.util.prefs.PreferenceChangeEvent; +import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; +import org.openide.filesystems.FileLock; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -61,6 +66,10 @@ public class TestPropertiesStorage extends TestFileStorage { private PropertiesStorage storage; private NbPreferences pref; + private boolean nodeAddedEvent; + private boolean nodeRemovedEvent; + private boolean prefChangedEvent; + private boolean prefRemovedEvent; public TestPropertiesStorage(String testName) { super(testName); @@ -133,45 +142,63 @@ assertNull(storage.toPropertiesFile()); } - public void testNodeIsReloadedAfterChange() throws Exception { - String key= "key"; - String value = "oldValue"; - String newValue = "newValue"; - storeEntry(key, value); - overrideStorageEntryWithNewValue(value, newValue); + public void testNodeIsReloadedAfterChange() throws Exception { + String key= "key"; + String value = "oldValue"; + String newValue = "newValue"; + storeEntry(key, value); + overrideStorageEntryWithNewData(constructNewEntryText(value, newValue)); - String reloadedValue = pref.get(key, null); + String reloadedValue = pref.get(key, null); - assertNotNull("Reloaded value must not be null", reloadedValue); - assertEquals("Reloaded value must equals to manually stored value", newValue, reloadedValue); - /* - Still need to cope with a memory leak + assertNotNull("Reloaded value must not be null", reloadedValue); + assertEquals("Reloaded value must equals to manually stored value", newValue, reloadedValue); + /* + Still need to cope with a memory leak - WeakReference weakPref = new WeakReference(pref); - storage = null; - pref = null; - assertGC("NbPreferences is not GC", weakPref); - */ + WeakReference weakPref = new WeakReference(pref); + storage = null; + pref = null; + assertGC("NbPreferences is not GC", weakPref); + */ - } + } - private void storeEntry(String keyName, String oldValue) throws BackingStoreException { - pref.put(keyName, oldValue); - pref.flush(); - } + private void storeEntry(String keyName, String oldValue) throws BackingStoreException { + pref.put(keyName, oldValue); + pref.flush(); + } - private void overrideStorageEntryWithNewValue(String oldValue, String newValue) throws IOException { - String newText = constructNewEntryText(oldValue, newValue); + private void overrideStorageEntryWithNewData(String newData) throws IOException { OutputStream storageOutputStream = storage.toPropertiesFile().getOutputStream(); - storageOutputStream.write(newText.getBytes("ISO-8859-1")); - storageOutputStream.close(); - } + storageOutputStream.write(newData.getBytes("ISO-8859-1")); + storageOutputStream.close(); + } - private String constructNewEntryText(String oldValue, String newValue) throws IOException { - String currentText = storage.toPropertiesFile().asText(); - String newText = currentText.replace(oldValue, newValue); - return newText; - } + // UNDER DEVELOPMENT + // + // NOTE: replacing the file should probably be a method on + // PropertiesStorage; or maybe a package method on + // NbPreferences for synchronization purposes. + // + // THIS METHOD should probably have an "subnode" argument, + // which (if not null) operates on subnode + // + private void XXXoverrideStorageEntryWithNewData(String newData) throws IOException { + FileObject foOrig = storage.toPropertiesFile(); + FileObject foNew = foOrig.getParent().createData("NewProperties"); + FileLock lock = foNew.lock(); + OutputStream os = foNew.getOutputStream(); + os.write(newData.getBytes("ISO-8859-1")); + os.close(); + foOrig.rename(lock, foOrig.getName(), foOrig.getExt()); + } + + private String constructNewEntryText(String oldValue, String newValue) throws IOException { + String currentText = storage.toPropertiesFile().asText(); + String newText = currentText.replace(oldValue, newValue); + return newText; + } public void testRemove() throws BackingStoreException { @@ -296,5 +323,86 @@ subnode.sync(); assertEquals(1, subnode.childrenNames().length); assertEquals("a", subnode.childrenNames()[0]); - } + } + + + public void testPreferencesEvents() throws Exception { + pref.addNodeChangeListener(new NodeListener()); + pref.addPreferenceChangeListener(new PrefListener()); + Preferences child = pref.node("a"); + Thread.currentThread().yield(); + assertTrue("Missing node added event", nodeAddedEvent); + pref.put("key","value"); + Thread.currentThread().yield(); + assertTrue("Missing preference change event", prefChangedEvent); + pref.remove("key"); + Thread.currentThread().yield(); + assertTrue("Missing preference removed event", prefRemovedEvent); + child.removeNode(); + Thread.currentThread().yield(); + assertTrue("Missing node removed event", nodeRemovedEvent); + } + + // started with testNodeIsReloadedAfterChange (memory leak issue?) + public void testPreferencesEventsAfterChange1() throws Exception { + String key= "key"; + String value = "oldValue"; + String newValue = "newValue"; + storeEntry(key, value); + + pref.addPreferenceChangeListener(new PrefListener()); + + overrideStorageEntryWithNewData(constructNewEntryText(value, newValue)); + Thread.currentThread().yield(); + + assertEquals("Reloaded value must equals to manually stored value", + newValue, pref.get(key, null)); + assertTrue("Missing preference change event", prefChangedEvent); + assertFalse("Unexpected preference removed event", prefRemovedEvent); + } + + // started with testNodeIsReloadedAfterChange (memory leak issue?) + public void testPreferencesEventsAfterChange2() throws Exception { + pref.put("targetKey","targetValue"); + pref.flush(); + // targetPrefs will be loaded as a file. + String targetPrefs = storage.toPropertiesFile().asText(); + + pref.clear(); + pref.put("key","value"); + pref.flush(); + + pref.addPreferenceChangeListener(new PrefListener()); + + overrideStorageEntryWithNewData(targetPrefs); + Thread.currentThread().yield(); + + assertEquals("not reloaded", "targetValue", pref.get("targetKey", "NONE")); + assertEquals("not unloaded", "NONE", pref.get("key", "NONE")); + assertTrue("Missing preference change event", prefChangedEvent); + assertTrue("Missing preference removed event", prefRemovedEvent); + } + + private class NodeListener implements NodeChangeListener { + @Override + public void childAdded(NodeChangeEvent evt) { + nodeAddedEvent = true; + } + + @Override + public void childRemoved(NodeChangeEvent evt) { + nodeRemovedEvent = true; + } + } + + private class PrefListener implements PreferenceChangeListener { + @Override + public void preferenceChange(PreferenceChangeEvent evt) { + if(evt.getNewValue() != null) { + prefChangedEvent = true; + } else { + prefRemovedEvent = true; + } + } + } }