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