修复一个表创建失败的问题 https://github.com/AriaLyy/Aria/issues/570

修复一个非分块模式下导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/571
修复一个服务器端无法创建socket连接,却没有返回码导致客户端卡住的问题 https://github.com/AriaLyy/Aria/issues/569
修复文件删除后,组合任务没有重新下载的问题 https://github.com/AriaLyy/Aria/issues/574
优化缓存队列和执行队列
This commit is contained in:
laoyuyu
2019-12-22 11:30:29 +08:00
parent 27c889e171
commit 8dc16ce302
38 changed files with 563 additions and 718 deletions

View File

@@ -51,15 +51,12 @@ public class RecordHelper {
File temp = new File(mTaskRecord.filePath);
boolean fileExists = false;
if (!temp.exists()) {
BufferedRandomAccessFile tempFile;
try {
tempFile = new BufferedRandomAccessFile(temp, "rw");
tempFile.setLength(mWrapper.getEntity().getFileSize());
} catch (IOException e) {
e.printStackTrace();
}
createPlaceHolderFile(temp);
} else {
if (temp.length() != mWrapper.getEntity().getFileSize()) {
FileUtil.deleteFile(temp);
createPlaceHolderFile(temp);
}
fileExists = true;
}
// 处理文件被删除的情况
@@ -81,6 +78,19 @@ public class RecordHelper {
mWrapper.setNewTask(false);
}
/**
* 创建非分块的占位文件
*/
private void createPlaceHolderFile(File temp) {
BufferedRandomAccessFile tempFile;
try {
tempFile = new BufferedRandomAccessFile(temp, "rw");
tempFile.setLength(mWrapper.getEntity().getFileSize());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 处理分块任务的记录分块文件blockFileLen长度必须需要小于等于线程区间threadRectLen的长度
*/

View File

@@ -27,6 +27,7 @@ import com.arialyy.aria.core.listener.IEventListener;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -83,14 +84,24 @@ public abstract class AbsGroupUtil implements IUtil, Runnable {
private void initState() {
mState = new GroupRunState(getWrapper().getKey(), mListener, mSubQueue);
for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) {
if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE) {
File subFile = new File(wrapper.getEntity().getFilePath());
if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE
&& subFile.exists()
&& subFile.length() == wrapper.getEntity().getFileSize()) {
mState.updateCompleteNum();
mCurrentLocation += wrapper.getEntity().getFileSize();
} else {
if (!subFile.exists()) {
wrapper.getEntity().setCurrentProgress(0);
}
wrapper.getEntity().setState(IEntity.STATE_POST_PRE);
mCache.put(wrapper.getKey(), wrapper);
mCurrentLocation += wrapper.getEntity().getCurrentProgress();
}
}
if (getWrapper().getSubTaskWrapper().size() != mState.getCompleteNum()) {
getWrapper().setState(IEntity.STATE_POST_PRE);
}
mState.updateProgress(mCurrentLocation);
mScheduler = new Handler(Looper.getMainLooper(), SimpleSchedulers.newInstance(mState));
}

View File

@@ -122,8 +122,9 @@ public abstract class BaseListener<ENTITY extends AbsEntity, TASK_WRAPPER extend
mTask.putExpand(AbsTask.ERROR_INFO_KEY, e);
sendInState2Target(ISchedulers.FAIL);
if (e != null) {
e.printStackTrace();
ErrorHelp.saveError(e.getTag(), "", ALog.getExceptionString(e));
String error = ALog.getExceptionString(e);
ALog.w(TAG, error);
ErrorHelp.saveError(e.getTag(), "", error);
}
}

View File

@@ -16,8 +16,8 @@
package com.arialyy.aria.core.manager;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.core.task.IThreadTask;
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashSet;
@@ -25,8 +25,9 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -34,11 +35,12 @@ import java.util.concurrent.locks.ReentrantLock;
* 线程任务管理器
*/
public class ThreadTaskManager {
private final String TAG = CommonUtil.getClassName(this);
private static volatile ThreadTaskManager INSTANCE = null;
private final String TAG = "ThreadTaskManager";
private ExecutorService mExePool;
private Map<String, Set<FutureContainer>> mThreadTasks = new ConcurrentHashMap<>();
private static final int CORE_POOL_NUM = 20;
private static final ReentrantLock LOCK = new ReentrantLock();
private ThreadPoolExecutor mExePool;
private Map<String, Set<FutureContainer>> mThreadTasks = new ConcurrentHashMap<>();
public static synchronized ThreadTaskManager getInstance() {
if (INSTANCE == null) {
@@ -48,7 +50,10 @@ public class ThreadTaskManager {
}
private ThreadTaskManager() {
mExePool = Executors.newCachedThreadPool();
mExePool = new ThreadPoolExecutor(CORE_POOL_NUM, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
mExePool.allowsCoreThreadTimeOut();
}
/**

View File

@@ -79,7 +79,7 @@ public abstract class AbsTask<TASK_WRAPPER extends AbsTaskWrapper>
ALog.e(TAG, "key 为空");
return;
} else if (obj == null) {
ALog.w(TAG, "扩展数据为空");
ALog.i(TAG, "扩展数据为空");
return;
}
mExpand.put(key, obj);

View File

@@ -79,6 +79,11 @@ public interface ITaskWrapper {
*/
int U_TCP_PEER = 11;
/**
* SFTP 下载
*/
int D_SFTP = 12;
/**
* 获取任务类型
*

View File

@@ -17,10 +17,6 @@ package com.arialyy.aria.orm;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.net.URLEncoder;
/**
* Created by laoyuyu on 2018/3/22.
@@ -28,52 +24,8 @@ import java.net.URLEncoder;
abstract class AbsDelegate {
static final String TAG = "AbsDelegate";
/**
* 检查list参数是否合法list只能是{@code List<String>}
*
* @return {@code true} 合法
*/
boolean checkList(Field list) {
Class t = CommonUtil.getListParamType(list);
if (t != null && t == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误支持List<String>的参数字段");
return false;
}
}
/**
* 检查map参数是否合法map只能是{@code Map<String, String>}
*
* @return {@code true} 合法
*/
boolean checkMap(Field map) {
Class[] ts = CommonUtil.getMapParamType(map);
if (ts != null
&& ts[0] != null
&& ts[1] != null
&& ts[0] == String.class
&& ts[1] == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误支持Map<String,String>的参数字段");
return false;
}
}
void closeCursor(Cursor cursor) {
synchronized (AbsDelegate.class) {
if (cursor != null && !cursor.isClosed()) {
try {
cursor.close();
} catch (android.database.SQLException e) {
e.printStackTrace();
}
}
}
SqlUtil.closeCursor(cursor);
}
/**
@@ -82,9 +34,6 @@ abstract class AbsDelegate {
* @return 返回数据库
*/
SQLiteDatabase checkDb(SQLiteDatabase db) {
if (db == null || !db.isOpen()) {
db = SqlHelper.getInstance().getDb();
}
return db;
return SqlUtil.checkDb(db);
}
}

View File

@@ -1,242 +0,0 @@
/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* 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 com.arialyy.aria.orm;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.arialyy.aria.orm.annotation.Default;
import com.arialyy.aria.orm.annotation.Foreign;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by laoyuyu on 2018/3/22.
* 通用委托,创建表,检查字段
*/
class DelegateCommon extends AbsDelegate {
private DelegateCommon() {
}
/**
* 删除指定的表
*/
void dropTable(SQLiteDatabase db, String tableName) {
db = checkDb(db);
String deleteSQL = String.format("DROP TABLE IF EXISTS %s", tableName);
//db.beginTransaction();
db.execSQL(deleteSQL);
//db.setTransactionSuccessful();
//db.endTransaction();
}
/**
* 清空表数据
*/
<T extends DbEntity> void clean(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db);
String tableName = CommonUtil.getClassName(clazz);
if (tableExists(db, clazz)) {
String sql = "DELETE FROM " + tableName;
db.execSQL(sql);
}
}
/**
* 查找表是否存在
*
* @param clazz 数据库实体
* @return true该数据库实体对应的表存在false不存在
*/
boolean tableExists(SQLiteDatabase db, Class clazz) {
return tableExists(db, CommonUtil.getClassName(clazz));
}
/**
* 查找表是否存在
*
* @param tableName 表名
* @return true该数据库实体对应的表存在false不存在
*/
boolean tableExists(SQLiteDatabase db, String tableName) {
db = checkDb(db);
Cursor cursor = null;
try {
String sql =
String.format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%s'",
tableName);
cursor = db.rawQuery(sql, null);
if (cursor != null && cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeCursor(cursor);
}
return false;
}
/**
* 检查某个字段的值是否存在
*
* @param expression 字段和值"url=xxx"
* @return {@code true}该字段的对应的value已存在
*/
boolean checkDataExist(SQLiteDatabase db, Class clazz, String... expression) {
db = checkDb(db);
if (!CommonUtil.checkSqlExpression(expression)) {
return false;
}
String sql = String.format("SELECT rowid, * FROM %s WHERE %s ", CommonUtil.getClassName(clazz),
expression[0]);
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1]));
}
sql = String.format(sql, params);
Cursor cursor = db.rawQuery(sql, null);
final boolean isExist = cursor.getCount() > 0;
closeCursor(cursor);
return isExist;
}
/**
* 创建表
*
* @param clazz 数据库实体
*/
void createTable(SQLiteDatabase db, Class clazz) {
db = checkDb(db);
List<Field> fields = CommonUtil.getAllFields(clazz);
if (fields != null && fields.size() > 0) {
//外键Map在Sqlite3中foreign修饰的字段必须放在最后
final List<Field> foreignArray = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE IF NOT EXISTS ")
.append(CommonUtil.getClassName(clazz))
.append(" (");
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
Class<?> type = field.getType();
sb.append(field.getName());
if (type == String.class || type.isEnum()) {
sb.append(" VARCHAR");
} else if (type == int.class || type == Integer.class) {
sb.append(" INTEGER");
} else if (type == float.class || type == Float.class) {
sb.append(" FLOAT");
} else if (type == double.class || type == Double.class) {
sb.append(" DOUBLE");
} else if (type == long.class || type == Long.class) {
sb.append(" BIGINT");
} else if (type == boolean.class || type == Boolean.class) {
sb.append(" BOOLEAN");
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" DATA");
} else if (type == byte.class || type == Byte.class) {
sb.append(" BLOB");
} else if (type == Map.class || type == List.class) {
sb.append(" TEXT");
} else {
continue;
}
if (SqlUtil.isPrimary(field)) {
Primary pk = field.getAnnotation(Primary.class);
sb.append(" PRIMARY KEY");
if (pk.autoincrement() && (type == int.class || type == Integer.class)) {
sb.append(" AUTOINCREMENT");
}
}
if (SqlUtil.isForeign(field)) {
foreignArray.add(field);
}
if (SqlUtil.isNoNull(field)) {
sb.append(" NOT NULL");
}
if (SqlUtil.isDefault(field)) {
Default d = field.getAnnotation(Default.class);
if (!TextUtils.isEmpty(d.value())) {
sb.append(" ERROR ").append("'").append(d.value()).append("'");
}
}
if (SqlUtil.isUnique(field)) {
sb.append(" UNIQUE");
}
sb.append(",");
}
for (Field field : foreignArray) {
Foreign foreign = field.getAnnotation(Foreign.class);
sb.append("FOREIGN KEY (")
.append(field.getName())
.append(") REFERENCES ")
.append(CommonUtil.getClassName(foreign.parent()))
.append("(")
.append(foreign.column())
.append(")");
ActionPolicy update = foreign.onUpdate();
ActionPolicy delete = foreign.onDelete();
if (update != ActionPolicy.NO_ACTION) {
sb.append(" ON UPDATE ").append(update.function);
}
if (delete != ActionPolicy.NO_ACTION) {
sb.append(" ON DELETE ").append(update.function);
}
sb.append(",");
}
String str = sb.toString();
str = str.substring(0, str.length() - 1) + ");";
db.execSQL(str);
}
}
/**
* 通过class 获取该class的表字段
*
* @return 表字段列表
*/
List<String> getColumns(Class<? extends DbEntity> clazz) {
List<String> columns = new ArrayList<>();
List<Field> fields = CommonUtil.getAllFields(clazz);
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
columns.add(field.getName());
}
return columns;
}
}

