package ro.nextreports.server.web.analysis; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import ro.nextreports.server.domain.Analysis; import ro.nextreports.server.domain.ReportResultEvent; import ro.nextreports.server.service.AnalysisService; import ro.nextreports.server.service.ReportService; import ro.nextreports.server.service.StorageService; import ro.nextreports.server.util.AnalysisUtil; import ro.nextreports.server.web.analysis.util.AnalysisException; import ro.nextreports.server.web.analysis.util.DatabaseUtil; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery; public class OrientDBAnalysisReader implements AnalysisReader { private StorageService storageService; private AnalysisService analysisService; private ReportService reportService; private ODatabaseDocumentTx db; private int rowCount = -1; private static final Logger LOG = LoggerFactory.getLogger(OrientDBAnalysisReader.class); public OrientDBAnalysisReader() { } @Override public List<String> getHeader(Analysis analysis) { if (analysis == null) { return new ArrayList<String>(); } List<String> columnNames = analysis.getColumns(); if ((columnNames == null) || columnNames.isEmpty()) { long start = System.currentTimeMillis(); initConnection(); if (db == null) { return new ArrayList<String>(); } System.out.println("---------- getHeader"); Columns columns = getColumns(analysis); columnNames = columns.getColumnNames(); analysis.setColumns(columnNames); analysis.setColumnTypes(columns.getColumnTypes()); // select all by default List<Boolean> selected = new ArrayList<Boolean>(); for (int i = 0, size = columnNames.size(); i < size; i++) { selected.add(true); } analysis.setSelected(selected); long end = System.currentTimeMillis(); closeConnection(); System.out.println("*** getHeader in " + (end-start) + " ms"); } if (analysis.getSortProperty() == null) { List<String> sortProperty = new ArrayList<String>(); System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$ sort = " + columnNames.get(0)); sortProperty.add(columnNames.get(0)); analysis.setSortProperty(sortProperty); List<Boolean> ascending = new ArrayList<Boolean>(); ascending.add(true); analysis.setAscending(ascending); } System.out.println("----------> HEADER : " + analysis.getSelectedColumns()); return getHeaderColumnNames(analysis.getSelectedColumns()); } @Override public Integer getRowCount(Analysis analysis) throws AnalysisException { if (analysis == null) { return 0; } if (rowCount == -1) { long start = System.currentTimeMillis(); initConnection(); if (db == null) { return 0; } System.out.println("---------- getRowCount"); String sql = analysis.toSql(false); System.out.println(" sql=" + sql); List<ODocument> list = null; try { list = db.query(new OSQLSynchQuery<ODocument>("SELECT COUNT(*) as count FROM ( " + sql + " )")); } catch (Throwable t) { // critical case // class (table) not found in database recordError(analysis, t); return 0; } int count = ((Long) list.get(0).field("count")).intValue(); closeConnection(); long end = System.currentTimeMillis(); System.out.println("*** count = " + count + " in " + (end-start) + " ms"); rowCount = count; } return rowCount; } @Override public Iterator<AnalysisRow> iterator(Analysis analysis, long first, long count) throws AnalysisException { long start = System.currentTimeMillis(); System.out.println("---------- iterator"); List<AnalysisRow> list = new ArrayList<AnalysisRow>(); if (analysis == null) { return list.iterator(); } initConnection(); if (db == null) { return list.iterator(); } String sql = analysis.toSql(false); System.out.println("*** SQL = " + sql); try { OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>(sql + " SKIP " + first + " LIMIT " + count); List<ODocument> resultset = db.query(query); List<String> header = getHeader(analysis); int cols = header.size(); for (ODocument doc : resultset) { //String[] fieldNames = doc.fieldNames(); // this returns only not-null fields! List<Object> cellValues = new ArrayList<Object>(); for (int i = 1; i <= cols; i++) { cellValues.add(doc.field(header.get(i-1))); } AnalysisRow row = new AnalysisRow(cellValues); list.add(row); } } catch (Throwable t) { recordError(analysis, t); } long end = System.currentTimeMillis(); closeConnection(); System.out.println("*** iterator in " + (end-start) + " ms"); return list.iterator(); } @Required public void setStorageService(StorageService storageService) { this.storageService = storageService; } @Required public void setAnalysisService(AnalysisService analysisService) { this.analysisService = analysisService; } @Required public void setReportService(ReportService reportService) { this.reportService = reportService; } private void initConnection() { if (db == null) { try { db = new ODatabaseDocumentTx(analysisService.getDatabasePath(), false).open("admin", "admin"); } catch (Throwable t) { // critical case when someone deleted the database folder t.printStackTrace(); LOG.error(t.getMessage(), t); } } } private void closeConnection() { if (db != null) { db.close(); db = null; } } private Columns getColumns(Analysis analysis) { String sql = analysis.toSql(true); System.out.println("*** SQL = " + sql); List<String> columnNames = new LinkedList<String>(); Map<String, String> columnTypes = new HashMap<String, String>(); try { OSQLSynchQuery<ODocument> query = new OSQLSynchQuery<ODocument>(sql + " LIMIT 1"); List<ODocument> resultset = db.query(query); String[] fieldNames = resultset.get(0).fieldNames(); int columnCount = fieldNames.length; for (int i = 0; i < columnCount; i++) { String name = fieldNames[i]; OType type = resultset.get(0).getSchemaClass().getProperty(name).getType(); columnNames.add(name); columnTypes.put(name, DatabaseUtil.getJavaType(name, type)); System.out.println("************ NAME="+name + " type="+type + " javaType="+DatabaseUtil.getJavaType(name, type)); } } catch (Throwable t) { recordError(analysis, t); } System.out.println("---> columnTypes=" + columnTypes); Columns columns = new Columns(); columns.setColumnNames(columnNames); columns.setColumnTypes(columnTypes); return columns; } public void reset() { rowCount = -1; } private class Columns { private List<String> columnNames; private Map<String, String> columnTypes; public Columns() { } public List<String> getColumnNames() { return columnNames; } public void setColumnNames(List<String> columnNames) { this.columnNames = columnNames; } public Map<String, String> getColumnTypes() { return columnTypes; } public void setColumnTypes(Map<String, String> columnTypes) { this.columnTypes = columnTypes; } } private List<String> getHeaderColumnNames(List<String> names) { List<String> result = new ArrayList<String>(); for (String name : names) { result.add(DatabaseUtil.getColumnAlias(name)); } return result; } private int findIndex(String[] elements, String element) { if (elements == null) { return -1; } else { for (int i=0, size=elements.length; i<size; i++) { if (elements[i].equals(element)) { return i; } } } return -1; } private void recordError(Analysis analysis, Throwable t) { LOG.error(t.getMessage(), t); ReportResultEvent event = new ReportResultEvent(analysis.getCreatedBy(), analysis.getName(), AnalysisUtil.ANY_ACTION, AnalysisUtil.ANY_ACTION_FAILED + t.getMessage()); reportService.notifyReportListener(event); } }