/** * Android Campus Maps * http://code.google.com/p/vuphone/ * * @author Kyle Prete * @date Dec 21, 2009 * * Copyright 2009 VUPhone Team * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License 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 License for the specific language governing * permissions and limitations under the License. */ package edu.vanderbilt.vuphone.android.campusmaps.storage; import java.util.ArrayList; import android.database.Cursor; import edu.vanderbilt.vuphone.android.campusmaps.Main; /** * This class abstracts database access and caches multiple like accesses. * Accessed through the Building class */ public class DBWrapper { private static final int CLOSED = 0; private static final int READABLE = 1; private static final int WRITABLE = 2; private static DBAdapter adapter; private static int state; private static ArrayList<Long> IDs; private static ArrayList<Building> cache; private static boolean idsCached = false; private static boolean mainDataCached = false; private static ArrayList<Boolean> cached; @SuppressWarnings("unchecked") public static ArrayList<Long> getIDs() { cacheIDs(); return (ArrayList<Long>) IDs.clone(); } public static Building get(long rowID) { int i = cacheBuilding(rowID); return cache.get(i); } public static String getName(long rowID) { cacheMainData(); return cache.get(IDs.indexOf(rowID)).getName(); } public static double getLat(long rowID) { cacheMainData(); return (cache.get(IDs.indexOf(rowID)).getLat_() / 1E6); } public static double getLon(long rowID) { cacheMainData(); return (cache.get(IDs.indexOf(rowID)).getLong_() / 1E6); } public static String getURL(long rowID) { cacheMainData(); return cache.get(IDs.indexOf(rowID)).getImageURL(); } public static String getDesc(long rowID) { cacheMainData(); return cache.get(IDs.indexOf(rowID)).getDescription(); } public static boolean create(Building b) { makeWritable(); long rID = adapter.createBuilding(b.getName(), b.getLat_(), b .getLong_(), b.getDescription(), b.getImageURL()); if (mainDataCached && rID != -1) { IDs.add(rID); cache.add(b); } return (rID != -1); } // updates the database and cache immediately with new values public static boolean update(long rowID, Building updated) { cacheIDs(); makeWritable(); int i = IDs.indexOf(rowID); if (i < 0) return false; boolean success = adapter.updateBuilding(rowID, updated.getName(), updated.getLat_(), updated.getLong_(), updated.getDescription(), updated.getImageURL()); if (mainDataCached && success) cache.set(i, updated); close(); return success; } public static boolean delete(long rowID) { makeWritable(); if (adapter.deleteBuilding(rowID)) { int i = getIDs().indexOf(rowID); if (i >= 0) { if (mainDataCached) cache.remove(i); IDs.remove(i); } return true; } else return false; } public static void cacheIDs() { if (idsCached) return; IDs = new ArrayList<Long>(); makeReadable(); Cursor c = adapter.getCursor(new String[] { DBAdapter.COLUMN_ID }); if (c.moveToFirst()) { do { IDs.add(c.getLong(c.getColumnIndex(DBAdapter.COLUMN_ID))); } while (c.moveToNext()); } idsCached = true; c.close(); } public static void cacheMainData() { if (mainDataCached) return; resetBuildingCache(); // ensures IDs are cached makeReadable(); Cursor c = adapter.getCursor(new String[] { DBAdapter.COLUMN_NAME, DBAdapter.COLUMN_LATITUDE, DBAdapter.COLUMN_LONGITUDE }); if (c.moveToFirst()) { do { Building current = new Building(c.getLong(c .getColumnIndex(DBAdapter.COLUMN_ID)), c.getInt(c .getColumnIndex(DBAdapter.COLUMN_LATITUDE)), c.getInt(c .getColumnIndex(DBAdapter.COLUMN_LONGITUDE)), c .getString(c.getColumnIndex(DBAdapter.COLUMN_NAME)), c .getString(c .getColumnIndex(DBAdapter.COLUMN_DESCRIPTION)), c.getString(c.getColumnIndex(DBAdapter.COLUMN_URL))); cache.add(current); cached.add(false); } while (c.moveToNext()); } mainDataCached = true; c.close(); close(); } public static int cacheBuilding(long rowID) { if (!mainDataCached) cacheMainData(); int i = IDs.indexOf(rowID); if (cached.get(i)) return i; makeReadable(); String[] columnsToRead; columnsToRead = new String[] { DBAdapter.COLUMN_DESCRIPTION, DBAdapter.COLUMN_URL }; Cursor c = adapter.getCursor(columnsToRead, rowID); if (!c.moveToFirst()) throw new RuntimeException( "Cannot cache building which doesnt exist"); if (i < 0) throw new RuntimeException( "error, discrepancy between database and memory cache"); Building b = cache.get(i); b.setDescription(c.getString(c .getColumnIndex(DBAdapter.COLUMN_DESCRIPTION))); b.setImageURL(c.getString(c.getColumnIndex(DBAdapter.COLUMN_URL))); c.close(); close(); cached.set(i, true); return i; } private static void resetBuildingCache() { int restaurants = getIDs().size(); cache = new ArrayList<Building>(); cache.ensureCapacity(restaurants); cached = new ArrayList<Boolean>(); cached.ensureCapacity(restaurants); mainDataCached = false; } private static void initialize() { if (adapter == null) { adapter = new DBAdapter(Main.applicationContext); state = CLOSED; } } private static void makeWritable() { initialize(); switch (state) { case READABLE: adapter.close(); adapter.openWritable(); state = WRITABLE; return; case WRITABLE: return; case CLOSED: adapter.openWritable(); state = WRITABLE; return; } } private static void makeReadable() { initialize(); switch (state) { case READABLE: return; case WRITABLE: adapter.close(); adapter.openReadable(); state = READABLE; return; case CLOSED: adapter.openReadable(); state = READABLE; return; } } // closes the underlying database adapter // no read/writes are to be performed in the // near future public static void close() { initialize(); switch (state) { case READABLE: adapter.close(); state = CLOSED; return; case WRITABLE: adapter.close(); state = CLOSED; return; case CLOSED: return; } } public static Cursor fetchAllBuildingsCursor() { return adapter.fetchAllBuildingsSortedCursor(); } }