parent
16e76b42ed
commit
3ac7b0f211
@ -1,45 +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.http.download; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DGTaskWrapper; |
|
||||||
import com.arialyy.aria.core.group.AbsGroupLoader; |
|
||||||
import com.arialyy.aria.core.group.AbsGroupLoaderUtil; |
|
||||||
import com.arialyy.aria.core.listener.DownloadGroupListener; |
|
||||||
import com.arialyy.aria.core.loader.LoaderStructure; |
|
||||||
import com.arialyy.aria.http.HttpTaskOption; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/30. |
|
||||||
* 任务组下载工具 |
|
||||||
*/ |
|
||||||
public final class HttpDGLoaderUtil extends AbsGroupLoaderUtil { |
|
||||||
|
|
||||||
@Override protected AbsGroupLoader getLoader() { |
|
||||||
if (mLoader == null) { |
|
||||||
getTaskWrapper().generateTaskOption(HttpTaskOption.class); |
|
||||||
mLoader = new HttpDGLoader(getTaskWrapper(), (DownloadGroupListener) getListener()); |
|
||||||
} |
|
||||||
return mLoader; |
|
||||||
} |
|
||||||
|
|
||||||
@Override protected LoaderStructure buildLoaderStructure() { |
|
||||||
LoaderStructure structure = new LoaderStructure(); |
|
||||||
structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper())); |
|
||||||
structure.accept(getLoader()); |
|
||||||
return structure; |
|
||||||
} |
|
||||||
} |
|
@ -1,132 +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.core; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.common.BaseOption; |
|
||||||
import com.arialyy.aria.core.inf.IEventHandler; |
|
||||||
import com.arialyy.aria.core.inf.IOptionConstant; |
|
||||||
import com.arialyy.aria.core.processor.FtpInterceptHandler; |
|
||||||
import com.arialyy.aria.core.processor.IBandWidthUrlConverter; |
|
||||||
import com.arialyy.aria.core.processor.IFtpUploadInterceptor; |
|
||||||
import com.arialyy.aria.core.processor.IHttpFileLenAdapter; |
|
||||||
import com.arialyy.aria.core.processor.IHttpFileNameAdapter; |
|
||||||
import com.arialyy.aria.core.processor.IKeyUrlConverter; |
|
||||||
import com.arialyy.aria.core.processor.ILiveTsUrlConverter; |
|
||||||
import com.arialyy.aria.core.processor.ITsMergeHandler; |
|
||||||
import com.arialyy.aria.core.processor.IVodTsUrlConverter; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
import java.lang.reflect.Field; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务配置参数 |
|
||||||
* |
|
||||||
* @author lyy |
|
||||||
* Date: 2019-09-10 |
|
||||||
*/ |
|
||||||
public class TaskOptionParams { |
|
||||||
|
|
||||||
private static List<Class> PROCESSORES = new ArrayList<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 普通参数 |
|
||||||
*/ |
|
||||||
private Map<String, Object> params = new HashMap<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 事件处理对象 |
|
||||||
*/ |
|
||||||
private Map<String, IEventHandler> handler = new HashMap<>(); |
|
||||||
|
|
||||||
static { |
|
||||||
PROCESSORES.add(FtpInterceptHandler.class); |
|
||||||
PROCESSORES.add(IBandWidthUrlConverter.class); |
|
||||||
PROCESSORES.add(IFtpUploadInterceptor.class); |
|
||||||
PROCESSORES.add(IHttpFileLenAdapter.class); |
|
||||||
PROCESSORES.add(IHttpFileNameAdapter.class); |
|
||||||
PROCESSORES.add(ILiveTsUrlConverter.class); |
|
||||||
PROCESSORES.add(ITsMergeHandler.class); |
|
||||||
PROCESSORES.add(IVodTsUrlConverter.class); |
|
||||||
PROCESSORES.add(IKeyUrlConverter.class); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置任务参数 |
|
||||||
* |
|
||||||
* @param option 任务配置 |
|
||||||
*/ |
|
||||||
public void setParams(BaseOption option) { |
|
||||||
List<Field> fields = CommonUtil.getAllFields(option.getClass()); |
|
||||||
|
|
||||||
for (Field field : fields) { |
|
||||||
field.setAccessible(true); |
|
||||||
try { |
|
||||||
|
|
||||||
if (PROCESSORES.contains(field.getType())) { |
|
||||||
Object eventHandler = field.get(option); |
|
||||||
if (eventHandler != null) { |
|
||||||
setObjs(field.getName(), (IEventHandler) eventHandler); |
|
||||||
} |
|
||||||
} else { |
|
||||||
Object params = field.get(option); |
|
||||||
if (params != null) { |
|
||||||
setParams(field.getName(), params); |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置普通参数 |
|
||||||
* |
|
||||||
* @param key {@link IOptionConstant} |
|
||||||
*/ |
|
||||||
public TaskOptionParams setParams(String key, Object value) { |
|
||||||
params.put(key, value); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置对象参数 |
|
||||||
*/ |
|
||||||
public TaskOptionParams setObjs(String key, IEventHandler handler) { |
|
||||||
this.handler.put(key, handler); |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
public Map<String, Object> getParams() { |
|
||||||
return params; |
|
||||||
} |
|
||||||
|
|
||||||
public Object getParam(String key) { |
|
||||||
return params.get(key); |
|
||||||
} |
|
||||||
|
|
||||||
public IEventHandler getHandler(String key) { |
|
||||||
return handler.get(key); |
|
||||||
} |
|
||||||
|
|
||||||
public Map<String, IEventHandler> getHandler() { |
|
||||||
return handler; |
|
||||||
} |
|
||||||
} |
|
@ -1,91 +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.core; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
import com.arialyy.aria.orm.annotation.Ignore; |
|
||||||
import com.arialyy.aria.orm.annotation.NoNull; |
|
||||||
import com.arialyy.aria.orm.annotation.Unique; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/21. |
|
||||||
* 任务上传或下载的任务记录 |
|
||||||
*/ |
|
||||||
public class TaskRecord extends DbEntity { |
|
||||||
//public static final int TYPE_HTTP_FTP = 0;
|
|
||||||
//public static final int TYPE_M3U8_VOD = 1;
|
|
||||||
//public static final int TYPE_M3U8_LIVE = 2;
|
|
||||||
|
|
||||||
@Ignore |
|
||||||
public List<ThreadRecord> threadRecords; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务线程数 |
|
||||||
*/ |
|
||||||
public int threadNum; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务文件路径 |
|
||||||
*/ |
|
||||||
public String filePath; |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件长度 |
|
||||||
*/ |
|
||||||
public long fileLength; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务文件名 |
|
||||||
*/ |
|
||||||
@NoNull |
|
||||||
public String fileName; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否是任务组的子任务记录 |
|
||||||
* {@code true}是 |
|
||||||
*/ |
|
||||||
public boolean isGroupRecord = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 下载任务组名 |
|
||||||
*/ |
|
||||||
public String dGroupHash; |
|
||||||
|
|
||||||
/** |
|
||||||
* 上传组任务名,暂时没有用 |
|
||||||
*/ |
|
||||||
@Ignore |
|
||||||
@Deprecated |
|
||||||
public String uGroupHash; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否是分块{@code true}是,{@code false} 不是 |
|
||||||
*/ |
|
||||||
public boolean isBlock = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务类型 |
|
||||||
* {@link ITaskWrapper} |
|
||||||
*/ |
|
||||||
public int taskType = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* m3u8文件码率 |
|
||||||
*/ |
|
||||||
public long bandWidth = 0; |
|
||||||
} |
|
@ -1,68 +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.core; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/5/8. |
|
||||||
* 任务的线程记录 |
|
||||||
*/ |
|
||||||
public class ThreadRecord extends DbEntity { |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务的文件路径,不是当前线程记录的的分块文件路径 |
|
||||||
*/ |
|
||||||
public String taskKey; |
|
||||||
|
|
||||||
/** |
|
||||||
* 开始位置 |
|
||||||
*/ |
|
||||||
public long startLocation; |
|
||||||
|
|
||||||
/** |
|
||||||
* 结束位置 |
|
||||||
*/ |
|
||||||
public long endLocation; |
|
||||||
|
|
||||||
/** |
|
||||||
* 线程是否完成 |
|
||||||
* {@code true}完成,{@code false}未完成 |
|
||||||
*/ |
|
||||||
public boolean isComplete = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 线程id |
|
||||||
*/ |
|
||||||
public int threadId = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* 分块长度 |
|
||||||
*/ |
|
||||||
public long blockLen = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* 线程类型 |
|
||||||
* {@link ITaskWrapper} |
|
||||||
*/ |
|
||||||
public int threadType = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* ts文件的下载地址 |
|
||||||
*/ |
|
||||||
public String tsUrl; |
|
||||||
} |
|
@ -1,32 +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.core.command; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.task.ITask; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/29. |
|
||||||
* 抽象命令工厂 |
|
||||||
*/ |
|
||||||
public abstract class AbsCmdFactory<TASK_ENTITY extends AbsTaskWrapper, CMD extends AbsCmd> { |
|
||||||
|
|
||||||
/** |
|
||||||
* @param entity 下载实体 |
|
||||||
* {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD} |
|
||||||
*/ |
|
||||||
public abstract CMD createCmd(TASK_ENTITY entity, int type, int taskType); |
|
||||||
} |
|
@ -1,198 +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.core.command; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DGTaskWrapper; |
|
||||||
import com.arialyy.aria.core.download.DTaskWrapper; |
|
||||||
import com.arialyy.aria.core.task.AbsTask; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.core.task.ITask; |
|
||||||
import com.arialyy.aria.core.queue.DGroupTaskQueue; |
|
||||||
import com.arialyy.aria.core.queue.DTaskQueue; |
|
||||||
import com.arialyy.aria.core.queue.UTaskQueue; |
|
||||||
import com.arialyy.aria.core.listener.ISchedulers; |
|
||||||
import com.arialyy.aria.core.upload.UTaskWrapper; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2016/8/22. 下载命令 |
|
||||||
*/ |
|
||||||
public abstract class AbsNormalCmd<T extends AbsTaskWrapper> extends AbsCmd<T> { |
|
||||||
/** |
|
||||||
* 能否执行命令 |
|
||||||
*/ |
|
||||||
boolean canExeCmd = true; |
|
||||||
|
|
||||||
int taskType; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param taskType 下载任务类型{@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link |
|
||||||
* ITask#UPLOAD} |
|
||||||
*/ |
|
||||||
AbsNormalCmd(T entity, int taskType) { |
|
||||||
this.taskType = taskType; |
|
||||||
mTaskWrapper = entity; |
|
||||||
TAG = CommonUtil.getClassName(this); |
|
||||||
if (taskType == ITask.DOWNLOAD) { |
|
||||||
if (!(entity instanceof DTaskWrapper)) { |
|
||||||
ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD"); |
|
||||||
return; |
|
||||||
} |
|
||||||
mQueue = DTaskQueue.getInstance(); |
|
||||||
} else if (taskType == ITask.DOWNLOAD_GROUP) { |
|
||||||
if (!(entity instanceof DGTaskWrapper)) { |
|
||||||
ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD_GROUP"); |
|
||||||
return; |
|
||||||
} |
|
||||||
mQueue = DGroupTaskQueue.getInstance(); |
|
||||||
} else if (taskType == ITask.UPLOAD) { |
|
||||||
if (!(entity instanceof UTaskWrapper)) { |
|
||||||
ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_UPLOAD"); |
|
||||||
return; |
|
||||||
} |
|
||||||
mQueue = UTaskQueue.getInstance(); |
|
||||||
} else { |
|
||||||
ALog.e(TAG, "任务类型错误,任务类型应该为ICM.TASK_TYPE_DOWNLOAD、TASK_TYPE_DOWNLOAD_GROUP、TASK_TYPE_UPLOAD"); |
|
||||||
return; |
|
||||||
} |
|
||||||
isDownloadCmd = taskType == ITask.DOWNLOAD || taskType == ITask.DOWNLOAD_GROUP; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 发送等待状态 |
|
||||||
*/ |
|
||||||
void sendWaitState() { |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
task = createTask(); |
|
||||||
} |
|
||||||
sendWaitState(task); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 发送等待状态 |
|
||||||
*/ |
|
||||||
void sendWaitState(AbsTask task) { |
|
||||||
if (task != null) { |
|
||||||
task.getTaskWrapper().setState(IEntity.STATE_WAIT); |
|
||||||
task.getOutHandler().obtainMessage(ISchedulers.WAIT, task).sendToTarget(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 停止所有任务 |
|
||||||
*/ |
|
||||||
void stopAll() { |
|
||||||
mQueue.stopAllTask(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 停止任务 |
|
||||||
*/ |
|
||||||
void stopTask() { |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
task = createTask(); |
|
||||||
} |
|
||||||
mQueue.stopTask(task); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除任务 |
|
||||||
*/ |
|
||||||
void removeTask() { |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
task = createTask(); |
|
||||||
} |
|
||||||
mQueue.cancelTask(task); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除任务 |
|
||||||
*/ |
|
||||||
void removeTask(AbsTaskWrapper wrapper) { |
|
||||||
AbsTask tempTask = getTask(wrapper.getKey()); |
|
||||||
if (tempTask == null) { |
|
||||||
tempTask = createTask(wrapper); |
|
||||||
} |
|
||||||
mQueue.cancelTask(tempTask); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 启动任务 |
|
||||||
*/ |
|
||||||
void startTask() { |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
task = createTask(); |
|
||||||
} |
|
||||||
mQueue.startTask(task); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 恢复任务 |
|
||||||
*/ |
|
||||||
void resumeTask() { |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
task = createTask(); |
|
||||||
} |
|
||||||
mQueue.resumeTask(task); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 从队列中获取任务 |
|
||||||
* |
|
||||||
* @return 执行任务 |
|
||||||
*/ |
|
||||||
AbsTask getTask() { |
|
||||||
return mQueue.getTask(mTaskWrapper.getEntity().getKey()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 从队列中获取任务 |
|
||||||
* |
|
||||||
* @return 执行任务 |
|
||||||
*/ |
|
||||||
AbsTask getTask(String key) { |
|
||||||
return mQueue.getTask(key); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建任务 |
|
||||||
* |
|
||||||
* @return 创建的任务 |
|
||||||
*/ |
|
||||||
AbsTask createTask() { |
|
||||||
return mQueue.createTask(mTaskWrapper); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建指定实体的任务 |
|
||||||
* |
|
||||||
* @param wrapper 特定的任务实体 |
|
||||||
* @return 创建的任务 |
|
||||||
*/ |
|
||||||
AbsTask createTask(AbsTaskWrapper wrapper) { |
|
||||||
|
|
||||||
return mQueue.createTask(wrapper); |
|
||||||
} |
|
||||||
} |
|
@ -1,114 +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.core.command; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.task.ITask; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by Lyy on 2016/9/23. |
|
||||||
* 命令工厂 |
|
||||||
*/ |
|
||||||
public class NormalCmdFactory extends AbsCmdFactory<AbsTaskWrapper, AbsNormalCmd> { |
|
||||||
/** |
|
||||||
* 创建任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_CREATE = 0xb1; |
|
||||||
/** |
|
||||||
* 启动任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_START = 0xb2; |
|
||||||
/** |
|
||||||
* 恢复任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_RESUME = 0xb3; |
|
||||||
/** |
|
||||||
* 取消任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_CANCEL = 0xb4; |
|
||||||
/** |
|
||||||
* 停止任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_STOP = 0xb5; |
|
||||||
/** |
|
||||||
* 设置任务为最高优先级 |
|
||||||
*/ |
|
||||||
public static final int TASK_HIGHEST_PRIORITY = 0xb6; |
|
||||||
/** |
|
||||||
* 停止所有任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_STOP_ALL = 0xb7; |
|
||||||
/** |
|
||||||
* 恢复所有停止的任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_RESUME_ALL = 0xb8; |
|
||||||
/** |
|
||||||
* 删除所有任务, |
|
||||||
*/ |
|
||||||
public static final int TASK_CANCEL_ALL = 0xb9; |
|
||||||
/** |
|
||||||
* 重启任务 |
|
||||||
*/ |
|
||||||
public static final int TASK_RESTART = 0xba; |
|
||||||
|
|
||||||
private static volatile NormalCmdFactory INSTANCE = null; |
|
||||||
|
|
||||||
private NormalCmdFactory() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public static NormalCmdFactory getInstance() { |
|
||||||
if (INSTANCE == null) { |
|
||||||
synchronized (NormalCmdFactory.class) { |
|
||||||
INSTANCE = new NormalCmdFactory(); |
|
||||||
} |
|
||||||
} |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param entity 下载实体 |
|
||||||
* @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link |
|
||||||
* #TASK_STOP}、{@link #TASK_HIGHEST_PRIORITY}、{@link #TASK_STOP_ALL}、{@link #TASK_RESUME_ALL} |
|
||||||
* @param taskType {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD} |
|
||||||
*/ |
|
||||||
public AbsNormalCmd createCmd(AbsTaskWrapper entity, int type, int taskType) { |
|
||||||
switch (type) { |
|
||||||
case TASK_CREATE: |
|
||||||
return new AddCmd<>(entity, taskType); |
|
||||||
case TASK_RESUME: |
|
||||||
case TASK_START: |
|
||||||
return new StartCmd<>(entity, taskType); |
|
||||||
case TASK_CANCEL: |
|
||||||
return new CancelCmd<>(entity, taskType); |
|
||||||
case TASK_STOP: |
|
||||||
return new StopCmd<>(entity, taskType); |
|
||||||
case TASK_HIGHEST_PRIORITY: |
|
||||||
return new HighestPriorityCmd<>(entity, taskType); |
|
||||||
case TASK_STOP_ALL: |
|
||||||
return new StopAllCmd<>(entity, taskType); |
|
||||||
case TASK_RESUME_ALL: |
|
||||||
return new ResumeAllCmd<>(entity, taskType); |
|
||||||
case TASK_CANCEL_ALL: |
|
||||||
return new CancelAllCmd<>(entity, taskType); |
|
||||||
case TASK_RESTART: |
|
||||||
return new ReStartCmd<>(entity, taskType); |
|
||||||
default: |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,47 +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.core.command; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.task.AbsTask; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2016/9/20. |
|
||||||
* 停止命令 |
|
||||||
*/ |
|
||||||
final class StopCmd<T extends AbsTaskWrapper> extends AbsNormalCmd<T> { |
|
||||||
|
|
||||||
StopCmd(T entity, int taskType) { |
|
||||||
super(entity, taskType); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void executeCmd() { |
|
||||||
if (!canExeCmd) return; |
|
||||||
AbsTask task = getTask(); |
|
||||||
if (task == null) { |
|
||||||
if (mTaskWrapper.getEntity().getState() == IEntity.STATE_RUNNING) { |
|
||||||
stopTask(); |
|
||||||
} else { |
|
||||||
ALog.w(TAG, "停止命令执行失败,【调度器中没有该任务】"); |
|
||||||
} |
|
||||||
} else { |
|
||||||
stopTask(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* 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.core.command |
||||||
|
|
||||||
|
import com.arialyy.aria.core.DuaContext |
||||||
|
import com.arialyy.aria.core.command.CmdResp.Companion.CODE_COMPLETE |
||||||
|
import com.arialyy.aria.core.command.CmdResp.Companion.CODE_INTERRUPT |
||||||
|
import com.arialyy.aria.core.task.ITask |
||||||
|
import com.arialyy.aria.core.task.ThreadTaskManager2 |
||||||
|
import kotlinx.coroutines.Dispatchers |
||||||
|
import kotlinx.coroutines.launch |
||||||
|
import timber.log.Timber |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by lyy on 2016/9/20. |
||||||
|
* 停止命令 |
||||||
|
*/ |
||||||
|
class StopCmd(task: ITask) : AbsCmd(task) { |
||||||
|
|
||||||
|
override fun executeCmd(): CmdResp { |
||||||
|
val resp = interceptor() |
||||||
|
if (resp.isInterrupt()) { |
||||||
|
Timber.w("interruption occurred, cancel cmd"); |
||||||
|
return resp; |
||||||
|
} |
||||||
|
|
||||||
|
if (!taskQueue.taskIsRunning(mTask?.taskId ?: -1)) { |
||||||
|
Timber.e("task not running") |
||||||
|
return CmdResp(CODE_INTERRUPT) |
||||||
|
} |
||||||
|
DuaContext.duaScope.launch(Dispatchers.IO) { |
||||||
|
ThreadTaskManager2.stopThreadTask(mTask!!.taskId) |
||||||
|
} |
||||||
|
return CmdResp(CODE_COMPLETE) |
||||||
|
} |
||||||
|
} |
@ -1,267 +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.core.common; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
import com.arialyy.aria.orm.annotation.Default; |
|
||||||
import com.arialyy.aria.orm.annotation.Ignore; |
|
||||||
import java.io.Serializable; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/29. |
|
||||||
*/ |
|
||||||
public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable, Serializable { |
|
||||||
/** |
|
||||||
* 速度 |
|
||||||
*/ |
|
||||||
@Ignore private long speed = 0; |
|
||||||
/** |
|
||||||
* 单位转换后的速度 |
|
||||||
*/ |
|
||||||
@Ignore private String convertSpeed; |
|
||||||
/** |
|
||||||
* 下载失败计数,每次开始都重置为0 |
|
||||||
*/ |
|
||||||
@Ignore private int failNum = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* 剩余时间,单位:s |
|
||||||
*/ |
|
||||||
@Ignore private int timeLeft = Integer.MAX_VALUE; |
|
||||||
|
|
||||||
/** |
|
||||||
* 扩展字段 |
|
||||||
*/ |
|
||||||
private String str; |
|
||||||
/** |
|
||||||
* 文件大小 |
|
||||||
*/ |
|
||||||
private long fileSize = 0; |
|
||||||
/** |
|
||||||
* 转换后的文件大小 |
|
||||||
*/ |
|
||||||
private String convertFileSize; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务状态{@link IEntity} |
|
||||||
*/ |
|
||||||
@Default("3") |
|
||||||
private int state = STATE_WAIT; |
|
||||||
/** |
|
||||||
* 当前下载进度 |
|
||||||
*/ |
|
||||||
private long currentProgress = 0; |
|
||||||
/** |
|
||||||
* 完成时间 |
|
||||||
*/ |
|
||||||
private long completeTime; |
|
||||||
|
|
||||||
/** |
|
||||||
* 进度百分比 |
|
||||||
*/ |
|
||||||
private int percent; |
|
||||||
|
|
||||||
@Default("false") |
|
||||||
private boolean isComplete = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 上一次停止时间 |
|
||||||
*/ |
|
||||||
private long stopTime = 0; |
|
||||||
|
|
||||||
@Ignore |
|
||||||
private int netCode = 200; |
|
||||||
|
|
||||||
public int getNetCode() { |
|
||||||
return netCode; |
|
||||||
} |
|
||||||
|
|
||||||
public void setNetCode(int netCode) { |
|
||||||
this.netCode = netCode; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取剩余时间,单位:s |
|
||||||
* 如果是m3u8任务,无法获取剩余时间;m2u8任务如果需要获取剩余时间,请设置文件长度{@link #setFileSize(long)} |
|
||||||
*/ |
|
||||||
public int getTimeLeft() { |
|
||||||
return timeLeft; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTimeLeft(int timeLeft) { |
|
||||||
this.timeLeft = timeLeft; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isComplete() { |
|
||||||
return isComplete; |
|
||||||
} |
|
||||||
|
|
||||||
public void setComplete(boolean complete) { |
|
||||||
isComplete = complete; |
|
||||||
} |
|
||||||
|
|
||||||
public String getConvertFileSize() { |
|
||||||
return convertFileSize; |
|
||||||
} |
|
||||||
|
|
||||||
public void setConvertFileSize(String convertFileSize) { |
|
||||||
this.convertFileSize = convertFileSize; |
|
||||||
} |
|
||||||
|
|
||||||
public int getFailNum() { |
|
||||||
return failNum; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFailNum(int failNum) { |
|
||||||
this.failNum = failNum; |
|
||||||
} |
|
||||||
|
|
||||||
public long getSpeed() { |
|
||||||
return speed; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSpeed(long speed) { |
|
||||||
this.speed = speed; |
|
||||||
} |
|
||||||
|
|
||||||
public String getConvertSpeed() { |
|
||||||
return convertSpeed; |
|
||||||
} |
|
||||||
|
|
||||||
public void setConvertSpeed(String convertSpeed) { |
|
||||||
this.convertSpeed = convertSpeed; |
|
||||||
} |
|
||||||
|
|
||||||
public String getStr() { |
|
||||||
return str; |
|
||||||
} |
|
||||||
|
|
||||||
public void setStr(String str) { |
|
||||||
this.str = str; |
|
||||||
} |
|
||||||
|
|
||||||
public long getFileSize() { |
|
||||||
return fileSize; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFileSize(long fileSize) { |
|
||||||
this.fileSize = fileSize; |
|
||||||
} |
|
||||||
|
|
||||||
public int getState() { |
|
||||||
return state; |
|
||||||
} |
|
||||||
|
|
||||||
public void setState(int state) { |
|
||||||
this.state = state; |
|
||||||
} |
|
||||||
|
|
||||||
public long getCurrentProgress() { |
|
||||||
return currentProgress; |
|
||||||
} |
|
||||||
|
|
||||||
public void setCurrentProgress(long currentProgress) { |
|
||||||
this.currentProgress = currentProgress; |
|
||||||
} |
|
||||||
|
|
||||||
public long getCompleteTime() { |
|
||||||
return completeTime; |
|
||||||
} |
|
||||||
|
|
||||||
public void setCompleteTime(long completeTime) { |
|
||||||
this.completeTime = completeTime; |
|
||||||
} |
|
||||||
|
|
||||||
public int getPercent() { |
|
||||||
return percent; |
|
||||||
} |
|
||||||
|
|
||||||
public void setPercent(int percent) { |
|
||||||
this.percent = percent; |
|
||||||
} |
|
||||||
|
|
||||||
public long getStopTime() { |
|
||||||
return stopTime; |
|
||||||
} |
|
||||||
|
|
||||||
public void setStopTime(long stopTime) { |
|
||||||
this.stopTime = stopTime; |
|
||||||
} |
|
||||||
|
|
||||||
public long getId() { |
|
||||||
return getRowID(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 实体唯一标识符 |
|
||||||
* 下载实体:下载url |
|
||||||
* 上传实体:文件路径 |
|
||||||
* 下载任务组:组名 |
|
||||||
* ftp文件夹下载:下载url |
|
||||||
*/ |
|
||||||
public abstract String getKey(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 实体驱动的下载任务类型 |
|
||||||
* |
|
||||||
* @return {@link ITaskWrapper#D_FTP}、{@link ITaskWrapper#D_FTP_DIR}、{@link |
|
||||||
* ITaskWrapper#U_HTTP}... |
|
||||||
*/ |
|
||||||
public abstract int getTaskType(); |
|
||||||
|
|
||||||
public AbsEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
dest.writeLong(this.rowID); |
|
||||||
dest.writeLong(this.speed); |
|
||||||
dest.writeString(this.convertSpeed); |
|
||||||
dest.writeInt(this.failNum); |
|
||||||
dest.writeString(this.str); |
|
||||||
dest.writeLong(this.fileSize); |
|
||||||
dest.writeString(this.convertFileSize); |
|
||||||
dest.writeInt(this.state); |
|
||||||
dest.writeLong(this.currentProgress); |
|
||||||
dest.writeLong(this.completeTime); |
|
||||||
dest.writeInt(this.percent); |
|
||||||
dest.writeByte(this.isComplete ? (byte) 1 : (byte) 0); |
|
||||||
dest.writeLong(this.stopTime); |
|
||||||
} |
|
||||||
|
|
||||||
protected AbsEntity(Parcel in) { |
|
||||||
this.rowID = in.readLong(); |
|
||||||
this.speed = in.readLong(); |
|
||||||
this.convertSpeed = in.readString(); |
|
||||||
this.failNum = in.readInt(); |
|
||||||
this.str = in.readString(); |
|
||||||
this.fileSize = in.readLong(); |
|
||||||
this.convertFileSize = in.readString(); |
|
||||||
this.state = in.readInt(); |
|
||||||
this.currentProgress = in.readLong(); |
|
||||||
this.completeTime = in.readLong(); |
|
||||||
this.percent = in.readInt(); |
|
||||||
this.isComplete = in.readByte() != 0; |
|
||||||
this.stopTime = in.readLong(); |
|
||||||
} |
|
||||||
} |
|
@ -1,103 +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.core.common; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import com.arialyy.aria.orm.annotation.Unique; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/3. |
|
||||||
*/ |
|
||||||
public abstract class AbsGroupEntity extends AbsEntity implements Parcelable { |
|
||||||
/** |
|
||||||
* 组合任务等hash为: 为子任务地址相加的url的Md5 |
|
||||||
* ftpdir为:ftpdir下载地址 |
|
||||||
*/ |
|
||||||
@Unique protected String groupHash; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务组别名 |
|
||||||
*/ |
|
||||||
private String alias; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务组下载文件的文件夹地址 |
|
||||||
*/ |
|
||||||
@Unique private String dirPath; |
|
||||||
|
|
||||||
/** |
|
||||||
* 子任务url地址 |
|
||||||
*/ |
|
||||||
private List<String> urls = new ArrayList<>(); |
|
||||||
|
|
||||||
public String getDirPath() { |
|
||||||
return dirPath; |
|
||||||
} |
|
||||||
|
|
||||||
public void setDirPath(String dirPath) { |
|
||||||
this.dirPath = dirPath; |
|
||||||
} |
|
||||||
|
|
||||||
public List<String> getUrls() { |
|
||||||
return urls; |
|
||||||
} |
|
||||||
|
|
||||||
public void setUrls(List<String> urls) { |
|
||||||
this.urls = urls; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 组合任务等hash为: 为子任务地址相加的url的Md5 |
|
||||||
* ftpdir为:ftpdir下载地址 |
|
||||||
*/ |
|
||||||
public String getGroupHash() { |
|
||||||
return groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
public String getAlias() { |
|
||||||
return alias; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public String getKey() { |
|
||||||
return groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
public void setAlias(String alias) { |
|
||||||
this.alias = alias; |
|
||||||
} |
|
||||||
|
|
||||||
public AbsGroupEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
super.writeToParcel(dest, flags); |
|
||||||
dest.writeString(this.groupHash); |
|
||||||
dest.writeString(this.alias); |
|
||||||
} |
|
||||||
|
|
||||||
protected AbsGroupEntity(Parcel in) { |
|
||||||
super(in); |
|
||||||
this.groupHash = in.readString(); |
|
||||||
this.alias = in.readString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,125 +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.core.common; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.annotation.Default; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/3. |
|
||||||
*/ |
|
||||||
public abstract class AbsNormalEntity extends AbsEntity implements Parcelable { |
|
||||||
|
|
||||||
/** |
|
||||||
* 服务器地址 |
|
||||||
*/ |
|
||||||
private String url; |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件名 |
|
||||||
*/ |
|
||||||
private String fileName; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否是任务组里面的下载实体 |
|
||||||
*/ |
|
||||||
@Default("false") |
|
||||||
private boolean isGroupChild = false; |
|
||||||
|
|
||||||
@Default("false") |
|
||||||
private boolean isRedirect = false; //是否重定向
|
|
||||||
private String redirectUrl; //重定向链接
|
|
||||||
|
|
||||||
/** |
|
||||||
* 任务类型 |
|
||||||
* {@link ITaskWrapper} |
|
||||||
*/ |
|
||||||
private int taskType; |
|
||||||
|
|
||||||
|
|
||||||
public void setTaskType(int taskType) { |
|
||||||
this.taskType = taskType; |
|
||||||
} |
|
||||||
|
|
||||||
public String getUrl() { |
|
||||||
return url; |
|
||||||
} |
|
||||||
|
|
||||||
public void setUrl(String url) { |
|
||||||
this.url = url; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isGroupChild() { |
|
||||||
return isGroupChild; |
|
||||||
} |
|
||||||
|
|
||||||
public void setGroupChild(boolean groupChild) { |
|
||||||
isGroupChild = groupChild; |
|
||||||
} |
|
||||||
|
|
||||||
public String getFileName() { |
|
||||||
return fileName; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFileName(String fileName) { |
|
||||||
this.fileName = fileName; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isRedirect() { |
|
||||||
return isRedirect; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRedirect(boolean redirect) { |
|
||||||
isRedirect = redirect; |
|
||||||
} |
|
||||||
|
|
||||||
public String getRedirectUrl() { |
|
||||||
return redirectUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRedirectUrl(String redirectUrl) { |
|
||||||
this.redirectUrl = redirectUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public abstract String getFilePath(); |
|
||||||
|
|
||||||
public AbsNormalEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
super.writeToParcel(dest, flags); |
|
||||||
dest.writeString(this.url); |
|
||||||
dest.writeString(this.fileName); |
|
||||||
dest.writeByte(this.isGroupChild ? (byte) 1 : (byte) 0); |
|
||||||
dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0); |
|
||||||
dest.writeString(this.redirectUrl); |
|
||||||
} |
|
||||||
|
|
||||||
protected AbsNormalEntity(Parcel in) { |
|
||||||
super(in); |
|
||||||
this.url = in.readString(); |
|
||||||
this.fileName = in.readString(); |
|
||||||
this.isGroupChild = in.readByte() != 0; |
|
||||||
this.isRedirect = in.readByte() != 0; |
|
||||||
this.redirectUrl = in.readString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,42 +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.core.common; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2018/3/3. |
|
||||||
* 获取文件信息完成后 回调给下载线程的信息 |
|
||||||
*/ |
|
||||||
public class CompleteInfo { |
|
||||||
/** |
|
||||||
* 自定义的状态码 |
|
||||||
*/ |
|
||||||
public int code; |
|
||||||
|
|
||||||
public ITaskWrapper wrapper; |
|
||||||
|
|
||||||
public Object obj; |
|
||||||
|
|
||||||
public CompleteInfo() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public CompleteInfo(int code, ITaskWrapper wrapper) { |
|
||||||
this.code = code; |
|
||||||
this.wrapper = wrapper; |
|
||||||
} |
|
||||||
} |
|
@ -1,33 +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.core.common; |
|
||||||
|
|
||||||
public enum ErrorCode { |
|
||||||
ERROR_CODE_NORMAL(0, "正常"), ERROR_CODE_TASK_ID_NULL(1, "任务id为空的错误码"), |
|
||||||
ERROR_CODE_URL_NULL(2, "url 为空"), ERROR_CODE_URL_INVALID(3, "url 无效"), |
|
||||||
ERROR_CODE_PAGE_NUM(4, "page和num不能小于1"), ERROR_CODE_GROUP_URL_NULL(5, "组合任务url列表为空"), |
|
||||||
ERROR_CODE_UPLOAD_FILE_NULL(7, "上传文件不存在"), |
|
||||||
ERROR_CODE_MEMBER_WARNING(8, "为了防止内存泄漏,请使用静态的成员类(public static class xxx)或文件类(A.java)"), |
|
||||||
ERROR_CODE_TASK_NOT_EXIST(9, "任务信息不存在"); |
|
||||||
|
|
||||||
public int code; |
|
||||||
public String msg; |
|
||||||
|
|
||||||
ErrorCode(int code, String msg) { |
|
||||||
this.code = code; |
|
||||||
this.msg = msg; |
|
||||||
} |
|
||||||
} |
|
@ -1,225 +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.core.common; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.TaskRecord; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.core.download.DownloadEntity; |
|
||||||
import com.arialyy.aria.core.loader.ILoaderVisitor; |
|
||||||
import com.arialyy.aria.core.loader.IRecordHandler; |
|
||||||
import com.arialyy.aria.core.upload.UploadEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.core.wrapper.RecordWrapper; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
import com.arialyy.aria.util.DbDataHelper; |
|
||||||
import com.arialyy.aria.util.FileUtil; |
|
||||||
import java.io.File; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Properties; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理任务记录,分配线程区间 |
|
||||||
*/ |
|
||||||
public abstract class RecordHandler implements IRecordHandler { |
|
||||||
protected final String TAG = CommonUtil.getClassName(this); |
|
||||||
|
|
||||||
@Deprecated private File mConfigFile; |
|
||||||
private TaskRecord mTaskRecord; |
|
||||||
private AbsTaskWrapper mTaskWrapper; |
|
||||||
private AbsNormalEntity mEntity; |
|
||||||
protected String mFilePath; |
|
||||||
protected long mFileSize; |
|
||||||
|
|
||||||
public RecordHandler(AbsTaskWrapper wrapper) { |
|
||||||
mTaskWrapper = wrapper; |
|
||||||
mEntity = (AbsNormalEntity) mTaskWrapper.getEntity(); |
|
||||||
} |
|
||||||
|
|
||||||
public AbsTaskWrapper getWrapper() { |
|
||||||
return mTaskWrapper; |
|
||||||
} |
|
||||||
|
|
||||||
public AbsNormalEntity getEntity() { |
|
||||||
return mEntity; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onPre() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务记录,如果任务记录存在,检查任务记录 |
|
||||||
* 检查记录 对于分块任务: 子分块不存在或被删除,子线程将重新下载 |
|
||||||
* 对于普通任务: 预下载文件不存在,则任务任务呗删除 |
|
||||||
* 如果任务记录不存在或线程记录不存在,初始化记录 |
|
||||||
* |
|
||||||
* @return 任务记录 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public TaskRecord getRecord(long fileSize) { |
|
||||||
mFileSize = fileSize; |
|
||||||
mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); |
|
||||||
if (mConfigFile.exists()) { |
|
||||||
convertDb(); |
|
||||||
} else { |
|
||||||
onPre(); |
|
||||||
mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType()); |
|
||||||
if (mTaskRecord == null) { |
|
||||||
initRecord(true); |
|
||||||
}else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.size() == 0){ |
|
||||||
if (mTaskRecord.threadRecords == null){ |
|
||||||
mTaskRecord.threadRecords = new ArrayList<>(); |
|
||||||
} |
|
||||||
initRecord(false); |
|
||||||
} |
|
||||||
handlerTaskRecord(mTaskRecord); |
|
||||||
} |
|
||||||
saveRecord(); |
|
||||||
return mTaskRecord; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* convertDb 是兼容性代码 从3.4.1开始,线程配置信息将存储在数据库中。 将配置文件的内容复制到数据库中,并将配置文件删除 |
|
||||||
*/ |
|
||||||
private void convertDb() { |
|
||||||
List<RecordWrapper> records = |
|
||||||
DbEntity.findRelationData(RecordWrapper.class, "TaskRecord.filePath=?", |
|
||||||
getFilePath()); |
|
||||||
if (records == null || records.size() == 0) { |
|
||||||
Properties pro = FileUtil.loadConfig(mConfigFile); |
|
||||||
if (pro.isEmpty()) { |
|
||||||
ALog.d(TAG, "老版本的线程记录为空,任务为新任务"); |
|
||||||
initRecord(true); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Set<Object> keys = pro.keySet(); |
|
||||||
// 老版本记录是5s存一次,但是5s中内,如果线程执行完成,record记录是没有的,只有state记录...
|
|
||||||
// 第一步应该是record 和 state去重取正确的线程数
|
|
||||||
Set<Integer> set = new HashSet<>(); |
|
||||||
for (Object key : keys) { |
|
||||||
String str = String.valueOf(key); |
|
||||||
int i = Integer.parseInt(str.substring(str.length() - 1)); |
|
||||||
set.add(i); |
|
||||||
} |
|
||||||
int threadNum = set.size(); |
|
||||||
if (threadNum == 0) { |
|
||||||
ALog.d(TAG, "线程数为空,任务为新任务"); |
|
||||||
initRecord(true); |
|
||||||
return; |
|
||||||
} |
|
||||||
mTaskWrapper.setNewTask(false); |
|
||||||
mTaskRecord = createTaskRecord(threadNum); |
|
||||||
mTaskRecord.isBlock = false; |
|
||||||
File tempFile = new File(getFilePath()); |
|
||||||
for (int i = 0; i < threadNum; i++) { |
|
||||||
ThreadRecord tRecord = new ThreadRecord(); |
|
||||||
tRecord.taskKey = mTaskRecord.filePath; |
|
||||||
Object state = pro.getProperty(tempFile.getName() + STATE + i); |
|
||||||
Object record = pro.getProperty(tempFile.getName() + RECORD + i); |
|
||||||
if (state != null && Integer.parseInt(String.valueOf(state)) == 1) { |
|
||||||
tRecord.isComplete = true; |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (record != null) { |
|
||||||
long temp = Long.parseLong(String.valueOf(record)); |
|
||||||
tRecord.startLocation = temp > 0 ? temp : 0; |
|
||||||
} else { |
|
||||||
tRecord.startLocation = 0; |
|
||||||
} |
|
||||||
mTaskRecord.threadRecords.add(tRecord); |
|
||||||
} |
|
||||||
FileUtil.deleteFile(mConfigFile); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 初始化任务记录,分配线程区间,如果任务记录不存在,则创建新的任务记录 |
|
||||||
* |
|
||||||
* @param newRecord {@code true} 需要创建新{@link TaskRecord} |
|
||||||
*/ |
|
||||||
private void initRecord(boolean newRecord) { |
|
||||||
if (newRecord) { |
|
||||||
mTaskRecord = createTaskRecord(initTaskThreadNum()); |
|
||||||
} |
|
||||||
mTaskWrapper.setNewTask(true); |
|
||||||
int requestType = mTaskWrapper.getRequestType(); |
|
||||||
if (requestType == ITaskWrapper.M3U8_LIVE) { |
|
||||||
return; |
|
||||||
} |
|
||||||
long blockSize = getFileSize() / mTaskRecord.threadNum; |
|
||||||
// 处理线程区间记录
|
|
||||||
for (int i = 0; i < mTaskRecord.threadNum; i++) { |
|
||||||
long startL = i * blockSize, endL = (i + 1) * blockSize; |
|
||||||
ThreadRecord tr = createThreadRecord(mTaskRecord, i, startL, endL); |
|
||||||
mTaskRecord.threadRecords.add(tr); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存任务记录 |
|
||||||
*/ |
|
||||||
private void saveRecord() { |
|
||||||
mTaskRecord.threadNum = mTaskRecord.threadRecords.size(); |
|
||||||
mTaskRecord.save(); |
|
||||||
if (mTaskRecord.threadRecords != null && !mTaskRecord.threadRecords.isEmpty()) { |
|
||||||
DbEntity.saveAll(mTaskRecord.threadRecords); |
|
||||||
} |
|
||||||
ALog.d(TAG, String.format("保存记录,线程记录数:%s", mTaskRecord.threadRecords.size())); |
|
||||||
} |
|
||||||
|
|
||||||
protected long getFileSize() { |
|
||||||
return mFileSize; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务路径 |
|
||||||
* |
|
||||||
* @return 任务文件路径 |
|
||||||
*/ |
|
||||||
private String getFilePath() { |
|
||||||
if (mEntity instanceof DownloadEntity) { |
|
||||||
return ((DownloadEntity) mTaskWrapper.getEntity()).getFilePath(); |
|
||||||
} else { |
|
||||||
return ((UploadEntity) mTaskWrapper.getEntity()).getFilePath(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void accept(ILoaderVisitor visitor) { |
|
||||||
visitor.addComponent(this); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public boolean checkTaskCompleted() { |
|
||||||
if (mTaskRecord == null |
|
||||||
|| mTaskRecord.threadRecords == null |
|
||||||
|| mTaskRecord.threadRecords.isEmpty()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
int completeNum = 0; |
|
||||||
for (ThreadRecord tr : mTaskRecord.threadRecords) { |
|
||||||
if (tr.isComplete) { |
|
||||||
completeNum++; |
|
||||||
} |
|
||||||
} |
|
||||||
return completeNum != 0 && completeNum == mTaskRecord.threadNum; |
|
||||||
} |
|
||||||
} |
|
@ -1,207 +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.core.common; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.TaskRecord; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.core.loader.IRecordHandler; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import com.arialyy.aria.util.BufferedRandomAccessFile; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
import com.arialyy.aria.util.FileUtil; |
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务记录帮助类,用于处理统一的逻辑 |
|
||||||
* |
|
||||||
* @author lyy |
|
||||||
* Date: 2019-09-19 |
|
||||||
*/ |
|
||||||
public class RecordHelper { |
|
||||||
private String TAG = CommonUtil.getClassName(getClass()); |
|
||||||
|
|
||||||
private AbsTaskWrapper mWrapper; |
|
||||||
protected TaskRecord mTaskRecord; |
|
||||||
|
|
||||||
public RecordHelper(AbsTaskWrapper wrapper, TaskRecord record) { |
|
||||||
mWrapper = wrapper; |
|
||||||
mTaskRecord = record; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理非分块的,多线程任务 |
|
||||||
*/ |
|
||||||
public void handleMultiRecord() { |
|
||||||
// 默认线程分块长度
|
|
||||||
long blockSize = mWrapper.getEntity().getFileSize() / mTaskRecord.threadRecords.size(); |
|
||||||
File temp = new File(mTaskRecord.filePath); |
|
||||||
boolean fileExists = false; |
|
||||||
if (!temp.exists()) { |
|
||||||
createPlaceHolderFile(temp); |
|
||||||
} else { |
|
||||||
if (temp.length() != mWrapper.getEntity().getFileSize()) { |
|
||||||
FileUtil.deleteFile(temp); |
|
||||||
createPlaceHolderFile(temp); |
|
||||||
} |
|
||||||
fileExists = true; |
|
||||||
} |
|
||||||
// 处理文件被删除的情况
|
|
||||||
if (!fileExists) { |
|
||||||
ALog.w(TAG, String.format("文件【%s】被删除,重新分配线程区间", mTaskRecord.filePath)); |
|
||||||
for (int i = 0; i < mTaskRecord.threadNum; i++) { |
|
||||||
long startL = i * blockSize, endL = (i + 1) * blockSize; |
|
||||||
ThreadRecord tr = mTaskRecord.threadRecords.get(i); |
|
||||||
tr.startLocation = startL; |
|
||||||
tr.isComplete = false; |
|
||||||
|
|
||||||
//最后一个线程的结束位置即为文件的总长度
|
|
||||||
if (tr.threadId == (mTaskRecord.threadNum - 1)) { |
|
||||||
endL = mWrapper.getEntity().getFileSize(); |
|
||||||
} |
|
||||||
tr.endLocation = endL; |
|
||||||
} |
|
||||||
} |
|
||||||
//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)的长度 |
|
||||||
*/ |
|
||||||
public void handleBlockRecord() { |
|
||||||
// 默认线程分块长度
|
|
||||||
long normalRectLen = mWrapper.getEntity().getFileSize() / mTaskRecord.threadRecords.size(); |
|
||||||
for (ThreadRecord tr : mTaskRecord.threadRecords) { |
|
||||||
long threadRect = tr.blockLen; |
|
||||||
|
|
||||||
File temp = |
|
||||||
new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, tr.threadId)); |
|
||||||
if (!temp.exists()) { |
|
||||||
ALog.i(TAG, String.format("分块文件【%s】不存在,该分块将重新开始", temp.getPath())); |
|
||||||
tr.isComplete = false; |
|
||||||
tr.startLocation = tr.threadId * normalRectLen; |
|
||||||
} else { |
|
||||||
if (!tr.isComplete) { |
|
||||||
ALog.i(TAG, String.format( |
|
||||||
"startLocation = %s; endLocation = %s; block = %s; tempLen = %s; threadId = %s", |
|
||||||
tr.startLocation, tr.endLocation, threadRect, temp.length(), tr.threadId)); |
|
||||||
|
|
||||||
long blockFileLen = temp.length(); // 磁盘中的分块文件长度
|
|
||||||
/* |
|
||||||
* 检查磁盘中的分块文件 |
|
||||||
*/ |
|
||||||
if (blockFileLen > threadRect) { |
|
||||||
ALog.i(TAG, String.format("分块【%s】错误,分块长度【%s】 > 线程区间长度【%s】,将重新开始该分块", |
|
||||||
tr.threadId, blockFileLen, threadRect)); |
|
||||||
temp.delete(); |
|
||||||
tr.startLocation = tr.threadId * threadRect; |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
//正常情况下,该线程的startLocation的位置
|
|
||||||
long realLocation = tr.threadId * normalRectLen + blockFileLen; |
|
||||||
/* |
|
||||||
* 检查记录文件 |
|
||||||
*/ |
|
||||||
if (blockFileLen == threadRect && blockFileLen != 0) { |
|
||||||
ALog.i(TAG, String.format("分块【%s】已完成,更新记录", temp.getPath())); |
|
||||||
tr.startLocation = blockFileLen; |
|
||||||
tr.isComplete = true; |
|
||||||
} else if (tr.startLocation != realLocation) { // 处理记录小于分块文件长度的情况
|
|
||||||
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation)); |
|
||||||
tr.startLocation = realLocation; |
|
||||||
} else { |
|
||||||
ALog.i(TAG, String.format("修正分块【%s】的进度记录为:%s", temp.getPath(), realLocation)); |
|
||||||
tr.startLocation = realLocation; |
|
||||||
tr.isComplete = false; |
|
||||||
} |
|
||||||
} else { |
|
||||||
ALog.i(TAG, String.format("分块【%s】已完成", temp.getPath())); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
//mWrapper.setNewTask(false);
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理单线程的任务的记录 |
|
||||||
*/ |
|
||||||
public void handleSingleThreadRecord() { |
|
||||||
// mTaskRecord.isBlock是为了兼容以前的文件格式
|
|
||||||
File file = new File( |
|
||||||
mTaskRecord.isBlock ? String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0) |
|
||||||
: mTaskRecord.filePath); |
|
||||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0); |
|
||||||
if (!file.exists()) { |
|
||||||
// 目标文件
|
|
||||||
File targetFile = new File(mTaskRecord.filePath); |
|
||||||
// 处理组合任务其中一个子任务完成的情况
|
|
||||||
if (tr.isComplete |
|
||||||
&& targetFile.exists() |
|
||||||
&& targetFile.length() != 0 |
|
||||||
&& targetFile.length() == mWrapper.getEntity().getFileSize()) { |
|
||||||
tr.isComplete = true; |
|
||||||
} else { |
|
||||||
ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath())); |
|
||||||
tr.startLocation = 0; |
|
||||||
tr.isComplete = false; |
|
||||||
tr.endLocation = mWrapper.getEntity().getFileSize(); |
|
||||||
} |
|
||||||
} else if (file.length() > mWrapper.getEntity().getFileSize()) { |
|
||||||
ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath())); |
|
||||||
FileUtil.deleteFile(file); |
|
||||||
tr.startLocation = 0; |
|
||||||
tr.isComplete = false; |
|
||||||
tr.endLocation = mWrapper.getEntity().getFileSize(); |
|
||||||
} else if (file.length() != 0 && file.length() == mWrapper.getEntity().getFileSize()) { |
|
||||||
ALog.d(TAG, "文件长度一致,线程完成"); |
|
||||||
tr.isComplete = true; |
|
||||||
} else { |
|
||||||
if (file.length() != tr.startLocation) { |
|
||||||
ALog.i(TAG, String.format("修正【%s】的进度记录为:%s", file.getPath(), file.length())); |
|
||||||
tr.startLocation = file.length(); |
|
||||||
tr.isComplete = false; |
|
||||||
} |
|
||||||
} |
|
||||||
//mWrapper.setNewTask(false);
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理不支持断点的记录 |
|
||||||
*/ |
|
||||||
public void handleNoSupportBPRecord() { |
|
||||||
ThreadRecord tr = mTaskRecord.threadRecords.get(0); |
|
||||||
tr.startLocation = 0; |
|
||||||
tr.endLocation = mWrapper.getEntity().getFileSize(); |
|
||||||
tr.taskKey = mTaskRecord.filePath; |
|
||||||
tr.blockLen = tr.endLocation; |
|
||||||
tr.isComplete = false; |
|
||||||
} |
|
||||||
} |
|
@ -1,113 +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.core.common; |
|
||||||
|
|
||||||
import android.os.Handler; |
|
||||||
import com.arialyy.aria.core.AriaConfig; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import java.io.File; |
|
||||||
|
|
||||||
/** |
|
||||||
* 子线程下载信息类 |
|
||||||
*/ |
|
||||||
public class SubThreadConfig { |
|
||||||
public static final int TYPE_HTTP = 1; |
|
||||||
public static final int TYPE_FTP = 2; |
|
||||||
public static final int TYPE_M3U8_PEER = 3; |
|
||||||
public static final int TYPE_HTTP_DG_SUB = 4; |
|
||||||
public static final int TYPE_FTP_DG_SUB = 5; |
|
||||||
|
|
||||||
public AbsTaskWrapper taskWrapper; |
|
||||||
public boolean isBlock = false; |
|
||||||
// 启动的线程
|
|
||||||
public int startThreadNum; |
|
||||||
// 真正的下载地址,如果是30x,则是30x后的地址
|
|
||||||
public String url; |
|
||||||
public File tempFile; |
|
||||||
// 线程记录
|
|
||||||
public ThreadRecord record; |
|
||||||
// 状态处理器
|
|
||||||
public Handler stateHandler; |
|
||||||
// m3u8切片索引
|
|
||||||
public int peerIndex; |
|
||||||
// 线程任务类型
|
|
||||||
public int threadType = TYPE_HTTP; |
|
||||||
// 进度更新间隔,单位:毫秒
|
|
||||||
public long updateInterval = 1000; |
|
||||||
// 扩展数据
|
|
||||||
public Object obj; |
|
||||||
// 忽略失败
|
|
||||||
public boolean ignoreFailure = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 转换线程任务类型 |
|
||||||
* |
|
||||||
* @param requestType {@link AbsTaskWrapper#getRequestType()} |
|
||||||
* @return {@link #threadType} |
|
||||||
*/ |
|
||||||
public static int getThreadType(int requestType) { |
|
||||||
int threadType = SubThreadConfig.TYPE_HTTP; |
|
||||||
switch (requestType) { |
|
||||||
case ITaskWrapper.D_HTTP: |
|
||||||
case ITaskWrapper.U_HTTP: |
|
||||||
threadType = SubThreadConfig.TYPE_HTTP; |
|
||||||
break; |
|
||||||
case ITaskWrapper.D_FTP: |
|
||||||
case ITaskWrapper.U_FTP: |
|
||||||
threadType = SubThreadConfig.TYPE_FTP; |
|
||||||
break; |
|
||||||
case ITaskWrapper.D_FTP_DIR: |
|
||||||
threadType = SubThreadConfig.TYPE_FTP_DG_SUB; |
|
||||||
break; |
|
||||||
case ITaskWrapper.DG_HTTP: |
|
||||||
threadType = SubThreadConfig.TYPE_HTTP_DG_SUB; |
|
||||||
break; |
|
||||||
case ITaskWrapper.M3U8_LIVE: |
|
||||||
case ITaskWrapper.M3U8_VOD: |
|
||||||
threadType = SubThreadConfig.TYPE_M3U8_PEER; |
|
||||||
break; |
|
||||||
} |
|
||||||
return threadType; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据配置肚脐更新间隔 |
|
||||||
* |
|
||||||
* @param requestType {@link AbsTaskWrapper#getRequestType()} |
|
||||||
* @return {@link #updateInterval} |
|
||||||
*/ |
|
||||||
public static long getUpdateInterval(int requestType) { |
|
||||||
long updateInterval = 1000; |
|
||||||
switch (requestType) { |
|
||||||
case ITaskWrapper.D_HTTP: |
|
||||||
case ITaskWrapper.D_FTP: |
|
||||||
case ITaskWrapper.M3U8_LIVE: |
|
||||||
case ITaskWrapper.M3U8_VOD: |
|
||||||
updateInterval = AriaConfig.getInstance().getDConfig().getUpdateInterval(); |
|
||||||
break; |
|
||||||
case ITaskWrapper.D_FTP_DIR: |
|
||||||
case ITaskWrapper.DG_HTTP: |
|
||||||
updateInterval = AriaConfig.getInstance().getDGConfig().getUpdateInterval(); |
|
||||||
break; |
|
||||||
case ITaskWrapper.U_HTTP: |
|
||||||
case ITaskWrapper.U_FTP: |
|
||||||
updateInterval = AriaConfig.getInstance().getUConfig().getUpdateInterval(); |
|
||||||
} |
|
||||||
return updateInterval; |
|
||||||
} |
|
||||||
} |
|
@ -1,48 +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.core.download; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.common.AbsEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* 组合任务实体包裹器,用于加载和任务相关的参数,如:组合任务实体{@link DownloadGroupEntity} |
|
||||||
*/ |
|
||||||
public abstract class AbsGroupTaskWrapper<ENTITY extends AbsEntity, SUB extends AbsTaskWrapper> |
|
||||||
extends AbsTaskWrapper<ENTITY> { |
|
||||||
|
|
||||||
public AbsGroupTaskWrapper(ENTITY entity) { |
|
||||||
super(entity); |
|
||||||
} |
|
||||||
|
|
||||||
public abstract List<SUB> getSubTaskWrapper(); |
|
||||||
|
|
||||||
public abstract void setSubTaskWrapper(List<SUB> subTaskWrapper); |
|
||||||
|
|
||||||
/** |
|
||||||
* {@code true} 忽略任务冲突,不考虑组任务hash冲突的情况 |
|
||||||
*/ |
|
||||||
private boolean ignoreTaskOccupy = false; |
|
||||||
|
|
||||||
public boolean isIgnoreTaskOccupy() { |
|
||||||
return ignoreTaskOccupy; |
|
||||||
} |
|
||||||
|
|
||||||
public void setIgnoreTaskOccupy(boolean ignoreTaskOccupy) { |
|
||||||
this.ignoreTaskOccupy = ignoreTaskOccupy; |
|
||||||
} |
|
||||||
} |
|
@ -1,44 +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.core.download; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DownloadEntity; |
|
||||||
import com.arialyy.aria.core.download.DownloadGroupEntity; |
|
||||||
import com.arialyy.aria.orm.AbsDbWrapper; |
|
||||||
import com.arialyy.aria.orm.annotation.Many; |
|
||||||
import com.arialyy.aria.orm.annotation.One; |
|
||||||
import com.arialyy.aria.orm.annotation.Wrapper; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/30. |
|
||||||
* 任务组实体和子任务实体的关系 |
|
||||||
*/ |
|
||||||
@Wrapper |
|
||||||
public class DGEntityWrapper extends AbsDbWrapper { |
|
||||||
|
|
||||||
@One |
|
||||||
public DownloadGroupEntity groupEntity; |
|
||||||
|
|
||||||
@Many(parentColumn = "groupHash", entityColumn = "groupHash") |
|
||||||
public List<DownloadEntity> subEntity; |
|
||||||
|
|
||||||
@Override protected void handleConvert() { |
|
||||||
if (subEntity != null && !subEntity.isEmpty()) { |
|
||||||
groupEntity.setSubEntities(subEntity); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,89 +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.core.download; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.config.Configuration; |
|
||||||
import com.arialyy.aria.core.config.DGroupConfig; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/7/1. 任务组的任务实体修饰器 |
|
||||||
*/ |
|
||||||
public class DGTaskWrapper extends AbsGroupTaskWrapper<DownloadGroupEntity, DTaskWrapper> { |
|
||||||
|
|
||||||
private List<DTaskWrapper> subWrappers; |
|
||||||
|
|
||||||
private boolean unknownSize = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存临时设置的文件夹路径 |
|
||||||
*/ |
|
||||||
private String dirPathTemp; |
|
||||||
|
|
||||||
/** |
|
||||||
* 子任务文件名 |
|
||||||
*/ |
|
||||||
private List<String> subNameTemp = new ArrayList<>(); |
|
||||||
|
|
||||||
public DGTaskWrapper(DownloadGroupEntity entity) { |
|
||||||
super(entity); |
|
||||||
} |
|
||||||
|
|
||||||
public List<String> getSubNameTemp() { |
|
||||||
return subNameTemp; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSubNameTemp(List<String> subNameTemp) { |
|
||||||
this.subNameTemp = subNameTemp; |
|
||||||
} |
|
||||||
|
|
||||||
public String getDirPathTemp() { |
|
||||||
return dirPathTemp; |
|
||||||
} |
|
||||||
|
|
||||||
public void setDirPathTemp(String mDirPathTemp) { |
|
||||||
this.dirPathTemp = mDirPathTemp; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setSubTaskWrapper(List<DTaskWrapper> subTaskEntities) { |
|
||||||
this.subWrappers = subTaskEntities; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isUnknownSize() { |
|
||||||
return unknownSize; |
|
||||||
} |
|
||||||
|
|
||||||
public void setUnknownSize(boolean unknownSize) { |
|
||||||
this.unknownSize = unknownSize; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public String getKey() { |
|
||||||
return getEntity().getKey(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public DGroupConfig getConfig() { |
|
||||||
return Configuration.getInstance().dGroupCfg; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public List<DTaskWrapper> getSubTaskWrapper() { |
|
||||||
if (subWrappers == null) { |
|
||||||
subWrappers = new ArrayList<>(); |
|
||||||
} |
|
||||||
return subWrappers; |
|
||||||
} |
|
||||||
} |
|
@ -1,122 +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.core.download; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.TaskOptionParams; |
|
||||||
import com.arialyy.aria.core.config.Configuration; |
|
||||||
import com.arialyy.aria.core.config.DownloadConfig; |
|
||||||
import com.arialyy.aria.core.inf.ITaskOption; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
import com.arialyy.aria.util.ComponentUtil; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/1/23. 下载任务实体和下载实体为一对一关系,下载实体删除,任务实体自动删除 |
|
||||||
*/ |
|
||||||
public class DTaskWrapper extends AbsTaskWrapper<DownloadEntity> { |
|
||||||
|
|
||||||
/** |
|
||||||
* 所属的任务组组名,如果不属于任务组,则为null |
|
||||||
*/ |
|
||||||
private String groupHash; |
|
||||||
|
|
||||||
/** |
|
||||||
* 该任务是否属于任务组 |
|
||||||
*/ |
|
||||||
private boolean isGroupTask = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* M3u8任务配置信息 |
|
||||||
*/ |
|
||||||
private ITaskOption m3u8Option; |
|
||||||
|
|
||||||
private TaskOptionParams m3u8Params = new TaskOptionParams(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件下载url的临时保存变量 |
|
||||||
*/ |
|
||||||
private String mTempUrl; |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件保存路径的临时变量 |
|
||||||
*/ |
|
||||||
private String mTempFilePath; |
|
||||||
|
|
||||||
public DTaskWrapper(DownloadEntity entity) { |
|
||||||
super(entity); |
|
||||||
} |
|
||||||
|
|
||||||
public ITaskOption getM3u8Option() { |
|
||||||
return m3u8Option; |
|
||||||
} |
|
||||||
|
|
||||||
public void generateM3u8Option(Class<? extends ITaskOption> clazz) { |
|
||||||
m3u8Option = ComponentUtil.getInstance().buildTaskOption(clazz, m3u8Params); |
|
||||||
} |
|
||||||
|
|
||||||
public TaskOptionParams getM3U8Params() { |
|
||||||
if (m3u8Params == null) { |
|
||||||
m3u8Params = new TaskOptionParams(); |
|
||||||
} |
|
||||||
return m3u8Params; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Task实体对应的key,下载url |
|
||||||
*/ |
|
||||||
@Override public String getKey() { |
|
||||||
return getEntity().getKey(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public DownloadConfig getConfig() { |
|
||||||
if (isGroupTask) { |
|
||||||
return Configuration.getInstance().dGroupCfg.getSubConfig(); |
|
||||||
} else { |
|
||||||
return Configuration.getInstance().downloadCfg; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public String getGroupHash() { |
|
||||||
return groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isGroupTask() { |
|
||||||
return isGroupTask; |
|
||||||
} |
|
||||||
|
|
||||||
public void setGroupHash(String groupHash) { |
|
||||||
this.groupHash = groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
public void setGroupTask(boolean groupTask) { |
|
||||||
isGroupTask = groupTask; |
|
||||||
} |
|
||||||
|
|
||||||
public String getTempUrl() { |
|
||||||
return mTempUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTempUrl(String mTempUrl) { |
|
||||||
this.mTempUrl = mTempUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public String getTempFilePath() { |
|
||||||
return mTempFilePath; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTempFilePath(String mTempFilePath) { |
|
||||||
this.mTempFilePath = mTempFilePath; |
|
||||||
} |
|
||||||
} |
|
@ -1,214 +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.core.download; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import android.text.TextUtils; |
|
||||||
import com.arialyy.aria.core.common.AbsNormalEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
import com.arialyy.aria.orm.annotation.Ignore; |
|
||||||
import com.arialyy.aria.orm.annotation.Unique; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/12/25. |
|
||||||
* 下载实体 |
|
||||||
*/ |
|
||||||
public class DownloadEntity extends AbsNormalEntity implements Parcelable, Cloneable { |
|
||||||
@Unique private String downloadPath; //保存路径
|
|
||||||
|
|
||||||
/** |
|
||||||
* 所属任务组 |
|
||||||
*/ |
|
||||||
private String groupHash; |
|
||||||
|
|
||||||
/** |
|
||||||
* 从服务器的返回信息中获取的文件md5信息,如果服务器没有返回,则不会设置该信息 |
|
||||||
* 如果你已经设置了该任务的MD5信息,Aria也不会从服务器返回的信息中获取该信息 |
|
||||||
*/ |
|
||||||
private String md5Code; |
|
||||||
|
|
||||||
/** |
|
||||||
* 从服务器的返回信息中获取的文件描述信息 |
|
||||||
*/ |
|
||||||
private String disposition; |
|
||||||
|
|
||||||
/** |
|
||||||
* 从disposition获取到的文件名,如果可以获取到,则会赋值到这个字段 |
|
||||||
*/ |
|
||||||
private String serverFileName; |
|
||||||
|
|
||||||
@Ignore |
|
||||||
private M3U8Entity m3U8Entity; |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取m3u8数据信息 |
|
||||||
* |
|
||||||
* @return 如果m3u8信息为空,则返回null |
|
||||||
*/ |
|
||||||
public M3U8Entity getM3U8Entity() { |
|
||||||
if (TextUtils.isEmpty(downloadPath)) { |
|
||||||
ALog.e("DownloadEntity", "文件保存路径为空,获取m3u8实体之前需要设置文件保存路径"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
if (m3U8Entity == null) { |
|
||||||
m3U8Entity = DbEntity.findFirst(M3U8Entity.class, "filePath=?", downloadPath); |
|
||||||
} |
|
||||||
return m3U8Entity; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置进来的地址,如果需要获取真实的下载地址,请使用{@link #getRealUrl()} |
|
||||||
*/ |
|
||||||
@Override public String getKey() { |
|
||||||
return getUrl(); |
|
||||||
} |
|
||||||
|
|
||||||
public String getRealUrl(){ |
|
||||||
return isRedirect() ? getRedirectUrl() : getUrl(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int getTaskType() { |
|
||||||
int type; |
|
||||||
if (getUrl() == null) { |
|
||||||
type = ITaskWrapper.ERROR; |
|
||||||
} else if (getUrl().startsWith("http")) { |
|
||||||
M3U8Entity temp = getM3U8Entity(); |
|
||||||
if (temp == null) { |
|
||||||
type = ITaskWrapper.D_HTTP; |
|
||||||
} else { |
|
||||||
type = temp.isLive() ? ITaskWrapper.M3U8_LIVE : ITaskWrapper.M3U8_VOD; |
|
||||||
} |
|
||||||
} else if (getUrl().startsWith("ftp")) { |
|
||||||
type = ITaskWrapper.D_FTP; |
|
||||||
} else if (getUrl().startsWith("sftp")) { |
|
||||||
type = ITaskWrapper.D_SFTP; |
|
||||||
} else { |
|
||||||
type = ITaskWrapper.ERROR; |
|
||||||
} |
|
||||||
return type; |
|
||||||
} |
|
||||||
|
|
||||||
public DownloadEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
public String getMd5Code() { |
|
||||||
return md5Code; |
|
||||||
} |
|
||||||
|
|
||||||
public void setMd5Code(String md5Code) { |
|
||||||
this.md5Code = md5Code; |
|
||||||
} |
|
||||||
|
|
||||||
public String getDisposition() { |
|
||||||
return TextUtils.isEmpty(disposition) ? "" : CommonUtil.decryptBASE64(disposition); |
|
||||||
} |
|
||||||
|
|
||||||
public void setDisposition(String disposition) { |
|
||||||
this.disposition = disposition; |
|
||||||
} |
|
||||||
|
|
||||||
public String getServerFileName() { |
|
||||||
return serverFileName; |
|
||||||
} |
|
||||||
|
|
||||||
public void setServerFileName(String serverFileName) { |
|
||||||
this.serverFileName = serverFileName; |
|
||||||
} |
|
||||||
|
|
||||||
public String getGroupHash() { |
|
||||||
return groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
public void setGroupHash(String groupHash) { |
|
||||||
this.groupHash = groupHash; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getFilePath() { |
|
||||||
return downloadPath; |
|
||||||
} |
|
||||||
|
|
||||||
public DownloadEntity setFilePath(String filePath) { |
|
||||||
this.downloadPath = filePath; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public DownloadEntity clone() throws CloneNotSupportedException { |
|
||||||
return (DownloadEntity) super.clone(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public String toString() { |
|
||||||
return "DownloadEntity{" |
|
||||||
+ "downloadPath='" |
|
||||||
+ downloadPath |
|
||||||
+ '\'' |
|
||||||
+ ", groupHash='" |
|
||||||
+ groupHash |
|
||||||
+ '\'' |
|
||||||
+ ", fileName='" |
|
||||||
+ getFileName() |
|
||||||
+ '\'' |
|
||||||
+ ", md5Code='" |
|
||||||
+ md5Code |
|
||||||
+ '\'' |
|
||||||
+ ", disposition='" |
|
||||||
+ disposition |
|
||||||
+ '\'' |
|
||||||
+ ", serverFileName='" |
|
||||||
+ serverFileName |
|
||||||
+ '\'' |
|
||||||
+ '}'; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
super.writeToParcel(dest, flags); |
|
||||||
dest.writeString(this.downloadPath); |
|
||||||
dest.writeString(this.groupHash); |
|
||||||
dest.writeString(this.md5Code); |
|
||||||
dest.writeString(this.disposition); |
|
||||||
dest.writeString(this.serverFileName); |
|
||||||
dest.writeParcelable(this.m3U8Entity, flags); |
|
||||||
} |
|
||||||
|
|
||||||
protected DownloadEntity(Parcel in) { |
|
||||||
super(in); |
|
||||||
this.downloadPath = in.readString(); |
|
||||||
this.groupHash = in.readString(); |
|
||||||
this.md5Code = in.readString(); |
|
||||||
this.disposition = in.readString(); |
|
||||||
this.serverFileName = in.readString(); |
|
||||||
this.m3U8Entity = in.readParcelable(M3U8Entity.class.getClassLoader()); |
|
||||||
} |
|
||||||
|
|
||||||
public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() { |
|
||||||
@Override public DownloadEntity createFromParcel(Parcel source) { |
|
||||||
return new DownloadEntity(source); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public DownloadEntity[] newArray(int size) { |
|
||||||
return new DownloadEntity[size]; |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
@ -1,86 +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.core.download; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.text.TextUtils; |
|
||||||
import com.arialyy.aria.core.common.AbsGroupEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.annotation.Ignore; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/6/29. 下载任务组实体 |
|
||||||
*/ |
|
||||||
public class DownloadGroupEntity extends AbsGroupEntity { |
|
||||||
|
|
||||||
@Ignore private List<DownloadEntity> subEntities; |
|
||||||
|
|
||||||
/** |
|
||||||
* 子任务实体列表 |
|
||||||
*/ |
|
||||||
public List<DownloadEntity> getSubEntities() { |
|
||||||
if (subEntities == null) { |
|
||||||
subEntities = new ArrayList<>(); |
|
||||||
} |
|
||||||
return subEntities; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSubEntities(List<DownloadEntity> subTasks) { |
|
||||||
this.subEntities = subTasks; |
|
||||||
} |
|
||||||
|
|
||||||
public void setGroupHash(String key) { |
|
||||||
this.groupHash = key; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int getTaskType() { |
|
||||||
if (getSubEntities() == null || getSubEntities().isEmpty() || TextUtils.isEmpty( |
|
||||||
getSubEntities().get(0).getUrl())) { |
|
||||||
return ITaskWrapper.ERROR; |
|
||||||
} |
|
||||||
return (groupHash.startsWith("ftp") || groupHash.startsWith("sftp")) ? ITaskWrapper.D_FTP_DIR |
|
||||||
: ITaskWrapper.DG_HTTP; |
|
||||||
} |
|
||||||
|
|
||||||
public DownloadGroupEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
super.writeToParcel(dest, flags); |
|
||||||
dest.writeTypedList(this.subEntities); |
|
||||||
} |
|
||||||
|
|
||||||
protected DownloadGroupEntity(Parcel in) { |
|
||||||
super(in); |
|
||||||
this.subEntities = in.createTypedArrayList(DownloadEntity.CREATOR); |
|
||||||
} |
|
||||||
|
|
||||||
public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() { |
|
||||||
@Override public DownloadGroupEntity createFromParcel(Parcel source) { |
|
||||||
return new DownloadGroupEntity(source); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public DownloadGroupEntity[] newArray(int size) { |
|
||||||
return new DownloadGroupEntity[size]; |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
@ -1,60 +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.core.listener; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.core.inf.TaskSchedulerType; |
|
||||||
import com.arialyy.aria.core.task.DownloadTask; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
import com.arialyy.aria.util.DeleteDRecord; |
|
||||||
|
|
||||||
/** |
|
||||||
* 下载监听类 |
|
||||||
*/ |
|
||||||
public class BaseDListener extends AbsEventListener implements IDLoadListener { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onPostPre(long fileSize) { |
|
||||||
mEntity.setFileSize(fileSize); |
|
||||||
mEntity.setConvertFileSize(CommonUtil.formatFileSize(fileSize)); |
|
||||||
saveData(IEntity.STATE_POST_PRE, -1); |
|
||||||
sendInState2Target(ISchedulers.POST_PRE); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void supportBreakpoint(boolean support) { |
|
||||||
if (!support) { |
|
||||||
sendInState2Target(ISchedulers.NO_SUPPORT_BREAK_POINT); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override protected void handleCancel() { |
|
||||||
int sType = getTask(DownloadTask.class).getSchedulerType(); |
|
||||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) { |
|
||||||
mEntity.setComplete(false); |
|
||||||
mEntity.setState(IEntity.STATE_WAIT); |
|
||||||
|
|
||||||
DeleteDRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false); |
|
||||||
//RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
|
||||||
// mTaskWrapper.isRemoveFile(), false);
|
|
||||||
} else { |
|
||||||
//RecordUtil.delTaskRecord(mEntity.getFilePath(), IRecordHandler.TYPE_DOWNLOAD,
|
|
||||||
// mTaskWrapper.isRemoveFile(), true);
|
|
||||||
|
|
||||||
DeleteDRecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,38 +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.core.listener; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.core.inf.TaskSchedulerType; |
|
||||||
import com.arialyy.aria.core.task.UploadTask; |
|
||||||
import com.arialyy.aria.util.DeleteURecord; |
|
||||||
|
|
||||||
/** |
|
||||||
* 下载监听类 |
|
||||||
*/ |
|
||||||
public class BaseUListener extends AbsEventListener implements IUploadListener { |
|
||||||
|
|
||||||
@Override protected void handleCancel() { |
|
||||||
int sType = getTask(UploadTask.class).getSchedulerType(); |
|
||||||
if (sType == TaskSchedulerType.TYPE_CANCEL_AND_NOT_NOTIFY) { |
|
||||||
mEntity.setComplete(false); |
|
||||||
mEntity.setState(IEntity.STATE_WAIT); |
|
||||||
DeleteURecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), false); |
|
||||||
} else { |
|
||||||
DeleteURecord.getInstance().deleteRecord(mEntity, mTaskWrapper.isRemoveFile(), true); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,54 +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.core.upload; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.config.Configuration; |
|
||||||
import com.arialyy.aria.core.config.UploadConfig; |
|
||||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/2/9. 上传任务实体 |
|
||||||
*/ |
|
||||||
public class UTaskWrapper extends AbsTaskWrapper<UploadEntity> { |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存临时设置的上传路径 |
|
||||||
*/ |
|
||||||
private String tempUrl; |
|
||||||
|
|
||||||
public UTaskWrapper(UploadEntity entity) { |
|
||||||
super(entity); |
|
||||||
} |
|
||||||
|
|
||||||
public String getTempUrl() { |
|
||||||
return tempUrl; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTempUrl(String tempUrl) { |
|
||||||
this.tempUrl = tempUrl; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 文件保存路径 |
|
||||||
*/ |
|
||||||
@Override public String getKey() { |
|
||||||
return getEntity().getKey(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public UploadConfig getConfig() { |
|
||||||
return Configuration.getInstance().uploadCfg; |
|
||||||
} |
|
||||||
} |
|
@ -1,94 +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.core.upload; |
|
||||||
|
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import android.text.TextUtils; |
|
||||||
import com.arialyy.aria.core.common.AbsNormalEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.orm.annotation.Primary; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/2/9. |
|
||||||
* 上传文件实体 |
|
||||||
*/ |
|
||||||
public class UploadEntity extends AbsNormalEntity implements Parcelable { |
|
||||||
/** |
|
||||||
* 文件上传路径 |
|
||||||
*/ |
|
||||||
@Primary private String filePath; |
|
||||||
|
|
||||||
/** |
|
||||||
* 上传完成后服务器返回的数据 |
|
||||||
*/ |
|
||||||
private String responseStr = ""; |
|
||||||
|
|
||||||
public String getResponseStr() { |
|
||||||
return responseStr; |
|
||||||
} |
|
||||||
|
|
||||||
public void setResponseStr(String responseStr) { |
|
||||||
this.responseStr = responseStr; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getFilePath() { |
|
||||||
return filePath; |
|
||||||
} |
|
||||||
|
|
||||||
public void setFilePath(String filePath) { |
|
||||||
this.filePath = filePath; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public String getKey() { |
|
||||||
return filePath; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int getTaskType() { |
|
||||||
if (TextUtils.isEmpty(getUrl())) { |
|
||||||
return ITaskWrapper.ERROR; |
|
||||||
} |
|
||||||
return getUrl().startsWith("ftp") ? ITaskWrapper.U_FTP : ITaskWrapper.U_HTTP; |
|
||||||
} |
|
||||||
|
|
||||||
public UploadEntity() { |
|
||||||
} |
|
||||||
|
|
||||||
@Override public int describeContents() { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void writeToParcel(Parcel dest, int flags) { |
|
||||||
super.writeToParcel(dest, flags); |
|
||||||
dest.writeString(this.filePath); |
|
||||||
} |
|
||||||
|
|
||||||
protected UploadEntity(Parcel in) { |
|
||||||
super(in); |
|
||||||
this.filePath = in.readString(); |
|
||||||
} |
|
||||||
|
|
||||||
public static final Creator<UploadEntity> CREATOR = new Creator<UploadEntity>() { |
|
||||||
@Override public UploadEntity createFromParcel(Parcel source) { |
|
||||||
return new UploadEntity(source); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public UploadEntity[] newArray(int size) { |
|
||||||
return new UploadEntity[size]; |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
@ -1,197 +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.core.wrapper; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.TaskOptionParams; |
|
||||||
import com.arialyy.aria.core.common.AbsEntity; |
|
||||||
import com.arialyy.aria.core.config.BaseTaskConfig; |
|
||||||
import com.arialyy.aria.core.download.DownloadEntity; |
|
||||||
import com.arialyy.aria.core.download.DownloadGroupEntity; |
|
||||||
import com.arialyy.aria.core.event.ErrorEvent; |
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
import com.arialyy.aria.core.inf.ITaskOption; |
|
||||||
import com.arialyy.aria.core.upload.UploadEntity; |
|
||||||
import com.arialyy.aria.util.ComponentUtil; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/2/23. 所有任务实体的父类 |
|
||||||
*/ |
|
||||||
public abstract class AbsTaskWrapper<ENTITY extends AbsEntity> implements ITaskWrapper { |
|
||||||
|
|
||||||
/** |
|
||||||
* 刷新信息 {@code true} 重新刷新下载信息 |
|
||||||
*/ |
|
||||||
private boolean refreshInfo = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否是新任务,{@code true} 新任务 |
|
||||||
*/ |
|
||||||
private boolean isNewTask = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 请求类型 {@link ITaskWrapper#D_HTTP}、{@link ITaskWrapper#D_FTP}、{@link |
|
||||||
* ITaskWrapper#D_FTP_DIR}.. |
|
||||||
*/ |
|
||||||
private int requestType = D_HTTP; |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除任务时,是否删除已下载完成的文件 未完成的任务,不管true还是false,都会删除文件 {@code true} 删除任务数据库记录,并且删除已经下载完成的文件 {@code |
|
||||||
* false} 如果任务已经完成,只删除任务数据库记录 |
|
||||||
*/ |
|
||||||
private boolean removeFile = false; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否支持断点, {@code true} 为支持断点 |
|
||||||
*/ |
|
||||||
private boolean isSupportBP = true; |
|
||||||
|
|
||||||
/** |
|
||||||
* 状态码 |
|
||||||
*/ |
|
||||||
private int code; |
|
||||||
|
|
||||||
/** |
|
||||||
* {@link DownloadEntity} or {@link UploadEntity} or {@link DownloadGroupEntity} |
|
||||||
*/ |
|
||||||
private ENTITY entity; |
|
||||||
|
|
||||||
/** |
|
||||||
* 错误信息 |
|
||||||
*/ |
|
||||||
private ErrorEvent errorEvent; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务配置 |
|
||||||
*/ |
|
||||||
private ITaskOption taskOption; |
|
||||||
|
|
||||||
/** |
|
||||||
* 任务配置信息 |
|
||||||
*/ |
|
||||||
private TaskOptionParams optionParams = new TaskOptionParams(); |
|
||||||
|
|
||||||
/** |
|
||||||
* {@code true}强制下载\上传,不考虑文件路径是否被占用 |
|
||||||
*/ |
|
||||||
private boolean ignoreFilePathOccupy = false; |
|
||||||
|
|
||||||
public boolean isIgnoreFilePathOccupy() { |
|
||||||
return ignoreFilePathOccupy; |
|
||||||
} |
|
||||||
|
|
||||||
public void setIgnoreFilePathOccupy(boolean ignoreFilePathOccupy) { |
|
||||||
this.ignoreFilePathOccupy = ignoreFilePathOccupy; |
|
||||||
} |
|
||||||
|
|
||||||
public void setTaskOption(ITaskOption option) { |
|
||||||
this.taskOption = option; |
|
||||||
} |
|
||||||
|
|
||||||
public ITaskOption getTaskOption() { |
|
||||||
return taskOption; |
|
||||||
} |
|
||||||
|
|
||||||
public void generateTaskOption(Class<? extends ITaskOption> clazz) { |
|
||||||
taskOption = ComponentUtil.getInstance().buildTaskOption(clazz, optionParams); |
|
||||||
} |
|
||||||
|
|
||||||
public TaskOptionParams getOptionParams() { |
|
||||||
if (optionParams == null) { |
|
||||||
optionParams = new TaskOptionParams(); |
|
||||||
} |
|
||||||
return optionParams; |
|
||||||
} |
|
||||||
|
|
||||||
public AbsTaskWrapper(ENTITY entity) { |
|
||||||
this.entity = entity; |
|
||||||
} |
|
||||||
|
|
||||||
public ErrorEvent getErrorEvent() { |
|
||||||
return errorEvent; |
|
||||||
} |
|
||||||
|
|
||||||
public void setErrorEvent(ErrorEvent errorEvent) { |
|
||||||
this.errorEvent = errorEvent; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public ENTITY getEntity() { |
|
||||||
return entity; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务下载状态 |
|
||||||
* |
|
||||||
* @return {@link IEntity} |
|
||||||
*/ |
|
||||||
public int getState() { |
|
||||||
return getEntity().getState(); |
|
||||||
} |
|
||||||
|
|
||||||
public abstract BaseTaskConfig getConfig(); |
|
||||||
|
|
||||||
public boolean isRefreshInfo() { |
|
||||||
return refreshInfo; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRefreshInfo(boolean refreshInfo) { |
|
||||||
this.refreshInfo = refreshInfo; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isNewTask() { |
|
||||||
return isNewTask; |
|
||||||
} |
|
||||||
|
|
||||||
public void setNewTask(boolean newTask) { |
|
||||||
isNewTask = newTask; |
|
||||||
} |
|
||||||
|
|
||||||
public void setState(int state) { |
|
||||||
entity.setState(state); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getRequestType() { |
|
||||||
return requestType; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRequestType(int requestType) { |
|
||||||
this.requestType = requestType; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isRemoveFile() { |
|
||||||
return removeFile; |
|
||||||
} |
|
||||||
|
|
||||||
public void setRemoveFile(boolean removeFile) { |
|
||||||
this.removeFile = removeFile; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isSupportBP() { |
|
||||||
return isSupportBP; |
|
||||||
} |
|
||||||
|
|
||||||
public void setSupportBP(boolean supportBP) { |
|
||||||
isSupportBP = supportBP; |
|
||||||
} |
|
||||||
|
|
||||||
public int getCode() { |
|
||||||
return code; |
|
||||||
} |
|
||||||
|
|
||||||
public void setCode(int code) { |
|
||||||
this.code = code; |
|
||||||
} |
|
||||||
} |
|
@ -1,111 +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.core.wrapper; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.inf.IEntity; |
|
||||||
|
|
||||||
/** |
|
||||||
* 组合任务实体包裹器,用于加载和任务相关的参数 |
|
||||||
*/ |
|
||||||
public interface ITaskWrapper { |
|
||||||
|
|
||||||
int ERROR = 0; |
|
||||||
|
|
||||||
/** |
|
||||||
* HTTP单任务载 |
|
||||||
*/ |
|
||||||
int D_HTTP = 1; |
|
||||||
|
|
||||||
/** |
|
||||||
* HTTP任务组下载 |
|
||||||
*/ |
|
||||||
int DG_HTTP = 2; |
|
||||||
|
|
||||||
/** |
|
||||||
* FTP单文件下载 |
|
||||||
*/ |
|
||||||
int D_FTP = 3; |
|
||||||
|
|
||||||
/** |
|
||||||
* FTP文件夹下载,为避免登录过多,子任务由单线程进行处理 |
|
||||||
*/ |
|
||||||
int D_FTP_DIR = 4; |
|
||||||
|
|
||||||
/** |
|
||||||
* HTTP单文件上传 |
|
||||||
*/ |
|
||||||
int U_HTTP = 5; |
|
||||||
|
|
||||||
/** |
|
||||||
* FTP单文件上传 |
|
||||||
*/ |
|
||||||
int U_FTP = 6; |
|
||||||
|
|
||||||
/** |
|
||||||
* M3u8点播 |
|
||||||
*/ |
|
||||||
int M3U8_VOD = 7; |
|
||||||
|
|
||||||
/** |
|
||||||
* m3u8直播 |
|
||||||
*/ |
|
||||||
int M3U8_LIVE = 8; |
|
||||||
|
|
||||||
/** |
|
||||||
* TCP 文件下载 |
|
||||||
*/ |
|
||||||
int D_TCP = 9; |
|
||||||
|
|
||||||
/** |
|
||||||
* TCP 文件上传 |
|
||||||
*/ |
|
||||||
int U_TCP = 10; |
|
||||||
|
|
||||||
/** |
|
||||||
* TCP 分片上传 |
|
||||||
*/ |
|
||||||
int U_TCP_PEER = 11; |
|
||||||
|
|
||||||
/** |
|
||||||
* SFTP 下载 |
|
||||||
*/ |
|
||||||
int D_SFTP = 12; |
|
||||||
|
|
||||||
/** |
|
||||||
* SFTP 上传 |
|
||||||
*/ |
|
||||||
int U_SFTP = 13; |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务类型 |
|
||||||
* |
|
||||||
* @return {@link ITaskWrapper} |
|
||||||
*/ |
|
||||||
int getRequestType(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务实体 |
|
||||||
*/ |
|
||||||
IEntity getEntity(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取任务唯一标志: |
|
||||||
* 下载任务,对应文件的下载地址 |
|
||||||
* 上传任务,对应需要上传的文件路径 |
|
||||||
* 组合任务,对应组合任务的groupHash |
|
||||||
*/ |
|
||||||
String getKey(); |
|
||||||
} |
|
@ -1,47 +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.core.wrapper; |
|
||||||
|
|
||||||
import com.arialyy.aria.core.TaskRecord; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.orm.AbsDbWrapper; |
|
||||||
import com.arialyy.aria.orm.annotation.Many; |
|
||||||
import com.arialyy.aria.orm.annotation.One; |
|
||||||
import com.arialyy.aria.orm.annotation.Wrapper; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/30. |
|
||||||
* 任务记录和线程记录的关系 |
|
||||||
*/ |
|
||||||
@Wrapper |
|
||||||
public class RecordWrapper extends AbsDbWrapper { |
|
||||||
|
|
||||||
@One |
|
||||||
public TaskRecord taskRecord; |
|
||||||
|
|
||||||
@Many(parentColumn = "filePath", entityColumn = "taskKey") |
|
||||||
public List<ThreadRecord> threadRecords; |
|
||||||
|
|
||||||
@Override protected void handleConvert() { |
|
||||||
if (threadRecords != null && !threadRecords.isEmpty()) { |
|
||||||
taskRecord.threadRecords = threadRecords; |
|
||||||
} else { |
|
||||||
taskRecord.threadRecords = new ArrayList<>(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,27 +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; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/30. |
|
||||||
*/ |
|
||||||
public abstract class AbsDbWrapper { |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理转换 |
|
||||||
*/ |
|
||||||
protected abstract void handleConvert(); |
|
||||||
} |
|
@ -1,39 +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; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/22. |
|
||||||
*/ |
|
||||||
public abstract class AbsDelegate { |
|
||||||
static final String TAG = "AbsDelegate"; |
|
||||||
|
|
||||||
void closeCursor(Cursor cursor) { |
|
||||||
SqlUtil.closeCursor(cursor); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 检查数据库是否关闭,已经关闭的话,打开数据库 |
|
||||||
* |
|
||||||
* @return 返回数据库 |
|
||||||
*/ |
|
||||||
SQLiteDatabase checkDb(SQLiteDatabase db) { |
|
||||||
return SqlUtil.checkDb(db); |
|
||||||
} |
|
||||||
} |
|
@ -1,62 +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 com.arialyy.aria.orm.annotation.Foreign; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/22. |
|
||||||
* on update 或 on delete 都可跟不同action功能 |
|
||||||
* |
|
||||||
* @see <a href="https://sqlite.org/foreignkeys.html"></a> |
|
||||||
* {@link Foreign#onDelete()}、{@link Foreign#onUpdate()} |
|
||||||
*/ |
|
||||||
public enum ActionPolicy { |
|
||||||
|
|
||||||
/** |
|
||||||
* 如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作 |
|
||||||
*/ |
|
||||||
NO_ACTION("NO ACTION"), |
|
||||||
|
|
||||||
/** |
|
||||||
* 和NO ACTION 作用一致,和NO ACTION的区别是: |
|
||||||
* 主表update/delete执行时,马上就触发约束; |
|
||||||
* 而NO ACTION 是执行完成语句后才触发约束, |
|
||||||
*/ |
|
||||||
RESTRICT("RESTRICT"), |
|
||||||
|
|
||||||
/** |
|
||||||
* 在父表上update/delete记录时,将子表上匹配记录的列设为null (要注意子表的外键列不能为not null) |
|
||||||
*/ |
|
||||||
SET_NULL("SET NULL"), |
|
||||||
|
|
||||||
/** |
|
||||||
* 父表有变更时,子表将外键列设置成一个默认的值,default配置的值 |
|
||||||
*/ |
|
||||||
SET_DEFAULT("SET ERROR"), |
|
||||||
|
|
||||||
/** |
|
||||||
* 在父表上update/delete记录时,同步update/delete掉子表的匹配记录 |
|
||||||
*/ |
|
||||||
CASCADE("CASCADE"); |
|
||||||
|
|
||||||
String function; |
|
||||||
|
|
||||||
ActionPolicy(String function) { |
|
||||||
this.function = function; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,61 +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.text.TextUtils; |
|
||||||
import com.arialyy.aria.core.TaskRecord; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.core.download.DownloadEntity; |
|
||||||
import com.arialyy.aria.core.download.DownloadGroupEntity; |
|
||||||
import com.arialyy.aria.core.download.M3U8Entity; |
|
||||||
import com.arialyy.aria.core.upload.UploadEntity; |
|
||||||
import java.util.LinkedHashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/4/6. |
|
||||||
* 数据库配置信息 |
|
||||||
*/ |
|
||||||
class DBConfig { |
|
||||||
/*adb pull /mnt/sdcard/Android/data/com.arialyy.simple/files/DB/AriaLyyDb d:/db*/ |
|
||||||
static boolean DEBUG = false; |
|
||||||
static Map<String, Class<? extends DbEntity>> mapping = new LinkedHashMap<>(); |
|
||||||
static String DB_NAME; |
|
||||||
static int VERSION = 58; |
|
||||||
|
|
||||||
/** |
|
||||||
* 是否将数据库保存在Sd卡,{@code true} 是 |
|
||||||
*/ |
|
||||||
static final boolean SAVE_IN_SDCARD = false; |
|
||||||
|
|
||||||
static { |
|
||||||
if (TextUtils.isEmpty(DB_NAME)) { |
|
||||||
DB_NAME = "AndroidAria.db"; |
|
||||||
} |
|
||||||
if (VERSION == -1) { |
|
||||||
VERSION = 1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static { |
|
||||||
mapping.put("DownloadEntity", DownloadEntity.class); |
|
||||||
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class); |
|
||||||
mapping.put("UploadEntity", UploadEntity.class); |
|
||||||
mapping.put("ThreadRecord", ThreadRecord.class); |
|
||||||
mapping.put("TaskRecord", TaskRecord.class); |
|
||||||
mapping.put("M3U8Entity", M3U8Entity.class); |
|
||||||
} |
|
||||||
} |
|
@ -1,93 +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.content.Context; |
|
||||||
import android.content.ContextWrapper; |
|
||||||
import android.database.DatabaseErrorHandler; |
|
||||||
import android.database.sqlite.SQLiteDatabase; |
|
||||||
import com.arialyy.aria.util.CommonUtil; |
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存在sd卡的数据库使用的Context |
|
||||||
*/ |
|
||||||
class DatabaseContext extends ContextWrapper { |
|
||||||
public DatabaseContext(Context context) { |
|
||||||
super(context); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获得数据库路径,如果不存在,则创建对象对象 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public File getDatabasePath(String name) { |
|
||||||
String dbDir = CommonUtil.getAppPath(getBaseContext()); |
|
||||||
|
|
||||||
dbDir += "DB";//数据库所在目录
|
|
||||||
String dbPath = dbDir + "/" + name;//数据库路径
|
|
||||||
//判断目录是否存在,不存在则创建该目录
|
|
||||||
File dirFile = new File(dbDir); |
|
||||||
if (!dirFile.exists()) { |
|
||||||
dirFile.mkdirs(); |
|
||||||
} |
|
||||||
|
|
||||||
//数据库文件是否创建成功
|
|
||||||
boolean isFileCreateSuccess = false; |
|
||||||
//判断文件是否存在,不存在则创建该文件
|
|
||||||
File dbFile = new File(dbPath); |
|
||||||
if (!dbFile.exists()) { |
|
||||||
try { |
|
||||||
isFileCreateSuccess = dbFile.createNewFile();//创建文件
|
|
||||||
} catch (IOException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} else { |
|
||||||
isFileCreateSuccess = true; |
|
||||||
} |
|
||||||
|
|
||||||
//返回数据库文件对象
|
|
||||||
if (isFileCreateSuccess) { |
|
||||||
return dbFile; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 重载这个方法,是用来打开SD卡上的数据库的,android 2.3及以下会调用这个方法。 |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, |
|
||||||
SQLiteDatabase.CursorFactory factory) { |
|
||||||
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Android 4.0会调用此方法获取数据库。 |
|
||||||
* |
|
||||||
* @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int, |
|
||||||
* android.database.sqlite.SQLiteDatabase.CursorFactory, |
|
||||||
* android.database.DatabaseErrorHandler) |
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, |
|
||||||
SQLiteDatabase.CursorFactory factory, |
|
||||||
DatabaseErrorHandler errorHandler) { |
|
||||||
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); |
|
||||||
} |
|
||||||
} |
|
@ -1,174 +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.content.ContentProvider |
|
||||||
import android.content.ContentValues |
|
||||||
import android.content.Context |
|
||||||
import android.database.Cursor |
|
||||||
import android.net.Uri |
|
||||||
import com.arialyy.aria.util.ALog |
|
||||||
import com.arialyy.aria.util.CommonUtil |
|
||||||
|
|
||||||
/** |
|
||||||
* @Author laoyuyu |
|
||||||
* @Description |
|
||||||
* @Date 2:25 下午 2022/4/25 |
|
||||||
**/ |
|
||||||
class DbContentProvider : ContentProvider() { |
|
||||||
val TAG = "DbContentProvider" |
|
||||||
|
|
||||||
companion object { |
|
||||||
// const val KEY_TABLE_NAME = "tableName" |
|
||||||
const val KEY_ROW_ID = "rowId" |
|
||||||
const val KEY_TABLE_CLAZZ = "tableClazz" |
|
||||||
const val KEY_LIMIT = "limit" |
|
||||||
|
|
||||||
fun createRequestUrl(context: Context, clazz: Class<*>): Uri { |
|
||||||
return Uri.parse("content://${context.packageName}.com.arialyy.aria.provide/request?${KEY_TABLE_CLAZZ}=${clazz.name}") |
|
||||||
} |
|
||||||
|
|
||||||
fun getRequestUrl(context: Context): String { |
|
||||||
return "content://${context.packageName}.com.arialyy.aria.provide/request" |
|
||||||
} |
|
||||||
|
|
||||||
fun getResponseUrl(context: Context): String { |
|
||||||
return "content://${context.packageName}.com.arialyy.aria.provide/response" |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* key: clazzPath, value: tableName |
|
||||||
*/ |
|
||||||
private val tableExistMap = mutableMapOf<String, String>() |
|
||||||
|
|
||||||
private lateinit var helper: SqlHelper |
|
||||||
|
|
||||||
override fun onCreate(): Boolean { |
|
||||||
helper = SqlHelper.init(context) |
|
||||||
return true |
|
||||||
} |
|
||||||
|
|
||||||
private fun getTableName(uri: Uri): String? { |
|
||||||
val db = SqlUtil.checkDb(helper.db) |
|
||||||
val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ) |
|
||||||
if (tableExistMap[clazzName!!] != null) { |
|
||||||
return tableExistMap[clazzName] |
|
||||||
} |
|
||||||
|
|
||||||
val clazz: Class<out DbEntity>? = |
|
||||||
javaClass.classLoader?.loadClass(clazzName) as Class<out DbEntity>? |
|
||||||
if (clazz == null) { |
|
||||||
ALog.e(TAG, "【$clazz】为空") |
|
||||||
return null |
|
||||||
} |
|
||||||
SqlUtil.checkOrCreateTable(db, clazz) |
|
||||||
val tableName = CommonUtil.getClassName(clazz) |
|
||||||
tableExistMap[clazzName] = tableName |
|
||||||
return tableName |
|
||||||
} |
|
||||||
|
|
||||||
override fun query( |
|
||||||
uri: Uri, |
|
||||||
projection: Array<out String>?, |
|
||||||
selection: String?, |
|
||||||
selectionArgs: Array<out String>?, |
|
||||||
sortOrder: String? |
|
||||||
): Cursor? { |
|
||||||
val db = SqlUtil.checkDb(helper.db) |
|
||||||
val tableName = getTableName(uri) |
|
||||||
if (tableName.isNullOrBlank()) { |
|
||||||
return null |
|
||||||
} |
|
||||||
val clazzName = uri.getQueryParameter(KEY_TABLE_CLAZZ) |
|
||||||
val clazz = javaClass.classLoader?.loadClass(clazzName) as Class<out DbEntity>? |
|
||||||
val columns = SqlUtil.getColumns(clazz) |
|
||||||
val limit = uri.getQueryParameter(KEY_LIMIT) |
|
||||||
return db.query( |
|
||||||
tableName, |
|
||||||
columns.toTypedArray(), |
|
||||||
selection, |
|
||||||
selectionArgs, |
|
||||||
null, |
|
||||||
null, |
|
||||||
null, |
|
||||||
limit |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
override fun getType(uri: Uri): String? { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
override fun insert(uri: Uri, values: ContentValues?): Uri? { |
|
||||||
val db = SqlUtil.checkDb(helper.db) |
|
||||||
val tableName = getTableName(uri) |
|
||||||
if (tableName.isNullOrBlank()) { |
|
||||||
return null |
|
||||||
} |
|
||||||
db.beginTransaction() |
|
||||||
try { |
|
||||||
val rowId = db.insert(tableName, null, values) |
|
||||||
if (rowId == -1L) { |
|
||||||
return null |
|
||||||
} |
|
||||||
return Uri.parse("${getResponseUrl(context!!)}?${KEY_ROW_ID}=$rowId") |
|
||||||
} finally { |
|
||||||
db.endTransaction() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int { |
|
||||||
val db = SqlUtil.checkDb(helper.db) |
|
||||||
val tableName = getTableName(uri) |
|
||||||
if (tableName.isNullOrBlank()) { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
db.beginTransaction() |
|
||||||
try { |
|
||||||
val rowId = db.delete(tableName, selection, selectionArgs) |
|
||||||
if (rowId == -1) { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
return rowId |
|
||||||
} finally { |
|
||||||
db.endTransaction() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override fun update( |
|
||||||
uri: Uri, |
|
||||||
values: ContentValues?, |
|
||||||
selection: String?, |
|
||||||
selectionArgs: Array<out String>? |
|
||||||
): Int { |
|
||||||
val db = SqlUtil.checkDb(helper.db) |
|
||||||
val tableName = getTableName(uri) |
|
||||||
if (tableName.isNullOrBlank()) { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
db.beginTransaction() |
|
||||||
try { |
|
||||||
val rowId = db.update(tableName, values, selection, selectionArgs) |
|
||||||
if (rowId == -1) { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
return rowId |
|
||||||
} finally { |
|
||||||
db.endTransaction() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,295 +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 java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. 所有数据库实体父类 |
|
||||||
*/ |
|
||||||
public abstract class DbEntity { |
|
||||||
private static final Object LOCK = new Object(); |
|
||||||
public long rowID = -1; |
|
||||||
|
|
||||||
protected DbEntity() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
protected long getRowID() { |
|
||||||
return rowID; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询关联数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findRelationData(DGEntityWrapper.class, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @param expression 查询条件 |
|
||||||
*/ |
|
||||||
public static <T extends AbsDbWrapper> List<T> findRelationData(Class<T> clazz, |
|
||||||
String... expression) { |
|
||||||
return DelegateWrapper.getInstance().findRelationData(clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页查询关联数据 |
|
||||||
* |
|
||||||
* <code> |
|
||||||
* DbEntity.findRelationData(DGEntityWrapper.class, 0, 10, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @param expression 查询条件 |
|
||||||
* @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null |
|
||||||
* @param num 每页返回的数量 |
|
||||||
* @return 没有数据返回null,如果页数大于总页数,返回null |
|
||||||
*/ |
|
||||||
public static <T extends AbsDbWrapper> List<T> findRelationData(Class<T> clazz, int page, int num, |
|
||||||
String... expression) { |
|
||||||
if (page < 1 || num < 1) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return DelegateWrapper.getInstance().findRelationData(clazz, page, num, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 检查某个字段的值是否存在 |
|
||||||
* |
|
||||||
* @param expression 字段和值"downloadPath=?" |
|
||||||
* @return {@code true}该字段的对应的value已存在 |
|
||||||
*/ |
|
||||||
public static boolean checkDataExist(Class clazz, String... expression) { |
|
||||||
return DelegateWrapper.getInstance().checkDataExist(clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 清空表数据 |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> void clean(Class<T> clazz) { |
|
||||||
DelegateWrapper.getInstance().clean(clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 直接执行sql语句 |
|
||||||
*/ |
|
||||||
public static void exeSql(String sql) { |
|
||||||
DelegateWrapper.getInstance().exeSql(sql); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询所有数据 |
|
||||||
* |
|
||||||
* @return 没有数据返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) { |
|
||||||
return DelegateWrapper.getInstance().findAllData(clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询第一条数据 |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> T findFirst(Class<T> clazz) { |
|
||||||
List<T> list = findAllData(clazz); |
|
||||||
return (list == null || list.size() == 0) ? null : list.get(0); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询一组数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @return 没有数据返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, String... expression) { |
|
||||||
return DelegateWrapper.getInstance().findData(clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页查询数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findFirst(DownloadEntity.class, 0, 10, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null |
|
||||||
* @param num 每页返回的数量 |
|
||||||
* @return 没有数据返回null,如果页数大于总页数,返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, int page, int num, |
|
||||||
String... expression) { |
|
||||||
if (page < 1 || num < 1) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return DelegateWrapper.getInstance().findData(clazz, page, num, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 模糊查询一组数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findDataByFuzzy(DownloadEntity.class, "downloadUrl like http://"); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @return 没有数据返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> List<T> findDataByFuzzy(Class<T> clazz, String conditions) { |
|
||||||
return DelegateWrapper.getInstance().findDataByFuzzy(clazz, conditions); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 模糊查询一组数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findDataByFuzzy(DownloadEntity.class, 0, 10, "downloadUrl like http://"); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @param page 需要查询的页数,从1开始,如果page小于1 或 num 小于1,返回null |
|
||||||
* @param num 每页返回的数量 |
|
||||||
* @return 没有数据返回null,如果页数大于总页数,返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> List<T> findDataByFuzzy(Class<T> clazz, int page, int num, |
|
||||||
String conditions) { |
|
||||||
return DelegateWrapper.getInstance().findDataByFuzzy(clazz, page, num, conditions); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询一行数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
* |
|
||||||
* @return 没有数据返回null |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> T findFirst(Class<T> clazz, String... expression) { |
|
||||||
DelegateWrapper util = DelegateWrapper.getInstance(); |
|
||||||
List<T> datas = util.findData(clazz, expression); |
|
||||||
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 插入多条数据 |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> void insertManyData(List<T> entities) { |
|
||||||
checkListData(entities); |
|
||||||
DelegateWrapper.getInstance().insertManyData(entities); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 修改多条数据 |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> void updateManyData(List<T> entities) { |
|
||||||
checkListData(entities); |
|
||||||
DelegateWrapper.getInstance().updateManyData(entities); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存多条数据,通过rowID来判断记录存在以否,如果数据库已有记录,则更新该记录;如果数据库中没有记录,则保存该记录 |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> void saveAll(List<T> entities) { |
|
||||||
checkListData(entities); |
|
||||||
List<T> insertD = new ArrayList<>(); |
|
||||||
List<T> updateD = new ArrayList<>(); |
|
||||||
DelegateWrapper wrapper = DelegateWrapper.getInstance(); |
|
||||||
for (T entity : entities) { |
|
||||||
if (entity.rowID == -1) { |
|
||||||
insertD.add(entity); |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (wrapper.isExist(entity.getClass(), entity.rowID)) { |
|
||||||
updateD.add(entity); |
|
||||||
} else { |
|
||||||
insertD.add(entity); |
|
||||||
} |
|
||||||
} |
|
||||||
if (!insertD.isEmpty()) { |
|
||||||
wrapper.insertManyData(insertD); |
|
||||||
} |
|
||||||
if (!updateD.isEmpty()) { |
|
||||||
wrapper.updateManyData(updateD); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 检查批量操作的列表数据,如果数据为空,抛出{@link NullPointerException} |
|
||||||
*/ |
|
||||||
private static <T extends DbEntity> void checkListData(List<T> entities) { |
|
||||||
if (entities == null || entities.isEmpty()) { |
|
||||||
throw new NullPointerException("列表数据为空"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除当前数据 |
|
||||||
*/ |
|
||||||
public void deleteData() { |
|
||||||
deleteData(getClass(), "rowid=?", rowID + ""); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据条件删除数据 |
|
||||||
* <code> |
|
||||||
* DbEntity.deleteData(DownloadEntity.class, "downloadUrl=?", downloadUrl); |
|
||||||
* </code> |
|
||||||
*/ |
|
||||||
public static <T extends DbEntity> void deleteData(Class<T> clazz, String... expression) { |
|
||||||
DelegateWrapper util = DelegateWrapper.getInstance(); |
|
||||||
util.delData(clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 修改数据 |
|
||||||
*/ |
|
||||||
public void update() { |
|
||||||
DelegateWrapper.getInstance().updateData(this); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 保存自身,如果表中已经有数据,则更新数据,否则插入数据 只有 target中checkEntity成功后才能保存,创建实体部分也不允许保存 |
|
||||||
*/ |
|
||||||
public void save() { |
|
||||||
synchronized (LOCK) { |
|
||||||
if (thisIsExist()) { |
|
||||||
update(); |
|
||||||
} else { |
|
||||||
insert(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查找数据在表中是否存在 |
|
||||||
*/ |
|
||||||
private boolean thisIsExist() { |
|
||||||
DelegateWrapper util = DelegateWrapper.getInstance(); |
|
||||||
return rowID != -1 && util.isExist(getClass(), rowID); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 表是否存在 |
|
||||||
* |
|
||||||
* @return {@code true} 存在 |
|
||||||
*/ |
|
||||||
public static boolean tableExists(Class<DbEntity> clazz) { |
|
||||||
return DelegateWrapper.getInstance().tableExists(clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 插入数据,只有 target中checkEntity成功后才能插入,创建实体部分也不允许操作 |
|
||||||
*/ |
|
||||||
public void insert() { |
|
||||||
DelegateWrapper.getInstance().insertData(this); |
|
||||||
} |
|
||||||
} |
|
@ -1,639 +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 android.util.SparseArray; |
|
||||||
import com.arialyy.aria.orm.annotation.Many; |
|
||||||
import com.arialyy.aria.orm.annotation.One; |
|
||||||
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.net.URLDecoder; |
|
||||||
import java.net.URLEncoder; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/22. |
|
||||||
* 查询数据 |
|
||||||
*/ |
|
||||||
class DelegateFind extends AbsDelegate { |
|
||||||
private final String PARENT_COLUMN_ALIAS = "p"; |
|
||||||
private final String CHILD_COLUMN_ALIAS = "c"; |
|
||||||
|
|
||||||
private DelegateFind() { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取{@link One}和{@link Many}注解的字段 |
|
||||||
* |
|
||||||
* @return 返回[OneField, ManyField] ,如果注解依赖错误返回null |
|
||||||
*/ |
|
||||||
private Field[] getOneAndManyField(Class clazz) { |
|
||||||
Field[] om = new Field[2]; |
|
||||||
Field[] fields = clazz.getDeclaredFields(); |
|
||||||
Field one = null, many = null; |
|
||||||
boolean hasOne = false, hasMany = false; |
|
||||||
for (Field field : fields) { |
|
||||||
if (SqlUtil.isOne(field)) { |
|
||||||
if (hasOne) { |
|
||||||
ALog.w(TAG, "查询数据失败,实体中有多个@One 注解"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
hasOne = true; |
|
||||||
one = field; |
|
||||||
} |
|
||||||
if (SqlUtil.isMany(field)) { |
|
||||||
if (hasMany) { |
|
||||||
ALog.w(TAG, "查询数据失败,实体中有多个@Many 注解"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
if (!field.getType().isAssignableFrom(List.class)) { |
|
||||||
ALog.w(TAG, "查询数据失败,@Many 注解的类型不是List"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
hasMany = true; |
|
||||||
many = field; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (one == null || many == null) { |
|
||||||
ALog.w(TAG, "查询数据失败,实体中没有@One或@Many注解"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
if (many.getType() != List.class) { |
|
||||||
ALog.w(TAG, "查询数据失败,@Many注解的字段必须是List"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
om[0] = one; |
|
||||||
om[1] = many; |
|
||||||
return om; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查找一对多的关联数据 |
|
||||||
* 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null |
|
||||||
* 如果实体中没有{@link One}或{@link Many}注解,将返回null |
|
||||||
* 如果实体中有多个{@link One}或{@link Many}注解,将返回nul |
|
||||||
* {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} |
|
||||||
*/ |
|
||||||
<T extends AbsDbWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz, |
|
||||||
String... expression) { |
|
||||||
return exeRelationSql(db, clazz, 1, Integer.MAX_VALUE, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查找一对多的关联数据 |
|
||||||
* 如果查找不到数据或实体没有被{@link Wrapper}注解,将返回null |
|
||||||
* 如果实体中没有{@link One}或{@link Many}注解,将返回null |
|
||||||
* 如果实体中有多个{@link One}或{@link Many}注解,将返回nul |
|
||||||
* {@link One} 的注解对象必须是{@link DbEntity},{@link Many}的注解对象必须是List,并且List中的类型必须是{@link DbEntity} |
|
||||||
*/ |
|
||||||
<T extends AbsDbWrapper> List<T> findRelationData(SQLiteDatabase db, Class<T> clazz, |
|
||||||
int page, int num, String... expression) { |
|
||||||
if (page < 1 || num < 1) { |
|
||||||
ALog.w(TAG, "page,num 小于1"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
return exeRelationSql(db, clazz, page, num, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 执行关联查询,如果不需要分页,page和num传-1 |
|
||||||
* |
|
||||||
* @param page 当前页 |
|
||||||
* @param num 一页的数量 |
|
||||||
*/ |
|
||||||
private <T extends AbsDbWrapper> List<T> exeRelationSql(SQLiteDatabase db, Class<T> wrapperClazz, |
|
||||||
int page, int num, String... expression) { |
|
||||||
db = checkDb(db); |
|
||||||
if (SqlUtil.isWrapper(wrapperClazz)) { |
|
||||||
Field[] om = getOneAndManyField(wrapperClazz); |
|
||||||
if (om == null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
Field one = om[0], many = om[1]; |
|
||||||
try { |
|
||||||
Many m = many.getAnnotation(Many.class); |
|
||||||
Class parentClazz = Class.forName(one.getType().getName()); |
|
||||||
Class childClazz = Class.forName(CommonUtil.getListParamType(many).getName()); |
|
||||||
// 检查表
|
|
||||||
SqlUtil.checkOrCreateTable(db, parentClazz); |
|
||||||
SqlUtil.checkOrCreateTable(db, childClazz); |
|
||||||
final String pTableName = parentClazz.getSimpleName(); |
|
||||||
final String cTableName = childClazz.getSimpleName(); |
|
||||||
List<Field> pColumn = SqlUtil.getAllNotIgnoreField(parentClazz); |
|
||||||
List<Field> cColumn = SqlUtil.getAllNotIgnoreField(childClazz); |
|
||||||
StringBuilder pSb = new StringBuilder(); |
|
||||||
StringBuilder cSb = new StringBuilder(); |
|
||||||
|
|
||||||
if (pColumn != null) { |
|
||||||
pSb.append(pTableName.concat(".rowid AS ").concat(PARENT_COLUMN_ALIAS).concat("rowid,")); |
|
||||||
for (Field f : pColumn) { |
|
||||||
String temp = PARENT_COLUMN_ALIAS.concat(f.getName()); |
|
||||||
pSb.append(pTableName.concat(".").concat(f.getName())) |
|
||||||
.append(" AS ") |
|
||||||
.append(temp) |
|
||||||
.append(","); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (cColumn != null) { |
|
||||||
pSb.append(cTableName.concat(".rowid AS ").concat(CHILD_COLUMN_ALIAS).concat("rowid,")); |
|
||||||
for (Field f : cColumn) { |
|
||||||
String temp = CHILD_COLUMN_ALIAS.concat(f.getName()); |
|
||||||
cSb.append(cTableName.concat(".").concat(f.getName())) |
|
||||||
.append(" AS ") |
|
||||||
.append(temp) |
|
||||||
.append(","); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
String pColumnAlia = pSb.toString(); |
|
||||||
String cColumnAlia = cSb.toString(); |
|
||||||
if (!TextUtils.isEmpty(pColumnAlia)) { |
|
||||||
pColumnAlia = pColumnAlia.substring(0, pColumnAlia.length() - 1); |
|
||||||
} |
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(cColumnAlia)) { |
|
||||||
cColumnAlia = cColumnAlia.substring(0, cColumnAlia.length() - 1); |
|
||||||
} |
|
||||||
|
|
||||||
sb.append("SELECT "); |
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(pColumnAlia)) { |
|
||||||
sb.append(pColumnAlia).append(","); |
|
||||||
} |
|
||||||
if (!TextUtils.isEmpty(cColumnAlia)) { |
|
||||||
sb.append(cColumnAlia); |
|
||||||
} |
|
||||||
if (TextUtils.isEmpty(pColumnAlia) && TextUtils.isEmpty(cColumnAlia)) { |
|
||||||
sb.append(" * "); |
|
||||||
} |
|
||||||
|
|
||||||
sb.append(" FROM ") |
|
||||||
.append(pTableName) |
|
||||||
.append(" INNER JOIN ") |
|
||||||
.append(cTableName) |
|
||||||
.append(" ON ") |
|
||||||
.append(pTableName.concat(".").concat(m.parentColumn())) |
|
||||||
.append(" = ") |
|
||||||
.append(cTableName.concat(".").concat(m.entityColumn())); |
|
||||||
String sql; |
|
||||||
if (expression != null && expression.length > 0) { |
|
||||||
if (!CommonUtil.checkSqlExpression(expression)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
sb.append(" WHERE ").append(expression[0]).append(" "); |
|
||||||
sql = sb.toString(); |
|
||||||
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); |
|
||||||
} else { |
|
||||||
sql = sb.toString(); |
|
||||||
} |
|
||||||
boolean paged = false; |
|
||||||
if (page != -1 && num != -1) { |
|
||||||
paged = true; |
|
||||||
sql = sql.concat(String.format(" Group by %s LIMIT %s,%s", |
|
||||||
pTableName.concat(".").concat(m.parentColumn()), (page - 1) * num, num)); |
|
||||||
} |
|
||||||
Cursor cursor = db.rawQuery(sql, null); |
|
||||||
List<T> data = |
|
||||||
newInstanceEntity(wrapperClazz, parentClazz, childClazz, cursor, pColumn, cColumn, |
|
||||||
paged, db, m.entityColumn(), m.parentColumn()); |
|
||||||
|
|
||||||
closeCursor(cursor); |
|
||||||
return data; |
|
||||||
} catch (ClassNotFoundException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} else { |
|
||||||
ALog.e(TAG, "查询数据失败,实体类没有使用@Wrapper 注解"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建关联查询的数据 |
|
||||||
* |
|
||||||
* @param pColumn 父表的所有字段 |
|
||||||
* @param cColumn 字表的所有字段 |
|
||||||
*/ |
|
||||||
private synchronized <T extends AbsDbWrapper, P extends DbEntity, C extends DbEntity> List<T> newInstanceEntity( |
|
||||||
Class<T> wrapperClazz, Class<P> parentClazz, |
|
||||||
Class<C> childClazz, |
|
||||||
Cursor cursor, |
|
||||||
List<Field> pColumn, List<Field> cColumn, boolean paged, SQLiteDatabase db, |
|
||||||
String entityColumn, String parentColumn) { |
|
||||||
List<T> wrappers = new ArrayList<>(); |
|
||||||
SparseArray<List<DbEntity>> childs = new SparseArray<>(); // 所有子表数据
|
|
||||||
SparseArray<DbEntity> parents = new SparseArray<>(); // 所有父表数据
|
|
||||||
|
|
||||||
try { |
|
||||||
while (cursor.moveToNext()) { |
|
||||||
int pRowId = cursor.getInt(cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat("rowid"))); |
|
||||||
if (childs.get(pRowId) == null) { |
|
||||||
childs.put(pRowId, new ArrayList<DbEntity>()); |
|
||||||
parents.put(pRowId, createParent(pRowId, parentClazz, pColumn, cursor)); |
|
||||||
} |
|
||||||
if (paged) { |
|
||||||
List<C> list = createChildren(db, childClazz, pColumn, entityColumn, parentColumn, |
|
||||||
parents.get(pRowId)); |
|
||||||
if (list != null) { |
|
||||||
childs.get(pRowId).addAll(list); |
|
||||||
} |
|
||||||
} else { |
|
||||||
childs.get(pRowId).add(createChild(childClazz, cColumn, cursor)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
List<Field> wFields = SqlUtil.getAllNotIgnoreField(wrapperClazz); |
|
||||||
if (wFields == null || wFields.isEmpty()) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
for (int i = 0; i < parents.size(); i++) { |
|
||||||
int pRowId = parents.keyAt(i); |
|
||||||
T wrapper = wrapperClazz.newInstance(); |
|
||||||
boolean isPSet = false, isCSet = false; // 保证One 或 Many 只设置一次
|
|
||||||
for (Field f : wFields) { |
|
||||||
if (!isPSet && f.getAnnotation(One.class) != null) { |
|
||||||
f.set(wrapper, parents.get(pRowId)); |
|
||||||
isPSet = true; |
|
||||||
} |
|
||||||
if (!isCSet && f.getAnnotation(Many.class) != null) { |
|
||||||
f.set(wrapper, childs.get(pRowId)); |
|
||||||
isCSet = true; |
|
||||||
} |
|
||||||
} |
|
||||||
wrapper.handleConvert(); //处理下转换
|
|
||||||
wrappers.add(wrapper); |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
|
|
||||||
return wrappers; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建子对象集合 |
|
||||||
*/ |
|
||||||
private <T extends DbEntity> List<T> createChildren(SQLiteDatabase db, Class<T> childClazz, |
|
||||||
List<Field> pColumn, |
|
||||||
String entityColumn, String parentColumn, DbEntity parents) |
|
||||||
throws IllegalAccessException { |
|
||||||
|
|
||||||
for (Field field : pColumn) { |
|
||||||
field.setAccessible(true); |
|
||||||
if (field.getName().equals(parentColumn)) { |
|
||||||
Object o = field.get(parents); |
|
||||||
if (o instanceof String) { |
|
||||||
o = URLEncoder.encode((String) o); |
|
||||||
} |
|
||||||
return findData(db, childClazz, entityColumn + "='" + o + "'"); |
|
||||||
} |
|
||||||
} |
|
||||||
return new ArrayList<T>(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建子对象 |
|
||||||
*/ |
|
||||||
private <T extends DbEntity> T createChild(Class<T> childClazz, List<Field> cColumn, |
|
||||||
Cursor cursor) |
|
||||||
throws InstantiationException, IllegalAccessException { |
|
||||||
T child = childClazz.newInstance(); |
|
||||||
child.rowID = cursor.getInt(cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat("rowid"))); |
|
||||||
for (Field field : cColumn) { |
|
||||||
field.setAccessible(true); |
|
||||||
int columnIndex = cursor.getColumnIndex(CHILD_COLUMN_ALIAS.concat(field.getName())); |
|
||||||
setFieldValue(field.getType(), field, columnIndex, cursor, child); |
|
||||||
} |
|
||||||
return child; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 创建父对象 |
|
||||||
*/ |
|
||||||
private <T extends DbEntity> T createParent(int rowId, Class<T> parentClazz, List<Field> pColumn, |
|
||||||
Cursor cursor) |
|
||||||
throws InstantiationException, IllegalAccessException { |
|
||||||
T parent = parentClazz.newInstance(); |
|
||||||
parent.rowID = rowId; |
|
||||||
for (Field field : pColumn) { |
|
||||||
field.setAccessible(true); |
|
||||||
int columnIndex = cursor.getColumnIndex(PARENT_COLUMN_ALIAS.concat(field.getName())); |
|
||||||
setFieldValue(field.getType(), field, columnIndex, cursor, parent); |
|
||||||
} |
|
||||||
return parent; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 条件查寻数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findData(SQLiteDatabase db, Class<T> clazz, String... expression) { |
|
||||||
db = checkDb(db); |
|
||||||
if (!CommonUtil.checkSqlExpression(expression)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
String sql = String.format("SELECT rowid, * FROM %s WHERE %s", CommonUtil.getClassName(clazz), |
|
||||||
expression[0]); |
|
||||||
String[] params = new String[expression.length - 1]; |
|
||||||
try { |
|
||||||
// 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450
|
|
||||||
System.arraycopy(expression, 1, params, 0, params.length); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
return exeNormalDataSql(db, clazz, sql, params); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取分页数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findData(SQLiteDatabase db, Class<T> clazz, int page, int num, |
|
||||||
String... expression) { |
|
||||||
if (page < 1 || num < 1) { |
|
||||||
ALog.w(TAG, "page, bum 小于1"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
db = checkDb(db); |
|
||||||
if (!CommonUtil.checkSqlExpression(expression)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", |
|
||||||
CommonUtil.getClassName(clazz), |
|
||||||
expression[0], (page - 1) * num, num); |
|
||||||
|
|
||||||
String[] params = new String[expression.length - 1]; |
|
||||||
try { |
|
||||||
// 处理系统出现的问题:https://github.com/AriaLyy/Aria/issues/450
|
|
||||||
System.arraycopy(expression, 1, params, 0, params.length); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
return exeNormalDataSql(db, clazz, sql, params); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 模糊查寻数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findDataByFuzzy(SQLiteDatabase db, Class<T> clazz, |
|
||||||
String conditions) { |
|
||||||
db = checkDb(db); |
|
||||||
if (TextUtils.isEmpty(conditions)) { |
|
||||||
throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); |
|
||||||
} |
|
||||||
if (!conditions.toUpperCase().contains("LIKE")) { |
|
||||||
throw new IllegalArgumentException("sql语句表达式未包含LIEK"); |
|
||||||
} |
|
||||||
String sql = String.format("SELECT rowid, * FROM %s, WHERE %s", CommonUtil.getClassName(clazz), |
|
||||||
conditions); |
|
||||||
return exeNormalDataSql(db, clazz, sql, null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 分页、模糊搜索数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findDataByFuzzy(SQLiteDatabase db, Class<T> clazz, |
|
||||||
int page, int num, String conditions) { |
|
||||||
if (page < 1 || num < 1) { |
|
||||||
ALog.w(TAG, "page, bum 小于1"); |
|
||||||
return null; |
|
||||||
} |
|
||||||
db = checkDb(db); |
|
||||||
if (TextUtils.isEmpty(conditions)) { |
|
||||||
throw new IllegalArgumentException("sql语句表达式不能为null或\"\""); |
|
||||||
} |
|
||||||
if (!conditions.toUpperCase().contains("LIKE")) { |
|
||||||
throw new IllegalArgumentException("sql语句表达式未包含LIEK"); |
|
||||||
} |
|
||||||
String sql = String.format("SELECT rowid, * FROM %s WHERE %s LIMIT %s,%s", |
|
||||||
CommonUtil.getClassName(clazz), conditions, (page - 1) * num, num); |
|
||||||
return exeNormalDataSql(db, clazz, sql, null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查找表的所有数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) { |
|
||||||
db = checkDb(db); |
|
||||||
String sql = String.format("SELECT rowid, * FROM %s", CommonUtil.getClassName(clazz)); |
|
||||||
return exeNormalDataSql(db, clazz, sql, null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 执行查询普通数据的sql语句,并创建对象 |
|
||||||
* |
|
||||||
* @param sql sql 查询语句 |
|
||||||
* @param selectionArgs 查询参数,如何sql语句中查询条件含有'?'则该参数不能为空 |
|
||||||
*/ |
|
||||||
private <T extends DbEntity> List<T> exeNormalDataSql(SQLiteDatabase db, Class<T> clazz, |
|
||||||
String sql, String[] selectionArgs) { |
|
||||||
SqlUtil.checkOrCreateTable(db, clazz); |
|
||||||
Cursor cursor; |
|
||||||
try { |
|
||||||
if (selectionArgs != null) { |
|
||||||
String[] temp = new String[selectionArgs.length]; |
|
||||||
int i = 0; |
|
||||||
for (String arg : selectionArgs) { |
|
||||||
temp[i] = SqlUtil.encodeStr(arg); |
|
||||||
i++; |
|
||||||
} |
|
||||||
//sql执行失败 android.database.sqlite.SQLiteException: no such column: filePath 异常
|
|
||||||
cursor = db.rawQuery(sql, temp); |
|
||||||
} else { |
|
||||||
cursor = db.rawQuery(sql, null); |
|
||||||
} |
|
||||||
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; |
|
||||||
closeCursor(cursor); |
|
||||||
return data; |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据数据游标创建一个具体的对象 |
|
||||||
*/ |
|
||||||
private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, |
|
||||||
Cursor cursor) { |
|
||||||
List<Field> fields = CommonUtil.getAllFields(clazz); |
|
||||||
List<T> entitys = new ArrayList<>(); |
|
||||||
if (fields != null && fields.size() > 0) { |
|
||||||
try { |
|
||||||
while (cursor.moveToNext()) { |
|
||||||
T entity = clazz.newInstance(); |
|
||||||
String primaryName = ""; |
|
||||||
for (Field field : fields) { |
|
||||||
field.setAccessible(true); |
|
||||||
if (SqlUtil.isIgnore(field)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
Class<?> type = field.getType(); |
|
||||||
if (SqlUtil.isPrimary(field) && (type == int.class || type == Integer.class)) { |
|
||||||
primaryName = field.getName(); |
|
||||||
} |
|
||||||
|
|
||||||
int column = cursor.getColumnIndex(field.getName()); |
|
||||||
if (column == -1) continue; |
|
||||||
setFieldValue(type, field, column, cursor, entity); |
|
||||||
} |
|
||||||
//当设置了主键,而且主键的类型为integer时,查询RowID等于主键
|
|
||||||
entity.rowID = cursor.getInt( |
|
||||||
cursor.getColumnIndex(TextUtils.isEmpty(primaryName) ? "rowid" : primaryName)); |
|
||||||
//mDataCache.put(getCacheKey(entity), entity);
|
|
||||||
entitys.add(entity); |
|
||||||
} |
|
||||||
closeCursor(cursor); |
|
||||||
} catch (InstantiationException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
return entitys; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置字段的值 |
|
||||||
* |
|
||||||
* @throws IllegalAccessException |
|
||||||
*/ |
|
||||||
private void setFieldValue(Class type, Field field, int columnIndex, Cursor cursor, |
|
||||||
DbEntity entity) |
|
||||||
throws IllegalAccessException { |
|
||||||
if (cursor == null || cursor.isClosed()) { |
|
||||||
ALog.e(TAG, "cursor没有初始化"); |
|
||||||
return; |
|
||||||
} |
|
||||||
if (type == String.class) { |
|
||||||
String temp = cursor.getString(columnIndex); |
|
||||||
if (!TextUtils.isEmpty(temp)) { |
|
||||||
field.set(entity, URLDecoder.decode(temp)); |
|
||||||
} |
|
||||||
} else if (type == int.class || type == Integer.class) { |
|
||||||
field.setInt(entity, cursor.getInt(columnIndex)); |
|
||||||
} else if (type == float.class || type == Float.class) { |
|
||||||
field.setFloat(entity, cursor.getFloat(columnIndex)); |
|
||||||
} else if (type == double.class || type == Double.class) { |
|
||||||
field.setDouble(entity, cursor.getDouble(columnIndex)); |
|
||||||
} else if (type == long.class || type == Long.class) { |
|
||||||
field.setLong(entity, cursor.getLong(columnIndex)); |
|
||||||
} else if (type == boolean.class || type == Boolean.class) { |
|
||||||
String temp = cursor.getString(columnIndex); |
|
||||||
if (TextUtils.isEmpty(temp)) { |
|
||||||
field.setBoolean(entity, false); |
|
||||||
} else { |
|
||||||
field.setBoolean(entity, !temp.equalsIgnoreCase("false")); |
|
||||||
} |
|
||||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) { |
|
||||||
field.set(entity, new Date(URLDecoder.decode(cursor.getString(columnIndex)))); |
|
||||||
} else if (type == byte[].class) { |
|
||||||
field.set(entity, cursor.getBlob(columnIndex)); |
|
||||||
} else if (type == Map.class) { |
|
||||||
String temp = cursor.getString(columnIndex); |
|
||||||
if (!TextUtils.isEmpty(temp)) { |
|
||||||
field.set(entity, SqlUtil.str2Map(URLDecoder.decode(temp))); |
|
||||||
} |
|
||||||
} else if (type == List.class) { |
|
||||||
String value = cursor.getString(columnIndex); |
|
||||||
if (!TextUtils.isEmpty(value)) { |
|
||||||
field.set(entity, SqlUtil.str2List(URLDecoder.decode(value), field)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取所在行Id |
|
||||||
*/ |
|
||||||
int[] getRowId(SQLiteDatabase db, Class clazz) { |
|
||||||
db = checkDb(db); |
|
||||||
Cursor cursor = db.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null); |
|
||||||
int[] ids = new int[cursor.getCount()]; |
|
||||||
int i = 0; |
|
||||||
while (cursor.moveToNext()) { |
|
||||||
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid")); |
|
||||||
i++; |
|
||||||
} |
|
||||||
cursor.close(); |
|
||||||
return ids; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取行Id |
|
||||||
*/ |
|
||||||
int getRowId(SQLiteDatabase db, Class clazz, Object[] wheres, Object[] values) { |
|
||||||
db = checkDb(db); |
|
||||||
if (wheres.length <= 0 || values.length <= 0) { |
|
||||||
ALog.e(TAG, "请输入删除条件"); |
|
||||||
return -1; |
|
||||||
} else if (wheres.length != values.length) { |
|
||||||
ALog.e(TAG, "groupHash 和 vaule 长度不相等"); |
|
||||||
return -1; |
|
||||||
} |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE "); |
|
||||||
int i = 0; |
|
||||||
for (Object where : wheres) { |
|
||||||
sb.append(where).append("=").append("'").append(values[i]).append("'"); |
|
||||||
sb.append(i >= wheres.length - 1 ? "" : ","); |
|
||||||
i++; |
|
||||||
} |
|
||||||
Cursor c = db.rawQuery(sb.toString(), null); |
|
||||||
int id = c.getColumnIndex("rowid"); |
|
||||||
c.close(); |
|
||||||
return id; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 通过rowId判断数据是否存在 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> boolean itemExist(SQLiteDatabase db, Class<T> clazz, long rowId) { |
|
||||||
return itemExist(db, CommonUtil.getClassName(clazz), rowId); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 通过rowId判断数据是否存在 |
|
||||||
*/ |
|
||||||
boolean itemExist(SQLiteDatabase db, String tableName, long rowId) { |
|
||||||
db = checkDb(db); |
|
||||||
String sql = "SELECT rowid FROM " + tableName + " WHERE rowid=" + rowId; |
|
||||||
Cursor cursor = db.rawQuery(sql, null); |
|
||||||
boolean isExist = cursor.getCount() > 0; |
|
||||||
cursor.close(); |
|
||||||
return isExist; |
|
||||||
} |
|
||||||
} |
|
@ -1,69 +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.util.SparseArray; |
|
||||||
import java.lang.reflect.Constructor; |
|
||||||
import java.lang.reflect.InvocationTargetException; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/22. |
|
||||||
* Delegate管理器 |
|
||||||
*/ |
|
||||||
class DelegateManager { |
|
||||||
private final String TAG = "ModuleFactory"; |
|
||||||
|
|
||||||
private SparseArray<AbsDelegate> mDelegates = new SparseArray<>(); |
|
||||||
private static volatile DelegateManager INSTANCE = null; |
|
||||||
|
|
||||||
private DelegateManager() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
static DelegateManager getInstance() { |
|
||||||
if (INSTANCE == null) { |
|
||||||
synchronized (DelegateManager.class) { |
|
||||||
INSTANCE = new DelegateManager(); |
|
||||||
} |
|
||||||
} |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取Module |
|
||||||
*/ |
|
||||||
<M extends AbsDelegate> M getDelegate(Class<M> clazz) { |
|
||||||
M delegate = (M) mDelegates.get(clazz.hashCode()); |
|
||||||
try { |
|
||||||
if (delegate == null) { |
|
||||||
Constructor c = clazz.getDeclaredConstructor(); |
|
||||||
c.setAccessible(true); |
|
||||||
delegate = (M) c.newInstance(); |
|
||||||
mDelegates.put(clazz.hashCode(), delegate); |
|
||||||
return delegate; |
|
||||||
} |
|
||||||
} catch (InstantiationException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} catch (IllegalAccessException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} catch (NoSuchMethodException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} catch (InvocationTargetException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
return delegate; |
|
||||||
} |
|
||||||
} |
|
@ -1,58 +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.content.ContentValues; |
|
||||||
import android.content.Context; |
|
||||||
import android.net.Uri; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/22. 增加数据、更新数据 |
|
||||||
*/ |
|
||||||
class DelegateUpdate extends AbsDelegate { |
|
||||||
private DelegateUpdate() { |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 修改某行数据 |
|
||||||
*/ |
|
||||||
synchronized void updateData(Context context, DbEntity dbEntity) { |
|
||||||
Uri uri = DbContentProvider.Companion.createRequestUrl(context, dbEntity.getClass()); |
|
||||||
ContentValues values = DbUtil.INSTANCE.createValues(dbEntity); |
|
||||||
if (values != null) { |
|
||||||
int rowId = context.getContentResolver() |
|
||||||
.update(uri, values, "rowid=?", new String[] { String.valueOf(dbEntity.rowID) }); |
|
||||||
if (rowId != -1) { |
|
||||||
ALog.d(TAG, "更新数据成功,rowid = " + rowId); |
|
||||||
} else { |
|
||||||
ALog.e(TAG, "更新数据成功,rowid = " + rowId); |
|
||||||
} |
|
||||||
return; |
|
||||||
} |
|
||||||
ALog.e(TAG, "更新记录失败,记录没有属性字段"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 更新多条记录 |
|
||||||
*/ |
|
||||||
synchronized <T extends DbEntity> void updateManyData(Context context, List<T> dbEntities) { |
|
||||||
for (DbEntity entity : dbEntities) { |
|
||||||
updateData(context, entity); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,213 +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.content.Context; |
|
||||||
import android.database.sqlite.SQLiteDatabase; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/2/11. 数据库操作工具 |
|
||||||
*/ |
|
||||||
public class DelegateWrapper { |
|
||||||
private static final String TAG = "DelegateWrapper"; |
|
||||||
private volatile static DelegateWrapper INSTANCE = null; |
|
||||||
|
|
||||||
private SQLiteDatabase mDb; |
|
||||||
private DelegateManager mDManager; |
|
||||||
private Context context; |
|
||||||
|
|
||||||
private DelegateWrapper() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private DelegateWrapper(Context context) { |
|
||||||
this.context = context.getApplicationContext(); |
|
||||||
SqlHelper helper = SqlHelper.init(context.getApplicationContext()); |
|
||||||
mDb = helper.getDb(); |
|
||||||
mDManager = DelegateManager.getInstance(); |
|
||||||
} |
|
||||||
|
|
||||||
public static DelegateWrapper init(Context context) { |
|
||||||
if (INSTANCE == null) { |
|
||||||
synchronized (DelegateWrapper.class) { |
|
||||||
if (INSTANCE == null) { |
|
||||||
INSTANCE = new DelegateWrapper(context); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
static DelegateWrapper getInstance() { |
|
||||||
if (INSTANCE == null) { |
|
||||||
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册"); |
|
||||||
} |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询关联表数据 |
|
||||||
* |
|
||||||
* @param expression 查询条件 |
|
||||||
*/ |
|
||||||
<T extends AbsDbWrapper> List<T> findRelationData(Class<T> clazz, String... expression) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).findRelationData(mDb, clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查询关联表数据 |
|
||||||
* |
|
||||||
* @param expression 查询条件 |
|
||||||
*/ |
|
||||||
<T extends AbsDbWrapper> List<T> findRelationData(Class<T> clazz, int page, int num, |
|
||||||
String... expression) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class) |
|
||||||
.findRelationData(mDb, clazz, page, num, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 检查某个字段的值是否存在 |
|
||||||
* |
|
||||||
* @param expression 字段和值"url=xxx" |
|
||||||
* @return {@code true}该字段的对应的value已存在 |
|
||||||
*/ |
|
||||||
boolean checkDataExist(Class clazz, String... expression) { |
|
||||||
return SqlUtil.checkDataExist(mDb, clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 清空表数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> void clean(Class<T> clazz) { |
|
||||||
SqlUtil.clean(mDb, clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 执行sql语句 |
|
||||||
*/ |
|
||||||
void exeSql(String sql) { |
|
||||||
mDb.execSQL(sql); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除某条数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> void delData(Class<T> clazz, String... expression) { |
|
||||||
mDManager.getDelegate(DelegateDel.class).delData(context, clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 修改某行数据 |
|
||||||
*/ |
|
||||||
void updateData(DbEntity dbEntity) { |
|
||||||
mDManager.getDelegate(DelegateUpdate.class).updateData(context, dbEntity); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 更新多条数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> void updateManyData(List<T> dbEntitys) { |
|
||||||
mDManager.getDelegate(DelegateUpdate.class).updateManyData(context, dbEntitys); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 遍历所有数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findAllData(Class<T> clazz) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).findAllData(mDb, clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 条件查寻数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findData(Class<T> clazz, String... expression) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).findData(mDb, clazz, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取分页数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findData(Class<T> clazz, int page, int num, String... expression) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).findData(mDb, clazz, page, num, expression); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 模糊查寻数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findDataByFuzzy(Class<T> clazz, String conditions) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).findDataByFuzzy(mDb, clazz, conditions); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 模糊查寻数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> List<T> findDataByFuzzy(Class<T> clazz, int page, int num, |
|
||||||
String conditions) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class) |
|
||||||
.findDataByFuzzy(mDb, clazz, page, num, conditions); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 通过rowId判断数据是否存在 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> boolean isExist(Class<T> clazz, long rowId) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, clazz, rowId); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 通过rowId判断数据是否存在 |
|
||||||
*/ |
|
||||||
boolean isExist(String tableName, long rowId) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).itemExist(mDb, tableName, rowId); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 插入数据 |
|
||||||
*/ |
|
||||||
void insertData(DbEntity dbEntity) { |
|
||||||
mDManager.getDelegate(DelegateInsert.class).insertData(context, dbEntity); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 插入多条数据 |
|
||||||
*/ |
|
||||||
<T extends DbEntity> void insertManyData(List<T> dbEntitys) { |
|
||||||
mDManager.getDelegate(DelegateInsert.class).insertManyData(context, dbEntitys); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 查找某张表是否存在 |
|
||||||
*/ |
|
||||||
public boolean tableExists(Class clazz) { |
|
||||||
return SqlUtil.tableExists(mDb, clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取所在行Id |
|
||||||
*/ |
|
||||||
int[] getRowId(Class clazz) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取行Id |
|
||||||
*/ |
|
||||||
int getRowId(Class clazz, Object[] wheres, Object[] values) { |
|
||||||
return mDManager.getDelegate(DelegateFind.class).getRowId(mDb, clazz, wheres, values); |
|
||||||
} |
|
||||||
} |
|
@ -1,552 +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.content.Context; |
|
||||||
import android.database.Cursor; |
|
||||||
import android.database.sqlite.SQLiteDatabase; |
|
||||||
import android.database.sqlite.SQLiteOpenHelper; |
|
||||||
import android.os.Build; |
|
||||||
import android.text.TextUtils; |
|
||||||
import com.arialyy.aria.core.TaskRecord; |
|
||||||
import com.arialyy.aria.core.ThreadRecord; |
|
||||||
import com.arialyy.aria.core.download.DownloadEntity; |
|
||||||
import com.arialyy.aria.core.download.M3U8Entity; |
|
||||||
import com.arialyy.aria.core.upload.UploadEntity; |
|
||||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; |
|
||||||
import com.arialyy.aria.util.ALog; |
|
||||||
import java.io.File; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* sql帮助类 |
|
||||||
*/ |
|
||||||
final class SqlHelper extends SQLiteOpenHelper { |
|
||||||
private static final String TAG = "SqlHelper"; |
|
||||||
private static volatile SqlHelper INSTANCE = null; |
|
||||||
private static boolean mainTmpDirSet = false; |
|
||||||
private Context mContext; |
|
||||||
|
|
||||||
synchronized static SqlHelper init(Context context) { |
|
||||||
if (INSTANCE == null) { |
|
||||||
synchronized (SqlHelper.class) { |
|
||||||
INSTANCE = new SqlHelper(context.getApplicationContext()); |
|
||||||
} |
|
||||||
} |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
static SqlHelper getInstance() { |
|
||||||
return INSTANCE; |
|
||||||
} |
|
||||||
|
|
||||||
private SqlHelper(Context context) { |
|
||||||
super(DBConfig.SAVE_IN_SDCARD ? new DatabaseContext(context) : context, DBConfig.DB_NAME, null, |
|
||||||
DBConfig.VERSION); |
|
||||||
mContext = context; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onOpen(SQLiteDatabase db) { |
|
||||||
super.onOpen(db); |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onConfigure(SQLiteDatabase db) { |
|
||||||
super.onConfigure(db); |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
|
||||||
db.setForeignKeyConstraintsEnabled(true); |
|
||||||
} else { |
|
||||||
// SQLite在3.6.19版本中开始支持外键约束,
|
|
||||||
// 而在Android中 2.1以前的版本使用的SQLite版本是3.5.9, 在2.2版本中使用的是3.6.22.
|
|
||||||
// 但是为了兼容以前的程序,默认并没有启用该功能,如果要启用该功能
|
|
||||||
// 需要使用如下语句:
|
|
||||||
db.execSQL("PRAGMA foreign_keys=ON;"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onCreate(SQLiteDatabase db) { |
|
||||||
Set<String> tables = DBConfig.mapping.keySet(); |
|
||||||
for (String tableName : tables) { |
|
||||||
Class clazz = DBConfig.mapping.get(tableName); |
|
||||||
if (!SqlUtil.tableExists(db, clazz)) { |
|
||||||
SqlUtil.createTable(db, clazz); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
|
||||||
if (oldVersion < newVersion) { |
|
||||||
if (oldVersion < 31) { |
|
||||||
handleLowAriaUpdate(db); |
|
||||||
} else if (oldVersion < 45) { |
|
||||||
handle360AriaUpdate(db); |
|
||||||
} else if (oldVersion < 51) { |
|
||||||
handle365Update(db); |
|
||||||
} else if (oldVersion < 53) { |
|
||||||
handle366Update(db); |
|
||||||
} else { |
|
||||||
handleDbUpdate(db, null); |
|
||||||
} |
|
||||||
// 处理380版本TaskRecord 增加的记录类型判断
|
|
||||||
if (newVersion == 57) { |
|
||||||
addTaskRecordType(db); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
|
||||||
if (oldVersion > newVersion) { |
|
||||||
handleDbUpdate(db, null); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取数据库连接 |
|
||||||
*/ |
|
||||||
SQLiteDatabase getDb() { |
|
||||||
SQLiteDatabase db; |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { |
|
||||||
SQLiteDatabase.OpenParams params = new SQLiteDatabase.OpenParams.Builder().setOpenFlags( |
|
||||||
SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READWRITE | |
|
||||||
SQLiteDatabase.CREATE_IF_NECESSARY).build(); |
|
||||||
setOpenParams(params); |
|
||||||
db = getWritableDatabase(); |
|
||||||
} else { |
|
||||||
//SQLiteDatabase.openOrCreateDatabase()
|
|
||||||
File dbFile = mContext.getDatabasePath(DBConfig.DB_NAME); |
|
||||||
if (!dbFile.exists()) { |
|
||||||
db = getWritableDatabase(); |
|
||||||
} else { |
|
||||||
// 触发一次SQLiteOpenHelper的流程,再使用NO_LOCALIZED_COLLATORS标志打开数据库
|
|
||||||
db = getReadableDatabase(); |
|
||||||
db.close(); |
|
||||||
db = SQLiteDatabase.openDatabase(dbFile.getPath(), null, |
|
||||||
SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READWRITE | |
|
||||||
SQLiteDatabase.CREATE_IF_NECESSARY); |
|
||||||
} |
|
||||||
} |
|
||||||
db.enableWriteAheadLogging(); |
|
||||||
return db; |
|
||||||
} |
|
||||||
|
|
||||||
@Override public SQLiteDatabase getWritableDatabase() { |
|
||||||
if (!mainTmpDirSet) { |
|
||||||
createDbCacheDir(); |
|
||||||
return super.getWritableDatabase(); |
|
||||||
} |
|
||||||
return super.getWritableDatabase(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 用于修复 Too many open files 的问题 |
|
||||||
* https://github.com/AriaLyy/Aria/issues/664
|
|
||||||
*/ |
|
||||||
@Override |
|
||||||
public SQLiteDatabase getReadableDatabase() { |
|
||||||
if (!mainTmpDirSet) { |
|
||||||
createDbCacheDir(); |
|
||||||
return super.getReadableDatabase(); |
|
||||||
} |
|
||||||
return super.getReadableDatabase(); |
|
||||||
} |
|
||||||
|
|
||||||
private void createDbCacheDir() { |
|
||||||
String cacheDir = mContext.getCacheDir().getPath() + "/AriaDbCacheDir"; |
|
||||||
File cacheFile = new File(cacheDir); |
|
||||||
if (!cacheFile.exists()){ |
|
||||||
boolean rs = cacheFile.mkdirs(); |
|
||||||
ALog.d(TAG, rs + ""); |
|
||||||
} |
|
||||||
super.getReadableDatabase() |
|
||||||
.execSQL("PRAGMA temp_store_directory = '" + cacheDir + "'"); |
|
||||||
mainTmpDirSet = true; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理数据库升级 |
|
||||||
* |
|
||||||
* @param modifyColumns 需要修改的表字段的映射,key为表名, |
|
||||||
* value{@code Map<String, String>}中的Map的key为老字段名称,value为该老字段对应的新字段名称 |
|
||||||
*/ |
|
||||||
private void handleDbUpdate(SQLiteDatabase db, Map<String, Map<String, String>> modifyColumns) { |
|
||||||
if (db == null) { |
|
||||||
ALog.e("SqlHelper", "db 为 null"); |
|
||||||
return; |
|
||||||
} else if (!db.isOpen()) { |
|
||||||
ALog.e("SqlHelper", "db已关闭"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
db.beginTransaction(); |
|
||||||
Set<String> tables = DBConfig.mapping.keySet(); |
|
||||||
for (String tableName : tables) { |
|
||||||
Class<? extends DbEntity> clazz = DBConfig.mapping.get(tableName); |
|
||||||
if (SqlUtil.tableExists(db, clazz)) { |
|
||||||
// ----------- 1、获取旧表字段、新表字段
|
|
||||||
Cursor columnC = |
|
||||||
db.rawQuery(String.format("PRAGMA table_info(%s)", tableName), null); |
|
||||||
|
|
||||||
// 获取新表的所有字段名称
|
|
||||||
List<String> newTabColumns = SqlUtil.getColumns(clazz); |
|
||||||
// 获取旧表的所有字段名称
|
|
||||||
List<String> oldTabColumns = new ArrayList<>(); |
|
||||||
|
|
||||||
while (columnC.moveToNext()) { |
|
||||||
String columnName = columnC.getString(columnC.getColumnIndex("name")); |
|
||||||
oldTabColumns.add(columnName); |
|
||||||
} |
|
||||||
columnC.close(); |
|
||||||
|
|
||||||
// ----------- 2、为防止字段增加失败的情况,先给旧表增加字段
|
|
||||||
List<String> newAddColum = getNewColumn(newTabColumns, oldTabColumns); |
|
||||||
// 删除重命名的字段
|
|
||||||
Map<String, String> modifyMap = null; |
|
||||||
if (modifyColumns != null) { |
|
||||||
modifyMap = modifyColumns.get(tableName); |
|
||||||
if (modifyMap != null) { |
|
||||||
Iterator<String> it = newAddColum.iterator(); |
|
||||||
while (it.hasNext()) { |
|
||||||
String s = it.next(); |
|
||||||
if (modifyMap.get(s) != null) { |
|
||||||
it.remove(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 给旧表增加字段,防止新增字段失败
|
|
||||||
if (newAddColum.size() > 0) { |
|
||||||
String sql = "ALTER TABLE %s ADD COLUMN %s %s"; |
|
||||||
for (String nc : newAddColum) { |
|
||||||
String temp = |
|
||||||
String.format(sql, tableName, nc, SqlUtil.getColumnTypeByFieldName(clazz, nc)); |
|
||||||
ALog.d(TAG, "添加表字段的sql:" + temp); |
|
||||||
db.execSQL(temp); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// ----------- 3、将旧表备份下,并创建新表
|
|
||||||
String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName); |
|
||||||
db.execSQL(alertSql); |
|
||||||
|
|
||||||
//创建新表
|
|
||||||
SqlUtil.createTable(db, clazz); |
|
||||||
|
|
||||||
String sql = String.format("SELECT COUNT(*) FROM %s_temp", tableName); |
|
||||||
Cursor cursor = db.rawQuery(sql, null); |
|
||||||
cursor.moveToFirst(); |
|
||||||
long count = cursor.getLong(0); |
|
||||||
cursor.close(); |
|
||||||
|
|
||||||
// ----------- 4、将旧表数据复制到新表
|
|
||||||
if (count > 0) { |
|
||||||
|
|
||||||
// 旧表需要删除的字段,删除旧表有而新表没的字段
|
|
||||||
List<String> diffTab = getDiffColumn(newTabColumns, oldTabColumns); |
|
||||||
StringBuilder params = new StringBuilder(); |
|
||||||
|
|
||||||
// 需要修改的列名映射表
|
|
||||||
//Map<String, String> modifyMap = null;
|
|
||||||
if (modifyColumns != null) { |
|
||||||
modifyMap = modifyColumns.get(tableName); |
|
||||||
} |
|
||||||
|
|
||||||
for (String column : oldTabColumns) { |
|
||||||
if (!diffTab.isEmpty() && diffTab.contains(column) |
|
||||||
// 如果旧表字段有修改,忽略这个删除
|
|
||||||
&& !(modifyMap != null && modifyMap.containsKey(column))) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
params.append(column).append(","); |
|
||||||
} |
|
||||||
|
|
||||||
String oldParamStr = params.toString(); |
|
||||||
oldParamStr = oldParamStr.substring(0, oldParamStr.length() - 1); |
|
||||||
String newParamStr = oldParamStr; |
|
||||||
// 处理字段名称改变
|
|
||||||
if (modifyMap != null && !modifyMap.isEmpty()) { |
|
||||||
Set<String> keys = modifyMap.keySet(); |
|
||||||
for (String key : keys) { |
|
||||||
if (newParamStr.contains(key)) { |
|
||||||
newParamStr = newParamStr.replace(key, modifyMap.get(key)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//恢复数据
|
|
||||||
String insertSql = |
|
||||||
String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr, |
|
||||||
oldParamStr, tableName); |
|
||||||
ALog.d(TAG, "恢复数据的sql:" + insertSql); |
|
||||||
|
|
||||||
db.execSQL(insertSql); |
|
||||||
} |
|
||||||
// ----------- 5、删除备份的表
|
|
||||||
SqlUtil.dropTable(db, tableName + "_temp"); |
|
||||||
} else { |
|
||||||
SqlUtil.createTable(db, clazz); |
|
||||||
} |
|
||||||
} |
|
||||||
db.setTransactionSuccessful(); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
db.endTransaction(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 取新表差值(需要删除的字段):旧表有而新表没的字段 |
|
||||||
* |
|
||||||
* @param newTab 新表字段 |
|
||||||
* @param oldTab 旧表字段 |
|
||||||
* @return 旧表有而新表没的字段 |
|
||||||
*/ |
|
||||||
private List<String> getDiffColumn(List<String> newTab, List<String> oldTab) { |
|
||||||
List<String> temp = new ArrayList<>(oldTab); // 拷贝旧表字段
|
|
||||||
temp.removeAll(newTab); |
|
||||||
return temp; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取新增字段 |
|
||||||
* |
|
||||||
* @param newTab 新表字段 |
|
||||||
* @param oldTab 就表字段 |
|
||||||
* @return 新表有而旧表没的字段 |
|
||||||
*/ |
|
||||||
private List<String> getNewColumn(List<String> newTab, List<String> oldTab) { |
|
||||||
List<String> temp = new ArrayList<>(newTab); |
|
||||||
temp.removeAll(oldTab); |
|
||||||
return temp; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 给TaskRecord 增加任务类型 |
|
||||||
*/ |
|
||||||
private void addTaskRecordType(SQLiteDatabase db) { |
|
||||||
try { |
|
||||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class); |
|
||||||
SqlUtil.checkOrCreateTable(db, TaskRecord.class); |
|
||||||
SqlUtil.checkOrCreateTable(db, UploadEntity.class); |
|
||||||
SqlUtil.checkOrCreateTable(db, DownloadEntity.class); |
|
||||||
|
|
||||||
db.beginTransaction(); |
|
||||||
/* |
|
||||||
* 增加下载实体的类型 |
|
||||||
*/ |
|
||||||
String dSql = "SELECT downloadPath, url FROM DownloadEntity"; |
|
||||||
Cursor c = db.rawQuery(dSql, null); |
|
||||||
while (c.moveToNext()) { |
|
||||||
int type; |
|
||||||
String filePath = c.getString(0); |
|
||||||
String url = c.getString(1); |
|
||||||
if (url.startsWith("ftp") || url.startsWith("sftp")) { |
|
||||||
type = ITaskWrapper.D_FTP; |
|
||||||
} else { |
|
||||||
if (SqlUtil.tableExists(db, M3U8Entity.class)) { |
|
||||||
Cursor m3u8c = db.rawQuery("SELECT isLive FROM M3U8Entity WHERE filePath=\"" |
|
||||||
+ SqlUtil.encodeStr(filePath) |
|
||||||
+ "\"", null); |
|
||||||
if (m3u8c.moveToNext()) { |
|
||||||
String temp = m3u8c.getString(0); |
|
||||||
type = |
|
||||||
(TextUtils.isEmpty(temp) ? false : Boolean.valueOf(temp)) ? ITaskWrapper.M3U8_LIVE |
|
||||||
: ITaskWrapper.M3U8_VOD; |
|
||||||
} else { |
|
||||||
type = ITaskWrapper.D_HTTP; |
|
||||||
} |
|
||||||
m3u8c.close(); |
|
||||||
} else { |
|
||||||
type = ITaskWrapper.D_HTTP; |
|
||||||
} |
|
||||||
} |
|
||||||
db.execSQL("UPDATE DownloadEntity SET taskType=? WHERE downloadPath=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
db.execSQL("UPDATE TaskRecord SET taskType=? WHERE filePath=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
db.execSQL("UPDATE ThreadRecord SET threadType=? WHERE taskKey=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
} |
|
||||||
c.close(); |
|
||||||
|
|
||||||
/* |
|
||||||
* 增加上传实体的类型 |
|
||||||
*/ |
|
||||||
String uSql = "SELECT filePath, url FROM UploadEntity"; |
|
||||||
c = db.rawQuery(uSql, null); |
|
||||||
while (c.moveToNext()) { |
|
||||||
int type; |
|
||||||
String filePath = c.getString(c.getColumnIndex("filePath")); |
|
||||||
String url = c.getString(c.getColumnIndex("url")); |
|
||||||
if (url.startsWith("ftp") || url.startsWith("sftp")) { |
|
||||||
type = ITaskWrapper.D_FTP; |
|
||||||
} else { |
|
||||||
type = ITaskWrapper.D_HTTP; |
|
||||||
} |
|
||||||
db.execSQL("UPDATE UploadEntity SET taskType=? WHERE filePath=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
db.execSQL("UPDATE TaskRecord SET taskType=? WHERE filePath=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
db.execSQL("UPDATE ThreadRecord SET threadType=? WHERE taskKey=?", |
|
||||||
new Object[] { type, filePath }); |
|
||||||
} |
|
||||||
c.close(); |
|
||||||
|
|
||||||
db.setTransactionSuccessful(); |
|
||||||
} finally { |
|
||||||
db.endTransaction(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 删除重复的repeat数据 |
|
||||||
*/ |
|
||||||
private void delRepeatThreadRecord(SQLiteDatabase db) { |
|
||||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class); |
|
||||||
String repeatSql = "DELETE FROM ThreadRecord WHERE (rowid) " |
|
||||||
+ "IN (SELECT rowid FROM ThreadRecord GROUP BY taskKey, threadId, endLocation HAVING COUNT(*) > 1) " |
|
||||||
+ "AND rowid NOT IN (SELECT MIN(rowid) FROM ThreadRecord GROUP BY taskKey, threadId, endLocation HAVING COUNT(*)> 1)"; |
|
||||||
ALog.d(TAG, repeatSql); |
|
||||||
db.execSQL(repeatSql); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理366版本以下的升级 |
|
||||||
*/ |
|
||||||
private void handle366Update(SQLiteDatabase db) { |
|
||||||
Map<String, Map<String, String>> modifyMap = new HashMap<>(); |
|
||||||
// 处理ThreadRecord的key字段名修改
|
|
||||||
Map<String, String> threadRecordModify = new HashMap<>(); |
|
||||||
threadRecordModify.put("key", "taskKey"); |
|
||||||
modifyMap.put("ThreadRecord", threadRecordModify); |
|
||||||
|
|
||||||
// 执行升级操作
|
|
||||||
handleDbUpdate(db, modifyMap); |
|
||||||
delRepeatThreadRecord(db); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理365版本以下的升级 |
|
||||||
*/ |
|
||||||
private void handle365Update(SQLiteDatabase db) { |
|
||||||
SqlUtil.checkOrCreateTable(db, ThreadRecord.class); |
|
||||||
db.execSQL("UPDATE ThreadRecord SET threadId=0 WHERE threadId=-1"); |
|
||||||
|
|
||||||
Map<String, Map<String, String>> modifyMap = new HashMap<>(); |
|
||||||
// 处理ThreadRecord的key字段名修改
|
|
||||||
Map<String, String> threadRecordModify = new HashMap<>(); |
|
||||||
threadRecordModify.put("key", "taskKey"); |
|
||||||
modifyMap.put("ThreadRecord", threadRecordModify); |
|
||||||
|
|
||||||
// 执行升级操作
|
|
||||||
handleDbUpdate(db, modifyMap); |
|
||||||
delRepeatThreadRecord(db); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理3.6以下版本的数据库升级 |
|
||||||
*/ |
|
||||||
private void handle360AriaUpdate(SQLiteDatabase db) { |
|
||||||
String[] taskTables = |
|
||||||
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; |
|
||||||
for (String taskTable : taskTables) { |
|
||||||
if (SqlUtil.tableExists(db, taskTable)) { |
|
||||||
SqlUtil.dropTable(db, taskTable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Map<String, Map<String, String>> modifyMap = new HashMap<>(); |
|
||||||
// 处理DownloadEntity、DownloadGroupEntity的 groupName字段名的修改
|
|
||||||
Map<String, String> entityModify = new HashMap<>(); |
|
||||||
entityModify.put("groupName", "groupHash"); |
|
||||||
modifyMap.put("DownloadEntity", entityModify); |
|
||||||
modifyMap.put("DownloadGroupEntity", entityModify); |
|
||||||
|
|
||||||
// 处理TaskRecord的dGroupName字段名的修改
|
|
||||||
Map<String, String> taskRecordModify = new HashMap<>(); |
|
||||||
taskRecordModify.put("dGroupName", "dGroupHash"); |
|
||||||
modifyMap.put("TaskRecord", taskRecordModify); |
|
||||||
|
|
||||||
// 处理ThreadRecord的key字段名修改
|
|
||||||
Map<String, String> threadRecordModify = new HashMap<>(); |
|
||||||
threadRecordModify.put("key", "taskKey"); |
|
||||||
modifyMap.put("ThreadRecord", threadRecordModify); |
|
||||||
|
|
||||||
// 执行升级操作
|
|
||||||
handleDbUpdate(db, modifyMap); |
|
||||||
delRepeatThreadRecord(db); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 处理低版本的数据库迁移,主要是修改子表外键字段对应的值 |
|
||||||
*/ |
|
||||||
private void handleLowAriaUpdate(SQLiteDatabase db) { |
|
||||||
String[] taskTables = |
|
||||||
new String[] { "UploadTaskEntity", "DownloadTaskEntity", "DownloadGroupTaskEntity" }; |
|
||||||
for (String taskTable : taskTables) { |
|
||||||
if (SqlUtil.tableExists(db, taskTable)) { |
|
||||||
SqlUtil.dropTable(db, taskTable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//删除所有主键为null和主键重复的数据
|
|
||||||
String[] tables = new String[] { "DownloadEntity", "DownloadGroupEntity" }; |
|
||||||
String[] keys = new String[] { "downloadPath", "groupName" }; |
|
||||||
int i = 0; |
|
||||||
for (String tableName : tables) { |
|
||||||
if (!SqlUtil.tableExists(db, tableName)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
String pColumn = keys[i]; |
|
||||||
String nullSql = |
|
||||||
String.format("DELETE FROM %s WHERE %s='' OR %s IS NULL", tableName, pColumn, pColumn); |
|
||||||
ALog.d(TAG, nullSql); |
|
||||||
db.execSQL(nullSql); |
|
||||||
|
|
||||||
//删除所有主键重复的数据
|
|
||||||
String repeatSql = |
|
||||||
String.format( |
|
||||||
"DELETE FROM %s WHERE %s IN(SELECT %s FROM %s GROUP BY %s HAVING COUNT(%s) > 1)", |
|
||||||
tableName, pColumn, pColumn, tableName, pColumn, pColumn); |
|
||||||
|
|
||||||
ALog.d(TAG, repeatSql); |
|
||||||
db.execSQL(repeatSql); |
|
||||||
i++; |
|
||||||
} |
|
||||||
|
|
||||||
// 处理数据库版本小于3的字段改变
|
|
||||||
Map<String, Map<String, String>> modifyMap = new HashMap<>(); |
|
||||||
Map<String, String> dEntityModifyMap = new HashMap<>(); |
|
||||||
dEntityModifyMap.put("groupName", "groupHash"); |
|
||||||
dEntityModifyMap.put("downloadUrl", "url"); |
|
||||||
dEntityModifyMap.put("isDownloadComplete", "isComplete"); |
|
||||||
modifyMap.put("DownloadEntity", dEntityModifyMap); |
|
||||||
|
|
||||||
Map<String, String> dGEntityModifyMap = new HashMap<>(); |
|
||||||
dGEntityModifyMap.put("groupName", "groupHash"); |
|
||||||
modifyMap.put("DownloadGroupEntity", dGEntityModifyMap); |
|
||||||
|
|
||||||
handleDbUpdate(db, modifyMap); |
|
||||||
} |
|
||||||
} |
|
@ -1,590 +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.core.AriaConfig; |
|
||||||
import com.arialyy.aria.orm.annotation.Default; |
|
||||||
import com.arialyy.aria.orm.annotation.Foreign; |
|
||||||
import com.arialyy.aria.orm.annotation.Ignore; |
|
||||||
import com.arialyy.aria.orm.annotation.Many; |
|
||||||
import com.arialyy.aria.orm.annotation.NoNull; |
|
||||||
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; |
|
||||||
import java.net.URLEncoder; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2017/7/24. |
|
||||||
* sql工具 |
|
||||||
*/ |
|
||||||
final class SqlUtil { |
|
||||||
private static final String TAG = CommonUtil.getClassName("SqlUtil"); |
|
||||||
|
|
||||||
/** |
|
||||||
* 检查表是否存在,不存在则创建表 |
|
||||||
*/ |
|
||||||
static void checkOrCreateTable(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(); |
|
||||||
String columnType = getColumnType(type); |
|
||||||
if (columnType == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
sb.append(field.getName()); |
|
||||||
sb.append(" ").append(columnType); |
|
||||||
|
|
||||||
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) + ");"; |
|
||||||
ALog.d(TAG, "创建表的sql:" + str); |
|
||||||
db.execSQL(str); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 根据字段名获取字段类型 |
|
||||||
*/ |
|
||||||
static String getColumnTypeByFieldName(Class tabClass, String fieldName) { |
|
||||||
List<Field> fields = CommonUtil.getAllFields(tabClass); |
|
||||||
for (Field field : fields) { |
|
||||||
if (field.getName().equals(fieldName)) { |
|
||||||
return getColumnType(field.getType()); |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取字段类型 |
|
||||||
*/ |
|
||||||
static String getColumnType(Class fieldtype) { |
|
||||||
if (fieldtype == String.class || fieldtype.isEnum()) { |
|
||||||
return "VARCHAR"; |
|
||||||
} else if (fieldtype == int.class || fieldtype == Integer.class) { |
|
||||||
return "INTEGER"; |
|
||||||
} else if (fieldtype == float.class || fieldtype == Float.class) { |
|
||||||
return "FLOAT"; |
|
||||||
} else if (fieldtype == double.class || fieldtype == Double.class) { |
|
||||||
return "DOUBLE"; |
|
||||||
} else if (fieldtype == long.class || fieldtype == Long.class) { |
|
||||||
return "BIGINT"; |
|
||||||
} else if (fieldtype == boolean.class || fieldtype == Boolean.class) { |
|
||||||
return "BOOLEAN"; |
|
||||||
} else if (fieldtype == java.util.Date.class || fieldtype == java.sql.Date.class) { |
|
||||||
return "DATA"; |
|
||||||
} else if (fieldtype == byte.class || fieldtype == Byte.class) { |
|
||||||
return "BLOB"; |
|
||||||
} else if (fieldtype == Map.class || fieldtype == List.class) { |
|
||||||
return "TEXT"; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* URL编码字符串 |
|
||||||
* |
|
||||||
* @param str 原始字符串 |
|
||||||
* @return 编码后的字符串 |
|
||||||
*/ |
|
||||||
static String encodeStr(String str) { |
|
||||||
str = str.replaceAll("\\+", "%2B"); |
|
||||||
return URLEncoder.encode(str); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取主键字段名 |
|
||||||
*/ |
|
||||||
static String getPrimaryName(Class<? extends DbEntity> clazz) { |
|
||||||
List<Field> fields = CommonUtil.getAllFields(clazz); |
|
||||||
String column; |
|
||||||
if (fields != null && !fields.isEmpty()) { |
|
||||||
|
|
||||||
for (Field field : fields) { |
|
||||||
field.setAccessible(true); |
|
||||||
if (isPrimary(field)) { |
|
||||||
column = field.getName(); |
|
||||||
return column; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取类中所有不被忽略的字段 |
|
||||||
*/ |
|
||||||
static List<Field> getAllNotIgnoreField(Class clazz) { |
|
||||||
List<Field> fields = CommonUtil.getAllFields(clazz); |
|
||||||
List<Field> temp = new ArrayList<>(); |
|
||||||
if (fields != null && fields.size() > 0) { |
|
||||||
for (Field f : fields) { |
|
||||||
f.setAccessible(true); |
|
||||||
if (!isIgnore(f)) { |
|
||||||
temp.add(f); |
|
||||||
} |
|
||||||
} |
|
||||||
return temp; |
|
||||||
} else { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 列表数据转字符串 |
|
||||||
* |
|
||||||
* @param field list反射字段 |
|
||||||
*/ |
|
||||||
static String list2Str(DbEntity dbEntity, Field field) throws IllegalAccessException { |
|
||||||
List list = (List) field.get(dbEntity); |
|
||||||
if (list == null || list.isEmpty()) return ""; |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
for (Object aList : list) { |
|
||||||
sb.append(aList).append("$$"); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 字符串转列表 |
|
||||||
* |
|
||||||
* @param str 数据库中的字段 |
|
||||||
* @return 如果str为null,则返回null |
|
||||||
*/ |
|
||||||
static List str2List(String str, Field field) { |
|
||||||
if (TextUtils.isEmpty(str)) return null; |
|
||||||
String[] datas = str.split("\\$\\$"); |
|
||||||
List list = new ArrayList(); |
|
||||||
Class clazz = CommonUtil.getListParamType(field); |
|
||||||
if (clazz != null) { |
|
||||||
String type = clazz.getName(); |
|
||||||
for (String data : datas) { |
|
||||||
list.add(checkData(type, data)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return list; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 字符串转Map,只支持 |
|
||||||
* <pre> |
|
||||||
* {@code Map<String, String>} |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
static Map<String, String> str2Map(String str) { |
|
||||||
Map<String, String> map = new HashMap<>(); |
|
||||||
if (TextUtils.isEmpty(str)) { |
|
||||||
return map; |
|
||||||
} |
|
||||||
boolean isDecode = false; |
|
||||||
if (str.endsWith("_&_decode_&_")) { |
|
||||||
isDecode = true; |
|
||||||
str = str.substring(0, str.length() - 12); |
|
||||||
} |
|
||||||
String[] element = str.split(","); |
|
||||||
for (String data : element) { |
|
||||||
String[] s = data.split("\\$"); |
|
||||||
if (isDecode) { |
|
||||||
map.put(CommonUtil.decryptBASE64(s[0]), CommonUtil.decryptBASE64(s[1])); |
|
||||||
} else { |
|
||||||
map.put(s[0], s[1]); |
|
||||||
} |
|
||||||
} |
|
||||||
return map; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Map转字符串,只支持 |
|
||||||
* <pre> |
|
||||||
* {@code Map<String, String>} |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
static String map2Str(Map<String, String> map) { |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
Set<String> keys = map.keySet(); |
|
||||||
for (String key : keys) { |
|
||||||
sb.append(CommonUtil.encryptBASE64(key)) |
|
||||||
.append("$") |
|
||||||
.append(CommonUtil.encryptBASE64(map.get(key))) |
|
||||||
.append(","); |
|
||||||
} |
|
||||||
String str = sb.toString(); |
|
||||||
str = TextUtils.isEmpty(str) ? str : str.substring(0, str.length() - 1); |
|
||||||
//3.3.10版本之前没有decode,需要加标志
|
|
||||||
if (map.size() != 0) { |
|
||||||
str += "_&_decode_&_"; |
|
||||||
} |
|
||||||
return str; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* shadow$_klass_、shadow$_monitor_、{@link Ignore}、rowID、{@link Field#isSynthetic()}、{@link |
|
||||||
* Modifier#isFinal(int)}、{@link Modifier#isStatic(int)}将被忽略 |
|
||||||
* |
|
||||||
* @return true 忽略该字段 |
|
||||||
*/ |
|
||||||
static boolean isIgnore(Field field) { |
|
||||||
// field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段
|
|
||||||
Ignore ignore = field.getAnnotation(Ignore.class); |
|
||||||
int modifiers = field.getModifiers(); |
|
||||||
String fieldName = field.getName(); |
|
||||||
return (ignore != null && ignore.value()) || fieldName.equals("rowID") || fieldName.equals( |
|
||||||
AriaConfig.IGNORE_CLASS_KLASS) || fieldName.equals(AriaConfig.IGNORE_CLASS_MONITOR) |
|
||||||
|| field.isSynthetic() || Modifier |
|
||||||
.isStatic(modifiers) || Modifier.isFinal(modifiers); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是Wrapper注解 |
|
||||||
* |
|
||||||
* @return {@code true} 是 |
|
||||||
*/ |
|
||||||
static boolean isWrapper(Class<? extends AbsDbWrapper> clazz) { |
|
||||||
Wrapper w = clazz.getAnnotation(Wrapper.class); |
|
||||||
return w != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否一对多注解 |
|
||||||
*/ |
|
||||||
static boolean isMany(Field field) { |
|
||||||
Many oneToMany = field.getAnnotation(Many.class); |
|
||||||
return oneToMany != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是一对一注解 |
|
||||||
*/ |
|
||||||
static boolean isOne(Field field) { |
|
||||||
One oneToOne = field.getAnnotation(One.class); |
|
||||||
return oneToOne != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是主键约束 |
|
||||||
* |
|
||||||
* @return {@code true}主键约束 |
|
||||||
*/ |
|
||||||
static boolean isPrimary(Field field) { |
|
||||||
Primary pk = field.getAnnotation(Primary.class); |
|
||||||
return pk != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是外键约束 |
|
||||||
* |
|
||||||
* @return {@code true}外键约束 |
|
||||||
*/ |
|
||||||
static boolean isForeign(Field field) { |
|
||||||
Foreign fk = field.getAnnotation(Foreign.class); |
|
||||||
return fk != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是非空约束 |
|
||||||
* |
|
||||||
* @return {@code true}为非空约束 |
|
||||||
*/ |
|
||||||
static boolean isNoNull(Field field) { |
|
||||||
NoNull nn = field.getAnnotation(NoNull.class); |
|
||||||
return nn != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是default |
|
||||||
* |
|
||||||
* @return {@code true}为default |
|
||||||
*/ |
|
||||||
static boolean isDefault(Field field) { |
|
||||||
Default nn = field.getAnnotation(Default.class); |
|
||||||
return nn != null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 判断是否是Unique |
|
||||||
* |
|
||||||
* @return {@code true}为Unique |
|
||||||
*/ |
|
||||||
static boolean isUnique(Field field) { |
|
||||||
Unique nn = field.getAnnotation(Unique.class); |
|
||||||
return nn != null; |
|
||||||
} |
|
||||||
|
|
||||||
private static Object checkData(String type, String data) { |
|
||||||
if (type.equalsIgnoreCase("java.lang.String")) { |
|
||||||
return data; |
|
||||||
} else if (type.equalsIgnoreCase("int") || type.equals("java.lang.Integer")) { |
|
||||||
return Integer.parseInt(data); |
|
||||||
} else if (type.equalsIgnoreCase("double") || type.equals("java.lang.Double")) { |
|
||||||
return Double.parseDouble(data); |
|
||||||
} else if (type.equalsIgnoreCase("float") || type.equals("java.lang.Float")) { |
|
||||||
return Float.parseFloat(data); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
@ -1,30 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* 默认数据 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Default { |
|
||||||
String value() default ""; |
|
||||||
} |
|
@ -1,50 +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.annotation; |
|
||||||
|
|
||||||
import com.arialyy.aria.orm.ActionPolicy; |
|
||||||
import com.arialyy.aria.orm.DbEntity; |
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/7/4. |
|
||||||
* 外键约束 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Foreign { |
|
||||||
|
|
||||||
/** |
|
||||||
* 关联的表 |
|
||||||
*/ |
|
||||||
Class<? extends DbEntity> parent(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 父表对应的列名 |
|
||||||
*/ |
|
||||||
String column(); |
|
||||||
|
|
||||||
/** |
|
||||||
* ON UPDATE 约束 |
|
||||||
*/ |
|
||||||
ActionPolicy onUpdate() default ActionPolicy.NO_ACTION; |
|
||||||
|
|
||||||
/** |
|
||||||
* ON DELETE 约束 |
|
||||||
*/ |
|
||||||
ActionPolicy onDelete() default ActionPolicy.NO_ACTION; |
|
||||||
} |
|
@ -1,30 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* 忽略某个字段 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Ignore { |
|
||||||
boolean value() default true; |
|
||||||
} |
|
@ -1,44 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/7/4. |
|
||||||
* 一对多 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Many { |
|
||||||
/** |
|
||||||
* 父表对应的字段名 |
|
||||||
*/ |
|
||||||
String parentColumn(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 父表在子表对应的字段 |
|
||||||
*/ |
|
||||||
String entityColumn(); |
|
||||||
|
|
||||||
///**
|
|
||||||
// * 是否是一对一关系
|
|
||||||
// *
|
|
||||||
// * @return {@code true} 是,{@code false} 不是
|
|
||||||
// */
|
|
||||||
//boolean isOne2One() default false;
|
|
||||||
} |
|
@ -1,30 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* 非空字段 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface NoNull { |
|
||||||
boolean value() default true; |
|
||||||
} |
|
@ -1,29 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by AriaL on 2017/7/4. |
|
||||||
* 一 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface One { |
|
||||||
|
|
||||||
} |
|
@ -1,35 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* 表ID字段指定 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary { |
|
||||||
int value() default -1; |
|
||||||
|
|
||||||
/** |
|
||||||
* 字段需要int类型才可以自增 |
|
||||||
*/ |
|
||||||
boolean autoincrement() default false; |
|
||||||
} |
|
@ -1,30 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by lyy on 2015/11/2. |
|
||||||
* 设置表名,如果不是使用该注解,默认为类名 |
|
||||||
*/ |
|
||||||
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { |
|
||||||
String tableName(); |
|
||||||
} |
|
@ -1,29 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/5/8. |
|
||||||
* 数据库 UNIQUE 约束 |
|
||||||
*/ |
|
||||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) |
|
||||||
public @interface Unique { |
|
||||||
} |
|
@ -1,29 +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.annotation; |
|
||||||
|
|
||||||
import java.lang.annotation.ElementType; |
|
||||||
import java.lang.annotation.Retention; |
|
||||||
import java.lang.annotation.RetentionPolicy; |
|
||||||
import java.lang.annotation.Target; |
|
||||||
|
|
||||||
/** |
|
||||||
* Created by laoyuyu on 2018/3/21. |
|
||||||
* 关系包裹 |
|
||||||
*/ |
|
||||||
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) |
|
||||||
public @interface Wrapper { |
|
||||||
} |
|
@ -1,3 +0,0 @@ |
|||||||
com.arialyy.aria.core.listener.BaseDListener |
|
||||||
com.arialyy.aria.core.listener.BaseUListener |
|
||||||
com.arialyy.aria.core.listener.DownloadGroupListener |
|
Loading…
Reference in new issue