/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.util.prefs; import java.io.File; import java.io.FilenameFilter; import java.util.HashSet; import java.util.Iterator; import java.util.Properties; import java.util.Set; /** * The default implementation of <code>AbstractPreferences</code> for the Linux * platform, using the file system as its back end. * * TODO some sync mechanism with backend, Performance - check file edit date * * @since 1.4 * * @hide */ public class FilePreferencesImpl extends AbstractPreferences { //prefs file name private static final String PREFS_FILE_NAME = "prefs.xml"; //file path for this preferences node private final String path; //internal cache for prefs key-value pair private Properties prefs; //file represents this preferences node private File prefsFile; //parent dir for this preferences node private File dir; //cache for removed prefs key-value pair private Set<String> removed = new HashSet<String>(); //cache for updated prefs key-value pair private Set<String> updated = new HashSet<String>(); /* * -------------------------------------------------------------- * Constructors * -------------------------------------------------------------- */ /** * Construct root <code>FilePreferencesImpl</code> instance rooted * at the given path. * * @hide */ public FilePreferencesImpl(String path, boolean isUserNode) { super(null, ""); this.path = path; this.userNode = isUserNode; initPrefs(); } /** * Construct a prefs using given parent and given name */ private FilePreferencesImpl(AbstractPreferences parent, String name) { super(parent, name); path = ((FilePreferencesImpl) parent).path + File.separator + name; initPrefs(); } private void initPrefs() { dir = new File(path); newNode = !dir.exists(); prefsFile = new File(path + File.separator + PREFS_FILE_NAME); prefs = XMLParser.readXmlPreferences(prefsFile); } @Override protected String[] childrenNamesSpi() throws BackingStoreException { String[] names = dir.list(new FilenameFilter() { public boolean accept(File parent, String name) { return new File(path + File.separator + name).isDirectory(); } }); if (names == null) {// file is not a directory, exception case throw new BackingStoreException("Cannot get child names for " + toString() + " (path is " + path + ")"); } return names; } @Override protected AbstractPreferences childSpi(String name) { FilePreferencesImpl child = new FilePreferencesImpl(this, name); return child; } @Override protected void flushSpi() throws BackingStoreException { try { //if removed, return if(isRemoved()){ return; } // reload Properties currentPrefs = XMLParser.readXmlPreferences(prefsFile); // merge Iterator<String> it = removed.iterator(); while (it.hasNext()) { currentPrefs.remove(it.next()); } removed.clear(); it = updated.iterator(); while (it.hasNext()) { Object key = it.next(); currentPrefs.put(key, prefs.get(key)); } updated.clear(); // flush prefs = currentPrefs; XMLParser.writeXmlPreferences(prefsFile, prefs); } catch (Exception e) { throw new BackingStoreException(e); } } @Override protected String getSpi(String key) { try { if (prefs == null) { prefs = XMLParser.readXmlPreferences(prefsFile); } return prefs.getProperty(key); } catch (Exception e) { // if Exception happened, return null return null; } } @Override protected String[] keysSpi() throws BackingStoreException { final Set<Object> ks = prefs.keySet(); return ks.toArray(new String[ks.size()]); } @Override protected void putSpi(String name, String value) { prefs.setProperty(name, value); updated.add(name); } @Override protected void removeNodeSpi() throws BackingStoreException { prefsFile.delete(); boolean removeSucceed = dir.delete(); if (!removeSucceed) { throw new BackingStoreException("Cannot remove " + toString()); } } @Override protected void removeSpi(String key) { prefs.remove(key); updated.remove(key); removed.add(key); } @Override protected void syncSpi() throws BackingStoreException { flushSpi(); } }