1 | // Jomic - a viewer for comic book archives. |
2 | // Copyright (C) 2004-2011 Thomas Aglassinger |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | package net.sf.jomic.tools; |
17 | |
18 | import java.io.File; |
19 | |
20 | /** |
21 | * An entry in the cache. |
22 | * |
23 | * @author Thomas Aglassinger. |
24 | */ |
25 | public class ArchiveCacheEntry |
26 | { |
27 | /** |
28 | * Digits used to map the cache entry index to a sub directory name. The "long" directory is |
29 | * split in smaller subdirectories in order to prevent the cache main directory being |
30 | * cluttered with a sub directory for each cache entry. |
31 | */ |
32 | private static final int CACHE_DIR_DIGIT_COUNT = 8; |
33 | |
34 | /** |
35 | * Digits used to map the cache entry index to a directory name. |
36 | */ |
37 | private static final int CACHE_SUB_DIR_DIGIT_COUNT = 2; |
38 | |
39 | private File archiveFile; |
40 | private String cachedDir; |
41 | private int index; |
42 | private /*@ spec_public @*/ long lastAccessed; |
43 | private /*@ spec_public @*/ long lastModified; |
44 | private /*@ spec_public @*/ int lockCount; |
45 | private MutexLock lockMutex; |
46 | private /*@ spec_public @*/ long size; |
47 | |
48 | //@ invariant getArchiveFile() != null; |
49 | //@ invariant getCachedDirName() != null; |
50 | //@ invariant getIndex() >= 0; |
51 | //@ invariant getLockCount() >= 0; |
52 | //@ invariant getSize() >= 0; |
53 | |
54 | public ArchiveCacheEntry(File newArchiveFile, int newIndex) { |
55 | this(newArchiveFile, 0, 0, newIndex); |
56 | assert CACHE_DIR_DIGIT_COUNT % CACHE_SUB_DIR_DIGIT_COUNT == 0; |
57 | lastModified = newArchiveFile.lastModified(); |
58 | } |
59 | |
60 | public ArchiveCacheEntry(File newArchiveFile, long newLastAccessed, long newLastModified, int newIndex) { |
61 | StringTools stringTools = StringTools.instance(); |
62 | |
63 | archiveFile = newArchiveFile; |
64 | lastAccessed = newLastAccessed; |
65 | lastModified = newLastModified; |
66 | index = newIndex; |
67 | cachedDir = ""; |
68 | lockMutex = new MutexLock("ArchiveCacheEntry"); |
69 | |
70 | String indexText = stringTools.hexString(index, CACHE_DIR_DIGIT_COUNT, ""); |
71 | String separator = System.getProperty("file.separator"); |
72 | |
73 | for (int i = 0; i < indexText.length(); i += CACHE_SUB_DIR_DIGIT_COUNT) { |
74 | String pathPart = indexText.substring(i, i + CACHE_SUB_DIR_DIGIT_COUNT); |
75 | |
76 | if (cachedDir.length() > 0) { |
77 | cachedDir += separator; |
78 | } |
79 | cachedDir += pathPart; |
80 | } |
81 | } |
82 | |
83 | /** |
84 | * Set the size used by all files stored in the cached directory relative to <code>baseDir</code> |
85 | * . |
86 | * |
87 | * @see ArchiveCache#setCacheEntrySize(ArchiveCacheEntry) |
88 | */ |
89 | //@ assignable size; |
90 | void setSize(File baseDir) { |
91 | FileTools fileTools = FileTools.instance(); |
92 | File dir = new File(baseDir, getCachedDirName()); |
93 | |
94 | size = fileTools.getSize(dir); |
95 | } |
96 | |
97 | /** |
98 | * Get the archive file from which the cache was extracted. |
99 | */ |
100 | public /*@ pure @*/ File getArchiveFile() { |
101 | return archiveFile; |
102 | } |
103 | |
104 | /** |
105 | * Get directory in <code>baseDir</code> where the files extracted from the archive are |
106 | * located. |
107 | */ |
108 | public /*@ pure @*/ File getCachedDir(File baseDir) { |
109 | assert baseDir != null; |
110 | return new File(baseDir, getCachedDirName()); |
111 | } |
112 | |
113 | /** |
114 | * Get relative directory name where the files extracted from the archive are located. |
115 | */ |
116 | public /*@ pure @*/ String getCachedDirName() { |
117 | return cachedDir; |
118 | } |
119 | |
120 | /** |
121 | * Get the index in the list of cached archives used to lookup the archive path. |
122 | */ |
123 | public /*@ pure @*/ int getIndex() { |
124 | return index; |
125 | } |
126 | |
127 | /** |
128 | * Get the timestamp when the cache was last accessed. |
129 | */ |
130 | public /*@ pure @*/ long getLastAccessed() { |
131 | return lastAccessed; |
132 | } |
133 | |
134 | /** |
135 | * Get the timestamp when the archive was cached. |
136 | */ |
137 | public /*@ pure @*/ long getLastModified() { |
138 | return lastModified; |
139 | } |
140 | |
141 | /** |
142 | * Number of clients that locked this entry to prevent it from being removed. |
143 | */ |
144 | public /*@ pure @*/ int getLockCount() { |
145 | return lockCount; |
146 | } |
147 | |
148 | /** |
149 | * Get the number of bytes used by all files in the archive. This is not the size it uses on |
150 | * the storage device though because this would depend on the block size of the device. |
151 | */ |
152 | public /*@ pure @*/ long getSize() { |
153 | return size; |
154 | } |
155 | |
156 | //@ assignable lockCount; |
157 | //@ ensures getLockCount() == \old(getLockCount()) + 1; |
158 | public void lock() { |
159 | synchronized (lockMutex) { |
160 | assert lockCount >= 0; |
161 | lockCount += 1; |
162 | } |
163 | } |
164 | |
165 | //@ requires getLockCount() > 0; |
166 | //@ assignable lockCount; |
167 | //@ ensures getLockCount() == \old(getLockCount()) - 1; |
168 | public void unlock() { |
169 | synchronized (lockMutex) { |
170 | assert lockCount > 0; |
171 | lockCount -= 1; |
172 | } |
173 | } |
174 | |
175 | //@ assignable lastAccessed; |
176 | void updateLastAccessed() { |
177 | lastAccessed = System.currentTimeMillis(); |
178 | } |
179 | |
180 | //@ assignable lastModified; |
181 | void updateLastModified() { |
182 | lastModified = System.currentTimeMillis(); |
183 | } |
184 | } |