1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.transaction.file;
18
19 import java.io.BufferedReader;
20 import java.io.BufferedWriter;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.io.OutputStreamWriter;
30 import java.io.UnsupportedEncodingException;
31
32 import org.apache.commons.transaction.util.FileHelper;
33 import org.apache.commons.transaction.util.LoggerFacade;
34
35
36
37
38
39
40
41 public class FileSequence {
42
43 protected final String storeDir;
44 protected final LoggerFacade logger;
45
46
47
48
49
50
51
52 public FileSequence(String storeDir, LoggerFacade logger) throws ResourceManagerException {
53 this.storeDir = storeDir;
54 this.logger = logger;
55 File file = new File(storeDir);
56 file.mkdirs();
57 if (!file.exists()) {
58 throw new ResourceManagerException("Can not create working directory " + storeDir);
59 }
60 }
61
62
63
64
65
66
67
68 public synchronized boolean exists(String sequenceName) {
69 String pathI = getPathI(sequenceName);
70 String pathII = getPathII(sequenceName);
71
72 return (FileHelper.fileExists(pathI) || FileHelper.fileExists(pathII));
73 }
74
75
76
77
78
79
80
81
82 public synchronized boolean create(String sequenceName, long initialValue) throws ResourceManagerException {
83 if (exists(sequenceName))
84 return false;
85 write(sequenceName, initialValue);
86 return true;
87 }
88
89
90
91
92
93
94
95 public synchronized boolean delete(String sequenceName) {
96 if (!exists(sequenceName))
97 return false;
98 String pathI = getPathI(sequenceName);
99 String pathII = getPathII(sequenceName);
100
101
102 boolean res1 = FileHelper.deleteFile(pathI);
103 boolean res2 = FileHelper.deleteFile(pathII);
104
105 return (res1 || res2);
106 }
107
108
109
110
111
112
113
114
115
116
117 public synchronized long nextSequenceValueBottom(String sequenceName, long increment)
118 throws ResourceManagerException {
119 if (!exists(sequenceName)) {
120 throw new ResourceManagerException("Sequence " + sequenceName + " does not exist");
121 }
122 if (increment <= 0) {
123 throw new IllegalArgumentException("Increment must be greater than 0, was " + increment);
124 }
125 long value = read(sequenceName);
126 long newValue = value + increment;
127 write(sequenceName, newValue);
128 return value;
129 }
130
131 protected long read(String sequenceName) throws ResourceManagerException {
132 String pathI = getPathI(sequenceName);
133 String pathII = getPathII(sequenceName);
134
135 long returnValue = -1;
136
137 long valueI = -1;
138 if (FileHelper.fileExists(pathI)) {
139 try {
140 valueI = readFromPath(pathI);
141 } catch (NumberFormatException e) {
142 throw new ResourceManagerException("Fatal internal error: Backup sequence value corrupted");
143 } catch (FileNotFoundException e) {
144 throw new ResourceManagerException("Fatal internal error: Backup sequence vanished");
145 } catch (IOException e) {
146 throw new ResourceManagerException("Fatal internal error: Backup sequence value corrupted");
147 }
148 }
149
150 long valueII = -1;
151 if (FileHelper.fileExists(pathII)) {
152 try {
153 valueII = readFromPath(pathII);
154 if (valueII > valueI) {
155 returnValue = valueII;
156 } else {
157
158 logger.logWarning("Latest sequence value smaller than previous, reverting to previous");
159 FileHelper.deleteFile(pathII);
160 returnValue = valueI;
161 }
162 } catch (NumberFormatException e) {
163 logger.logWarning("Latest sequence value corrupted, reverting to previous");
164 FileHelper.deleteFile(pathII);
165 returnValue = valueI;
166 } catch (FileNotFoundException e) {
167 logger.logWarning("Can not find latest sequence value, reverting to previous");
168 FileHelper.deleteFile(pathII);
169 returnValue = valueI;
170 } catch (IOException e) {
171 logger.logWarning("Can not read latest sequence value, reverting to previous");
172 FileHelper.deleteFile(pathII);
173 returnValue = valueI;
174 }
175 } else {
176 logger.logWarning("Can not read latest sequence value, reverting to previous");
177 returnValue = valueI;
178 }
179
180 if (returnValue != -1) {
181 return returnValue;
182 } else {
183 throw new ResourceManagerException("Fatal internal error: Could not compute valid sequence value");
184 }
185 }
186
187 protected void write(String sequenceName, long value) throws ResourceManagerException {
188 String pathII = getPathII(sequenceName);
189
190 File f2 = new File(pathII);
191
192 if (f2.exists()) {
193
194 String pathI = getPathI(sequenceName);
195 File f1 = new File(pathI);
196 f1.delete();
197 if (!f2.renameTo(f1)) {
198 throw new ResourceManagerException("Fatal internal error: Can not create backup value at" + pathI);
199 }
200 }
201 try {
202 if (!f2.createNewFile()) {
203 throw new ResourceManagerException("Fatal internal error: Can not create new value at" + pathII);
204 }
205 } catch (IOException e) {
206 throw new ResourceManagerException("Fatal internal error: Can not create new value at" + pathII, e);
207 }
208 writeToPath(pathII, value);
209 }
210
211 protected String getPathI(String sequenceName) {
212 return storeDir + "/" + sequenceName + "_1.seq";
213 }
214
215 protected String getPathII(String sequenceName) {
216 return storeDir + "/" + sequenceName + "_2.seq";
217 }
218
219 protected long readFromPath(String path)
220 throws ResourceManagerException, NumberFormatException, FileNotFoundException, IOException {
221 File file = new File(path);
222 BufferedReader reader = null;
223 try {
224 InputStream is = new FileInputStream(file);
225
226
227 reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
228 String valueString = reader.readLine();
229 long value = Long.parseLong(valueString);
230 return value;
231 } catch (UnsupportedEncodingException e) {
232 throw new ResourceManagerException("Fatal internal error, encoding UTF-8 unknown");
233 } finally {
234 if (reader != null) {
235 try {
236 reader.close();
237 } catch (IOException e) {
238 }
239
240 }
241 }
242 }
243
244 protected void writeToPath(String path, long value) throws ResourceManagerException {
245 File file = new File(path);
246 BufferedWriter writer = null;
247 try {
248 OutputStream os = new FileOutputStream(file);
249 writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
250 String valueString = Long.toString(value);
251 writer.write(valueString);
252 writer.write('\n');
253 } catch (FileNotFoundException e) {
254 throw new ResourceManagerException("Fatal internal error: Can not find sequence at " + path);
255 } catch (IOException e) {
256 throw new ResourceManagerException("Fatal internal error: Can not write to sequence at " + path);
257 } finally {
258 if (writer != null) {
259 try {
260 writer.close();
261 } catch (IOException e) {
262 }
263
264 }
265 }
266 }
267 }