View Javadoc

1   /**
2    *  MicroEmulator
3    *  Copyright (C) 2001-2007 Bartek Teodorczyk <barteo@barteo.net>
4    *
5    *  This library is free software; you can redistribute it and/or
6    *  modify it under the terms of the GNU Lesser General Public
7    *  License as published by the Free Software Foundation; either
8    *  version 2.1 of the License, or (at your option) any later version.
9    *
10   *  This library is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   *  Lesser General Public License for more details.
14   *
15   *  You should have received a copy of the GNU Lesser General Public
16   *  License along with this library; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.microemu.app.util;
21  
22  import java.io.DataInputStream;
23  import java.io.DataOutputStream;
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileNotFoundException;
27  import java.io.FileOutputStream;
28  import java.io.FilenameFilter;
29  import java.io.IOException;
30  import java.security.AccessControlContext;
31  import java.security.AccessController;
32  import java.security.PrivilegedActionException;
33  import java.security.PrivilegedExceptionAction;
34  import java.util.Hashtable;
35  
36  import javax.microedition.rms.RecordStore;
37  import javax.microedition.rms.RecordStoreException;
38  import javax.microedition.rms.RecordStoreNotFoundException;
39  import javax.microedition.rms.RecordStoreNotOpenException;
40  
41  import org.microemu.MicroEmulator;
42  import org.microemu.RecordStoreManager;
43  import org.microemu.app.Config;
44  import org.microemu.log.Logger;
45  import org.microemu.util.ExtendedRecordListener;
46  import org.microemu.util.RecordStoreImpl;
47  
48  public class FileRecordStoreManager implements RecordStoreManager {
49  
50  	private final static String RECORD_STORE_SUFFIX = ".rs";
51  
52  	private MicroEmulator emulator;
53  
54  	private Hashtable testOpenRecordStores = new Hashtable();
55  
56  	private ExtendedRecordListener recordListener = null;
57  
58  	/* The context to be used when accessing files in Webstart */
59  	private AccessControlContext acc;
60  
61  	private FilenameFilter filter = new FilenameFilter() {
62  		public boolean accept(File dir, String name) {
63  			if (name.endsWith(RECORD_STORE_SUFFIX)) {
64  				return true;
65  			} else {
66  				return false;
67  			}
68  		}
69  	};
70  
71  	public void init(MicroEmulator emulator) {
72  		this.emulator = emulator;
73  		this.acc = AccessController.getContext();
74  	}
75  
76  	public String getName() {
77  		return "File record store";
78  	}
79  
80  	private File getSuiteFolder() {
81  		return new File(Config.getConfigPath(), "suite-" + emulator.getLauncher().getSuiteName());
82  	}
83  
84  	public void deleteRecordStore(final String recordStoreName) throws RecordStoreNotFoundException,
85  			RecordStoreException {
86  		final File storeFile = new File(getSuiteFolder(), recordStoreName + RECORD_STORE_SUFFIX);
87  
88  		RecordStoreImpl recordStoreImpl = (RecordStoreImpl) testOpenRecordStores.get(storeFile.getName());
89  		if (recordStoreImpl != null && recordStoreImpl.isOpen()) {
90  			throw new RecordStoreException();
91  		}
92  
93  		try {
94  			recordStoreImpl = loadFromDisk(storeFile);
95  		} catch (FileNotFoundException ex) {
96  			throw new RecordStoreNotFoundException(recordStoreName);
97  		}
98  
99  		try {
100 			AccessController.doPrivileged(new PrivilegedExceptionAction() {
101 				public Object run() throws FileNotFoundException {
102 					storeFile.delete();
103 					fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_DELETE, recordStoreName);
104 					return null;
105 				}
106 			}, acc);
107 		} catch (PrivilegedActionException e) {
108 			Logger.error("Unable remove file " + storeFile, e);
109 			throw new RecordStoreException();
110 		}
111 	}
112 
113 	public RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary) throws RecordStoreException {
114 		File storeFile = new File(getSuiteFolder(), recordStoreName + RECORD_STORE_SUFFIX);
115 
116 		RecordStoreImpl recordStoreImpl;
117 		try {
118 			recordStoreImpl = loadFromDisk(storeFile);
119 		} catch (FileNotFoundException e) {
120 			if (!createIfNecessary) {
121 				throw new RecordStoreNotFoundException(recordStoreName);
122 			}
123 			recordStoreImpl = new RecordStoreImpl(this, recordStoreName);
124 			saveToDisk(storeFile, recordStoreImpl);
125 		}
126 		recordStoreImpl.setOpen(true);
127 		if (recordListener != null) {
128 			recordStoreImpl.addRecordListener(recordListener);
129 		}
130 
131 		testOpenRecordStores.put(storeFile.getName(), recordStoreImpl);
132 
133 		fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_OPEN, recordStoreName);
134 
135 		return recordStoreImpl;
136 	}
137 
138 	public String[] listRecordStores() {
139 		String[] result;
140 		try {
141 			result = (String[]) AccessController.doPrivileged(new PrivilegedExceptionAction() {
142 				public Object run() {
143 					return getSuiteFolder().list(filter);
144 				}
145 			}, acc);
146 		} catch (PrivilegedActionException e) {
147 			Logger.error("Unable to acess storeFiles", e);
148 			return null;
149 		}
150 		if (result != null) {
151 			if (result.length == 0) {
152 				result = null;
153 			} else {
154 				for (int i = 0; i < result.length; i++) {
155 					result[i] = result[i].substring(0, result[i].length() - RECORD_STORE_SUFFIX.length());
156 				}
157 			}
158 		}
159 		return result;
160 	}
161 
162 	public void saveChanges(RecordStoreImpl recordStoreImpl) throws RecordStoreNotOpenException, RecordStoreException {
163 
164 		File storeFile = new File(getSuiteFolder(), recordStoreImpl.getName() + RECORD_STORE_SUFFIX);
165 
166 		saveToDisk(storeFile, recordStoreImpl);
167 	}
168 
169 	public void init() {
170 	}
171 
172 	public void deleteStores() {
173 		String[] stores = listRecordStores();
174 		for (int i = 0; i < stores.length; i++) {
175 			String store = stores[i];
176 			try {
177 				deleteRecordStore(store);
178 			} catch (RecordStoreException e) {
179 				Logger.debug("deleteRecordStore", e);
180 			}
181 		}
182 	}
183 
184 	private RecordStoreImpl loadFromDisk(final File recordStoreFile) throws FileNotFoundException {
185 		try {
186 			return (RecordStoreImpl) AccessController.doPrivileged(new PrivilegedExceptionAction() {
187 				public Object run() throws FileNotFoundException {
188 					return loadFromDiskSecure(recordStoreFile);
189 				}
190 			}, acc);
191 		} catch (PrivilegedActionException e) {
192 			if (e.getCause() instanceof FileNotFoundException) {
193 				throw (FileNotFoundException) e.getCause();
194 			}
195 			Logger.error("Unable access file " + recordStoreFile, e);
196 			throw new FileNotFoundException();
197 		}
198 	}
199 
200 	private RecordStoreImpl loadFromDiskSecure(File recordStoreFile) throws FileNotFoundException {
201 		RecordStoreImpl store = null;
202 		try {
203 			DataInputStream dis = new DataInputStream(new FileInputStream(recordStoreFile));
204 			store = new RecordStoreImpl(this, dis);
205 			dis.close();
206 		} catch (FileNotFoundException e) {
207 			throw e;
208 		} catch (IOException e) {
209 			Logger.error("RecordStore.loadFromDisk: ERROR reading " + recordStoreFile.getName(), e);
210 		}
211 		return store;
212 	}
213 
214 	private void saveToDisk(final File recordStoreFile, final RecordStoreImpl recordStore) throws RecordStoreException {
215 		try {
216 			AccessController.doPrivileged(new PrivilegedExceptionAction() {
217 				public Object run() throws RecordStoreException {
218 					saveToDiskSecure(recordStoreFile, recordStore);
219 					return null;
220 				}
221 			}, acc);
222 		} catch (PrivilegedActionException e) {
223 			if (e.getCause() instanceof RecordStoreException) {
224 				throw (RecordStoreException) e.getCause();
225 			}
226 			Logger.error("Unable access file " + recordStoreFile, e);
227 			throw new RecordStoreException();
228 		}
229 	}
230 
231 	private void saveToDiskSecure(final File recordStoreFile, final RecordStoreImpl recordStore)
232 			throws RecordStoreException {
233 		if (!recordStoreFile.getParentFile().exists()) {
234 			if (!recordStoreFile.getParentFile().mkdirs()) {
235 				throw new RecordStoreException("Unable to create recordStore directory");
236 			}
237 		}
238 		try {
239 			DataOutputStream dos = new DataOutputStream(new FileOutputStream(recordStoreFile));
240 			recordStore.write(dos);
241 			dos.close();
242 		} catch (IOException e) {
243 			Logger.error("RecordStore.saveToDisk: ERROR writting object to " + recordStoreFile.getName(), e);
244 			throw new RecordStoreException(e.getMessage());
245 		}
246 	}
247 
248 	public int getSizeAvailable(RecordStoreImpl recordStoreImpl) {
249 		// FIXME should return free space on device
250 		return 1024 * 1024;
251 	}
252 
253 	public void setRecordListener(ExtendedRecordListener recordListener) {
254 		this.recordListener = recordListener;
255 	}
256 
257 	public void fireRecordStoreListener(int type, String recordStoreName) {
258 		if (recordListener != null) {
259 			recordListener.recordStoreEvent(type, System.currentTimeMillis(), recordStoreName);
260 		}
261 	}
262 }