Clover coverage report - Coverage timestamp: Sa Jul 7 2007 09:11:40 CEST FRAMES NO FRAMES |
file stats: | LOC: | 113 |  | Methods: | 3
| NCLOC: | 60 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
HashDiskPersistenceListener.java | 80% | 82,1% | 100% | 82,9% |

1 |  | /*
2 |  | * Copyright (c) 2002-2007 by OpenSymphony
3 |  | * All rights reserved.
4 |  | */
5 |  | package com.opensymphony.oscache.plugins.diskpersistence;
6 |  |
7 |  | import com.opensymphony.oscache.base.Config;
8 |  | import com.opensymphony.oscache.base.persistence.PersistenceListener;
9 |  |
10 |  | import java.io.File;
11 |  | import java.security.MessageDigest;
12 |  | import java.security.NoSuchAlgorithmException;
13 |  |
14 |  | /**
15 |  | * Persists cache data to disk. Provides a hash of the standard key name as the file name.
16 |  | *
17 |  | * A configurable hash algorithm is used to create a digest of the cache key for the
18 |  | * disk filename. This is to allow for more sane filenames for objects which dont generate
19 |  | * friendly cache keys.
20 |  | *
21 |  | * @author <a href="mailto:jparrott@soe.sony.com">Jason Parrott</a>
22 |  | */
23 |  | public class HashDiskPersistenceListener extends AbstractDiskPersistenceListener {
24 |  |
25 |  | private static final int DIR_LEVELS = 3;
26 |  |
27 |  | public final static String HASH_ALGORITHM_KEY = "cache.persistence.disk.hash.algorithm";
28 |  | public final static String DEFAULT_HASH_ALGORITHM = "MD5";
29 |  | protected MessageDigest md = null;
30 |  |
31 |  | /**
32 |  | * Initializes the <tt>HashDiskPersistenceListener</tt>. Namely this involves only setting up the
33 |  | * message digester to hash the key values.
34 |  | * @see com.opensymphony.oscache.base.persistence.PersistenceListener#configure(com.opensymphony.oscache.base.Config)
35 |  | */
36 | 59 | public PersistenceListener configure(Config config) {
37 | 59 | try {
38 | 59 | if (config.getProperty(HashDiskPersistenceListener.HASH_ALGORITHM_KEY) != null) {
39 | 30 | try {
40 | 30 | md = MessageDigest.getInstance(config.getProperty(HashDiskPersistenceListener.HASH_ALGORITHM_KEY));
41 |  | } catch (NoSuchAlgorithmException e) {
42 | 0 | md = MessageDigest.getInstance(HashDiskPersistenceListener.DEFAULT_HASH_ALGORITHM);
43 |  | }
44 |  | } else {
45 | 29 | md = MessageDigest.getInstance(HashDiskPersistenceListener.DEFAULT_HASH_ALGORITHM);
46 |  | }
47 |  | } catch (NoSuchAlgorithmException e) {
48 | 0 | e.printStackTrace();
49 | 0 | throw new RuntimeException("No hash algorithm available for disk persistence", e);
50 |  | }
51 |  |
52 | 59 | return super.configure(config);
53 |  | }
54 |  |
55 |  | /**
56 |  | * Generates a file name for the given cache key. In this case the file name is attempted to be
57 |  | * generated from the hash of the standard key name. Cache algorithm is configured via the
58 |  | * <em>cache.persistence.disk.hash.algorithm</em> configuration variable.
59 |  | * @param key cache entry key
60 |  | * @return char[] file name
61 |  | */
62 | 482 | protected synchronized char[] getCacheFileName(String key) {
63 | 482 | if ((key == null) || (key.length() == 0)) {
64 | 0 | throw new IllegalArgumentException("Invalid key '" + key + "' specified to getCacheFile.");
65 |  | }
66 |  |
67 | 482 | String hexDigest = byteArrayToHexString(md.digest(key.getBytes()));
68 |  |
69 |  | // CACHE-249: Performance improvement for large disk persistence usage
70 | 482 | StringBuffer filename = new StringBuffer(hexDigest.length() + 2 * DIR_LEVELS);
71 | 482 | for (int i=0; i < DIR_LEVELS; i++) {
72 | 1446 | filename.append(hexDigest.charAt(i)).append(File.separator);
73 |  | }
74 | 482 | filename.append(hexDigest);
75 |  |
76 | 482 | return filename.toString().toCharArray();
77 |  | }
78 |  |
79 |  | /**
80 |  | * Nibble conversion. Thanks to our friends at:
81 |  | * http://www.devx.com/tips/Tip/13540
82 |  | * @param in the byte array to convert
83 |  | * @return a java.lang.String based version of they byte array
84 |  | */
85 | 522 | static String byteArrayToHexString(byte[] in) {
86 | 522 | if ((in == null) || (in.length <= 0)) {
87 | 0 | return null;
88 |  | }
89 |  |
90 | 522 | StringBuffer out = new StringBuffer(in.length * 2);
91 |  |
92 | 522 | for (int i = 0; i < in.length; i++) {
93 | 7767 | byte ch = (byte) (in[i] & 0xF0); // Strip off high nibble
94 | 7767 | ch = (byte) (ch >>> 4);
95 |  |
96 |  | // shift the bits down
97 | 7767 | ch = (byte) (ch & 0x0F);
98 |  |
99 |  | // must do this is high order bit is on!
100 | 7767 | out.append(PSEUDO[(int) ch]); // convert the nibble to a String Character
101 | 7767 | ch = (byte) (in[i] & 0x0F); // Strip off low nibble
102 | 7767 | out.append(PSEUDO[(int) ch]); // convert the nibble to a String Character
103 |  | }
104 |  |
105 | 522 | return out.toString();
106 |  | }
107 |  |
108 |  | static final String[] PSEUDO = {
109 |  | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D",
110 |  | "E", "F"
111 |  | };
112 |  |
113 |  | }