1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.microemu.app.util;
26
27 import java.io.DataInputStream;
28 import java.io.DataOutputStream;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.FileOutputStream;
33 import java.io.FilenameFilter;
34 import java.io.IOException;
35 import java.security.AccessControlContext;
36 import java.security.AccessController;
37 import java.security.PrivilegedActionException;
38 import java.security.PrivilegedExceptionAction;
39 import java.util.Hashtable;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Vector;
43
44 import javax.microedition.rms.RecordStore;
45 import javax.microedition.rms.RecordStoreException;
46 import javax.microedition.rms.RecordStoreNotFoundException;
47 import javax.microedition.rms.RecordStoreNotOpenException;
48
49 import org.microemu.MicroEmulator;
50 import org.microemu.RecordStoreManager;
51 import org.microemu.app.Config;
52 import org.microemu.log.Logger;
53 import org.microemu.util.ExtendedRecordListener;
54 import org.microemu.util.RecordStoreImpl;
55
56 public class FileRecordStoreManager implements RecordStoreManager {
57
58 private final static String RECORD_STORE_SUFFIX = ".rs";
59
60 private final static List replaceChars = new Vector();
61
62 private MicroEmulator emulator;
63
64 private Hashtable testOpenRecordStores = new Hashtable();
65
66 private ExtendedRecordListener recordListener = null;
67
68
69 private AccessControlContext acc;
70
71 static {
72 replaceChars.add(":");
73 replaceChars.add("*");
74 replaceChars.add("?");
75 replaceChars.add("=");
76 replaceChars.add("|");
77 replaceChars.add("/");
78 replaceChars.add("\\");
79 replaceChars.add("\"");
80 }
81
82 private FilenameFilter filter = new FilenameFilter() {
83 public boolean accept(File dir, String name) {
84 if (name.endsWith(RECORD_STORE_SUFFIX)) {
85 return true;
86 } else {
87 return false;
88 }
89 }
90 };
91
92 public void init(MicroEmulator emulator) {
93 this.emulator = emulator;
94 this.acc = AccessController.getContext();
95 }
96
97 public String getName() {
98 return "File record store";
99 }
100
101 private File getSuiteFolder() {
102 return new File(Config.getConfigPath(), "suite-" + emulator.getLauncher().getSuiteName());
103 }
104
105 private static String escapeCharacter(String charcter) {
106 return "_%%" + (int) (charcter.charAt(0)) + "%%_";
107 }
108
109 static String recordStoreName2FileName(String recordStoreName) {
110 for (Iterator iterator = replaceChars.iterator(); iterator.hasNext();) {
111 String c = (String) iterator.next();
112 String newValue = escapeCharacter(c);
113 if (c.equals("\\")) {
114 c = "\\\\";
115 }
116 c = "[" + c + "]";
117 recordStoreName = recordStoreName.replaceAll(c, newValue);
118 }
119 return recordStoreName + RECORD_STORE_SUFFIX;
120 }
121
122 static String fileName2RecordStoreName(String fileName) {
123 for (Iterator iterator = replaceChars.iterator(); iterator.hasNext();) {
124 String c = (String) iterator.next();
125 String newValue = escapeCharacter(c);
126 if (c.equals("\\")) {
127 c = "\\\\";
128 }
129 fileName = fileName.replaceAll(newValue, c);
130 }
131 return fileName.substring(0, fileName.length() - RECORD_STORE_SUFFIX.length());
132 }
133
134 public void deleteRecordStore(final String recordStoreName) throws RecordStoreNotFoundException,
135 RecordStoreException {
136 final File storeFile = new File(getSuiteFolder(), recordStoreName2FileName(recordStoreName));
137
138 RecordStoreImpl recordStoreImpl = (RecordStoreImpl) testOpenRecordStores.get(storeFile.getName());
139 if (recordStoreImpl != null && recordStoreImpl.isOpen()) {
140 throw new RecordStoreException();
141 }
142
143 try {
144 recordStoreImpl = loadFromDisk(storeFile);
145 } catch (FileNotFoundException ex) {
146 throw new RecordStoreNotFoundException(recordStoreName);
147 }
148
149 try {
150 AccessController.doPrivileged(new PrivilegedExceptionAction() {
151 public Object run() throws FileNotFoundException {
152 storeFile.delete();
153 fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_DELETE, recordStoreName);
154 return null;
155 }
156 }, acc);
157 } catch (PrivilegedActionException e) {
158 Logger.error("Unable remove file " + storeFile, e);
159 throw new RecordStoreException();
160 }
161 }
162
163 public RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary) throws RecordStoreException {
164 File storeFile = new File(getSuiteFolder(), recordStoreName2FileName(recordStoreName));
165
166 RecordStoreImpl recordStoreImpl;
167 try {
168 recordStoreImpl = loadFromDisk(storeFile);
169 } catch (FileNotFoundException e) {
170 if (!createIfNecessary) {
171 throw new RecordStoreNotFoundException(recordStoreName);
172 }
173 recordStoreImpl = new RecordStoreImpl(this, recordStoreName);
174 saveToDisk(storeFile, recordStoreImpl);
175 }
176 recordStoreImpl.setOpen(true);
177 if (recordListener != null) {
178 recordStoreImpl.addRecordListener(recordListener);
179 }
180
181 testOpenRecordStores.put(storeFile.getName(), recordStoreImpl);
182
183 fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_OPEN, recordStoreName);
184
185 return recordStoreImpl;
186 }
187
188 public String[] listRecordStores() {
189 String[] result;
190 try {
191 result = (String[]) AccessController.doPrivileged(new PrivilegedExceptionAction() {
192 public Object run() {
193 return getSuiteFolder().list(filter);
194 }
195 }, acc);
196 } catch (PrivilegedActionException e) {
197 Logger.error("Unable to access storeFiles", e);
198 return null;
199 }
200 if (result != null) {
201 if (result.length == 0) {
202 result = null;
203 } else {
204 for (int i = 0; i < result.length; i++) {
205 result[i] = fileName2RecordStoreName(result[i]);
206 }
207 }
208 }
209 return result;
210 }
211
212 public void saveChanges(RecordStoreImpl recordStoreImpl) throws RecordStoreNotOpenException, RecordStoreException {
213
214 File storeFile = new File(getSuiteFolder(), recordStoreName2FileName(recordStoreImpl.getName()));
215
216 saveToDisk(storeFile, recordStoreImpl);
217 }
218
219 public void init() {
220 }
221
222 public void deleteStores() {
223 String[] stores = listRecordStores();
224 for (int i = 0; i < stores.length; i++) {
225 String store = stores[i];
226 try {
227 deleteRecordStore(store);
228 } catch (RecordStoreException e) {
229 Logger.debug("deleteRecordStore", e);
230 }
231 }
232 }
233
234 private RecordStoreImpl loadFromDisk(final File recordStoreFile) throws FileNotFoundException {
235 try {
236 return (RecordStoreImpl) AccessController.doPrivileged(new PrivilegedExceptionAction() {
237 public Object run() throws FileNotFoundException {
238 return loadFromDiskSecure(recordStoreFile);
239 }
240 }, acc);
241 } catch (PrivilegedActionException e) {
242 if (e.getCause() instanceof FileNotFoundException) {
243 throw (FileNotFoundException) e.getCause();
244 }
245 Logger.error("Unable access file " + recordStoreFile, e);
246 throw new FileNotFoundException();
247 }
248 }
249
250 private RecordStoreImpl loadFromDiskSecure(File recordStoreFile) throws FileNotFoundException {
251 RecordStoreImpl store = null;
252 try {
253 DataInputStream dis = new DataInputStream(new FileInputStream(recordStoreFile));
254 store = new RecordStoreImpl(this, dis);
255 dis.close();
256 } catch (FileNotFoundException e) {
257 throw e;
258 } catch (IOException e) {
259 Logger.error("RecordStore.loadFromDisk: ERROR reading " + recordStoreFile.getName(), e);
260 }
261 return store;
262 }
263
264 private void saveToDisk(final File recordStoreFile, final RecordStoreImpl recordStore) throws RecordStoreException {
265 try {
266 AccessController.doPrivileged(new PrivilegedExceptionAction() {
267 public Object run() throws RecordStoreException {
268 saveToDiskSecure(recordStoreFile, recordStore);
269 return null;
270 }
271 }, acc);
272 } catch (PrivilegedActionException e) {
273 if (e.getCause() instanceof RecordStoreException) {
274 throw (RecordStoreException) e.getCause();
275 }
276 Logger.error("Unable access file " + recordStoreFile, e);
277 throw new RecordStoreException();
278 }
279 }
280
281 private void saveToDiskSecure(final File recordStoreFile, final RecordStoreImpl recordStore)
282 throws RecordStoreException {
283 if (!recordStoreFile.getParentFile().exists()) {
284 if (!recordStoreFile.getParentFile().mkdirs()) {
285 throw new RecordStoreException("Unable to create recordStore directory");
286 }
287 }
288 try {
289 DataOutputStream dos = new DataOutputStream(new FileOutputStream(recordStoreFile));
290 recordStore.write(dos);
291 dos.close();
292 } catch (IOException e) {
293 Logger.error("RecordStore.saveToDisk: ERROR writting object to " + recordStoreFile.getName(), e);
294 throw new RecordStoreException(e.getMessage());
295 }
296 }
297
298 public int getSizeAvailable(RecordStoreImpl recordStoreImpl) {
299
300 return 1024 * 1024;
301 }
302
303 public void setRecordListener(ExtendedRecordListener recordListener) {
304 this.recordListener = recordListener;
305 }
306
307 public void fireRecordStoreListener(int type, String recordStoreName) {
308 if (recordListener != null) {
309 recordListener.recordStoreEvent(type, System.currentTimeMillis(), recordStoreName);
310 }
311 }
312 }