修复一个表创建失败的问题 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:
@@ -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)的长度
|
||||
*/
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -79,6 +79,11 @@ public interface ITaskWrapper {
|
||||
*/
|
||||
int U_TCP_PEER = 11;
|
||||
|
||||
/**
|
||||
* SFTP 下载
|
||||
*/
|
||||
int D_SFTP = 12;
|
||||
|
||||
/**
|
||||
* 获取任务类型
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user