1 package org.jboss.cache.loader; 2 3 import org.apache.commons.logging.Log; 4 import org.apache.commons.logging.LogFactory; 5 import org.jboss.cache.Fqn; 6 import org.jboss.cache.Modification; 7 import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig; 8 import org.jboss.util.stream.MarshalledValueInputStream; 9 10 import java.io.File ; 11 import java.io.FileInputStream ; 12 import java.io.FileOutputStream ; 13 import java.io.IOException ; 14 import java.io.ObjectOutputStream ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.List ; 18 import java.util.Map ; 19 import java.util.Set ; 20 import java.util.concurrent.ConcurrentHashMap ; 21 import java.util.regex.Matcher ; 22 import java.util.regex.Pattern ; 23 24 30 public class FileCacheLoader extends AbstractCacheLoader 31 { 32 File root = null; 33 String rootPath = null; 34 Log log = LogFactory.getLog(getClass()); 35 36 private FileCacheLoaderConfig config; 37 38 42 Map <Object , List <Modification>> transactions = new ConcurrentHashMap (); 43 44 47 public static final String DATA = "data.dat"; 48 49 52 public static final String DIR_SUFFIX = "fdb"; 53 54 57 public static final Pattern PATH_PATTERN = Pattern.compile("[\\*<>|\"?]"); 58 59 62 public static final Pattern FQN_PATTERN = Pattern.compile("[\\\\\\/:*<>|\"?]"); 63 64 public FileCacheLoader() 65 { 66 } 67 68 public void setConfig(IndividualCacheLoaderConfig base) 69 { 70 if (base instanceof FileCacheLoaderConfig) 71 { 72 this.config = (FileCacheLoaderConfig) base; 73 } 74 else if (base != null) 75 { 76 this.config = new FileCacheLoaderConfig(base); 77 } 78 79 String location = this.config != null ? this.config.getLocation() : null; 80 if (location != null && location.length() > 0) 81 { 82 root = new File (location); 83 rootPath = root.getAbsolutePath() + File.separator; 84 } 85 } 86 87 public IndividualCacheLoaderConfig getConfig() 88 { 89 return config; 90 } 91 92 public void create() throws Exception 93 { 94 if (root == null) 95 { 96 String tmpLocation = System.getProperty("java.io.tmpdir", "C:\\tmp"); 97 root = new File (tmpLocation); 98 rootPath = root.getAbsolutePath() + File.separator; 99 } 100 if (!root.exists()) 101 { 102 if (log.isTraceEnabled()) 103 { 104 log.trace("Creating cache loader location " + root); 105 } 106 107 if (config.isCheckCharacterPortability()) 108 { 109 111 isCharacterPortableLocation(root.getAbsolutePath()); 112 } 113 114 boolean created = root.mkdirs(); 115 if (!created) 116 { 117 throw new IOException ("Unable to create cache loader location " + root); 118 } 119 } 120 121 if (!root.isDirectory()) 122 { 123 throw new IOException ("Cache loader location [" + root + "] is not a directory!"); 124 } 125 } 126 127 public void start() throws Exception 128 { 129 } 130 131 public void stop() 132 { 133 } 134 135 public void destroy() 136 { 137 } 138 139 public Set <String > getChildrenNames(Fqn fqn) throws Exception 140 { 141 File parent = getDirectory(fqn, false); 142 if (parent == null) return null; 143 File [] children = parent.listFiles(); 144 Set <String > s = new HashSet <String >(); 145 for (int i = 0; i < children.length; i++) 146 { 147 File child = children[i]; 148 if (child.isDirectory() && child.getName().endsWith(DIR_SUFFIX)) 149 { 150 String child_name = child.getName(); 151 child_name = child_name.substring(0, child_name.lastIndexOf(DIR_SUFFIX) - 1); 152 s.add(child_name); 153 } 154 } 155 return s.size() == 0 ? null : s; 156 } 157 158 public Map get(Fqn fqn) throws Exception 159 { 160 return loadAttributes(fqn); 161 } 162 163 public boolean exists(Fqn fqn) throws Exception 164 { 165 File f = getDirectory(fqn, false); 166 return f != null; 167 } 168 169 public Object put(Fqn fqn, Object key, Object value) throws Exception 170 { 171 Object retval; 172 Map m = loadAttributes(fqn); 173 if (m == null) m = new HashMap (); 174 retval = m.put(key, value); 175 storeAttributes(fqn, m); 176 return retval; 177 } 178 179 public void put(Fqn fqn, Map attributes) throws Exception 180 { 181 put(fqn, attributes, false); 182 } 183 184 185 public void put(Fqn fqn, Map attributes, boolean erase) throws Exception 186 { 187 Map m = erase ? new HashMap () : loadAttributes(fqn); 188 if (m == null) m = new HashMap (); 189 if (attributes != null) 190 { 191 m.putAll(attributes); 192 } 193 storeAttributes(fqn, m); 194 } 195 196 void put(Fqn fqn) throws Exception 197 { 198 getDirectory(fqn, true); 199 } 200 201 public Object remove(Fqn fqn, Object key) throws Exception 202 { 203 Object retval; 204 Map m = loadAttributes(fqn); 205 if (m == null) return null; 206 retval = m.remove(key); 207 storeAttributes(fqn, m); 208 return retval; 209 } 210 211 public void remove(Fqn fqn) throws Exception 212 { 213 File dir = getDirectory(fqn, false); 214 if (dir != null) 215 { 216 boolean flag = removeDirectory(dir, true); 217 if (!flag) 218 { 219 log.warn("failed removing " + fqn); 220 } 221 } 222 } 223 224 public void removeData(Fqn fqn) throws Exception 225 { 226 File f = getDirectory(fqn, false); 227 if (f != null) 228 { 229 File data = new File (f, DATA); 230 if (data.exists()) 231 { 232 boolean flag = data.delete(); 233 if (!flag) 234 { 235 log.warn("failed removing file " + data.getName()); 236 } 237 } 238 } 239 } 240 241 public void prepare(Object tx, List <Modification> modifications, boolean one_phase) throws Exception 242 { 243 if (one_phase) 244 { 245 put(modifications); 246 } 247 else 248 { 249 transactions.put(tx, modifications); 250 } 251 } 252 253 public void commit(Object tx) throws Exception 254 { 255 List modifications = transactions.remove(tx); 256 if (modifications == null) 257 { 258 throw new Exception ("transaction " + tx + " not found in transaction table"); 259 } 260 put(modifications); 261 } 262 263 public void rollback(Object tx) 264 { 265 transactions.remove(tx); 266 } 267 268 269 270 File getDirectory(Fqn fqn, boolean create) 271 { 272 File f = new File (getFullPath(fqn)); 273 if (!f.exists()) 274 { 275 if (create) 276 { 277 f.mkdirs(); 278 } 279 else 280 { 281 return null; 282 } 283 } 284 return f; 285 } 286 287 288 296 boolean removeDirectory(File dir, boolean include_start_dir) 297 { 298 boolean success = true; 299 File [] subdirs = dir.listFiles(); 300 for (int i = 0; i < subdirs.length; i++) 301 { 302 File file = subdirs[i]; 303 if (file.isFile() && file.getName().equals(DATA)) 304 { 305 if (!file.delete()) 306 { 307 success = false; 308 } 309 continue; 310 } 311 if (file.isDirectory() && file.getName().endsWith(DIR_SUFFIX)) 312 { 313 if (!removeDirectory(file, false)) 314 { 315 success = false; 316 } 317 if (!file.delete()) 318 { 319 success = false; 320 } 321 } 322 } 323 324 if (include_start_dir) 325 { 326 if (!dir.equals(root)) 327 { 328 if (dir.delete()) 329 { 330 return success; 331 } 332 success = false; 333 } 334 } 335 336 return success; 337 } 338 339 String getFullPath(Fqn fqn) 340 { 341 StringBuffer sb = new StringBuffer (rootPath); 342 for (int i = 0; i < fqn.size(); i++) 343 { 344 Object tmp = fqn.get(i); 345 String tmp_dir = tmp.toString(); sb.append(tmp_dir).append(".").append(DIR_SUFFIX).append(File.separator); 348 } 349 return sb.toString(); 350 } 351 352 protected Map loadAttributes(Fqn fqn) throws Exception 353 { 354 File f = getDirectory(fqn, false); 355 if (f == null) return null; File child = new File (f, DATA); 358 if (!child.exists()) return new HashMap (0); FileInputStream in = new FileInputStream (child); 361 MarshalledValueInputStream input = new MarshalledValueInputStream(in); 362 Map m = (Map ) input.readObject(); 363 in.close(); 364 return m; 365 } 366 367 protected void storeAttributes(Fqn fqn, Map attrs) throws Exception 368 { 369 File f = getDirectory(fqn, true); 370 File child = new File (f, DATA); 371 if (!child.exists()) 372 { 373 if (config.isCheckCharacterPortability()) 374 { 375 376 isLengthPortablePath(child.getAbsolutePath()); 377 378 isCharacterPortableTree(fqn); 379 } 380 381 if (!child.createNewFile()) 382 { 383 throw new IOException ("Unable to create file: " + child); 384 } 385 } 386 FileOutputStream out = new FileOutputStream (child); 387 ObjectOutputStream output = new ObjectOutputStream (out); 388 output.writeObject(attrs); 389 out.close(); 390 } 391 392 protected boolean isCharacterPortableLocation(String fileAbsolutePath) 393 { 394 Matcher matcher = PATH_PATTERN.matcher(fileAbsolutePath); 395 if (matcher.find()) 396 { 397 log.warn("Cache loader location ( " + fileAbsolutePath + " ) contains one of these characters: '*' '<' '>' '|' '\"' '?'"); 398 log.warn("Directories containing these characters are illegal in some operative systems and could lead to portability issues"); 399 return false; 400 } 401 402 return true; 403 } 404 405 protected boolean isCharacterPortableTree(Fqn fqn) 406 { 407 List elements = fqn.peekElements(); 408 for (Object anElement : elements) 410 { 411 Matcher matcher = FQN_PATTERN.matcher(anElement.toString()); 413 if (matcher.find()) 414 { 415 log.warn("One of the Fqn ( " + fqn + " ) elements contains one of these characters: '*' '<' '>' '|' '\"' '?' '\\' '/' ':' "); 416 log.warn("Directories containing these characters are illegal in some operating systems and could lead to portability issues"); 417 return false; 418 } 419 } 420 421 return true; 422 } 423 424 protected boolean isLengthPortablePath(String absoluteFqnPath) 425 { 426 if (absoluteFqnPath.length() > 255) 427 { 428 log.warn("The full absolute path to the fqn that you are trying to store is bigger than 255 characters, this could lead to problems in Windows systems: " + absoluteFqnPath); 429 return false; 430 } 431 432 return true; 433 } 434 } 435 | Popular Tags |