/**
* MicroEmulator
* Copyright (C) 2008 Bartek Teodorczyk <barteo@barteo.net>
*
* It is licensed under the following two licenses as alternatives:
* 1. GNU Lesser General Public License (the "LGPL") version 2.1 or any newer version
* 2. Apache License (the "AL") Version 2.0
*
* You may not use this file except in compliance with at least one of
* the above two licenses.
*
* You may obtain a copy of the LGPL at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
*
* You may obtain a copy of the AL at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the LGPL or the AL for the specific language governing permissions and
* limitations.
*
* @version $Id: AndroidRecordStoreManager.java 2134 2009-08-27 10:30:20Z barteo $
*/
package org.microemu.android.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.microedition.rms.InvalidRecordIDException;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;
import org.microemu.MicroEmulator;
import org.microemu.RecordStoreManager;
import org.microemu.log.Logger;
import org.microemu.util.ExtendedRecordListener;
import org.microemu.util.RecordStoreImpl;
import android.app.Activity;
import android.content.Context;
public class AndroidRecordStoreManager implements RecordStoreManager {
private final static String RECORD_STORE_HEADER_SUFFIX = ".rsh";
private final static String RECORD_STORE_RECORD_SUFFIX = ".rsr";
private final static Object NULL_STORE = new Object();
private Activity activity;
private ConcurrentHashMap<String, Object> recordStores = null;
private ExtendedRecordListener recordListener = null;
public AndroidRecordStoreManager(Activity context) {
this.activity = context;
}
public void init(MicroEmulator emulator) {
}
public String getName() {
return "Android record store";
}
private synchronized void initializeIfNecessary()
{
if (recordStores == null) {
recordStores = new ConcurrentHashMap<String, Object>();
String[] list = activity.fileList();
if (list != null && list.length > 0) {
for (int i = 0; i < list.length; i++) {
if (list[i].endsWith(RECORD_STORE_HEADER_SUFFIX)) {
recordStores.put(
list[i].substring(0, list[i].length() - RECORD_STORE_HEADER_SUFFIX.length()),
NULL_STORE);
}
}
}
}
}
public void deleteRecordStore(final String recordStoreName)
throws RecordStoreNotFoundException, RecordStoreException
{
initializeIfNecessary();
Object value = recordStores.get(recordStoreName);
if (value == null) {
throw new RecordStoreNotFoundException(recordStoreName);
}
if (value instanceof RecordStoreImpl && ((RecordStoreImpl) value).isOpen()) {
throw new RecordStoreException();
}
RecordStoreImpl recordStoreImpl;
try {
DataInputStream dis = new DataInputStream(activity.openFileInput(getHeaderFileName(recordStoreName)));
recordStoreImpl = new RecordStoreImpl(this);
recordStoreImpl.readHeader(dis);
dis.close();
} catch (IOException e) {
Logger.error("RecordStore.deleteRecordStore: ERROR reading " + getHeaderFileName(recordStoreName), e);
throw new RecordStoreException();
}
recordStoreImpl.setOpen(true);
RecordEnumeration re = recordStoreImpl.enumerateRecords(null, null, false);
while (re.hasNextElement()) {
activity.deleteFile(getRecordFileName(recordStoreName, re.nextRecordId()));
}
recordStoreImpl.setOpen(false);
activity.deleteFile(getHeaderFileName(recordStoreName));
recordStores.remove(recordStoreName);
fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_DELETE, recordStoreName);
}
public RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary)
throws RecordStoreException
{
initializeIfNecessary();
RecordStoreImpl recordStoreImpl;
try {
DataInputStream dis = new DataInputStream(
activity.openFileInput(getHeaderFileName(recordStoreName)));
recordStoreImpl = new RecordStoreImpl(this);
recordStoreImpl.readHeader(dis);
recordStoreImpl.setOpen(true);
dis.close();
} catch (FileNotFoundException e) {
if (!createIfNecessary) {
throw new RecordStoreNotFoundException(recordStoreName);
}
recordStoreImpl = new RecordStoreImpl(this, recordStoreName);
recordStoreImpl.setOpen(true);
saveToDisk(recordStoreImpl, -1);
} catch (IOException e) {
throw new RecordStoreException();
}
if (recordListener != null) {
recordStoreImpl.addRecordListener(recordListener);
}
recordStores.put(recordStoreName, recordStoreImpl);
fireRecordStoreListener(ExtendedRecordListener.RECORDSTORE_OPEN, recordStoreName);
return recordStoreImpl;
}
public String[] listRecordStores() {
initializeIfNecessary();
String[] result = recordStores.keySet().toArray(new String[0]);
if (result.length > 0) {
return result;
} else {
return null;
}
}
public void deleteRecord(RecordStoreImpl recordStoreImpl, int recordId)
throws RecordStoreNotOpenException, RecordStoreException
{
deleteFromDisk(recordStoreImpl, recordId);
}
public void loadRecord(RecordStoreImpl recordStoreImpl, int recordId)
throws RecordStoreNotOpenException, InvalidRecordIDException, RecordStoreException
{
try {
DataInputStream dis = new DataInputStream(
activity.openFileInput(getRecordFileName(recordStoreImpl.getName(), recordId)));
recordStoreImpl.readRecord(dis);
dis.close();
} catch (FileNotFoundException e) {
throw new InvalidRecordIDException();
} catch (IOException e) {
Logger.error("RecordStore.loadFromDisk: ERROR reading " + getRecordFileName(recordStoreImpl.getName(), recordId), e);
}
}
public void saveRecord(RecordStoreImpl recordStoreImpl, int recordId)
throws RecordStoreNotOpenException, RecordStoreException
{
saveToDisk(recordStoreImpl, recordId);
}
public void init() {
}
public void deleteStores() {
String[] stores = listRecordStores();
for (int i = 0; i < stores.length; i++) {
String store = stores[i];
try {
deleteRecordStore(store);
} catch (RecordStoreException e) {
Logger.debug("deleteRecordStore", e);
}
}
}
private synchronized void deleteFromDisk(RecordStoreImpl recordStore, int recordId)
throws RecordStoreException
{
try {
DataOutputStream dos = new DataOutputStream(
activity.openFileOutput(getHeaderFileName(recordStore.getName()), Context.MODE_PRIVATE));
recordStore.writeHeader(dos);
dos.close();
} catch (IOException e) {
Logger.error("RecordStore.saveToDisk: ERROR writting object to " + getHeaderFileName(recordStore.getName()), e);
throw new RecordStoreException(e.getMessage());
}
activity.deleteFile(getRecordFileName(recordStore.getName(), recordId));
}
/**
* @param recordId -1 for storing only header
*/
private synchronized void saveToDisk(RecordStoreImpl recordStore, int recordId)
throws RecordStoreException
{
try {
DataOutputStream dos = new DataOutputStream(
activity.openFileOutput(getHeaderFileName(recordStore.getName()), Context.MODE_PRIVATE));
recordStore.writeHeader(dos);
dos.close();
} catch (IOException e) {
Logger.error("RecordStore.saveToDisk: ERROR writting object to " + getHeaderFileName(recordStore.getName()), e);
throw new RecordStoreException(e.getMessage());
}
if (recordId != -1) {
try {
DataOutputStream dos = new DataOutputStream(
activity.openFileOutput(getRecordFileName(recordStore.getName(), recordId), Context.MODE_PRIVATE));
recordStore.writeRecord(dos, recordId);
dos.close();
} catch (IOException e) {
Logger.error("RecordStore.saveToDisk: ERROR writting object to " + getRecordFileName(recordStore.getName(), recordId), e);
throw new RecordStoreException(e.getMessage());
}
}
}
public int getSizeAvailable(RecordStoreImpl recordStoreImpl) {
// FIXME should return free space on device
return 1024 * 1024;
}
public void setRecordListener(ExtendedRecordListener recordListener) {
this.recordListener = recordListener;
}
public void fireRecordStoreListener(int type, String recordStoreName) {
if (recordListener != null) {
recordListener.recordStoreEvent(type, System.currentTimeMillis(), recordStoreName);
}
}
private String getHeaderFileName(String recordStoreName)
{
return recordStoreName + RECORD_STORE_HEADER_SUFFIX;
}
private String getRecordFileName(String recordStoreName, int recordId)
{
return recordStoreName + "." + recordId + RECORD_STORE_RECORD_SUFFIX;
}
}