package com.ycsoft.report.query; import java.io.File; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.ycsoft.commons.exception.ReportException; import com.ycsoft.commons.helper.LoggerHelper; import com.ycsoft.report.bean.RepDefine; import com.ycsoft.report.commons.CacheInput; import com.ycsoft.report.commons.CacheOutput; import com.ycsoft.report.commons.FileObjectInputStream; import com.ycsoft.report.commons.FileObjectOutputStream; import com.ycsoft.report.commons.OlapPageExcel; import com.ycsoft.report.commons.ReportConstants; import com.ycsoft.report.commons.StringUtil; import com.ycsoft.report.commons.SystemConfig; import com.ycsoft.report.db.ConnContainer; import com.ycsoft.report.query.cube.CellType; import com.ycsoft.report.query.cube.CubeCell; import com.ycsoft.report.query.cube.CubeHeadCell; import com.ycsoft.report.query.cube.DimensionType; import com.ycsoft.report.query.cube.compute.CellCompute; import com.ycsoft.report.query.cube.compute.DataCompute; import com.ycsoft.report.query.cube.compute.GroupCompute; import com.ycsoft.report.query.cube.compute.TotalCompute; import com.ycsoft.report.query.cube.graph.CubeGraph; import com.ycsoft.report.query.cube.impl.AbstractDataSet; import com.ycsoft.report.query.cube.showclass.cellwarn.CellColour; import com.ycsoft.report.query.cube.showclass.cellwarn.MeaWarnApplyTo; import com.ycsoft.report.query.daq.CubeCache; import com.ycsoft.report.query.daq.DataReader; import com.ycsoft.report.query.daq.QueryExtract; /** * cubeOLAP展现 */ public class QueryResultOlap extends AbstractDataSet implements QueryResult{ protected int rows = 0; protected String rep_id=null; protected String query_id = null; protected String database = null; private Date visit_date=new Date(); protected String rep_type=null; private static final int exprot_max=1000; protected String cache_query_id=null; /** * 数据体sql */ private String datasetsql; public String getCacheQueryID(){ return this.cache_query_id; } public QueryResultOlap(String query_id, RepDefine rep, String sql,String cache_query_id) { this.query_id=query_id; this.database=rep.getDatabase(); this.rep_type=rep.getRep_type(); this.rep_id=rep.getRep_id(); this.datasetsql = sql; this.cache_query_id=cache_query_id; } /** * 获得原始配置的sql */ public String getDataSet() { return this.datasetsql; } /** * 验证变换后的sql是否正确 * @throws ReportException */ public String validate() throws ReportException { Connection conn = null; Statement stmt = null; ResultSet rs = null; String sql=""; try { conn = ConnContainer.getConn(database); stmt = conn.createStatement(); sql= this.getAssembleDataSet(); LoggerHelper.debug(this.getClass(), sql); rs = stmt.executeQuery(sql); return null; } catch (SQLException e) { throw new ReportException("error:"+e.getMessage(),e,sql); //return "error:" + e.getMessage(); } finally { try { if (rs != null) { rs.close(); rs = null; } } catch (Exception e) { } try { if (stmt != null) { stmt.close(); stmt = null; } } catch (Exception e) { } try { if (conn != null) { conn.close(); conn = null; } } catch (Exception e) { } } } /** * 创建前台展现的内容写入文件缓存对象 * @return * @throws IOException * @throws ReportException */ protected CacheOutput createCacheOutput() throws IOException, ReportException{ return new FileObjectOutputStream(ReportConstants.REP_TEMP_TXT+ query_id); } /** * 创建cube计算结果提取器对象 * @return */ protected QueryExtract getQueryExtract(){ return new CubeCache(this.cache_query_id,this,this); } /** * 执行查询,数据写入文件 * @param sql * @throws ReportException */ public void execute() throws ReportException{ CacheOutput foo = null; DataReader datareader=null; try { rows=0; foo =this.createCacheOutput(); //数据提取 QueryExtract cache=this.getQueryExtract(); this.cache_query_id= cache.extractCache(); datareader=cache.getData(); //打开数据源,如果是查数据库则创建数据区查询并返回结果集,如果缓存则执行key排序 datareader.open(); // 结果集字段属性 List<CubeHeadCell[]> olapheadlist=this.getCube().getCubeHead(); CubeHeadCell[] headcells=olapheadlist.get(olapheadlist.size()-1); // 设置文件头 foo.writeHead(olapheadlist);//保存到文件 CubeCell[] datacells=null; //数据行计算器 CellCompute<CubeCell[]> datacompute=new DataCompute(headcells,datareader); //分组小计行计算器 CellCompute<CubeCell[]>[] groupcomputes=GroupCompute.createGroupCompute(headcells); //合计行计算器 CellCompute<CubeCell[]> totalcompute=new TotalCompute(headcells); //警戒计算配置 List<MeaWarnApplyTo> checks=CellColour.createCellColour(this); datacompute.setWarnCheck(CellColour.getMeaWarnCheck(checks,CellType.data)); for( CellCompute<CubeCell[]> group: groupcomputes){ group.setWarnCheck(CellColour.getMeaWarnCheck(checks, CellType.group)); } totalcompute.setWarnCheck(CellColour.getMeaWarnCheck(checks, CellType.total)); while (datareader.next()) { // 一行查询结果 datacells = new CubeCell[headcells.length]; //生成数据行 datacompute.compute(datacells); datacells=datacompute.getResult(); //分组小计 for(CellCompute<CubeCell[]> group:groupcomputes){ if(group.compute(datacells)){ foo.writeObject(group.getResult()); rows++; } } foo.writeObject(datacells); rows++; totalcompute.compute(datacells); } //末尾分组写入文件 if(rows>0) for(CellCompute<CubeCell[]> group:groupcomputes){ group.compute(null);//末尾分组计算 foo.writeObject(group.getResult()); rows++; } //合计行写入文件 if(rows>0){ foo.writeObject(totalcompute.getResult()); rows++; } } catch (IOException e) { throw new ReportException(e); } catch (ReportException e) { throw e; }catch (Exception e) { throw new ReportException(e); } finally { try { if (foo != null){ foo.close(); foo=null; } } catch (Exception e1) { } try { if (datareader != null){ datareader.close(); } } catch (Exception e) { } } } /** * 数据体合并单元格 * page 数据体 * row_start 开始的行索引 * row_max 结束的行索引 * col_index 计算的列索引 * @param page * @param row * @param col */ private void consolidateOlapPage(List<CubeCell[]> page,int row_start,int row_max,int col_index,int col_max){ if(row_max==0) return; if(col_index>=col_max-1) return; CubeCell datecell=null; for(int i=row_start;i<row_max;i++){ CubeCell[] cells=page.get(i); if(datecell==null){ //空值 datecell=cells[col_index]; }else if(datecell.getId()==null||!datecell.getId().equals(cells[col_index].getId())){ //id变化 datecell=cells[col_index]; consolidateOlapPage(page,row_start,i,col_index+1,col_max); row_start=i; }else{ datecell.setRowspan(datecell.getRowspan()+cells[col_index].getRowspan()); cells[col_index].setRowspan(0); cells[col_index].setColspan(0); //最后一行 if(i==row_max-1){ consolidateOlapPage(page,row_start,i,col_index+1,col_max); } } } } /** * 创建 展现结果缓存读取对象 * @return * @throws IOException * @throws ReportException */ protected CacheInput createCacheInput() throws IOException, ReportException{ return new FileObjectInputStream(ReportConstants.REP_TEMP_TXT + query_id); } public List<CubeCell[]> getPage(Integer start, Integer limit) throws ReportException{ CacheInput foi = null; if (start > this.rows || start < 0 || limit <= 0) throw new ReportException("page_index start or limit error."); try { foi = this.createCacheInput(); List<CubeCell[]> pagelist = new ArrayList<CubeCell[]>(limit); CubeCell[] list = null; int i = 0; int min_i = start; int max_i = start + limit; //查询头 List<CubeHeadCell[]> headlist=(List<CubeHeadCell[]>)foi.readHead(); int cross_col_max=0; for(CubeHeadCell cell:headlist.get(headlist.size()-1)){ if(cell.getDim_type().equals(DimensionType.crosswise)) cross_col_max++; } while ((list = (CubeCell[]) foi.readObject()) != null) { if (i >= min_i) pagelist.add(list); i++; if (i >= max_i) break; } //单元格合并 consolidateOlapPage(pagelist,0,pagelist.size(),0,cross_col_max); return pagelist; } catch (IOException e) { throw new ReportException(e); } catch (ClassNotFoundException e) { throw new ReportException(e); } finally { try { if (foi != null){ foi.close(); foi=null; } } catch (Exception e) { } } } public String getDatabase() { return this.database; } public String getQueryId() { return this.query_id; } public List<CubeHeadCell[]> getHead() throws ReportException { CacheInput foi = null; try { foi = this.createCacheInput(); List<CubeHeadCell[]> list=(List<CubeHeadCell[]>) foi.readHead(); if(list==null) throw new ReportException("rephead is null"); return list; }catch (IOException e) { throw new ReportException(e); } catch (ClassNotFoundException e) { throw new ReportException(e); } finally { try { if (foi != null){ foi.close(); foi=null; } } catch (Exception e) { } } } public void updateVisitDate() { this.visit_date = new Date(); } public Date getVisitDate() { return visit_date; } public int getRowSize() { return rows; } public void clear() { File file = new File(ReportConstants.REP_TEMP_TXT+ query_id); if (file.exists()) file.delete(); file = new File(ReportConstants.REP_TEMP_TXT + query_id + ".xls"); if (file.exists()) file.delete(); file = new File(ReportConstants.REP_TEMP_TXT +query_id + ".zip"); if (file.exists()) file.delete(); file = new File(ReportConstants.REP_TEMP_TXT +query_id + "_index"); if (file.exists()) file.delete(); //清理_base文件 if(ReportConstants.DATABASETYPE_REALTIME.equals(SystemConfig.getDatabaseMap().get(database).getType())){ file=new File(ReportConstants.REP_TEMP_TXT +query_id + ReportConstants.CACHE_BASE); if(file.exists()) file.delete(); } } public String getRepId() { return rep_id; } /** * 导出单个excel文档 * @param query_id * @return * @throws ReportException */ private static String exportXls(QueryResultOlap olap) throws ReportException{ OlapPageExcel re=new OlapPageExcel(olap,exprot_max); return re.getExportFile(); } /** * 导出Zip,加同步标志(保证整个系统只能执行一个Zip包压缩) * @param query_id * @return * @throws ReportException */ private synchronized static String exportZip(QueryResultOlap olap) throws ReportException{ OlapPageExcel re=new OlapPageExcel(olap,exprot_max); return re.getExportFile(); } /** * 返回导出文档的全文件名 * col_indexs为列索引数组,值为空表示导出快逸初始化数据源 * @throws ReportException */ public String export(Integer... col_indexs) throws ReportException { this.updateVisitDate(); //导出明细报表 //当生成excel文档需要zip压缩时,现在只能同时执行一个压缩(使用同步实现或其他省资源的方式 if(this.rows>exprot_max) return exportZip(this); else return exportXls(this); } /** * 图形运算 */ public CubeGraph graph(CubeGraph cg) throws ReportException { QueryGraph query=new QueryGraph(this,cg,this.cache_query_id); query.execute(); return query.getGraph(); } private String qrkeys_sha1=null; public String getQRSHA() { return qrkeys_sha1; } public void setQRSHA(String qrkeys) throws ReportException { try { this.qrkeys_sha1=StringUtil.SHA1(qrkeys); } catch (Exception e) { throw new ReportException("sha1计算失败",e); } } }