blob: 1ae25f2506565042ff4fcea4a45567cd38f810fb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.weex.appfram.storage;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.apache.weex.utils.WXLogUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class WXSQLiteOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "WXStorage";
private static final int DATABASE_VERSION = 2;
static final String TAG_STORAGE = "weex_storage";
private long mMaximumDatabaseSize = 5 * 10 * 1024 * 1024L;//50mb
static SimpleDateFormat sDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
private Context mContext;
private SQLiteDatabase mDb;
static final String TABLE_STORAGE = "default_wx_storage";
static final String COLUMN_KEY = "key";
static final String COLUMN_VALUE = "value";
static final String COLUMN_TIMESTAMP = "timestamp";
static final String COLUMN_PERSISTENT = "persistent";
private static final int SLEEP_TIME_MS = 30;
private static final String STATEMENT_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_STORAGE + " ("
+ COLUMN_KEY
+ " TEXT PRIMARY KEY,"
+ COLUMN_VALUE
+ " TEXT NOT NULL,"
+ COLUMN_TIMESTAMP
+ " TEXT NOT NULL,"
+ COLUMN_PERSISTENT
+ " INTEGER DEFAULT 0"
+ ")";
public WXSQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.mContext = context;
}
/**
* retrieve sqlite database
*
* @return a {@link SQLiteDatabase} instance or null if retrieve fails.
* */
public @Nullable SQLiteDatabase getDatabase() {
ensureDatabase();
return mDb;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(STATEMENT_CREATE_TABLE);
}
/**
* version 1:
*
* ----------------
* | key | value |
* ---------------
*
* version 2:
*
* ----------------------------------------
* | key | value | timestamp | persistent |
* ----------------------------------------
**/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion != newVersion) {
if(newVersion == 2 && oldVersion == 1){
WXLogUtils.d(TAG_STORAGE,"storage is updating from version "+oldVersion+" to version "+newVersion);
boolean updateResult = true;
try {
long start = System.currentTimeMillis();
db.beginTransaction();
// update table structure
String SQL_ADD_COLUMN_TIMESTAMP = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_TIMESTAMP+" TEXT;";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_TIMESTAMP);
db.execSQL(SQL_ADD_COLUMN_TIMESTAMP);
String SQL_ADD_COLUMN_PERSISTENT = "ALTER TABLE "+TABLE_STORAGE+" ADD COLUMN "+COLUMN_PERSISTENT+" INTEGER;";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_ADD_COLUMN_PERSISTENT);
db.execSQL(SQL_ADD_COLUMN_PERSISTENT);
// update timestamp & persistent
String SQL_UPDATE_TABLE = "UPDATE "+TABLE_STORAGE+" SET "+ COLUMN_TIMESTAMP+" = '"+sDateFormatter.format(new Date())+"' , "+ COLUMN_PERSISTENT +" = 0";
WXLogUtils.d(TAG_STORAGE,"exec sql : "+ SQL_UPDATE_TABLE);
db.execSQL(SQL_UPDATE_TABLE);
db.setTransactionSuccessful();
long time = System.currentTimeMillis() - start;
WXLogUtils.d(TAG_STORAGE,"storage updated success ("+time+"ms)");
}catch (Exception e){
WXLogUtils.d(TAG_STORAGE,"storage updated failed from version "+oldVersion+" to version "+newVersion+","+e.getMessage());
updateResult = false;
}finally {
db.endTransaction();
}
//rollback
if(!updateResult){
WXLogUtils.d(TAG_STORAGE,"storage is rollback,all data will be removed");
deleteDB();
onCreate(db);
}
}else{
deleteDB();
onCreate(db);
}
}
}
synchronized void ensureDatabase() {
if (mDb != null && mDb.isOpen()) {
return;
}
try {
// Sometimes retrieving the database fails. We do 2 retries: first without database deletion
// and then with deletion.
for (int tries = 0; tries < 2; tries++) {
try {
if (tries > 0) {
//delete db and recreate
deleteDB();
}
mDb = getWritableDatabase();
break;
} catch (SQLiteException e) {
e.printStackTrace();
}
// Wait before retrying.
try {
Thread.sleep(SLEEP_TIME_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if(mDb == null){
return;
}
createTableIfNotExists(mDb);
mDb.setMaximumSize(mMaximumDatabaseSize);
} catch (Throwable e) {
mDb = null;
WXLogUtils.d(TAG_STORAGE,"ensureDatabase failed, throwable = " + e.getMessage());
}
}
public synchronized void setMaximumSize(long size) {
mMaximumDatabaseSize = size;
if (mDb != null) {
mDb.setMaximumSize(mMaximumDatabaseSize);
}
}
private boolean deleteDB() {
closeDatabase();
return mContext.deleteDatabase(DATABASE_NAME);
}
public synchronized void closeDatabase() {
if (mDb != null && mDb.isOpen()) {
mDb.close();
mDb = null;
}
}
private void createTableIfNotExists(@NonNull SQLiteDatabase db) {
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name = '"+TABLE_STORAGE+"'", null);
if(cursor != null && cursor.getCount() > 0) {
return;
}
db.execSQL(STATEMENT_CREATE_TABLE);
}catch (Exception e){
e.printStackTrace();
}finally {
if(cursor != null){
cursor.close();
}
}
}
}