package com.fr.design.data;
import com.fr.base.StoreProcedureParameter;
import com.fr.base.TableData;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.TableDataSourceTailor;
import com.fr.data.core.DataCoreXmlUtils;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.data.impl.storeproc.ProcedureDataModel;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.data.impl.storeproc.StoreProcedureConstants;
import com.fr.data.impl.storeproc.StoreProcedureHelper;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataNameWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.ServerTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataFactory;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.gui.iprogressbar.AutoProgressBar;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.parameter.ParameterInputPane;
import com.fr.file.ProcedureConfig;
import com.fr.file.TableDataConfig;
import com.fr.general.ComparatorUtils;
import com.fr.general.data.DataModel;
import com.fr.general.data.TableDataException;
import com.fr.log.FineLoggerFactory;
import com.fr.module.ModuleContext;
import com.fr.script.Calculator;
import com.fr.stable.ArrayUtils;
import com.fr.stable.ParameterProvider;
import com.fr.stable.StringUtils;
import com.fr.stable.xml.XMLPrintWriter;
import javax.swing.JFrame;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.io.ByteArrayOutputStream;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 设计器管理操作数据集的类:
* 1.对于每个TableData,会生成相应的TableDataWrapper.TableDataWrapper里面有TableData的数据列缓存
* 2.TableDataWrapper是不支持对TableData的修改查询语句 重命名等修改删除操作
* 如果TableData变化了,那么TableDataWrapper 也会重新生成,然后存进缓存.这样保证缓存是正确的,不会取到错误的数据列。
* 3.对于模板数据集,关键词应该保证各个模板数据集之间不同,所以默认有个加上模板名的操作。
* 4.个人觉得完全没有必要做成那种一个SQL语句对应一个数据列的情况,那样子太复杂了。而且每次比较关键词都很慢
*
* !!!Notice: 除了预览数据集的操作,其他所有涉及到数据集的界面操作,都要经过这个类(因为它有数据集的缓存,不需要重复计算)
*
* @author zhou
*/
public abstract class DesignTableDataManager {
/**
* 其实globalDsCache没有绝对的必要,只是为了操作方便。如果没有它,那么每次清空服务器数据集或者存储过程的时候,还要去遍历找一下,
* 这个操作可能比较复杂 。 从减少代码复杂度的角度看,还是很有必要的
*/
private static Map globalDsCache = new java.util.HashMap();
private static Set dsNameChangedSet = new LinkedHashSet<>();
private static List globalDsListeners = new ArrayList<>();
private static Map> dsListenersMap = new ConcurrentHashMap<>();
public static String NO_PARAMETER = "no_paramater_pane";
//用于记录是否要弹出参数框
private static ThreadLocal threadLocal = new ThreadLocal();
private static Map> columnCache = new HashMap<>();
/**
* 清除全局 数据集缓存.
*/
public static void clearGlobalDs() {
globalDsCache.clear();
}
/**
* 响应数据集改变.
*/
private static void fireDsChanged() {
fireDsChanged(globalDsListeners);
for (Iterator>> entryIterator = dsListenersMap.entrySet().iterator(); entryIterator.hasNext(); ) {
List dsListeners = entryIterator.next().getValue();
fireDsChanged(dsListeners);
}
}
private static void fireDsChanged(List dsListeners) {
for (int i = 0; i < dsListeners.size(); i++) {
//增强for循环用的iterator实现的, 如果中间哪个listener修改或删除了(如ChartEditPane.dsChangeListener),
// 由于dsListeners是arraylist, 此时会ConcurrentModifyException
ChangeEvent e = null;
dsListeners.get(i).stateChanged(e);
}
}
public static void closeTemplate(JTemplate, ?> template) {
if (template != null) {
template.whenClose();
columnCache.remove(getEditingTableDataSource());
dsListenersMap.remove(template.getPath());
}
}
public static void envChange() {
columnCache.clear();
dsListenersMap.clear();
dsNameChangedSet.clear();
clearGlobalDs();
}
/**
* 响应数据集改变
*
* @param dsNameChangedMap 改变名字的数据集
*/
public static void fireDSChanged(Map dsNameChangedMap) {
clearGlobalDs();
if (!dsNameChangedMap.isEmpty()) {
setDsNameChangedSet(dsNameChangedMap);
}
fireDsChanged();
dsNameChangedMap.clear();
}
private static void setDsNameChangedSet(Map map) {
Iterator iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
dsNameChangedSet.add(new NameChangeBean(key, map.get(key)));
}
}
/**
* 数据库是否改变
*
* @param oldDsName 旧名字
* @return 是则返回true
*/
public static boolean isDsNameChanged(String oldDsName) {
for (NameChangeBean bean : dsNameChangedSet) {
if (ComparatorUtils.equals(oldDsName, bean.getOldName())) {
return true;
}
}
return false;
}
public static String getChangedDsNameByOldDsName(String dsName) {
for (NameChangeBean bean : dsNameChangedSet) {
if (ComparatorUtils.equals(dsName, bean.getOldName())) {
dsName = bean.getChangedName();
}
}
return dsName;
}
public static void addGlobalDsChangeListener(ChangeListener l) {
globalDsListeners.add(l);
}
/**
* 添加模板数据集改变 监听事件.
*
* @param l ChangeListener监听器
*/
public static void addDsChangeListener(ChangeListener l) {
JTemplate, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
String key = StringUtils.EMPTY;
if (JTemplate.isValid(template)) {
key = template.getPath();
}
List dsListeners = dsListenersMap.get(key);
if (dsListeners == null) {
dsListeners = new ArrayList();
dsListenersMap.put(key, dsListeners);
}
dsListeners.add(l);
}
/**
* 获取数据源source中dsName的所有字段
*
* @param source 数据源
* @param dsName 数据集名字
* @return
*/
public static String[] getSelectedColumnNames(TableDataSource source, String dsName) {
java.util.Map resMap = getAllEditingDataSet(source);
java.util.Map dsMap = getAllDataSetIncludingProcedure(resMap);
TableDataWrapper tabledataWrapper = dsMap.get(dsName);
if (tabledataWrapper == null) {
return new String[0];
} else {
return getSelectedColumnNamesFromCache(source, dsName, tabledataWrapper);
}
}
private static String[] getSelectedColumnNamesFromCache(TableDataSource dataSource, String dsName, TableDataWrapper tableDataWrapper) {
Map map = columnCache.get(dataSource);
if (map == null) {
map = new HashMap<>();
String[] columnNames = tableDataWrapper.calculateColumnNameList().toArray(new String[0]);
map.put(dsName, columnNames);
columnCache.put(dataSource, map);
return columnNames;
} else {
String[] columnNames = map.get(dsName);
if (columnNames == null) {
columnNames = tableDataWrapper.calculateColumnNameList().toArray(new String[0]);
map.put(dsName, columnNames);
return columnNames;
} else {
return columnNames;
}
}
}
public static void removeSelectedColumnNames(String dsName) {
Map map = columnCache.get(getEditingTableDataSource());
if (map == null) {
return;
}
map.remove(dsName);
}
public static void addDsColumnNames(String dsName, String[] columnNames) {
TableDataSource dataSource = getEditingTableDataSource();
Map map = columnCache.get(dataSource);
if (map == null) {
map = new HashMap<>();
map.put(dsName, columnNames);
columnCache.put(dataSource, map);
} else {
map.put(dsName, columnNames);
}
}
public static String[] getDsColumnNames(String dsName) {
TableDataSource dataSource = getEditingTableDataSource();
Map map = columnCache.get(dataSource);
if (map == null) {
return new String[0];
}
return map.get(dsName);
}
/**
* august:返回当前正在编辑的具有报表数据源的模板(基本报表、聚合报表) 包括 : 图表模板
*
* @return TableDataSource
* attention:与这个方法有关系的静态组件(不随着切换模板tab而变化的),应该重新执行该方法,再刷新组件
*/
public static TableDataSource getEditingTableDataSource() {
return DesignModelAdapter.getCurrentModelAdapter() == null ? null : DesignModelAdapter.getCurrentModelAdapter().getBook();
}
/**
* 返回当前模板(source)数据集、服务器数据集和存储过程中所有的数据集名字
*
* @param source
* @return
*/
public static String[] getAllDSNames(TableDataSource source) {
Iterator> entryIt = getAllEditingDataSet(source).entrySet().iterator();
List list = new ArrayList();
while (entryIt.hasNext()) {
Entry entry = entryIt.next();
list.add(entry.getKey());
}
return list.toArray(new String[0]);
}
/**
* 获取所有的数据集名称,无论模板是不是有数据集的权限
*/
public static Set getAllDSNamesWithoutPermissions(TableDataSource source) {
Set names = new HashSet<>();
Map resMap = new HashMap<>();
// 模板数据集
addTemplateData(resMap, source);
// 存储过程
addStoreProcedureData(resMap);
for (Map.Entry entry : resMap.entrySet()) {
names.add(entry.getKey());
}
//服务器数据集
Map tableDatas = TableDataConfig.getInstance().getTableDatas();
for (Map.Entry entry : tableDatas.entrySet()) {
names.add(entry.getKey());
}
return names;
}
/**
* 不根据过滤设置,返回当前模板数据集、服务器数据集、存储过程本身,是有顺序的
*/
public static java.util.Map getAllEditingDataSet(TableDataSource source) {
java.util.Map resMap = new java.util.LinkedHashMap();
// 模板数据集
addTemplateData(resMap, source);
// 服务器数据集
addServerData(resMap);
// 存储过程
addStoreProcedureData(resMap);
return resMap;
}
/**
* 不根据过滤设置,返回当前模板数据集,是有顺序的
*/
public static java.util.Map getTemplateDataSet(TableDataSource source) {
java.util.Map resMap = new java.util.LinkedHashMap();
// 模板数据集
addTemplateData(resMap, source);
return resMap;
}
public static java.util.Map getAllDataSetIncludingProcedure(java.util.Map resMap) {
java.util.LinkedHashMap dsMap = new java.util.LinkedHashMap();
for (Entry entry : resMap.entrySet()) {
String key = entry.getKey();
TableDataWrapper tableDataWrapper = resMap.get(key);
if (tableDataWrapper.getTableData() instanceof MultiResultTableData) {
MultiResultTableData> tableData = (MultiResultTableData>) tableDataWrapper.getTableData();
String name = tableDataWrapper.getTableDataName();
List resultNames = tableData.getResultNames();
TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name + "_Table", tableData);
boolean hasSchemaOrResult = false;
// 存储过程的特殊处理,还有其它名称
if (tableData instanceof StoreProcedure) {
StoreProcedure storeProcedure = (StoreProcedure) tableData;
StoreProcedureParameter[] parameters = StoreProcedureHelper.getSortPara(storeProcedure.getParameters());
for (StoreProcedureParameter parameter : parameters) {
if (parameter.getSchema() != StoreProcedureConstants.IN) {
String parameterName = name + "_" + parameter.getName();
TableDataWrapper newTwd = new MultiResultTableDataWrapper(storeProcedure, name, parameterName, false);
dsMap.put(parameterName, newTwd);
hasSchemaOrResult = true;
}
}
} /*else {
// TODO getDataModelList是空的
for (String n : tableData.getResultNames()) {
String dmName = name + "_" + n;
dsMap.put(n, new MultiResultTableDataWrapper(tableData, name, dmName, false));
}
}*/
if (!resultNames.isEmpty()) {
hasSchemaOrResult = true;
for (String resultName : resultNames) {
String dmName = name + "_" + resultName;
TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, dmName, false);
dsMap.put(dmName, newTwd);
}
}
if (!hasSchemaOrResult) {
dsMap.put(name + "_Table", tdw);
}
} else {
dsMap.put(key, tableDataWrapper);
}
}
return dsMap;
}
/**
* 不根据过滤设置,返回当前服务器数据集、存储过程所有的数据集,是有顺序的
*/
public static java.util.Map getGlobalDataSet() {
java.util.Map resMap = new java.util.LinkedHashMap();
// 服务器数据集
addServerData(resMap);
// 存储过程
addStoreProcedureData(resMap);
return resMap;
}
/**
* 根据过滤设置,返回当前模板数据集、服务器数据集、存储过程所有的数据集,是有顺序的
*/
public static List