View File

@@ -136,6 +136,9 @@ class DelegateFind extends AbsDelegate {
Many m = many.getAnnotation(Many.class);
Class parentClazz = Class.forName(one.getType().getName());
Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName());
// 检查表
SqlUtil.checkTable(db, parentClazz);
SqlUtil.checkTable(db, childClazz);
final String pTableName = parentClazz.getSimpleName();
final String cTableName = childClazz.getSimpleName();
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz);
@@ -418,6 +421,7 @@ class DelegateFind extends AbsDelegate {
*/
private <T extends DbEntity> List<T> exeNormalDataSql(SQLiteDatabase db, Class<T> clazz,
String sql, String[] selectionArgs) {
SqlUtil.checkTable(db, clazz);
String[] temp = new String[selectionArgs.length];
int i = 0;
for (String arg : selectionArgs) {

View File

@@ -38,6 +38,7 @@ class DelegateUpdate extends AbsDelegate {
*/
synchronized <T extends DbEntity> void delData(SQLiteDatabase db, Class<T> clazz,
String... expression) {
SqlUtil.checkTable(db, clazz);
db = checkDb(db);
if (!CommonUtil.checkSqlExpression(expression)) {
return;
@@ -57,6 +58,7 @@ class DelegateUpdate extends AbsDelegate {
* 修改某行数据
*/
synchronized void updateData(SQLiteDatabase db, DbEntity dbEntity) {
SqlUtil.checkTable(db, dbEntity.getClass());
db = checkDb(db);
ContentValues values = createValues(dbEntity);
if (values != null) {
@@ -109,6 +111,7 @@ class DelegateUpdate extends AbsDelegate {
if (oldClazz == null || oldClazz != entity.getClass() || table == null) {
oldClazz = entity.getClass();
table = CommonUtil.getClassName(oldClazz);
SqlUtil.checkTable(db, oldClazz);
}
ContentValues value = createValues(entity);
@@ -130,6 +133,7 @@ class DelegateUpdate extends AbsDelegate {
* 插入数据
*/
synchronized void insertData(SQLiteDatabase db, DbEntity dbEntity) {
SqlUtil.checkTable(db, dbEntity.getClass());
db = checkDb(db);
ContentValues values = createValues(dbEntity);
if (values != null) {
@@ -156,9 +160,9 @@ class DelegateUpdate extends AbsDelegate {
}
String value = null;
Type type = field.getType();
if (type == Map.class && checkMap(field)) {
if (type == Map.class && SqlUtil.checkMap(field)) {
value = SqlUtil.map2Str((Map<String, String>) field.get(dbEntity));
} else if (type == List.class && checkList(field)) {
} else if (type == List.class && SqlUtil.checkList(field)) {
value = SqlUtil.list2Str(dbEntity, field);
} else {
Object obj = field.get(dbEntity);

View File

@@ -85,15 +85,14 @@ public class DelegateWrapper {
* @return {@code true}该字段的对应的value已存在
*/
boolean checkDataExist(Class clazz, String... expression) {
return mDManager.getDelegate(DelegateCommon.class)
.checkDataExist(mDb, clazz, expression);
return SqlUtil.checkDataExist(mDb, clazz, expression);
}
/**
* 清空表数据
*/
<T extends DbEntity> void clean(Class<T> clazz) {
mDManager.getDelegate(DelegateCommon.class).clean(mDb, clazz);
SqlUtil.clean(mDb, clazz);
}
/**
@@ -193,7 +192,7 @@ public class DelegateWrapper {
* 查找某张表是否存在
*/
public boolean tableExists(Class clazz) {
return mDManager.getDelegate(DelegateCommon.class).tableExists(mDb, clazz);
return SqlUtil.tableExists(mDb, clazz);
}
/**

View File

@@ -41,13 +41,10 @@ final class SqlHelper extends SQLiteOpenHelper {
private static volatile SqlHelper INSTANCE = null;
private Context mContext;
private DelegateCommon mDelegate;
synchronized static SqlHelper init(Context context) {
if (INSTANCE == null) {
synchronized (SqlHelper.class) {
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
INSTANCE = new SqlHelper(context.getApplicationContext(), delegate);
INSTANCE = new SqlHelper(context.getApplicationContext());
}
}
return INSTANCE;
@@ -57,11 +54,10 @@ final class SqlHelper extends SQLiteOpenHelper {
return INSTANCE;
}
private SqlHelper(Context context, DelegateCommon delegate) {
private SqlHelper(Context context) {
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null,
DBConfig.VERSION);
mContext = context;
mDelegate = delegate;
}
@Override public void onOpen(SQLiteDatabase db) {
@@ -82,12 +78,11 @@ final class SqlHelper extends SQLiteOpenHelper {
}
@Override public void onCreate(SQLiteDatabase db) {
DelegateCommon delegate = DelegateManager.getInstance().getDelegate(DelegateCommon.class);
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class clazz = DBConfig.mapping.get(tableName);
if (!delegate.tableExists(db, clazz)) {
delegate.createTable(db, clazz);
if (!SqlUtil.tableExists(db, clazz)) {
SqlUtil.createTable(db, clazz);
}
}
}
@@ -167,13 +162,13 @@ final class SqlHelper extends SQLiteOpenHelper {
Set<String> tables = DBConfig.mapping.keySet();
for (String tableName : tables) {
Class<? extends DbEntity> clazz = DBConfig.mapping.get(tableName);
if (mDelegate.tableExists(db, clazz)) {
if (SqlUtil.tableExists(db, clazz)) {
//修改表名为中介表名
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName);
db.execSQL(alertSql);
//创建新表
mDelegate.createTable(db, clazz);
SqlUtil.createTable(db, clazz);
String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName);
Cursor cursor = db.rawQuery(sql, null);
@@ -187,7 +182,7 @@ final class SqlHelper extends SQLiteOpenHelper {
db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null);
// 获取新表的所有字段名称
List<String> newTabColumns = mDelegate.getColumns(clazz);
List<String> newTabColumns = SqlUtil.getColumns(clazz);
// 获取旧表的所有字段名称
List<String> oldTabColumns = new ArrayList<>();
@@ -237,9 +232,9 @@ final class SqlHelper extends SQLiteOpenHelper {
db.execSQL(insertSql);
}
//删除中介表
mDelegate.dropTable(db, tableName + "_temp");
SqlUtil.dropTable(db, tableName + "_temp");
} else {
mDelegate.createTable(db, clazz);
SqlUtil.createTable(db, clazz);
}
}
db.setTransactionSuccessful();
@@ -281,7 +276,7 @@ final class SqlHelper extends SQLiteOpenHelper {
if (url.startsWith("ftp") || url.startsWith("sftp")) {
type = ITaskWrapper.D_FTP;
} else {
if (mDelegate.tableExists(db, M3U8Entity.class)) {
if (SqlUtil.tableExists(db, M3U8Entity.class)) {
Cursor m3u8c = db.rawQuery("SELECT isLive FROM M3U8Entity WHERE filePath=\""
+ SqlUtil.encodeStr(filePath)
+ "\"", null);
@@ -386,8 +381,8 @@ final class SqlHelper extends SQLiteOpenHelper {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
if (SqlUtil.tableExists(db, taskTable)) {
SqlUtil.dropTable(db, taskTable);
}
}
@@ -420,8 +415,8 @@ final class SqlHelper extends SQLiteOpenHelper {
String[] taskTables =
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" };
for (String taskTable : taskTables) {
if (mDelegate.tableExists(db, taskTable)) {
mDelegate.dropTable(db, taskTable);
if (SqlUtil.tableExists(db, taskTable)) {
SqlUtil.dropTable(db, taskTable);
}
}
@@ -430,7 +425,7 @@ final class SqlHelper extends SQLiteOpenHelper {
String[] keys = new String[] { "downloadPath", "groupName" };
int i = 0;
for (String tableName : tables) {
if (!mDelegate.tableExists(db, tableName)) {
if (!SqlUtil.tableExists(db, tableName)) {
continue;
}
String pColumn = keys[i];

View File

@@ -15,6 +15,8 @@
*/
package com.arialyy.aria.orm;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaConfig;
import com.arialyy.aria.orm.annotation.Default;
@@ -26,6 +28,7 @@ import com.arialyy.aria.orm.annotation.One;
import com.arialyy.aria.orm.annotation.Primary;
import com.arialyy.aria.orm.annotation.Unique;
import com.arialyy.aria.orm.annotation.Wrapper;
import com.arialyy.aria.util.ALog;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -41,6 +44,280 @@ import java.util.Set;
* sql工具
*/
final class SqlUtil {
private static final String TAG = CommonUtil.getClassName("SqlUtil");
/**
* 检查表是否存在,不存在则创建表
*/
static void checkTable(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
if (!tableExists(db, clazz)) {
createTable(db, clazz);
}
}
static void closeCursor(Cursor cursor) {
synchronized (AbsDelegate.class) {
if (cursor != null && !cursor.isClosed()) {
try {
cursor.close();
} catch (android.database.SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 查找表是否存在
*
* @param clazz 数据库实体
* @return true该数据库实体对应的表存在false不存在
*/
static boolean tableExists(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
return tableExists(db, CommonUtil.getClassName(clazz));
}
/**
* 查找表是否存在
*
* @param tableName 表名
* @return true该数据库实体对应的表存在false不存在
*/
static boolean tableExists(SQLiteDatabase db, String tableName) {
db = checkDb(db);
Cursor cursor = null;
try {
String sql =
String.format("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%s'",
tableName);
cursor = db.rawQuery(sql, null);
if (cursor != null && cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeCursor(cursor);
}
return false;
}
/**
* 检查list参数是否合法list只能是{@code List<String>}
*
* @return {@code true} 合法
*/
static boolean checkList(Field list) {
Class t = CommonUtil.getListParamType(list);
if (t == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误支持List<String>的参数字段");
return false;
}
}
/**
* 检查map参数是否合法map只能是{@code Map<String, String>}
*
* @return {@code true} 合法
*/
static boolean checkMap(Field map) {
Class[] ts = CommonUtil.getMapParamType(map);
if (ts != null
&& ts[0] != null
&& ts[1] != null
&& ts[0] == String.class
&& ts[1] == String.class) {
return true;
} else {
ALog.d(TAG, "map参数错误支持Map<String,String>的参数字段");
return false;
}
}
/**
* 删除指定的表
*/
static void dropTable(SQLiteDatabase db, String tableName) {
db = checkDb(db);
String deleteSQL = String.format("DROP TABLE IF EXISTS %s", tableName);
//db.beginTransaction();
db.execSQL(deleteSQL);
//db.setTransactionSuccessful();
//db.endTransaction();
}
/**
* 清空表数据
*/
static void clean(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
db = checkDb(db);
String tableName = CommonUtil.getClassName(clazz);
if (tableExists(db, clazz)) {
String sql = "DELETE FROM " + tableName;
db.execSQL(sql);
}
}
/**
* 检查某个字段的值是否存在
*
* @param expression 字段和值"url=xxx"
* @return {@code true}该字段的对应的value已存在
*/
static boolean checkDataExist(SQLiteDatabase db, Class<? extends DbEntity> clazz,
String... expression) {
db = checkDb(db);
if (!CommonUtil.checkSqlExpression(expression)) {
return false;
}
String sql = String.format("SELECT rowid, * FROM %s WHERE %s ", CommonUtil.getClassName(clazz),
expression[0]);
sql = sql.replace("?", "%s");
Object[] params = new String[expression.length - 1];
for (int i = 0, len = params.length; i < len; i++) {
params[i] = String.format("'%s'", SqlUtil.encodeStr(expression[i + 1]));
}
sql = String.format(sql, params);
Cursor cursor = db.rawQuery(sql, null);
final boolean isExist = cursor.getCount() > 0;
closeCursor(cursor);
return isExist;
}
/**
* 通过class 获取该class的表字段
*
* @return 表字段列表
*/
static List<String> getColumns(Class<? extends DbEntity> clazz) {
List<String> columns = new ArrayList<>();
List<Field> fields = CommonUtil.getAllFields(clazz);
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
columns.add(field.getName());
}
return columns;
}
/**
* 检查数据库是否关闭,已经关闭的话,打开数据库
*
* @return 返回数据库
*/
static SQLiteDatabase checkDb(SQLiteDatabase db) {
if (db == null || !db.isOpen()) {
db = SqlHelper.getInstance().getDb();
}
return db;
}
/**
* 创建表
*
* @param clazz 数据库实体
*/
static void createTable(SQLiteDatabase db, Class<? extends DbEntity> clazz) {
db = checkDb(db);
List<Field> fields = CommonUtil.getAllFields(clazz);
if (fields != null && fields.size() > 0) {
//外键Map在Sqlite3中foreign修饰的字段必须放在最后
final List<Field> foreignArray = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE IF NOT EXISTS ")
.append(CommonUtil.getClassName(clazz))
.append(" (");
for (Field field : fields) {
field.setAccessible(true);
if (SqlUtil.isIgnore(field)) {
continue;
}
Class<?> type = field.getType();
sb.append(field.getName());
if (type == String.class || type.isEnum()) {
sb.append(" VARCHAR");
} else if (type == int.class || type == Integer.class) {
sb.append(" INTEGER");
} else if (type == float.class || type == Float.class) {
sb.append(" FLOAT");
} else if (type == double.class || type == Double.class) {
sb.append(" DOUBLE");
} else if (type == long.class || type == Long.class) {
sb.append(" BIGINT");
} else if (type == boolean.class || type == Boolean.class) {
sb.append(" BOOLEAN");
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" DATA");
} else if (type == byte.class || type == Byte.class) {
sb.append(" BLOB");
} else if (type == Map.class || type == List.class) {
sb.append(" TEXT");
} else {
continue;
}
if (SqlUtil.isPrimary(field)) {
Primary pk = field.getAnnotation(Primary.class);
sb.append(" PRIMARY KEY");
if (pk.autoincrement() && (type == int.class || type == Integer.class)) {
sb.append(" AUTOINCREMENT");
}
}
if (SqlUtil.isForeign(field)) {
foreignArray.add(field);
}
if (SqlUtil.isNoNull(field)) {
sb.append(" NOT NULL");
}
if (SqlUtil.isDefault(field)) {
Default d = field.getAnnotation(Default.class);
if (!TextUtils.isEmpty(d.value())) {
sb.append(" ERROR ").append("'").append(d.value()).append("'");
}
}
if (SqlUtil.isUnique(field)) {
sb.append(" UNIQUE");
}
sb.append(",");
}
for (Field field : foreignArray) {
Foreign foreign = field.getAnnotation(Foreign.class);
sb.append("FOREIGN KEY (")
.append(field.getName())
.append(") REFERENCES ")
.append(CommonUtil.getClassName(foreign.parent()))
.append("(")
.append(foreign.column())
.append(")");
ActionPolicy update = foreign.onUpdate();
ActionPolicy delete = foreign.onDelete();
if (update != ActionPolicy.NO_ACTION) {
sb.append(" ON UPDATE ").append(update.function);
}
if (delete != ActionPolicy.NO_ACTION) {
sb.append(" ON DELETE ").append(update.function);
}
sb.append(",");
}
String str = sb.toString();
str = str.substring(0, str.length() - 1) + ");";
db.execSQL(str);
}
}
/**
* URL编码字符串
@@ -56,7 +333,7 @@ final class SqlUtil {
/**
* 获取主键字段名
*/
static String getPrimaryName(Class clazz) {
static String getPrimaryName(Class<? extends DbEntity> clazz) {
List<Field> fields = CommonUtil.getAllFields(clazz);
String column;
if (fields != null && !fields.isEmpty()) {
@@ -201,8 +478,8 @@ final class SqlUtil {
*
* @return {@code true} 是
*/
static boolean isWrapper(Class clazz) {
Wrapper w = (Wrapper) clazz.getAnnotation(Wrapper.class);
static boolean isWrapper(Class<? extends AbsDbWrapper> clazz) {
Wrapper w = clazz.getAnnotation(Wrapper.class);
return w != null;
}

View File

@@ -28,6 +28,7 @@ import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.List;
/**