/* * Tencent is pleased to support the open source community by making * Tencent GT (Version 2.4 and subsequent versions) available. * * Notwithstanding anything to the contrary herein, any previous version * of Tencent GT shall not be subject to the license hereunder. * All right, title, and interest, including all intellectual property rights, * in and to the previous version of Tencent GT (including any and all copies thereof) * shall be owned and retained by Tencent and subject to the license under the * Tencent GT End User License Agreement (http://gt.qq.com/wp-content/EULA_EN.html). * * Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the MIT License (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://opensource.org/licenses/MIT * * 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.tencent.wstt.gt.log; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import com.tencent.wstt.gt.api.utils.Env; import com.tencent.wstt.gt.ui.model.LogEntry; import com.tencent.wstt.gt.utils.GTUtils; public abstract class AbsLogController implements ICacheable { // 过滤锚点,上次过滤对于数据源的位置,用于后面过滤条件不变的情况提高效率 protected int lastFilterEndLocation = 0; protected RemoveRangeArrayList<LogEntry> showLogList = new RemoveRangeArrayList<LogEntry>(); protected List<LogEntry> filterdLogList; protected LinkedHashSet<String> showTagSet = new LinkedHashSet<String>(); protected LogTaskConsumer logConsumer; protected ArrayList<LogListener> listenerList = new ArrayList<LogListener>(); protected TempLogConsumer tempLogConsumer; protected boolean allowSave = true; // 保留作为日志总开关的字段 // 用于写日志的读写锁 protected ReadWriteLock lock = new ReentrantReadWriteLock(false); public AbsLogController() { if (GTUtils.isSDCardExist() && !Env.ROOT_LOG_FOLDER.exists()) { Env.ROOT_LOG_FOLDER.mkdirs(); } } void setLogTaskConsumer(LogTaskConsumer logConsumer) { this.logConsumer = logConsumer; } void setTempLogConsumer(TempLogConsumer tempLogConsumer) { this.tempLogConsumer = tempLogConsumer; } List<LogEntry> getShowLogList() { return showLogList; // TODO 外面需要加读锁 } List<LogEntry> getFilterdLogList() { return filterdLogList; } void setFilterdLogList(List<LogEntry> list) { filterdLogList = list; } public List<String> getShowTags() { List<String> result = new ArrayList<String>(); String[] ss = showTagSet.toArray(new String[]{}); Collections.addAll(result, ss); return result; } synchronized int getLastFilterEndLocation() { return lastFilterEndLocation; } synchronized void resetLastFilterEndLocation() { lock.readLock().lock(); lastFilterEndLocation = showLogList.size(); lock.readLock().unlock(); } @Override synchronized public void clearCache() { lock.writeLock().lock(); if (null != showLogList) { lastFilterEndLocation = 0; showLogList.clear(); // showTagSet.clear(); } lock.writeLock().unlock(); // 此时需要刷新UI onDataChanged(); } public void setAllowSave(boolean flag) { allowSave = flag; } public boolean getAllowSave() { return allowSave; } @Override /* * 这个方法是被生产者线程调用的,所以可以阻塞 * 目前实现是读写锁,这里应该是优先级最低的写锁 */ public void addEntrys(Collection logList) { lock.writeLock().lock(); try { // 需要显示的log只控制显示1000行,多于1000行,则把list队头的删除 showLogList.addAll(logList); if (showLogList.size() > LogUtils.CACHE) { int length = showLogList.size(); lastFilterEndLocation = lastFilterEndLocation - length + LogUtils.CACHE; // 如果lastFilterEndLocation小于0,对调用程序来说已经没有用处了,取0即可 lastFilterEndLocation = Math.max(lastFilterEndLocation, 0); showLogList.remove(0, length - LogUtils.CACHE); } for (Object o : logList) { LogEntry entry = (LogEntry)o; showTagSet.add(entry.tag); } } finally { lock.writeLock().unlock(); } // 此时最适合刷新UI,走过滤逻辑刷新 onDataChanged(); } @Override synchronized public void onDataChanged() { // 此时最适合刷新UI,走过滤逻辑刷新 for (LogListener listener : listenerList) { listener.onLogChanged(); } } @Override synchronized public void saveCache(String fileName) { lock.readLock().lock(); try { // 路径的情况,直接存在指定路径 if (fileName.contains("/") || fileName.contains("\\")) { int la = fileName.lastIndexOf("."); if (la < 0) { fileName = fileName + LogUtils.LOG_POSFIX; } else { String temp = fileName.substring(la); if (temp.contains("/") || temp.contains("\\")) { // "."是目录名的一部分而不是后缀名的情况 fileName = fileName + LogUtils.LOG_POSFIX; } // else fileName = fileName } LogUtils.writeLog(showLogList, fileName, false); return; } else { // 文件名的情况,保存在默认日志路径 String filePath = null; if (fileName.contains(".")) // 自带后缀了 { filePath = fileName; } else { filePath = fileName + LogUtils.LOG_POSFIX; } File f = new File(Env.S_ROOT_LOG_FOLDER, filePath); if (f.exists()) { f.delete(); } LogUtils.writeLog(showLogList, f, false); } } finally { lock.readLock().unlock(); } } @Override public void addListener(LogListener listener) { if (! listenerList.contains(listener)) { listenerList.add(listener); } } @Override public void removeListener(LogListener listener) { listenerList.remove(listener); } @Override public void removeAllListener() { listenerList.clear(); } @Override public void addEntry(Object entry) { // do nothing } @Override public void removeEntry(Object entry){ // do nothing } }