1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.calendar; 18 19 import android.content.ContentValues; 20 import android.database.Cursor; 21 import android.database.sqlite.SQLiteDatabase; 22 import android.database.sqlite.SQLiteOpenHelper; 23 import android.util.Log; 24 25 /** 26 * Class for managing a persistent Cache of (key, value) pairs. The persistent storage used is 27 * a SQLite database. 28 */ 29 public class CalendarCache { 30 private static final String TAG = "CalendarCache"; 31 32 public static final String DATABASE_NAME = "CalendarCache"; 33 34 public static final String KEY_TIMEZONE_DATABASE_VERSION = "timezoneDatabaseVersion"; 35 public static final String DEFAULT_TIMEZONE_DATABASE_VERSION = "2009s"; 36 37 private static final String COLUMN_NAME_ID = "_id"; 38 private static final String COLUMN_NAME_KEY = "key"; 39 private static final String COLUMN_NAME_VALUE = "value"; 40 41 private static final String[] sProjection = { 42 COLUMN_NAME_KEY, 43 COLUMN_NAME_VALUE 44 }; 45 46 private static final int COLUMN_INDEX_KEY = 0; 47 private static final int COLUMN_INDEX_VALUE = 1; 48 49 private final SQLiteOpenHelper mOpenHelper; 50 51 /** 52 * This exception is thrown when the cache encounter a null key or a null database reference 53 */ 54 public static class CacheException extends Exception { 55 public CacheException() { 56 } 57 58 public CacheException(String detailMessage) { 59 super(detailMessage); 60 } 61 } 62 63 public CalendarCache(SQLiteOpenHelper openHelper) { 64 mOpenHelper = openHelper; 65 } 66 67 public void writeTimezoneDatabaseVersion(String timezoneDatabaseVersion) throws CacheException { 68 writeData(KEY_TIMEZONE_DATABASE_VERSION, 69 timezoneDatabaseVersion); 70 } 71 72 public String readTimezoneDatabaseVersion() throws CacheException { 73 return readData(KEY_TIMEZONE_DATABASE_VERSION); 74 } 75 76 /** 77 * Write a (key, value) pair in the Cache. 78 * 79 * @param key the key (must not be null) 80 * @param value the value (can be null) 81 * @throws CacheException when key is null 82 */ 83 public void writeData(String key, String value) throws CacheException { 84 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 85 db.beginTransaction(); 86 try { 87 writeDataLocked(db, key, value); 88 db.setTransactionSuccessful(); 89 if (Log.isLoggable(TAG, Log.VERBOSE)) { 90 Log.i(TAG, "Wrote (key, value) = [ " + key + ", " + value + "] "); 91 } 92 } finally { 93 db.endTransaction(); 94 } 95 } 96 97 /** 98 * Write a (key, value) pair in the database used by the cache. This call should be called into 99 * a transaction. 100 * 101 * @param db the database (must not be null) 102 * @param key the key (must not be null) 103 * @param value the value 104 * @throws CacheException when key or database are null 105 */ 106 protected void writeDataLocked(SQLiteDatabase db, String key, String value) 107 throws CacheException { 108 if (null == db) { 109 throw new CacheException("Database cannot be null"); 110 } 111 if (null == key) { 112 throw new CacheException("Cannot use null key for write"); 113 } 114 115 ContentValues values = new ContentValues(); 116 values.put(COLUMN_NAME_ID, key.hashCode()); 117 values.put(COLUMN_NAME_KEY, key); 118 values.put(COLUMN_NAME_VALUE, value); 119 120 db.replace(DATABASE_NAME, null /* null column hack */, values); 121 } 122 123 /** 124 * Read a value from the database used by the cache and depending on a key. 125 * 126 * @param key the key from which we want the value (must not be null) 127 * @return the value that was found for the key. Can be null if no key has been found 128 * @throws CacheException when key is null 129 */ 130 public String readData(String key) throws CacheException { 131 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 132 return readDataLocked(db, key); 133 } 134 135 /** 136 * Read a value from the database used by the cache and depending on a key. The database should 137 * be "readable" at minimum 138 * 139 * @param db the database (must not be null) 140 * @param key the key from which we want the value (must not be null) 141 * @return the value that was found for the key. Can be null if no value has been found for the 142 * key. 143 * @throws CacheException when key or database are null 144 */ 145 protected String readDataLocked(SQLiteDatabase db, String key) throws CacheException { 146 if (null == db) { 147 throw new CacheException("Database cannot be null"); 148 } 149 if (null == key) { 150 throw new CacheException("Cannot use null key for read"); 151 } 152 153 String rowValue = null; 154 155 Cursor cursor = db.query(DATABASE_NAME, sProjection, 156 COLUMN_NAME_KEY + "=?", new String[] { key }, null, null, null); 157 try { 158 if (cursor.moveToNext()) { 159 rowValue = cursor.getString(COLUMN_INDEX_VALUE); 160 } 161 else { 162 if (Log.isLoggable(TAG, Log.VERBOSE)) { 163 Log.i(TAG, "Could not find key = [ " + key + " ]"); 164 } 165 } 166 } finally { 167 cursor.close(); 168 cursor = null; 169 } 170 return rowValue; 171 } 172 } 173