package vandy.mooc.model;
import java.util.HashMap;
import vandy.mooc.model.CharacterContract.CharacterEntry;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
/**
* Content Provider implementation that uses a HashMap to manage
* Hobbit characters. This class plays the role of the "Concrete
* Implementor" in the Bridge pattern and the "Concrete Class" in the
* TemplateMethod pattern.
*/
public class HobbitProviderImplHashMap
extends HobbitProviderImpl {
/**
* This implementation uses a simple HashMap to map IDs to
* CharacterRecords.
*/
private static final HashMap<Long, CharacterRecord> mCharacterMap =
new HashMap<>();
/**
* Constructor initializes the super class.
*/
public HobbitProviderImplHashMap(Context context) {
super(context);
}
/**
* Method called to handle insert requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public Uri insertCharacters(Uri uri,
ContentValues cvs) {
synchronized (this) {
if (cvs.containsKey(CharacterEntry.COLUMN_NAME)) {
CharacterRecord rec =
new CharacterRecord(cvs.getAsString
(CharacterEntry.COLUMN_NAME),
cvs.getAsString
(CharacterEntry.COLUMN_RACE));
mCharacterMap.put(rec.getId(),
rec);
return CharacterContract.CharacterEntry.buildUri(rec.getId());
} else
throw new RuntimeException("Failed to insert row into "
+ uri);
}
}
/**
* Method that handles bulk insert requests. This plays the role
* of the "concrete hook method" in the Template Method pattern.
*/
@Override
public int bulkInsertCharacters(Uri uri,
ContentValues[] cvsArray) {
int returnCount = 0;
synchronized (this) {
for (ContentValues cvs : cvsArray) {
if (cvs.containsKey(CharacterEntry.COLUMN_NAME)) {
CharacterRecord rec =
new CharacterRecord(cvs.getAsString
(CharacterEntry.COLUMN_NAME),
cvs.getAsString
(CharacterEntry.COLUMN_RACE));
mCharacterMap.put(rec.getId(),
rec);
returnCount++;
} else
throw new RuntimeException("Failed to insert row into "
+ uri);
}
}
return returnCount;
}
/**
* Method called to handle query requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public Cursor queryCharacters(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
final MatrixCursor cursor =
new MatrixCursor(CharacterContract.CharacterEntry.sColumnsToDisplay);
synchronized (this) {
// Implement a simple query mechanism for the table.
for (CharacterRecord cr : mCharacterMap.values())
buildCursorConditionally(cursor,
cr,
selection,
selectionArgs);
}
return cursor;
}
/**
* Method called to handle query requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public Cursor queryCharacter(Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder) {
final MatrixCursor cursor =
new MatrixCursor(CharacterContract.CharacterEntry.sColumnsToDisplay);
// Just return a single item from the database.
long requestId = ContentUris.parseId(uri);
synchronized (this) {
CharacterRecord cr =
mCharacterMap.get(requestId);
if (cr != null) {
buildCursorConditionally(cursor,
cr,
selection,
selectionArgs);
}
}
return cursor;
}
/**
* Build a MatrixCursor that matches the parameters. This plays
* the role of the "concrete hook method" in the Template Method
* pattern.
*/
private void buildCursorConditionally(MatrixCursor cursor,
CharacterRecord cr,
String selection,
String[] selectionArgs) {
if (selectionArgs == null)
cursor.addRow(new Object[] {
cr.getId(),
cr.getName(),
cr.getRace()
});
else
for (String item : selectionArgs)
if ((selection.equals(CharacterContract.CharacterEntry.COLUMN_NAME)
&& item.equals(cr.getName()))
|| (selection.equals(CharacterContract.CharacterEntry.COLUMN_RACE)
&& item.equals(cr.getRace()))) {
cursor.addRow(new Object[] {
cr.getId(),
cr.getName(),
cr.getRace()
});
}
}
/**
* Method called to handle update requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public int updateCharacters(Uri uri,
ContentValues cvs,
String selection,
String[] selectionArgs) {
int recsUpdated = 0;
synchronized (this) {
// Implement a simple update mechanism for the table.
for (CharacterRecord cr :
mCharacterMap.values().toArray
(new CharacterRecord[mCharacterMap.values().size()]))
recsUpdated +=
updateEntryConditionally(cr,
cvs,
selection,
selectionArgs);
}
return recsUpdated;
}
/**
* Method called to handle update requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public int updateCharacter(Uri uri,
ContentValues cvs,
String selection,
String[] selectionArgs) {
// Just update a single item in the database.
final long requestId = ContentUris.parseId(uri);
synchronized (this) {
CharacterRecord cr = mCharacterMap.get(requestId);
if (cr != null)
return updateEntryConditionally(cr,
cvs,
selection,
selectionArgs);
else
return 0;
}
}
/**
* Update @a rec in the HashMap with the contents of the @a
* ContentValues if it matches the @a selection criteria.
*/
private int updateEntryConditionally(CharacterRecord rec,
ContentValues cvs,
String selection,
String[] selectionArgs) {
if (selectionArgs == null) {
final CharacterRecord updatedRec =
new CharacterRecord(rec.getId(),
cvs.getAsString
(CharacterEntry.COLUMN_NAME),
cvs.getAsString
(CharacterEntry.COLUMN_RACE));
mCharacterMap.put(updatedRec.getId(),
updatedRec);
return 1;
} else
for (String character : selectionArgs)
if ((selection.equals(CharacterContract.CharacterEntry.COLUMN_NAME)
&& character.equals(rec.getName()))
|| (selection.equals(CharacterContract.CharacterEntry.COLUMN_RACE)
&& character.equals(rec.getRace()))) {
final CharacterRecord updatedRec =
new CharacterRecord(rec.getId(),
cvs.getAsString
(CharacterEntry.COLUMN_NAME),
cvs.getAsString
(CharacterEntry.COLUMN_RACE));
mCharacterMap.put(updatedRec.getId(),
updatedRec);
return 1;
}
return 0;
}
/**
* Method called to handle delete requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public int deleteCharacters(Uri uri,
String selection,
String[] selectionArgs) {
int recsDeleted = 0;
// Implement a simple delete mechanism for the table.
synchronized (this) {
for (CharacterRecord cr :
mCharacterMap.values().toArray
(new CharacterRecord[mCharacterMap.values().size()]))
recsDeleted +=
deleteEntryConditionally(cr,
selection,
selectionArgs);
}
return recsDeleted;
}
/**
* Method called to handle delete requests from client
* applications. This plays the role of the "concrete hook
* method" in the Template Method pattern.
*/
@Override
public int deleteCharacter(Uri uri,
String selection,
String[] selectionArgs) {
// Just delete a single item in the database.
final long requestId = ContentUris.parseId(uri);
synchronized (this) {
CharacterRecord rec = mCharacterMap.get(requestId);
if (rec != null)
return deleteEntryConditionally(rec,
selection,
selectionArgs);
else
return 0;
}
}
/**
* Delete @a rec from the HashMap if it matches the @a selection
* criteria.
*/
private int deleteEntryConditionally(CharacterRecord rec,
String selection,
String[] selectionArgs) {
if (selectionArgs == null) {
mCharacterMap.remove(rec.getId());
return 1;
}
else
for (String character : selectionArgs)
if ((selection.equals(CharacterContract.CharacterEntry.COLUMN_NAME)
&& character.equals(rec.getName()))
|| (selection.equals(CharacterContract.CharacterEntry.COLUMN_RACE)
&& character.equals(rec.getRace()))) {
mCharacterMap.remove(rec.getId());
return 1;
}
return 0;
}
}