Home | History | Annotate | Download | only in prefs
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package java.util.prefs;
     18 
     19 import java.io.File;
     20 import java.io.FilenameFilter;
     21 import java.security.AccessController;
     22 import java.security.PrivilegedAction;
     23 import java.util.HashSet;
     24 import java.util.Iterator;
     25 import java.util.Properties;
     26 import java.util.Set;
     27 
     28 import org.apache.harmony.prefs.internal.nls.Messages;
     29 
     30 /**
     31  * The default implementation of <code>AbstractPreferences</code> for the Linux
     32  * platform, using the file system as its back end.
     33  *
     34  * TODO some sync mechanism with backend, Performance - check file edit date
     35  *
     36  * @since 1.4
     37  */
     38 class FilePreferencesImpl extends AbstractPreferences {
     39 
     40     /*
     41      * --------------------------------------------------------------
     42      * Class fields
     43      * --------------------------------------------------------------
     44      */
     45 
     46     //prefs file name
     47     private static final String PREFS_FILE_NAME = "prefs.xml"; //$NON-NLS-1$
     48 
     49     //home directory for user prefs
     50     private static String USER_HOME;
     51 
     52     //home directory for system prefs
     53     private static String SYSTEM_HOME;
     54 
     55     /*
     56      * --------------------------------------------------------------
     57      * Class initializer
     58      * --------------------------------------------------------------
     59      */
     60     static {
     61         AccessController.doPrivileged(new PrivilegedAction<Void>() {
     62             public Void run() {
     63                 USER_HOME = System.getProperty("user.home") + "/.java/.userPrefs";//$NON-NLS-1$ //$NON-NLS-2$
     64                 SYSTEM_HOME = System.getProperty("java.home") + "/.systemPrefs";//$NON-NLS-1$//$NON-NLS-2$
     65                 return null;
     66             }
     67         });
     68     }
     69 
     70     /*
     71      * --------------------------------------------------------------
     72      * Instance fields
     73      * --------------------------------------------------------------
     74      */
     75 
     76     //file path for this preferences node
     77     private String path;
     78 
     79     //internal cache for prefs key-value pair
     80     private Properties prefs;
     81 
     82     //file represents this preferences node
     83     private File prefsFile;
     84 
     85     //parent dir for this preferences node
     86     private File dir;
     87 
     88     //cache for removed prefs key-value pair
     89     private Set<String> removed = new HashSet<String>();
     90 
     91     //cache for updated prefs key-value pair
     92     private Set<String> updated = new HashSet<String>();
     93 
     94     /*
     95      * --------------------------------------------------------------
     96      * Constructors
     97      * --------------------------------------------------------------
     98      */
     99 
    100     /**
    101      * Construct root <code>FilePreferencesImpl</code> instance, construct
    102      * user root if userNode is true, system root otherwise
    103      */
    104     FilePreferencesImpl(boolean userNode) {
    105         super(null, ""); //$NON-NLS-1$
    106         this.userNode = userNode;
    107         path = userNode ? USER_HOME : SYSTEM_HOME;
    108         initPrefs();
    109     }
    110 
    111     /**
    112      * Construct a prefs using given parent and given name
    113      */
    114     private FilePreferencesImpl(AbstractPreferences parent, String name) {
    115         super(parent, name);
    116         path = ((FilePreferencesImpl) parent).path + File.separator + name;
    117         initPrefs();
    118     }
    119 
    120     private void initPrefs() {
    121         dir = new File(path);
    122         newNode = (AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
    123             public Boolean run() {
    124                 return Boolean.valueOf(!dir.exists());
    125             }
    126         })).booleanValue();
    127         prefsFile = new File(path + File.separator + PREFS_FILE_NAME);
    128         prefs = XMLParser.loadFilePrefs(prefsFile);
    129     }
    130 
    131     @Override
    132     protected String[] childrenNamesSpi() throws BackingStoreException {
    133         String[] names = AccessController
    134         .doPrivileged(new PrivilegedAction<String[]>() {
    135             public String[] run() {
    136                 return dir.list(new FilenameFilter() {
    137                     public boolean accept(File parent, String name) {
    138                         return new File(path + File.separator + name).isDirectory();
    139                     }
    140                 });
    141 
    142             }
    143         });
    144         if (null == names) {// file is not a directory, exception case
    145             // prefs.3=Cannot get children names for {0}!
    146             throw new BackingStoreException(
    147                     Messages.getString("prefs.3", toString()));  //$NON-NLS-1$
    148         }
    149         return names;
    150     }
    151 
    152     @Override
    153     protected AbstractPreferences childSpi(String name) {
    154         FilePreferencesImpl child = new FilePreferencesImpl(this, name);
    155         return child;
    156     }
    157 
    158     @Override
    159     protected void flushSpi() throws BackingStoreException {
    160         try {
    161             //if removed, return
    162             if(isRemoved()){
    163                 return;
    164             }
    165             // reload
    166             Properties currentPrefs = XMLParser.loadFilePrefs(prefsFile);
    167             // merge
    168             Iterator<String> it = removed.iterator();
    169             while (it.hasNext()) {
    170                 currentPrefs.remove(it.next());
    171             }
    172             removed.clear();
    173             it = updated.iterator();
    174             while (it.hasNext()) {
    175                 Object key = it.next();
    176                 currentPrefs.put(key, prefs.get(key));
    177             }
    178             updated.clear();
    179             // flush
    180             prefs = currentPrefs;
    181             XMLParser.flushFilePrefs(prefsFile, prefs);
    182         } catch (Exception e) {
    183             throw new BackingStoreException(e);
    184         }
    185     }
    186 
    187     @Override
    188     protected String getSpi(String key) {
    189         try {
    190             if (null == prefs) {
    191                 prefs = XMLParser.loadFilePrefs(prefsFile);
    192             }
    193             return prefs.getProperty(key);
    194         } catch (Exception e) {
    195             // if Exception happened, return null
    196             return null;
    197         }
    198     }
    199 
    200     @Override
    201     protected String[] keysSpi() throws BackingStoreException {
    202         final Set<Object> ks = prefs.keySet();
    203         return ks.toArray(new String[ks.size()]);
    204     }
    205 
    206     @Override
    207     protected void putSpi(String name, String value) {
    208         prefs.setProperty(name, value);
    209         updated.add(name);
    210     }
    211 
    212     @Override
    213     protected void removeNodeSpi() throws BackingStoreException {
    214         boolean removeSucceed = (AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
    215             public Boolean run() {
    216                 prefsFile.delete();
    217                 return Boolean.valueOf(dir.delete());
    218             }
    219         })).booleanValue();
    220         if (!removeSucceed) {
    221             // prefs.4=Cannot remove {0}!
    222             throw new BackingStoreException(Messages.getString("prefs.4", toString()));  //$NON-NLS-1$
    223         }
    224     }
    225 
    226     @Override
    227     protected void removeSpi(String key) {
    228         prefs.remove(key);
    229         updated.remove(key);
    230         removed.add(key);
    231     }
    232 
    233     @Override
    234     protected void syncSpi() throws BackingStoreException {
    235         flushSpi();
    236     }
    237 }
    238