/*
* Created on Sep 13, 2004
*
*/
package lancs.mobilemedia.core.ui.datamodel;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreFullException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;
import lancs.mobilemedia.lib.exceptions.ImageNotFoundException;
import lancs.mobilemedia.lib.exceptions.ImagePathNotValidException;
import lancs.mobilemedia.lib.exceptions.InvalidArrayFormatException;
import lancs.mobilemedia.lib.exceptions.InvalidImageDataException;
import lancs.mobilemedia.lib.exceptions.InvalidImageFormatException;
import lancs.mobilemedia.lib.exceptions.InvalidPhotoAlbumNameException;
import lancs.mobilemedia.lib.exceptions.PersistenceMechanismException;
/**
* @author trevor
*
* This is the main data access class. It handles all the connectivity with the
* RMS record stores to fetch and save data associated with MobileMedia TODO:
* Refactor into stable interface for future updates. We may want to access data
* from RMS, or eventually direct from the 'file system' on devices that support
* the FileConnection optional API.
*
*/
public abstract class MediaAccessor {
// Note: Our midlet only ever has access to Record Stores it created
// For now, use naming convention to create record stores used by
// MobileMedia
protected String album_label; // "mpa- all album names
// are prefixed with
// this label
protected String info_label; // "mpi- all album info
// stores are prefixed with
// this label
protected String default_album_name; // default
// album
// name
//imageInfo holds image metadata like label, album name and 'foreign key' index to
// corresponding RMS entry that stores the actual Image object
protected Hashtable mediaInfoTable = new Hashtable();
protected String[] albumNames; // User defined names of photo albums
// Record Stores
private RecordStore mediaRS = null;
private RecordStore mediaInfoRS = null;
/**
* @param album_label
* @param info_label
* @param default_album_name
*/
public MediaAccessor(String album_label, String info_label, String default_album_name) {
this.album_label = album_label;
this.info_label = info_label;
this.default_album_name = default_album_name;
}
/**
* Load all existing photo albums that are defined in the record store.
*
* @throws InvalidImageDataException
* @throws PersistenceMechanismException
*/
public void loadAlbums() throws InvalidImageDataException,
PersistenceMechanismException {
// Try to find any existing Albums (record stores)
String[] currentStores = RecordStore.listRecordStores();
if (currentStores != null) {
System.out.println("MediaAccessor::loadAlbums: Found: " + currentStores.length + " existing record stores");
String[] temp = new String[currentStores.length];
int count = 0;
// Only use record stores that follow the naming convention defined
for (int i = 0; i < currentStores.length; i++) {
String curr = currentStores[i];
System.out.println("MediaAccessor::loadAlbums: Current store"+curr+"="+album_label);
// If this record store is a photo album...
if (curr.startsWith(album_label)) {
// Strip out the mpa- identifier
curr = curr.substring(4);
// Add the album name to the array
temp[i] = curr;
count++;
}
}
// Re-copy the contents into a smaller array now that we know the
// size
albumNames = new String[count];
int count2 = 0;
for (int i = 0; i < temp.length; i++) {
if (temp[i] != null) {
albumNames[count2] = temp[i];
count2++;
}
}
} else {
System.out.println("MediaAccessor::loadAlbums: 0 record stores exist. Creating default one.");
resetRecordStore();
loadAlbums();
}
}
protected abstract void resetRecordStore()
throws InvalidImageDataException, PersistenceMechanismException;
protected abstract byte[] getByteFromMediaInfo(MediaData ii)
throws InvalidImageDataException;
protected abstract byte[] getMediaArrayOfByte(String path)
throws ImagePathNotValidException, InvalidImageFormatException;
protected abstract MediaData getMediaFromBytes(byte[] data)
throws InvalidArrayFormatException;
public void addMediaData(String photoname, String path, String albumname)
throws InvalidImageDataException, PersistenceMechanismException {
try {
byte[] data1 = getMediaArrayOfByte(path);
addMediaArrayOfBytes(photoname, albumname, data1);
} catch (RecordStoreException e) {
throw new PersistenceMechanismException();
}
}
protected void addMediaArrayOfBytes(String photoname, String albumname,
byte[] data1) throws RecordStoreException,
RecordStoreFullException, RecordStoreNotFoundException,
RecordStoreNotOpenException, InvalidImageDataException {
mediaRS = RecordStore.openRecordStore(album_label + albumname, true);
mediaInfoRS = RecordStore.openRecordStore(info_label + albumname, true);
int rid; // new record ID for Image (bytes)
int rid2; // new record ID for ImageData (metadata)
rid = mediaRS.addRecord(data1, 0, data1.length);
MediaData ii = new MediaData(rid,
album_label + albumname, photoname);
rid2 = mediaInfoRS.getNextRecordID();
ii.setRecordId(rid2);
data1 = getByteFromMediaInfo(ii);
mediaInfoRS.addRecord(data1, 0, data1.length);
mediaRS.closeRecordStore();
mediaInfoRS.closeRecordStore();
}
// #ifdef includeCopyPhoto
/**
* [EF] Add in scenario 05
* @param photoname
* @param imageData
* @param albumname
* @throws InvalidImageDataException
* @throws PersistenceMechanismException
*/
public void addMediaData(MediaData mediaData, String albumname) throws InvalidImageDataException, PersistenceMechanismException {
try {
mediaRS = RecordStore.openRecordStore(album_label + albumname, true);
mediaInfoRS = RecordStore.openRecordStore(info_label + albumname, true);
int rid2; // new record ID for ImageData (metadata)
rid2 = mediaInfoRS.getNextRecordID();
mediaData.setRecordId(rid2);
byte[] data1 = getByteFromMediaInfo(mediaData);
mediaInfoRS.addRecord(data1, 0, data1.length);
} catch (RecordStoreException e) {
throw new PersistenceMechanismException();
}finally{
try {
mediaRS.closeRecordStore();
mediaInfoRS.closeRecordStore();
} catch (RecordStoreNotOpenException e) {
e.printStackTrace();
} catch (RecordStoreException e) {
e.printStackTrace();
}
}
}
// #endif
/**
* This will populate the imageInfo hashtable with the ImageInfo object,
* referenced by label name and populate the imageTable hashtable with Image
* objects referenced by the RMS record Id
*
* @throws PersistenceMechanismException
*/
public MediaData[] loadMediaDataFromRMS(String recordName)
throws PersistenceMechanismException, InvalidImageDataException {
Vector mediaVector = new Vector();
try {
String infoStoreName = info_label + recordName;
RecordStore infoStore = RecordStore.openRecordStore(infoStoreName,
false);
RecordEnumeration isEnum = infoStore.enumerateRecords(null, null,
false);
while (isEnum.hasNextElement()) {
// Get next record
int currentId = isEnum.nextRecordId();
byte[] data = infoStore.getRecord(currentId);
// Convert the data from a byte array into our ImageData
// (metadata) object
MediaData iiObject = getMediaFromBytes(data);
// Add the info to the metadata hashtable
String label = iiObject.getMediaLabel();
mediaVector.addElement(iiObject);
getMediaInfoTable().put(label, iiObject);
}
infoStore.closeRecordStore();
}catch (RecordStoreException rse) {
throw new PersistenceMechanismException(rse);
}
// Re-copy the contents into a smaller array
MediaData[] labelArray = new MediaData[mediaVector.size()];
mediaVector.copyInto(labelArray);
return labelArray;
}
/**
* Update the Image metadata associated with this named photo
* @throws InvalidImageDataException
* @throws PersistenceMechanismException
*/
public boolean updateMediaInfo(MediaData oldData, MediaData newData) throws InvalidImageDataException, PersistenceMechanismException {
boolean success = false;
RecordStore infoStore = null;
try {
// Parse the Data store name to get the Info store name
String infoStoreName = oldData.getParentAlbumName();
infoStoreName = info_label + infoStoreName.substring(album_label.length());
infoStore = RecordStore.openRecordStore(infoStoreName, false);
byte[] mediaDataBytes = getByteFromMediaInfo(newData);
infoStore.setRecord(oldData.getRecordId(), mediaDataBytes, 0, mediaDataBytes.length);
} catch (RecordStoreException rse) {
throw new PersistenceMechanismException(rse);
}
// Update the Hashtable 'cache'
setMediaInfo(oldData.getMediaLabel(), newData);
try {
infoStore.closeRecordStore();
} catch (RecordStoreNotOpenException e) {
//No problem if the RecordStore is not Open
} catch (RecordStoreException e) {
throw new PersistenceMechanismException(e);
}
return success;
}
/**
* Retrieve the metadata associated with a specified image (by name)
* @throws ImageNotFoundException
* @throws NullAlbumDataReference
*/
public MediaData getMediaInfo(String imageName) throws ImageNotFoundException {
MediaData ii = (MediaData) getMediaInfoTable().get(imageName);
if (ii == null)
throw new ImageNotFoundException(imageName +" was NULL in ImageAccessor Hashtable.");
return ii;
}
/**
* Update the hashtable with new ImageInfo data
*/
public void setMediaInfo(String mediaName, MediaData newData) {
getMediaInfoTable().put(newData.getMediaLabel(), newData);
}
/**
* Get the data for an Image as a byte array. This is useful for sending
* images via SMS or HTTP
* @throws PersistenceMechanismException
*/
public byte[] loadMediaBytesFromRMS(String recordName,
int recordId) throws PersistenceMechanismException {
byte[] mediaData = null;
try {
RecordStore albumStore = RecordStore.openRecordStore(recordName,
false);
mediaData = albumStore.getRecord(recordId);
albumStore.closeRecordStore();
} catch (RecordStoreException rse) {
System.out.println("Error:"+rse.getMessage());
throw new PersistenceMechanismException(rse);
}
return mediaData;
}
/**
* Delete a single (specified) image from the (specified) record store. This
* will permanently delete the image data and metadata from the device.
* @throws PersistenceMechanismException
* @throws NullAlbumDataReference
* @throws ImageNotFoundException
*/
public boolean deleteSingleMediaFromRMS(String storeName, String mediaName) throws PersistenceMechanismException, ImageNotFoundException {
boolean success = false;
// Open the record stores containing the byte data and the meta data
// (info)
try {
// Verify storeName is name without pre-fix
mediaRS = RecordStore
.openRecordStore(album_label + storeName, true);
mediaInfoRS = RecordStore.openRecordStore(info_label + storeName,
true);
MediaData mediaData = getMediaInfo(mediaName);
int rid = mediaData.getForeignRecordId();
mediaRS.deleteRecord(rid);
mediaInfoRS.deleteRecord(rid);
mediaRS.closeRecordStore();
mediaInfoRS.closeRecordStore();
} catch (RecordStoreException rse) {
throw new PersistenceMechanismException(rse);
}
return success;
}
/**
* Define a new photo album for mobile photo users. This creates a new
* record store to store photos for the album.
* @throws PersistenceMechanismException
* @throws InvalidPhotoAlbumNameException
*/
public void createNewAlbum(String albumName) throws PersistenceMechanismException, InvalidPhotoAlbumNameException {
RecordStore newAlbumRS = null;
RecordStore newAlbumInfoRS = null;
if (albumName.equals("")){
throw new InvalidPhotoAlbumNameException();
}
String[] names = getAlbumNames();
for (int i = 0; i < names.length; i++) {
if (names[i].equals(albumName))
throw new InvalidPhotoAlbumNameException();
}
try {
newAlbumRS = RecordStore.openRecordStore(album_label + albumName,
true);
newAlbumInfoRS = RecordStore.openRecordStore(
info_label + albumName, true);
newAlbumRS.closeRecordStore();
newAlbumInfoRS.closeRecordStore();
} catch (RecordStoreException rse) {
throw new PersistenceMechanismException(rse);
}
}
/**
* @param albumName
* @throws PersistenceMechanismException
*/
public void deleteAlbum(String albumName) throws PersistenceMechanismException {
try {
RecordStore.deleteRecordStore(album_label + albumName);
RecordStore.deleteRecordStore(info_label + albumName);
} catch (RecordStoreException rse) {
throw new PersistenceMechanismException(rse);
}
}
/**
* Get the list of photo album names currently loaded.
*
* @return Returns the albumNames.
*/
public String[] getAlbumNames() {
return albumNames;
}
/**
* Get the hashtable that stores the image metadata in memory.
* @return Returns the imageInfoTable.
*/
public Hashtable getMediaInfoTable() {
return mediaInfoTable;
}
/**
* Update the hashtable that stores the image metadata in memory
* @param imageInfoTable
* The imageInfoTable to set.
*/
public void setMediaInfoTable(Hashtable mediaInfoTable) {
this.mediaInfoTable = mediaInfoTable;
}
}