diff --git a/config/log4j.properties b/config/log4j.properties index 9c1f0e036b..efe37bca77 100644 --- a/config/log4j.properties +++ b/config/log4j.properties @@ -1,7 +1,7 @@ log4j.rootLogger=INFO, console log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%d{MM/dd HH:mm:ss} %5p - %m [%t] (%c{2}#%M:%L)%n +log4j.appender.console.layout.ConversionPattern=%d{MM/dd HH:mm:ss} %5p - %.2000m [%t] (%c{2}#%M:%L)%n # ${host.name} is defined as an evironment variable at tomcat startup... not a log4j variable. log4j.appender.@app-name@_stats=org.apache.log4j.DailyRollingFileAppender @@ -14,7 +14,7 @@ log4j.appender.@app-name@_brief=org.apache.log4j.DailyRollingFileAppender log4j.appender.@app-name@_brief.File=${catalina.base}/logs/@app-name@.log log4j.appender.@app-name@_brief.DatePattern='.'yyyy-ww log4j.appender.@app-name@_brief.layout=org.apache.log4j.PatternLayout -log4j.appender.@app-name@_brief.layout.ConversionPattern=%d{MM/dd HH:mm:ss} %5p - %m [%t] (%c{2}#%M:%L)%n +log4j.appender.@app-name@_brief.layout.ConversionPattern=%d{MM/dd HH:mm:ss} %5p - %.2000m [%t] (%c{2}#%M:%L)%n log4j.appender.@app-name@=org.apache.log4j.DailyRollingFileAppender log4j.appender.@app-name@.File=${catalina.base}/logs/@app-name@.log @@ -22,7 +22,7 @@ log4j.appender.@app-name@.DatePattern='.'yyyy-ww log4j.appender.@app-name@.layout=org.apache.log4j.PatternLayout log4j.appender.@app-name@.layout.ConversionPattern=\ %d{MM/dd HH:mm:ss} %5p Thread: %t %c{2}#%M:%L\ -%n %m%n +%n %.2000m%n # this renderer print the object into multiple lines diff --git a/src/firefly/html/demo/ffapi-highlevel-charttest.html b/src/firefly/html/demo/ffapi-highlevel-charttest.html index 5c3b12eeb2..ebb82a3386 100644 --- a/src/firefly/html/demo/ffapi-highlevel-charttest.html +++ b/src/firefly/html/demo/ffapi-highlevel-charttest.html @@ -184,7 +184,7 @@

Default chart for 'allwise' table group below

firefly.showChart('defaultChart', {tbl_group: 'allwise'}); // using column expressions - var tblReqXpr = Object.assign({}, tblReq, {inclCols: 'ra + dec as radec, ra, dec, ln(dec) as LnOfDec, power(ra, 2) as ra_sq'}); + var tblReqXpr = Object.assign({}, tblReq, {inclCols: '"ra" + "dec" as "radec", "ra", "dec", ln("dec") as "LnOfDec", power("ra", 2) as "ra_sq"'}); tblReqXpr.META_INFO.tbl_id = 'tblwithXpr'; tblReqXpr.META_INFO.title = 'table with expressions'; tblReqXpr.tbl_id = 'tblwithXpr'; diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/CatMasterTableQuery.java b/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/CatMasterTableQuery.java index 0c95f3abeb..27446e9883 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/CatMasterTableQuery.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/CatMasterTableQuery.java @@ -25,9 +25,6 @@ import edu.caltech.ipac.util.DataObject; import edu.caltech.ipac.util.DataType; import edu.caltech.ipac.util.StringUtils; -import edu.caltech.ipac.util.cache.Cache; -import edu.caltech.ipac.util.cache.CacheManager; -import edu.caltech.ipac.util.cache.StringKey; import java.io.File; import java.io.IOException; @@ -257,17 +254,7 @@ public static DataGroup getBaseGatorData(String originalFilename) throws IOExcep } protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { - File retFile; - - StringKey key = new StringKey(CatMasterTableQuery.class.getName(), getUniqueID(request)); - Cache cache = CacheManager.getCache(Cache.TYPE_TEMP_FILE); - retFile = (File) cache.get(key); - if (retFile == null) { - retFile = getMasterCatalogFile(request); - cache.put(key, retFile); - } - - return retFile; + return getMasterCatalogFile(request); } } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/GatorDD.java b/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/GatorDD.java index 3456fe93bd..5e7ec2afdb 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/GatorDD.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/catquery/GatorDD.java @@ -19,7 +19,9 @@ import edu.caltech.ipac.firefly.server.query.EmbeddedDbProcessor; import edu.caltech.ipac.firefly.server.query.ParamDoc; import edu.caltech.ipac.firefly.server.query.SearchProcessorImpl; +import edu.caltech.ipac.firefly.server.query.SharedDbProcessor; import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; +import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupReader; import edu.caltech.ipac.firefly.server.util.ipactable.TableDef; import edu.caltech.ipac.util.AppProperties; import edu.caltech.ipac.util.DataGroup; @@ -52,69 +54,23 @@ @ParamDoc(name = CatalogRequest.SERVICE_ROOT, desc = "the part of the URL string that specifies the service and first params. " + "optional: almost never used") }) -public class GatorDD extends EmbeddedDbProcessor { +public class GatorDD extends SharedDbProcessor { - public FileInfo createDbFile(TableServerRequest treq) throws DataAccessException { - - DbAdapter dbAdapter = DbAdapter.getAdapter(treq); - File dbFile = new File(ServerContext.getTempWorkDir(), String.format("GatorDD-%s.%s", FileUtil.getHostname(), dbAdapter.getName())); + public DataGroup fetchData(TableServerRequest treq) throws DataAccessException { + TableServerRequest ntreq = (TableServerRequest) treq.cloneRequest(); + ntreq.keepBaseParamOnly(); try { - if (dbFile.createNewFile()) { - // created for the first time... populate dd and meta tables - DataGroup dd = new DataGroup("DD for GatorDD", new DataType[]{ - new DataType("name", String.class), - new DataType("description", String.class), - new DataType("units", String.class), - new DataType("indx", String.class), - new DataType("dbtype", String.class), - new DataType("tableflg", Integer.class), - new DataType("sel", String.class) - }); - EmbeddedDbUtil.createDDTbl(dbFile, dd, dbAdapter, "data"); - EmbeddedDbUtil.setDbMetaInfo(treq, DbAdapter.getAdapter(treq), dbFile); - } + File results = new GatorDDImpl().loadDataFile(treq); + return DataGroupReader.read(results); } catch (IOException e) { - // should not happen. + throw new DataAccessException(e.getMessage(), e); } - return new FileInfo(dbFile); - } - - @Override - protected DataGroupPart getResultSet(TableServerRequest treq, File dbFile) throws DataAccessException { - DbAdapter dbAdapter = DbAdapter.getAdapter(treq); - DbInstance dbInstance = dbAdapter.getDbInstance(dbFile); - String tblName = treq.getParam(CatalogRequest.CATALOG); - - String tblExists = String.format("select count(*) from %s", tblName); - try { - JdbcFactory.getSimpleTemplate(dbInstance).queryForInt(tblExists); - } catch (Exception e) { - // DD for this catalog does not exists.. fetch data and populate - fetchDataIntoTable(treq, tblName, dbFile, dbAdapter); - } - - treq.setParam(TableServerRequest.SQL_FROM, tblName); - treq.setPageSize(Integer.MAX_VALUE); - String sql = String.format("%s %s %s", dbAdapter.selectPart(treq), dbAdapter.fromPart(treq), dbAdapter.wherePart(treq)); - sql = dbAdapter.translateSql(sql); - - DataGroup dg = EmbeddedDbUtil.runQuery(dbAdapter, dbFile, sql, "data"); - TableDef tm = new TableDef(); - tm.setStatus(DataGroupPart.State.COMPLETED); - return new DataGroupPart(tm, dg, treq.getStartIndex(), dg.size()); } @Override public boolean doLogging() { return false; } - - private void fetchDataIntoTable(TableServerRequest treq, String tblName, File dbFile, DbAdapter dbAdapter) throws DataAccessException { - TableServerRequest ntreq = (TableServerRequest) treq.cloneRequest(); - ntreq.keepBaseParamOnly(); - DataGroupPart dgp = new GatorDDImpl().getData(treq); - EmbeddedDbUtil.createDataTbl(dbFile, dgp.getData(), dbAdapter, tblName); - } } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/db/BaseDbAdapter.java b/src/firefly/java/edu/caltech/ipac/firefly/server/db/BaseDbAdapter.java index d2312a2dbb..b8ba7a195d 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/db/BaseDbAdapter.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/db/BaseDbAdapter.java @@ -28,7 +28,7 @@ * @version $Id: DbInstance.java,v 1.3 2012/03/15 20:35:40 loi Exp $ */ abstract public class BaseDbAdapter implements DbAdapter { - private static long MAX_IDLE_TIME = 1000 * 60 * 5; // will be cleaned up if idle more than 5 minutes. + private static long MAX_IDLE_TIME = 1000 * 60 * 15; // will be purged up if idle more than 15 minutes. private static Map dbInstances = new HashMap<>(); private static Logger.LoggerImpl LOGGER = Logger.getLogger(); @@ -75,7 +75,7 @@ public String createDataSql(DataType[] dtTypes, String tblName) { tblName = StringUtils.isEmpty(tblName) ? "data" : tblName; List coldefs = new ArrayList<>(); for(DataType dt : dtTypes) { - coldefs.add( String.format("\"%s\" %s", dt.getKeyName().toUpperCase(),getDataType(dt.getDataType()))); + coldefs.add( String.format("\"%s\" %s", dt.getKeyName(), getDataType(dt.getDataType()))); // add quotes to avoid reserved words clashes } return String.format("create table %s (%s)", tblName, StringUtils.toString(coldefs, ",")); @@ -103,13 +103,6 @@ public String selectPart(TableServerRequest treq) { return cols; } - public String fromPart(TableServerRequest treq) { - String from = treq.getParam(TableServerRequest.SQL_FROM); - from = from == null ? EmbeddedDbUtil.getResultSetID(treq) : from; - from = "from " + (StringUtils.isEmpty(from) ? "data" : from); - return from; - } - public String wherePart(TableServerRequest treq) { String where = ""; if (treq.getFilters() != null && treq.getFilters().size() > 0) { @@ -171,12 +164,16 @@ public String getDataType(Class type) { } public DbInstance getDbInstance(File dbFile) { + return getDbInstance(dbFile, true); + } + + public DbInstance getDbInstance(File dbFile, boolean create) { EmbeddedDbInstance ins = dbInstances.get(dbFile.getPath()); - if (ins == null) { + if (ins == null && create) { ins = createDbInstance(dbFile); dbInstances.put(dbFile.getPath(), ins); } - ins.touch(); + if (ins != null ) ins.touch(); return ins; } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/db/DbAdapter.java b/src/firefly/java/edu/caltech/ipac/firefly/server/db/DbAdapter.java index c45363afb5..3880f6987e 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/db/DbAdapter.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/db/DbAdapter.java @@ -60,7 +60,6 @@ public interface DbAdapter { String getMetaSql(String forTable); String selectPart(TableServerRequest treq); - String fromPart(TableServerRequest treq); String wherePart(TableServerRequest treq); String orderByPart(TableServerRequest treq) ; String pagingPart(TableServerRequest treq) ; diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/db/EmbeddedDbUtil.java b/src/firefly/java/edu/caltech/ipac/firefly/server/db/EmbeddedDbUtil.java index 251220b71c..02e432521e 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/db/EmbeddedDbUtil.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/db/EmbeddedDbUtil.java @@ -8,6 +8,7 @@ import edu.caltech.ipac.firefly.server.ServerContext; import edu.caltech.ipac.firefly.server.db.spring.JdbcFactory; import edu.caltech.ipac.firefly.server.db.spring.mapper.DataGroupUtil; +import edu.caltech.ipac.firefly.server.query.DataAccessException; import edu.caltech.ipac.firefly.server.query.SearchProcessor; import edu.caltech.ipac.firefly.server.util.Logger; import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; @@ -16,8 +17,6 @@ import edu.caltech.ipac.util.DataGroup; import edu.caltech.ipac.util.DataType; import edu.caltech.ipac.util.StringUtils; -import edu.caltech.ipac.util.decimate.DecimateKey; -import org.apache.commons.codec.digest.DigestUtils; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; @@ -27,6 +26,7 @@ import javax.validation.constraints.NotNull; import java.io.File; +import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -49,23 +49,38 @@ public class EmbeddedDbUtil { private static final Logger.LoggerImpl logger = Logger.getLogger(); + /** + * setup a database + * @param dbFile the file to save the database to. + * @param dbAdapter DbAdapter to use.. ie sqlite, h2, etc. + */ + public static void createDbFile(File dbFile, DbAdapter dbAdapter) throws IOException { + dbAdapter.close(dbFile); // in case database exists in memory. + File[] toRemove = dbFile.getParentFile().listFiles((dir, name) -> name.startsWith(dbFile.getName())); + if (toRemove != null && toRemove.length > 0) { + Arrays.stream(toRemove).forEach(f -> f.delete()); + } + dbFile.createNewFile(); // creates the file + createCustomFunctions(dbFile, dbAdapter); // add custom functions + } + /** * ingest the given datagroup into a database file using the provided DbAdpater. * @param dbFile the file to save the database to. * @param dg the datagroup containing the data * @param dbAdapter DbAdapter to use.. ie sqlite, h2, etc. + * @param forTable the name of the table to ingest to * @return a FileInfo with sizeInBytes representing to the number of rows. */ - public static FileInfo createDbFile(File dbFile, DataGroup dg, DbAdapter dbAdapter) { + public static FileInfo ingestDataGroup(File dbFile, DataGroup dg, DbAdapter dbAdapter, String forTable) { // remove ROW_IDX or ROW_NUM if exists dg.removeDataDefinition(DataGroup.ROW_IDX); dg.removeDataDefinition(DataGroup.ROW_NUM); - createCustomFunctions(dbFile, dbAdapter); - int rowCount = createDataTbl(dbFile, dg, dbAdapter); - createDDTbl(dbFile, dg, dbAdapter, "data"); - createMetaTbl(dbFile, dg, dbAdapter, "data"); + createDataTbl(dbFile, dg, dbAdapter, forTable); + createDDTbl(dbFile, dg, dbAdapter, forTable); + createMetaTbl(dbFile, dg, dbAdapter, forTable); FileInfo finfo = new FileInfo(dbFile); return finfo; } @@ -134,93 +149,48 @@ public static int insertDD(DataGroup dg, ResultSet rs) { return 0; } - public static String setupDatasetTable(TableServerRequest treq) { - String resultSetID = getResultSetID(treq); - - DbAdapter dbAdapter = DbAdapter.getAdapter(treq); - DbInstance dbInstance = dbAdapter.getDbInstance(getDbFile(treq)); - - try { - JdbcFactory.getSimpleTemplate(dbInstance).queryForInt(String.format("select count(*) from %s", resultSetID)); - } catch (Exception e) { - // does not exists.. create table from orignal 'data' table - List cols = treq.getInclColumns() == null ? getColumnNames(dbInstance, "DATA") - : StringUtils.asList(treq.getInclColumns(), ","); - String wherePart = dbAdapter.wherePart(treq); - String orderBy = dbAdapter.orderByPart(treq); - String tblName = getResultSetID(treq); - - cols = cols.stream().filter((s) -> !(s.equals(DataGroup.ROW_IDX) || s.equals(DataGroup.ROW_NUM))).collect(Collectors.toList()); // remove this cols because it will be automatically added - - // copy data - String datasetSql = String.format("select %s, %s from data %s %s", StringUtils.toString(cols), DataGroup.ROW_IDX, wherePart, orderBy); - String datasetSqlWithIdx = String.format("select b.*, (ROWNUM-1) as %s from (%s) as b", DataGroup.ROW_NUM, datasetSql); - String sql = dbAdapter.createTableFromSelect(tblName, datasetSqlWithIdx); - JdbcFactory.getSimpleTemplate(dbInstance).update(sql); - - // copy dd - String ddSql = "select * from data_dd"; - ddSql = dbAdapter.createTableFromSelect(tblName + "_dd", ddSql); - JdbcFactory.getSimpleTemplate(dbInstance).update(ddSql); - - // copy meta - String metaSql = "select * from data_meta"; - metaSql = dbAdapter.createTableFromSelect(tblName + "_meta", metaSql); - JdbcFactory.getSimpleTemplate(dbInstance).update(metaSql); - - } - - return resultSetID; - } - - public static List getColumnNames(DbInstance dbInstance, String forTable) { - List cols = JdbcFactory.getSimpleTemplate(dbInstance).query(String.format("select cname from %s_DD", forTable), (rs, i) -> rs.getString(1)); - cols = cols.stream().map((s) -> "\"" + s.toUpperCase() + "\"").collect(Collectors.toList()); // internally.. columns are stored as uppercase. adding quotes to avoid db reserved words. - return cols; - } - - /** - * return the DB file this request mapped to. - * @param treq - * @return - */ - public static File getDbFile(TableServerRequest treq) { - String fname = String.format("%s_%s.%s", treq.getRequestId(), DigestUtils.md5Hex(getUniqueID(treq)), DbAdapter.getAdapter(treq).getName()); - return new File(ServerContext.getTempWorkDir(), fname); - } - public static void setDbMetaInfo(TableServerRequest treq, DbAdapter dbAdapter, File dbFile) { treq.setMeta(TBL_FILE_PATH, ServerContext.replaceWithPrefix(dbFile)); treq.setMeta(TBL_FILE_TYPE, dbAdapter.getName()); } - public static String getTblFileType(TableServerRequest treq) { - return treq.getMeta(TBL_FILE_TYPE); - } - - @NotNull - public static String getResultSetID(TableServerRequest treq) { - String id = StringUtils.toString(treq.getResultSetParam(), "|"); - return StringUtils.isEmpty(id) ? "data" : "data_" + DigestUtils.md5Hex(id); - } @NotNull public static String getUniqueID(TableServerRequest treq) { return SearchProcessor.getUniqueIDDef(treq); } - public static DataGroupPart getResults(TableServerRequest treq, String sql, String tblName) { - DataGroup dg = runQuery(DbAdapter.getAdapter(treq), getDbFile(treq), sql, tblName); + public static DataGroupPart getResultForTable(TableServerRequest treq, File dbFile, String tblName) throws DataAccessException { + try { + DbAdapter dbAdapter = DbAdapter.getAdapter(treq); + + // select a page from the dataset table + String pageSql = getPageSql(dbAdapter, treq, tblName); + DataGroupPart page = EmbeddedDbUtil.getResults(treq, pageSql, dbFile, tblName); + + // fetch total row count for the query.. datagroup may contain partial results(paging) + String cntSql = String.format("select count(*) from %s", tblName); + int rowCnt = JdbcFactory.getSimpleTemplate(dbAdapter.getDbInstance(dbFile)).queryForInt(cntSql); + + page.setRowCount(rowCnt); + page.getTableDef().setAttribute(TableServerRequest.RESULTSET_ID, tblName); + if (!StringUtils.isEmpty(treq.getTblTitle())) { + page.getData().setTitle(treq.getTblTitle()); // set the datagroup's title to the request title. + } + return page; + } catch (Exception ex) { + throw new DataAccessException(ex); + } + } + + public static DataGroupPart getResults(TableServerRequest treq, String sql, File dbFile, String tblName) { + DataGroup dg = runQuery(DbAdapter.getAdapter(treq), dbFile, sql, tblName); TableDef tm = new TableDef(); tm.setStatus(DataGroupPart.State.COMPLETED); tm.setRowCount(dg.size()); return new DataGroupPart(tm, dg, treq.getStartIndex(), dg.size()); } - public static int createDataTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter) { - return createDataTbl(dbFile, dg, dbAdapter, null); - } - public static int createDataTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter, String tblName) { DataType[] colsAry = makeDbCols(dg); @@ -319,16 +289,21 @@ public static void createMetaTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter, JdbcFactory.getSimpleTemplate(dbAdapter.getDbInstance(dbFile)).batchUpdate(insertDDSql, data); } + /** + * @param dbFile + * @param dg + * @param dbAdapter + * @param tblName + */ + public static void createDDTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter, String tblName) { - public static void createDDTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter, String forTable) { - - makeDbCols(dg); - String createDDSql = dbAdapter.createDDSql(forTable); + DataType[] colsAry = makeDbCols(dg); + String createDDSql = dbAdapter.createDDSql(tblName); JdbcFactory.getSimpleTemplate(dbAdapter.getDbInstance(dbFile)).update(createDDSql); Map meta = dg.getAttributes(); List data = new ArrayList<>(); - for(DataType dt : dg.getDataDefinitions()) { + for(DataType dt : colsAry) { int width = getIntVal(meta, WIDTH_TAG, dt, 0); width = width > 0 ? width : dt.getFormatInfo().getWidth(); String format = getStrVal(meta, FORMAT_TAG, dt, null); @@ -351,10 +326,21 @@ public static void createDDTbl(File dbFile, DataGroup dg, DbAdapter dbAdapter, S } ); } - String insertDDSql = dbAdapter.insertDDSql(forTable); + String insertDDSql = dbAdapter.insertDDSql(tblName); JdbcFactory.getSimpleTemplate(dbAdapter.getDbInstance(dbFile)).batchUpdate(insertDDSql, data); } +//==================================================================== +// +//==================================================================== + + private static String getPageSql(DbAdapter dbAdapter, TableServerRequest treq, String fromTable) { + String selectPart = dbAdapter.selectPart(treq); + String pagingPart = dbAdapter.pagingPart(treq); + + return String.format("%s from %s %s", selectPart, fromTable, pagingPart); + } + private static DataType[] makeDbCols(DataGroup dg) { DataType[] cols = new DataType[dg.getDataDefinitions().length + 2]; if (dg.getDataDefintion(ROW_IDX) != null) { @@ -369,7 +355,7 @@ private static DataType[] makeDbCols(DataGroup dg) { } private static String getStrVal(Map meta, String tag, DataType col, String def) { - DataGroup.Attribute val = meta.get(makeAttribKey(LABEL_TAG, col.getKeyName())); + DataGroup.Attribute val = meta.get(makeAttribKey(tag, col.getKeyName())); return val == null ? def : val.getValue(); } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/db/HsqlDbAdapter.java b/src/firefly/java/edu/caltech/ipac/firefly/server/db/HsqlDbAdapter.java index 4ee55ab285..42b90dc9ea 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/db/HsqlDbAdapter.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/db/HsqlDbAdapter.java @@ -3,7 +3,6 @@ */ package edu.caltech.ipac.firefly.server.db; -import edu.caltech.ipac.firefly.data.TableServerRequest; import edu.caltech.ipac.firefly.server.db.spring.JdbcFactory; import java.io.File; @@ -19,7 +18,7 @@ public String getName() { } protected EmbeddedDbInstance createDbInstance(File dbFile) { - String dbUrl = String.format("jdbc:hsqldb:file:%s;hsqldb.cache_size=256000;hsqldb.log_size=256;sql.syntax_ora=true", dbFile.getPath()); + String dbUrl = String.format("jdbc:hsqldb:file:%s;hsqldb.log_size=1024;sql.syntax_ora=true", dbFile.getPath()); return new EmbeddedDbInstance(getName(), dbFile, dbUrl, "org.hsqldb.jdbc.JDBCDriver"); } @@ -28,6 +27,16 @@ public String createTableFromSelect(String tblName, String selectSql) { } public void close(File dbFile) { - JdbcFactory.getTemplate(getDbInstance(dbFile)).execute("SHUTDOWN"); + DbInstance db = getDbInstance(dbFile, false); + if (db != null) { + JdbcFactory.getTemplate(db).execute("SHUTDOWN"); + } } + + + // this is a list of HSQLDB keywords +// private static final List KEYWORDS = Arrays.asList("ALL", "AND", "ANY", "AS", "AT", "AVG", "BETWEEN", "BOTH", "BY", "CALL", "CASE", "CAST", "COALESCE", "CORRESPONDING", "CONVERT", "COUNT", "CREATE", +// "CROSS", "DEFAULT", "DISTINCT", "DROP", "ELSE", "EVERY", "EXISTS", "EXCEPT", "FOR", "FROM", "FULL", "GRANT", "GROUP", "HAVING", "IN", "INNER", "INTERSECT", "INTO", "IS", "JOIN", "LEFT", "LEADING", +// "LIKE", "MAX", "MIN", "NATURAL", "NOT", "NULLIF", "ON", "ORDER", "OR", "OUTER", "PRIMARY", "REFERENCES", "RIGHT", "SELECT", "SET", "SOME", "STDDEV_POP", "STDDEV_SAMP", "SUM", "TABLE", "THEN", "TO", +// "TRAILING", "TRIGGER", "UNION", "UNIQUE", "USING", "VALUES", "VAR_POP", "VAR_SAMP", "WHEN", "WHERE", "WITH"); } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServiceInput.java b/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServiceInput.java index 7ea12bc755..43dc258d49 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServiceInput.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServiceInput.java @@ -4,6 +4,7 @@ package edu.caltech.ipac.firefly.server.network; +import edu.caltech.ipac.firefly.server.ServerContext; import edu.caltech.ipac.util.StringUtils; import java.io.File; @@ -109,4 +110,12 @@ public String getDesc() { return sb.toString(); } + + public static HttpServiceInput createWithCredential() { + HttpServiceInput input = new HttpServiceInput(); + Map cookies = ServerContext.getRequestOwner().getIdentityCookies(); + cookies.entrySet().stream().forEach( entry -> input.setCookie(entry.getKey(), entry.getValue())); + return input; + } + } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServices.java b/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServices.java index b092c5065f..6d93e3f8e4 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServices.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/network/HttpServices.java @@ -81,7 +81,7 @@ public void releaseConnection(HttpConnection conn) { * @return */ public static int getData(String url, File results) { - return getData(url, results); + return getData(url, results, null); } public static int getData(String url, OutputStream results) { diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryRTreeInventory.java b/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryRTreeInventory.java index 0750883153..6013bb5644 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryRTreeInventory.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryRTreeInventory.java @@ -91,37 +91,9 @@ protected String getQueryString(TableServerRequest req) throws DataAccessExcepti return serviceurl + "?dataset=" + dataset + "®ion=cone+" + wpt.getLon() + "+" + wpt.getLat() + "+" + radDeg; } - @Override - public boolean doCache() { - return true; - } - @Override protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { - - long start = System.currentTimeMillis(); - - String fromCacheStr = ""; - - StringKey key = new StringKey(this.getClass().getName(), getUniqueID(request)); - Cache cache = CacheManager.getCache(Cache.TYPE_PERM_FILE); - File retFile = (File) cache.get(key); - if (retFile == null) { - retFile = doQuery(request); // all the work is done here - cache.put(key, retFile); - } else { - fromCacheStr = " (from Cache)"; - } - - long elaspe = System.currentTimeMillis() - start; - String sizeStr = FileUtil.getSizeAsString(retFile.length()); - String timeStr = UTCTimeUtil.getHMSFromMills(elaspe); - - _log.info("catalog: " + timeStr + fromCacheStr, - "filename: " + retFile.getPath(), - "size: " + sizeStr); - - return retFile; + return doQuery(request); // all the work is done here } private File doQuery(TableServerRequest req) throws IOException, DataAccessException { diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryVOTABLE.java b/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryVOTABLE.java index cb162afc6c..1e27f3a2ed 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryVOTABLE.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/persistence/QueryVOTABLE.java @@ -15,9 +15,6 @@ import edu.caltech.ipac.firefly.server.query.IpacTablePartProcessor; import edu.caltech.ipac.firefly.server.util.Logger; import edu.caltech.ipac.util.*; -import edu.caltech.ipac.util.cache.Cache; -import edu.caltech.ipac.util.cache.CacheManager; -import edu.caltech.ipac.util.cache.StringKey; import edu.caltech.ipac.visualize.plot.CoordinateSys; import java.io.File; @@ -50,30 +47,7 @@ public boolean doCache() { @Override protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { - - long start = System.currentTimeMillis(); - - String fromCacheStr = ""; - - StringKey key = new StringKey(this.getClass().getName(), getUniqueID(request)); - Cache cache = CacheManager.getCache(Cache.TYPE_PERM_FILE); - File retFile = (File) cache.get(key); - if (retFile == null) { - retFile = queryVOSearchService(request); // all the work is done here - cache.put(key, retFile); - } else { - fromCacheStr = " (from Cache)"; - } - - long elaspe = System.currentTimeMillis() - start; - String sizeStr = FileUtil.getSizeAsString(retFile.length()); - String timeStr = UTCTimeUtil.getHMSFromMills(elaspe); - - _log.info("catalog: " + timeStr + fromCacheStr, - "filename: " + retFile.getPath(), - "size: " + sizeStr); - - return retFile; + return queryVOSearchService(request); // all the work is done here } protected abstract String getQueryString(TableServerRequest req) throws DataAccessException; @@ -151,53 +125,45 @@ private File getSearchResult(String urlQuery, String filePrefix) throws IOExcept _log.error(e, e.toString()); throw new EndUserException("query failed - bad url: "+urlQuery, e.toString()); } - StringKey cacheKey = new StringKey(url); - File f = (File) getCache().get(cacheKey); - if (f != null && f.canRead()) { - return f; - } else { - URLConnection conn = null; - - //File outFile = createFile(req, ".xml"); - File outFile = File.createTempFile(filePrefix, ".xml", ServerContext.getPermWorkDir()); - try { - conn = URLDownload.makeConnection(url); - conn.setRequestProperty("Accept", "*/*"); - - URLDownload.getDataToFile(conn, outFile); - getCache().put(cacheKey, outFile, 60 * 60 * 24); // 1 day - - } catch (MalformedURLException e) { - _log.error(e, "Bad URL"); - throw makeException(e, "query failed - bad url."); - - } catch (IOException e) { - _log.error(e, e.toString()); - if (conn != null && conn instanceof HttpURLConnection) { - HttpURLConnection httpConn = (HttpURLConnection) conn; - int respCode = httpConn.getResponseCode(); - if (respCode == 400 || respCode == 404 || respCode == 500) { - InputStream is = httpConn.getErrorStream(); - if (is != null) { - String msg = parseMessageFromServer(DynServerUtils.convertStreamToString(is)); - throw new EndUserException("query failed: " + msg, msg); - - } else { - String msg = httpConn.getResponseMessage(); - throw new EndUserException("query failed: " + msg, msg); - } - } + URLConnection conn = null; + + //File outFile = createFile(req, ".xml"); + File outFile = File.createTempFile(filePrefix, ".xml", ServerContext.getPermWorkDir()); + try { + conn = URLDownload.makeConnection(url); + conn.setRequestProperty("Accept", "*/*"); + + URLDownload.getDataToFile(conn, outFile); - } else { - throw makeException(e, "query failed - network error."); + } catch (MalformedURLException e) { + _log.error(e, "Bad URL"); + throw makeException(e, "query failed - bad url."); + + } catch (IOException e) { + _log.error(e, e.toString()); + if (conn != null && conn instanceof HttpURLConnection) { + HttpURLConnection httpConn = (HttpURLConnection) conn; + int respCode = httpConn.getResponseCode(); + if (respCode == 400 || respCode == 404 || respCode == 500) { + InputStream is = httpConn.getErrorStream(); + if (is != null) { + String msg = parseMessageFromServer(DynServerUtils.convertStreamToString(is)); + throw new EndUserException("query failed: " + msg, msg); + + } else { + String msg = httpConn.getResponseMessage(); + throw new EndUserException("query failed: " + msg, msg); + } } - } catch (Exception e) { - throw makeException(e, "query failed"); + } else { + throw makeException(e, "query failed - network error."); } - return outFile; - } + } catch (Exception e) { + throw makeException(e, "query failed"); + } + return outFile; } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/DecimationProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/DecimationProcessor.java index 47d0d902aa..ebc349f3cf 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/DecimationProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/DecimationProcessor.java @@ -14,6 +14,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @SearchProcessorImpl(id = "DecimateTable") @@ -39,12 +40,16 @@ protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter db requestedCols.addAll(xColExpr.getParsedVariables()); requestedCols.addAll(yColExpr.getParsedVariables()); } + requestedCols = requestedCols.stream().map(c -> "\"" + c + "\"").collect(Collectors.toList()); // column name need to be in quotes sreq.setInclColumns(requestedCols.toArray(new String[requestedCols.size()])); DataGroup dg = new SearchManager().getDataGroup(sreq).getData(); if (decimateInfo != null) { DataGroup retval = QueryUtil.doDecimation(dg, decimateInfo); + dg.getAttributeKeys().stream().forEach(k -> { + retval.addAttribute(k, dg.getAttribute(k).getValue()); + }); return retval; } else { return dg; diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/DynQueryProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/DynQueryProcessor.java index a97733070b..8d46054d88 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/DynQueryProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/DynQueryProcessor.java @@ -30,7 +30,7 @@ abstract public class DynQueryProcessor extends IpacTablePartProcessor { - protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { + public File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { File dataFile = loadDynDataFile(request); diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessor.java index a5555c6277..7d317b7ee7 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessor.java @@ -11,13 +11,17 @@ import edu.caltech.ipac.firefly.data.table.TableMeta; import edu.caltech.ipac.firefly.server.ServerContext; import edu.caltech.ipac.firefly.server.db.DbAdapter; +import edu.caltech.ipac.firefly.server.db.DbInstance; import edu.caltech.ipac.firefly.server.db.EmbeddedDbUtil; import edu.caltech.ipac.firefly.server.db.spring.JdbcFactory; import edu.caltech.ipac.firefly.server.util.StopWatch; import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; +import edu.caltech.ipac.util.DataGroup; import edu.caltech.ipac.util.DataType; import edu.caltech.ipac.util.StringUtils; +import org.apache.commons.codec.digest.DigestUtils; +import javax.validation.constraints.NotNull; import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -25,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; /** * NOTE: We're using spring jdbc v2.x. API changes dramatically in later versions. @@ -50,12 +55,8 @@ * 2. storing the original ROW_IDX of DATA in relation to the results. * [hash_id] is an MD5 hex of the filter/sort parameters. * - * - Database columns when not quoted are usually stored as uppercase. Columns used in an SQL statement when not quoted - * are converted to uppercase in order to match the name of the table's columns. With that said: - * - DataGroup columns are stored as uppercase - * - DD table is used to convert it back to original casing - * - Every database has its list reserved words. To reference a column with the same name, enclose it with double-quotes("). - * + * - All column names must be enclosed in double-quotes(") to avoid reserved keywords clashes. + * This applies to inputs used by the database component, ie. INCL_COLUMNS, FILTERS, SORT_INFO, etc */ abstract public class EmbeddedDbProcessor implements SearchProcessor, CanGetDataFile { private static final Map activeRequests = new HashMap<>(); @@ -72,8 +73,36 @@ abstract public class EmbeddedDbProcessor implements SearchProcessor cols = StringUtils.isEmpty(treq.getInclColumns()) ? getColumnNames(dbInstance, "DATA") + : StringUtils.asList(treq.getInclColumns(), ","); + String wherePart = dbAdapter.wherePart(treq); + String orderBy = dbAdapter.orderByPart(treq); + + cols = cols.stream().filter((s) -> { + s = s.replaceFirst("^\"(.+)\"$", "$1"); + return !(s.equals(DataGroup.ROW_IDX) || s.equals(DataGroup.ROW_NUM)); + }).collect(Collectors.toList()); // remove this cols because it will be automatically added + + // copy data + String datasetSql = String.format("select %s, %s from data %s %s", StringUtils.toString(cols), DataGroup.ROW_IDX, wherePart, orderBy); + String datasetSqlWithIdx = String.format("select b.*, (ROWNUM-1) as %s from (%s) as b", DataGroup.ROW_NUM, datasetSql); + String sql = dbAdapter.createTableFromSelect(resultSetID, datasetSqlWithIdx); + JdbcFactory.getSimpleTemplate(dbInstance).update(sql); + + // copy dd + String ddSql = "select * from data_dd"; + ddSql = dbAdapter.createTableFromSelect(resultSetID + "_dd", ddSql); + JdbcFactory.getSimpleTemplate(dbInstance).update(ddSql); + + // copy meta + String metaSql = "select * from data_meta"; + metaSql = dbAdapter.createTableFromSelect(resultSetID + "_meta", metaSql); + JdbcFactory.getSimpleTemplate(dbInstance).update(metaSql); - page.setRowCount(rowCnt); - page.getTableDef().setAttribute(TableServerRequest.RESULTSET_ID, tblName); - if (!StringUtils.isEmpty(treq.getTblTitle())) { - page.getData().setTitle(treq.getTblTitle()); // set the datagroup's title to the request title. - } - return page; - } catch (Exception ex) { - throw new DataAccessException(ex); } + return EmbeddedDbUtil.getResultForTable(treq, dbFile, resultSetID); } + public boolean isSecurityAware() { return false; } + //==================================================================== // //==================================================================== - - private String getPageSql(DbAdapter dbAdapter, TableServerRequest treq, String fromTable) { - String selectPart = dbAdapter.selectPart(treq); - String pagingPart = dbAdapter.pagingPart(treq); - - return String.format("%s from %s %s", selectPart, fromTable, pagingPart); + private static List getColumnNames(DbInstance dbInstance, String forTable) { + List cols = JdbcFactory.getSimpleTemplate(dbInstance).query(String.format("select cname from %s_DD", forTable), (rs, i) -> "\"" + rs.getString(1) + "\""); + return cols; } - + } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessorWrapper.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessorWrapper.java index ed5f9dc452..f4fbb60c7a 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessorWrapper.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/EmbeddedDbProcessorWrapper.java @@ -16,7 +16,6 @@ import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; import edu.caltech.ipac.util.DataGroup; import edu.caltech.ipac.util.DataType; -import edu.caltech.ipac.util.decimate.DecimateKey; import java.io.File; import java.io.IOException; @@ -38,7 +37,7 @@ public EmbeddedDbProcessorWrapper(IpacTablePartProcessor processor) { } - public FileInfo createDbFile(TableServerRequest treq) throws DataAccessException { + public FileInfo ingestDataIntoDb(TableServerRequest treq, File dbFile) throws DataAccessException { try { DbAdapter dbAdapter = DbAdapter.getAdapter(treq); @@ -50,11 +49,7 @@ public FileInfo createDbFile(TableServerRequest treq) throws DataAccessException setupMeta(dg, treq); - File dbFile = EmbeddedDbUtil.getDbFile(treq); - if (!dbFile.createNewFile()) { - LOGGER.error("This should not happen.. can't create dbFile:" + dbFile.getPath()); - } - FileInfo finfo = EmbeddedDbUtil.createDbFile(dbFile, dg, dbAdapter); + FileInfo finfo = EmbeddedDbUtil.ingestDataGroup(dbFile, dg, dbAdapter, "data"); return finfo; } catch (IpacTableException | IOException | DataAccessException ex) { throw new DataAccessException(ex); diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/IBESearchProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/IBESearchProcessor.java index 8a5ddbe3dc..1546ced992 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/IBESearchProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/IBESearchProcessor.java @@ -5,28 +5,24 @@ import edu.caltech.ipac.firefly.core.EndUserException; import edu.caltech.ipac.firefly.data.ServerRequest; +import edu.caltech.ipac.firefly.data.TableServerRequest; import edu.caltech.ipac.firefly.data.table.TableMeta; import edu.caltech.ipac.firefly.server.ServerContext; +import edu.caltech.ipac.firefly.server.util.Logger; import edu.caltech.ipac.firefly.server.util.QueryUtil; -import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupReader; import edu.caltech.ipac.firefly.server.util.multipart.MultiPartPostBuilder; import edu.caltech.ipac.firefly.util.DataSetParser; import edu.caltech.ipac.util.DataGroup; import edu.caltech.ipac.util.DataObject; import edu.caltech.ipac.util.DataType; import edu.caltech.ipac.util.StringUtils; -import edu.caltech.ipac.util.cache.Cache; -import edu.caltech.ipac.util.cache.CacheKey; -import edu.caltech.ipac.util.cache.CacheManager; -import edu.caltech.ipac.util.cache.StringKey; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; import java.util.List; public abstract class IBESearchProcessor extends DynQueryProcessor { + private static final Logger.LoggerImpl LOGGER = Logger.getLogger(); abstract protected String getDDUrl(ServerRequest request); @@ -71,13 +67,20 @@ public void prepareTableMeta(TableMeta meta, List columns, ServerReque setXmlParams(request); String url = getDDUrl(request); if (url != null) { - DataGroup template = getTemplate(url); - for (DataObject row : template) { - String col = String.valueOf(row.getDataElement("name")); - if (exists(columns, col)) { - String desc = String.valueOf(row.getDataElement("description")); - meta.setAttribute(DataSetParser.makeAttribKey(DataSetParser.DESC_TAG, col), desc); + try { + TableServerRequest treg = new TableServerRequest(IbeTemplateProcessor.PROC_ID); + treg.setParam("url", url); + DataGroup template = new SearchManager().getDataGroup(treg).getData(); + for (DataObject row : template) { + String col = String.valueOf(row.getDataElement("name")); + if (exists(columns, col)) { + String desc = String.valueOf(row.getDataElement("description")); + meta.setAttribute(DataSetParser.makeAttribKey(DataSetParser.DESC_TAG, col), desc); + } } + } catch (DataAccessException e) { + // cannot find template.. this is not normal + LOGGER.error(e); } } } @@ -198,46 +201,5 @@ protected static IOException makeException(Exception e, String reason) { return eio; } - - private DataGroup getTemplate(String url) { - - if (StringUtils.isEmpty(url)) { - return null; - } - try { - CacheKey cacheKey = new StringKey("IBETemplateGenerator", url); - Cache cache = CacheManager.getCache(Cache.TYPE_PERM_SMALL); - DataGroup template = (DataGroup) cache.get(cacheKey); - if (template == null) { - template = loadTemplate(url); - cache.put(cacheKey, template); - } - return template; - } catch (Exception e) { - LOGGER.warn(e, "Unable to get template for url:" + url); - } - return null; - } - - private DataGroup loadTemplate(String urlStr) { - - DataGroup template = null; - try { - URL url = new URL(urlStr); - File ofile = File.createTempFile("IBETemplateGenerator", ".tbl", ServerContext.getTempWorkDir()); - downloadFile(url, ofile); - - if (ofile.canRead()) { - template = DataGroupReader.read(ofile); - } - } catch (MalformedURLException e) { - LOGGER.error(e, "not a valid url:" + urlStr); - } catch (EndUserException e) { - LOGGER.error(e, "Unable to connect to service url:" + urlStr); - } catch (IOException e) { - LOGGER.error(e); - } - return template; - } } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/IbeTemplateProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/IbeTemplateProcessor.java new file mode 100644 index 0000000000..4b2fa0a838 --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/IbeTemplateProcessor.java @@ -0,0 +1,45 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query; + +import edu.caltech.ipac.firefly.data.TableServerRequest; +import edu.caltech.ipac.firefly.server.network.HttpServiceInput; +import edu.caltech.ipac.firefly.server.network.HttpServices; +import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupReader; +import edu.caltech.ipac.util.DataGroup; +import org.apache.tools.ant.filters.StringInputStream; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static edu.caltech.ipac.firefly.server.query.IbeTemplateProcessor.PROC_ID; + + +/** + * Creates table definition for IBE tables. This extends SharedDbProcessor, meaning all of the tables will + * be saved in one database. + */ +@SearchProcessorImpl(id = PROC_ID, params = + {@ParamDoc(name = "url", desc = "the url for table definition") + }) +public class IbeTemplateProcessor extends SharedDbProcessor { + public static final String PROC_ID = "IbeTemplate"; + + public DataGroup fetchData(TableServerRequest treq) throws DataAccessException { + try { + String url = treq.getParam("url"); + ByteArrayOutputStream results = new ByteArrayOutputStream(); + HttpServices.getData(url, results, HttpServiceInput.createWithCredential()); + return DataGroupReader.read(new StringInputStream(results.toString())); + } catch (IOException e) { + throw new DataAccessException(e.getMessage(), e); + } + } + + @Override + public boolean doLogging() { + return false; + } +} + diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/SearchServerCommands.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/SearchServerCommands.java index dc510b3451..efe3aa051b 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/SearchServerCommands.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/SearchServerCommands.java @@ -23,7 +23,6 @@ import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; import edu.caltech.ipac.firefly.server.util.ipactable.JsonTableUtil; import edu.caltech.ipac.firefly.server.SrvParam; -import edu.caltech.ipac.util.CollectionUtil; import edu.caltech.ipac.util.DataGroup; import edu.caltech.ipac.util.StringUtils; import org.json.simple.JSONObject; @@ -72,17 +71,18 @@ public static class SelectedValues extends ServCommand { public String doCommand(SrvParam params) throws Exception { String requestJson = params.getRequired(ServerParams.REQUEST); TableServerRequest treq = QueryUtil.convertToServerRequest(requestJson); + EmbeddedDbProcessor proc = (EmbeddedDbProcessor) new SearchManager().getProcessor(treq.getRequestId()); treq.setPageSize(Integer.MAX_VALUE); try { List cols = StringUtils.asList(params.getRequired("columnNames"), ","); List rows = StringUtils.convertToListInteger(params.getRequired("selectedRows"), ","); // hitting the database directly. String selCols = cols.size() > 0 ? StringUtils.toString(cols) : "*"; - String tblName = EmbeddedDbUtil.getResultSetID(treq) ; + String tblName = proc.getResultSetID(treq) ; String inRows = rows.size() > 0 ? StringUtils.toString(rows) : "-1"; String sql = String.format("select %s from %s where %s in (%s)", selCols, tblName, DataGroup.ROW_NUM, inRows); - DataGroupPart page = EmbeddedDbUtil.getResults(treq, sql ,tblName); + DataGroupPart page = EmbeddedDbUtil.getResults(treq, sql , proc.getDbFile(treq), tblName); return JsonTableUtil.toJsonTableModel(page, treq).toJSONString(); } catch (IOException e) { diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/SharedDbProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/SharedDbProcessor.java new file mode 100644 index 0000000000..f28cd242ab --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/SharedDbProcessor.java @@ -0,0 +1,66 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query; + +import edu.caltech.ipac.firefly.data.FileInfo; +import edu.caltech.ipac.firefly.data.Param; +import edu.caltech.ipac.firefly.data.TableServerRequest; +import edu.caltech.ipac.firefly.server.ServerContext; +import edu.caltech.ipac.firefly.server.db.DbAdapter; +import edu.caltech.ipac.firefly.server.db.DbInstance; +import edu.caltech.ipac.firefly.server.db.EmbeddedDbUtil; +import edu.caltech.ipac.firefly.server.db.spring.JdbcFactory; +import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupPart; +import edu.caltech.ipac.util.DataGroup; +import edu.caltech.ipac.util.StringUtils; +import org.apache.commons.codec.digest.DigestUtils; + +import java.io.File; +import java.util.SortedSet; + + +/** + * This is a base class for processors in which query results are stored as a table + * within the same database. + */ +public abstract class SharedDbProcessor extends EmbeddedDbProcessor { + + public abstract DataGroup fetchData(TableServerRequest treq) throws DataAccessException; + + @Override + /** + * All results from this processor will be saved in the same database. It's also based on sessionID so that + * it can be easily cleared. + */ + public File getDbFile(TableServerRequest treq) { + DbAdapter dbAdapter = DbAdapter.getAdapter(treq); + String fname = String.format("%s_%s.%s", treq.getRequestId(), ServerContext.getRequestOwner().getRequestAgent().getSessId(), dbAdapter.getName()); + return new File(ServerContext.getTempWorkDir(), fname); + } + + public FileInfo ingestDataIntoDb(TableServerRequest treq, File dbFile) throws DataAccessException { + // nothing to do here. + return new FileInfo(dbFile); + } + + @Override + protected DataGroupPart getResultSet(TableServerRequest treq, File dbFile) throws DataAccessException { + DbAdapter dbAdapter = DbAdapter.getAdapter(treq); + DbInstance dbInstance = dbAdapter.getDbInstance(dbFile); + SortedSet params = treq.getSearchParams(); + params.addAll(treq.getResultSetParam()); + String tblName = "data_" + DigestUtils.md5Hex(StringUtils.toString(params, "|")); + + String tblExists = String.format("select count(*) from %s", tblName); + try { + JdbcFactory.getSimpleTemplate(dbInstance).queryForInt(tblExists); + } catch (Exception e) { + // DD for this catalog does not exists.. fetch data and populate + DataGroup data = fetchData(treq); + EmbeddedDbUtil.ingestDataGroup(dbFile, data, dbAdapter, tblName); + } + return EmbeddedDbUtil.getResultForTable(treq, dbFile, tblName); + } +} + diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/StatisticsProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/StatisticsProcessor.java index f0973c09af..a434bc2125 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/StatisticsProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/StatisticsProcessor.java @@ -42,7 +42,8 @@ protected String getResultSetTablePrefix() { } protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter dbAdapter) throws DataAccessException { - String origDataTblName = EmbeddedDbUtil.getResultSetID(getSearchRequest(treq)); + EmbeddedDbProcessor proc = getSearchProcessor(getSearchRequest(treq)); + String origDataTblName = proc.getResultSetID(treq); // check to see if a resultset table exists... if not, use orginal data table. DbInstance dbInstance = dbAdapter.getDbInstance(dbFile); String tblExists = String.format("select count(*) from %s", origDataTblName); @@ -64,16 +65,15 @@ protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter db String visi = (String) col.getDataElement("VISIBILITY"); if (DataType.NUMERIC_TYPES.contains(type) && !StringUtils.areEqual(visi, "hidden")) { String cname = col.getStringData("CNAME"); - String cnameUC = cname.toUpperCase(); String desc = col.getStringData("DESC"); String units = col.getStringData("UNITS"); DataObject row = new DataObject(stats); row.setDataElement(columns[0], cname); row.setDataElement(columns[1], desc); row.setDataElement(columns[2], units); - sqlCols.add(String.format("min(\"%1$s\") as \"%1$s_min\"", cnameUC)); - sqlCols.add(String.format("max(\"%1$s\") as \"%1$s_max\"", cnameUC)); - sqlCols.add(String.format("count(\"%1$s\") as \"%1$s_count\"", cnameUC)); + sqlCols.add(String.format("min(\"%1$s\") as \"%1$s_min\"", cname)); + sqlCols.add(String.format("max(\"%1$s\") as \"%1$s_max\"", cname)); + sqlCols.add(String.format("count(\"%1$s\") as \"%1$s_count\"", cname)); stats.add(row); } @@ -82,7 +82,7 @@ protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter db DataObject data = EmbeddedDbUtil.runQuery(dbAdapter, dbFile, String.format("select %s from %s",StringUtils.toString(sqlCols), origDataTblName), null).get(0); for (int i = 0; i < stats.size(); i++) { DataObject col = stats.get(i); - String cname = col.getStringData("columnName").toUpperCase(); + String cname = col.getStringData("columnName"); col.setDataElement(columns[3], getDouble(data.getDataElement(cname + "_min"))); col.setDataElement(columns[4], getDouble(data.getDataElement(cname + "_max"))); col.setDataElement(columns[5], data.getDataElement(cname + "_count")); diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/TableFunctionProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/TableFunctionProcessor.java index fa48c2b2d0..e65883c7cd 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/TableFunctionProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/TableFunctionProcessor.java @@ -21,25 +21,50 @@ import static edu.caltech.ipac.firefly.data.TableServerRequest.FILTERS; +/** + * This is a base class for processors which perform a task on the original table + * and then save the results into the original table's database. + */ public abstract class TableFunctionProcessor extends EmbeddedDbProcessor { public static final String SEARCH_REQUEST = "searchRequest"; - + /** + * results will be saved as a new set of tables(data, dd, meta) with the returned prefix. + * @return + */ + abstract protected String getResultSetTablePrefix(); abstract protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter dbAdapter) throws DataAccessException; + @Override + public File getDbFile(TableServerRequest treq) { + try { + TableServerRequest sreq = getSearchRequest(treq); + return getSearchProcessor(sreq).getDbFile(sreq); + } catch (DataAccessException e) { + // should not happen + return super.getDbFile(treq); + } + } + + @Override + public File createDbFile(TableServerRequest treq) throws DataAccessException { + try { + TableServerRequest sreq = getSearchRequest(treq); + return getSearchProcessor(sreq).createDbFile(sreq); + } catch (DataAccessException e) { + // should not happen + return super.createDbFile(treq); + } + } + /** - * recreate the table database if does not exists. otherwise, return the table's database + * original database no longer available.. recreate it. */ @Override - public FileInfo createDbFile(TableServerRequest treq) throws DataAccessException { + public FileInfo ingestDataIntoDb(TableServerRequest treq, File dbFile) throws DataAccessException { TableServerRequest sreq = getSearchRequest(treq); - File dbFile = EmbeddedDbUtil.getDbFile(sreq); - if (dbFile == null || !dbFile.canRead()) { - sreq.setPageSize(1); - sreq.setStartIndex(0); - new SearchManager().getDataGroup(sreq).getData(); - } - EmbeddedDbUtil.setDbMetaInfo(treq, DbAdapter.getAdapter(treq), dbFile); + sreq.setPageSize(1); // set to small number it's not used. + new SearchManager().getDataGroup(sreq).getData(); return new FileInfo(dbFile); } @@ -64,7 +89,7 @@ protected DataGroupPart getResultSet(TableServerRequest treq, File dbFile) throw EmbeddedDbUtil.createMetaTbl(dbFile, data, dbAdapter, resTblName); } treq.setParam(TableServerRequest.SQL_FROM, resTblName); - String sql = String.format("%s %s %s", dbAdapter.selectPart(treq), dbAdapter.fromPart(treq), dbAdapter.wherePart(treq)); + String sql = String.format("%s from %s %s", dbAdapter.selectPart(treq), resTblName, dbAdapter.wherePart(treq)); sql = dbAdapter.translateSql(sql); DataGroup dg = EmbeddedDbUtil.runQuery(dbAdapter, dbFile, sql, resTblName); @@ -103,7 +128,10 @@ protected String getResultSetTable(TableServerRequest treq) throws DataAccessExc return String.format("%s_data_%s", getResultSetTablePrefix(), DigestUtils.md5Hex(id)); } - abstract protected String getResultSetTablePrefix(); + protected EmbeddedDbProcessor getSearchProcessor(TableServerRequest searchReq) throws DataAccessException { + return (EmbeddedDbProcessor) new SearchManager().getProcessor(searchReq.getRequestId()); + } + } diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/XYGenericProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/XYGenericProcessor.java index 90aac087cd..6d6692db7d 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/query/XYGenericProcessor.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/XYGenericProcessor.java @@ -4,6 +4,7 @@ package edu.caltech.ipac.firefly.server.query; import edu.caltech.ipac.firefly.data.TableServerRequest; +import edu.caltech.ipac.firefly.server.db.DbAdapter; import edu.caltech.ipac.firefly.server.util.QueryUtil; import edu.caltech.ipac.firefly.server.util.ipactable.DataGroupWriter; import edu.caltech.ipac.util.*; @@ -14,20 +15,104 @@ import java.util.ArrayList; import java.util.List; +import static edu.caltech.ipac.firefly.server.query.XYGenericProcessor.createColumnsToList; +import static edu.caltech.ipac.firefly.server.query.XYGenericProcessor.getCol; + + +@SearchProcessorImpl(id = "XYGeneric") +public class XYGenericProcessor extends TableFunctionProcessor { + + protected String getResultSetTablePrefix() { + return "xy"; + } + + protected DataGroup fetchData(TableServerRequest treq, File dbFile, DbAdapter dbAdapter) throws DataAccessException { + try { + return new XYGenericProcessorImpl().loadDataIntoDataGroup(treq); + } catch (IOException e) { + throw new DataAccessException(e); + } + } + + public static void createColumnsToList(ArrayListcolumnList, DataGroup dg, Col[] cols, + ArrayList colMeta) { + DataType dt, dtSrc; + + for (Col col : cols) { + if (col.getter.isExpression()) { + dt = new DataType(col.colname, col.colname, Double.class, DataType.Importance.HIGH, "", false); + DataType.FormatInfo fi = dt.getFormatInfo(); + fi.setDataFormat("%.14g"); + dt.setFormatInfo(fi); + columnList.add(dt); + } else { + dtSrc = dg.getDataDefintion(col.colname); + dt = dtSrc.copyWithNoColumnIdx(columnList.size()); + dt.setMaxDataWidth(dtSrc.getMaxDataWidth()); + dt.setFormatInfo(dtSrc.getFormatInfo()); + columnList.add(dt); + colMeta.addAll(IpacTableUtil.getAllColMeta(dg.getAttributes().values(), col.colname)); + } + } + } + + public static Col getCol(DataType[] dataTypes, String colOrExpr, String exprColName, boolean canBeNaN) throws DataAccessException { + Col col = new Col(dataTypes, colOrExpr, exprColName, canBeNaN); + if (!col.getter.isValid()) { + throw new DataAccessException("Invalid column or expression: "+colOrExpr); + } + return col; + } + + + public static class Col { + DataObjectUtil.DoubleValueGetter getter; + String colname; + String exprColName; + String colOrExpr; + boolean canBeNaN; + + Col(DataType[] dataTypes, String colOrExpr, String exprColName, boolean canBeNaN) { + this.colOrExpr = colOrExpr; + this.exprColName = exprColName; + this.getter = new DataObjectUtil.DoubleValueGetter(dataTypes, colOrExpr); + if (getter.isExpression()) { + this.colname = exprColName; + } else { + this.colname = colOrExpr; + } + this.canBeNaN = canBeNaN; + } + } + +} + + + + + /** * @author c.w. */ -@SearchProcessorImpl(id = "XYGeneric") -public class XYGenericProcessor extends IpacTablePartProcessor { +class XYGenericProcessorImpl extends IpacTablePartProcessor { private static final String SEARCH_REQUEST = "searchRequest"; private static final String ColExpKey = "ColOrExp"; @Override protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { - String searchRequestJson = request.getParam(SEARCH_REQUEST); - DataGroup dg = SearchRequestUtils.dataGroupFromSearchRequest(searchRequestJson); + DataGroup retVal = loadDataIntoDataGroup(request); + File outFile = createFile(request); + DataGroupWriter.write(outFile, retVal); + return outFile; + } + + protected DataGroup loadDataIntoDataGroup(TableServerRequest request) throws IOException, DataAccessException { + TableServerRequest sreq = QueryUtil.convertToServerRequest(request.getParam(SEARCH_REQUEST)); + sreq.setPageSize(Integer.MAX_VALUE); + DataGroup dg = new SearchManager().getDataGroup(sreq).getData(); + List allParams = request.getParams(); - ArrayList colsLst = new ArrayList<>(); + ArrayList colsLst = new ArrayList<>(); ArrayList txtcolsLst = new ArrayList<>(); // the output table columns with the names like x, y, z, r, t, values, labels, etc. @@ -38,7 +123,7 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data String name = p.getName(); String colName; String val; - Col aCol; + XYGenericProcessor.Col aCol; TextCol tCol; if (name.endsWith(ColExpKey)) { @@ -55,7 +140,7 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data } } - Col[] cols = colsLst.toArray(new Col[colsLst.size()]); + XYGenericProcessor.Col[] cols = colsLst.toArray(new XYGenericProcessor.Col[colsLst.size()]); TextCol[] textcols = txtcolsLst.toArray(new TextCol[txtcolsLst.size()]); // create the array of output columns @@ -79,7 +164,7 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data // render data from numeric columns for (int c = 0; c < numCols ; c++) { - Col col = cols[c]; + XYGenericProcessor.Col col = cols[c]; double val; val = col.getter.getValue(row); @@ -88,12 +173,7 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data break; } else { dt = columns[c]; - formatted = col.getter.getFormattedValue(row); - if (formatted == null) { - retRow.setDataElement(dt, QueryUtil.convertData(dt.getDataType(), val)); - } else { - retRow.setFormattedData(dt, formatted); - } + retRow.setDataElement(dt, QueryUtil.convertData(dt.getDataType(), val)); } } @@ -102,13 +182,7 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data for (int c = 0; c < textcols.length; c++) { TextCol tcol = textcols[c]; dt = columns[c + numCols]; - - formatted = tcol.getFormattedValue(row); - if (formatted == null) { - retRow.setDataElement(dt, tcol.getValue(row)); - } else { - retRow.setFormattedData(dt, formatted); - } + retRow.setDataElement(dt, tcol.getValue(row)); } } @@ -117,16 +191,14 @@ protected File loadDataFile(TableServerRequest request) throws IOException, Data } } - for (Col c : cols) { + for (XYGenericProcessor.Col c : cols) { colMeta.add(new DataGroup.Attribute(c.exprColName, c.colOrExpr)); } for (TextCol c : textcols) { colMeta.add(new DataGroup.Attribute(c.colname, c.colOrExpr)); } retVal.setAttributes(colMeta); - File outFile = createFile(request); - DataGroupWriter.write(outFile, retVal); - return outFile; + return retVal; } @@ -147,7 +219,7 @@ private TextCol getTextCol(DataType[] dataTypes, String colOrExpr, String exprCo return tCol; } - private static class TextCol { + class TextCol { DataType col; String colname; String colOrExpr; @@ -191,12 +263,12 @@ String getFormattedValue(DataObject row){ } } - private static void createColumnsOnTextCol(ArrayListcolumnList, DataGroup dg, - TextCol[] textCols, - ArrayList colMeta) { + private static void createColumnsOnTextCol(ArrayList columnList, DataGroup dg, + XYGenericProcessorImpl.TextCol[] textCols, + ArrayList colMeta) { DataType dt, dtDef; - for (TextCol col : textCols) { + for (XYGenericProcessorImpl.TextCol col : textCols) { dtDef = dg.getDataDefintion(col.colOrExpr); dt = dtDef.copyWithNoColumnIdx(columnList.size()); dt.setMaxDataWidth(dtDef.getMaxDataWidth()); @@ -206,56 +278,6 @@ private static void createColumnsOnTextCol(ArrayListcolumnList, DataGr } } - public static void createColumnsToList(ArrayListcolumnList, DataGroup dg, Col[] cols, - ArrayList colMeta) { - DataType dt, dtSrc; - - for (Col col : cols) { - if (col.getter.isExpression()) { - dt = new DataType(col.colname, col.colname, Double.class, DataType.Importance.HIGH, "", false); - DataType.FormatInfo fi = dt.getFormatInfo(); - fi.setDataFormat("%.14g"); - dt.setFormatInfo(fi); - columnList.add(dt); - } else { - dtSrc = dg.getDataDefintion(col.colname); - dt = dtSrc.copyWithNoColumnIdx(columnList.size()); - dt.setMaxDataWidth(dtSrc.getMaxDataWidth()); - dt.setFormatInfo(dtSrc.getFormatInfo()); - columnList.add(dt); - colMeta.addAll(IpacTableUtil.getAllColMeta(dg.getAttributes().values(), col.colname)); - } - } - } - - public static Col getCol(DataType[] dataTypes, String colOrExpr, String exprColName, boolean canBeNaN) throws DataAccessException { - Col col = new Col(dataTypes, colOrExpr, exprColName, canBeNaN); - if (!col.getter.isValid()) { - throw new DataAccessException("Invalid column or expression: "+colOrExpr); - } - return col; - } - - - public static class Col { - DataObjectUtil.DoubleValueGetter getter; - String colname; - String exprColName; - String colOrExpr; - boolean canBeNaN; - - Col(DataType[] dataTypes, String colOrExpr, String exprColName, boolean canBeNaN) { - this.colOrExpr = colOrExpr; - this.exprColName = exprColName; - this.getter = new DataObjectUtil.DoubleValueGetter(dataTypes, colOrExpr); - if (getter.isExpression()) { - this.colname = exprColName; - } else { - this.colname = colOrExpr; - } - this.canBeNaN = canBeNaN; - } - } - } + diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/util/ipactable/DataGroupReader.java b/src/firefly/java/edu/caltech/ipac/firefly/server/util/ipactable/DataGroupReader.java index f4cf684af4..5a57fcf72d 100644 --- a/src/firefly/java/edu/caltech/ipac/firefly/server/util/ipactable/DataGroupReader.java +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/util/ipactable/DataGroupReader.java @@ -100,6 +100,12 @@ public static DataGroup read(File inf, boolean isFixedLength, boolean readAsStri return doRead(bufferedReader, tableDef, isFixedLength, readAsString, saveFormattedData, onlyColumns); } + public static DataGroup read(InputStream inputStream, String... onlyColumns) throws IOException { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream), IpacTableUtil.FILE_IO_BUFFER_SIZE); + TableDef tableDef = IpacTableUtil.getMetaInfo(bufferedReader); + return doRead(bufferedReader, tableDef, true, false, false, onlyColumns); + } + public static DataGroup read(Reader reader, boolean isFixedLength, boolean readAsString, boolean saveFormattedData, String... onlyColumns) throws IOException { BufferedReader bufferedReader = new BufferedReader(reader, IpacTableUtil.FILE_IO_BUFFER_SIZE); TableDef tableDef = IpacTableUtil.getMetaInfo(bufferedReader); diff --git a/src/firefly/java/edu/caltech/ipac/util/decimate/DecimateKey.java b/src/firefly/java/edu/caltech/ipac/util/decimate/DecimateKey.java index 244c1e86aa..99e3d56ad1 100644 --- a/src/firefly/java/edu/caltech/ipac/util/decimate/DecimateKey.java +++ b/src/firefly/java/edu/caltech/ipac/util/decimate/DecimateKey.java @@ -105,7 +105,7 @@ public static DecimateKey parse(String str) { @Override public String toString() { - return DECIMATE_KEY+"("+xColNameOrExpr+","+yColNameOrExpr+","+ + return DECIMATE_KEY+"(\""+xColNameOrExpr+"\",\""+yColNameOrExpr+"\","+ xMin+","+yMin+","+nX+","+nY+","+xUnit+","+yUnit+")"; } } diff --git a/src/firefly/js/charts/dataTypes/FireflyHeatmap.js b/src/firefly/js/charts/dataTypes/FireflyHeatmap.js index 9778b7e962..ef5c2b3bf8 100644 --- a/src/firefly/js/charts/dataTypes/FireflyHeatmap.js +++ b/src/firefly/js/charts/dataTypes/FireflyHeatmap.js @@ -19,6 +19,9 @@ import BrowserInfo from '../../util/BrowserInfo.js'; */ export function getTraceTSEntries({traceTS, chartId, traceNum}) { const {mappings} = traceTS; + + if (!mappings) return {}; + const {fireflyData, fireflyLayout} = getChartData(chartId) || {}; // server call parameters const xbins = get(fireflyData, `${traceNum}.nbins.x`); diff --git a/src/firefly/js/drawingLayers/Catalog.js b/src/firefly/js/drawingLayers/Catalog.js index e8c4d65f2c..d366845e1d 100644 --- a/src/firefly/js/drawingLayers/Catalog.js +++ b/src/firefly/js/drawingLayers/Catalog.js @@ -387,8 +387,7 @@ function doFilter(dl,p,sel) { const rowidIdx= findColIdx(dl.tableData.columns,'ROW_IDX'); let idxs= getSelectedPts(sel, p, dl.drawData.data); idxs = rowidIdx < 0 ? idxs : idxs.map( (idx) => get(dl,`tableData.data[${idx}][${rowidIdx}]`) ); - filter= `IN (${idxs.toString()})`; - // filterInfoCls.setFilter(filter); + filter= `IN (${idxs.length === 0 ? -1 : idxs.toString()})`; // ROW_IDX is always positive.. use -1 to force no row selected filterInfoCls.setFilter('ROW_IDX', filter); newRequest = {tbl_id: tbl.tbl_id, filters: filterInfoCls.serialize()}; dispatchTableFilter(newRequest); diff --git a/src/firefly/js/tables/Decimate.js b/src/firefly/js/tables/Decimate.js index e2af69a49b..563f9b03ce 100644 --- a/src/firefly/js/tables/Decimate.js +++ b/src/firefly/js/tables/Decimate.js @@ -46,8 +46,8 @@ export const parseDecimateInfo = function(str) { const [xColumnName,yColumnName,maxPoints,xyRatio,xMin,xMax,yMin,yMax,deciEnableLimit='-1'] = kv[1].split(','); if (xColumnName && yColumnName) { return { - xColumnName, - yColumnName, + xColumnName: xColumnName.replace(/^"(.+)"$/, '$1'), + yColumnName: yColumnName.replace(/^"(.+)"$/, '$1'), maxPoints : Number.parseInt(maxPoints,10), xyRatio: Number.parseFloat(xyRatio), xMin: Number.parseFloat(xMin), @@ -76,8 +76,8 @@ export const parseDecimateKey = function(str) { v = v.substring(1,v.length-1); // remove outer braces const parts = v.split(','); if (parts.length === 8) { - const xColNameOrExpr= parts[0]; - const yColNameOrExpr = parts[1]; + const xColNameOrExpr= parts[0].replace(/^"(.+)"$/, '$1'); + const yColNameOrExpr = parts[1].replace(/^"(.+)"$/, '$1'); const xMin = Number(parts[2]); const yMin = Number(parts[3]); const nX = Number(parts[4]); diff --git a/src/firefly/js/tables/FilterInfo.js b/src/firefly/js/tables/FilterInfo.js index 94f2c266bd..c08e17e5df 100644 --- a/src/firefly/js/tables/FilterInfo.js +++ b/src/firefly/js/tables/FilterInfo.js @@ -44,12 +44,13 @@ export class FilterInfo { */ static parse(filterString) { var filterInfo = new FilterInfo(); - if (filterString) { - filterString && filterString.split(';').forEach( (v) => { - const [, cname, op, val] = v.trim().match(filter_regex) || []; - if (cname) filterInfo.addFilter(cname, `${op} ${val}`); - }); - } + filterString && filterString.split(';').forEach( (v) => { + let [, cname, op, val] = v.trim().match(filter_regex) || []; + if (cname && op) { + cname = cname.replace(/^"(.+)"$/, '$1'); // strip quotes if any + filterInfo.addFilter(cname, `${op} ${val}`); + } + }); return filterInfo; } @@ -214,14 +215,12 @@ export class FilterInfo { } serialize() { - return Object.keys(this).reduce( (rval, key) => { - this[key].split(';').forEach((v) => { - if (v.length) { - rval = (rval.length ? rval + ';': '') + `${key} ${v.trim()}`; - } - } ); - return rval; - }, ''); + return Object.entries(this) + .map(([k,v]) => v.split(';') + .filter((f) => f) + .map( (f) => k.includes('"') ? `${k} ${f}` : `"${k}" ${f}`) // add quotes to key if it does not contains quotes + .join(';')) + .join(';'); } /** diff --git a/src/firefly/js/tables/SortInfo.js b/src/firefly/js/tables/SortInfo.js index 6013a91844..9f89a8a73b 100644 --- a/src/firefly/js/tables/SortInfo.js +++ b/src/firefly/js/tables/SortInfo.js @@ -33,6 +33,7 @@ export function sortInfoString(colName, isAscending=true) { * @returns {*} */ getDirection(colName) { + colName = colName.replace(/^"(.+)"$/, '$1'); // strip quotes is any; if (this.sortColumns[0] === colName) { return this.direction; } else { @@ -51,11 +52,11 @@ export function sortInfoString(colName, isAscending=true) { const direction = dir === UNSORTED ? SORT_ASC : dir === SORT_ASC ? SORT_DESC : UNSORTED; const sortColumns = UNSORTED ? [] : [colName]; - return direction === UNSORTED ? '' : `${direction},${sortColumns.toString()}`; + return new SortInfo(direction, sortColumns).serialize(); } serialize() { - return this.direction === UNSORTED ? '' : `${this.direction},${this.sortColumns.toString()}`; + return this.direction === UNSORTED ? '' : `${this.direction},${this.sortColumns.map( (c) => `"${c}"`).join()}`; } static parse(sortInfo) { @@ -63,7 +64,7 @@ export function sortInfoString(colName, isAscending=true) { const parts = sortInfo.split(',').map((s) => s.trim()); if (parts) { const direction = parts[0] && parts[0].toUpperCase(); - const sortColumns = parts[1] && parts.slice(1); + const sortColumns = parts[1] && parts.slice(1).map( (c) => c.replace(/^"(.+)"$/, '$1')); // strip quotes is any return new SortInfo(direction, sortColumns); } } else { diff --git a/src/firefly/js/tables/TableUtil.js b/src/firefly/js/tables/TableUtil.js index 3d78d53144..0d0535b025 100644 --- a/src/firefly/js/tables/TableUtil.js +++ b/src/firefly/js/tables/TableUtil.js @@ -642,13 +642,10 @@ export function getAsyncTableSourceUrl(tbl_ui_id) { function makeTableSourceUrl(columns, request) { const tableRequest = Object.assign(cloneDeep(request), {startIdx: 0,pageSize : MAX_ROW}); - const visiCols = columns.filter( (col) => { - return get(col, 'visibility', 'show') === 'show'; - }).map( (col) => { - return col.name; - } ); + const visiCols = columns.filter( (col) => get(col, 'visibility', 'show') === 'show') + .map( (col) => col.name); if (visiCols.length !== columns.length) { - tableRequest['inclCols'] = visiCols.toString(); + tableRequest['inclCols'] = visiCols.map( (c) => c.includes('"') ? c : '"' + c + '"'); // add quotes to cname unless it's already quoted. } Reflect.deleteProperty(tableRequest, 'tbl_id'); const params = omitBy({ diff --git a/src/firefly/js/tables/ui/BasicTableView.jsx b/src/firefly/js/tables/ui/BasicTableView.jsx index d735408b3c..55e8888e5e 100644 --- a/src/firefly/js/tables/ui/BasicTableView.jsx +++ b/src/firefly/js/tables/ui/BasicTableView.jsx @@ -18,6 +18,10 @@ import './TablePanel.css'; const {Table, Column} = FixedDataTable; + +const noDataMsg = 'No Data Found'; +const noDataFromFilter = 'No data match these criteria'; + export class BasicTableView extends PureComponent { constructor(props) { super(props); @@ -167,7 +171,7 @@ export class BasicTableView extends PureComponent { } {!error && showMask &&
} - {!error && !showMask && isEmpty(data) &&
No Data Found
} + {!error && !showMask && isEmpty(data) &&
{filterInfo ? noDataFromFilter : noDataMsg}
} ); } diff --git a/src/firefly/js/tables/ui/TablePanel.css b/src/firefly/js/tables/ui/TablePanel.css index fb3c3dbc01..14e47eed11 100644 --- a/src/firefly/js/tables/ui/TablePanel.css +++ b/src/firefly/js/tables/ui/TablePanel.css @@ -14,11 +14,15 @@ .TablePanel_NoData { position: absolute; - top: 50%; - left: 42%; + top: 45px; z-index: 1; color: gray; font-size: large; + height: calc(100% - 45px); + width: 100%; + display: flex; + justify-content: center; + align-items: center; } .TablePanel__wrapper { diff --git a/src/firefly/js/tables/ui/TablePanel.jsx b/src/firefly/js/tables/ui/TablePanel.jsx index 6916b6bc34..ad642f34e2 100644 --- a/src/firefly/js/tables/ui/TablePanel.jsx +++ b/src/firefly/js/tables/ui/TablePanel.jsx @@ -4,13 +4,13 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {isEmpty, truncate, get} from 'lodash'; +import {isEmpty, truncate, get, cloneDeep, omit} from 'lodash'; import shallowequal from 'shallowequal'; import {flux} from '../../Firefly.js'; import {download} from '../../util/WebUtil.js'; import * as TblUtil from '../TableUtil.js'; -import {dispatchTableRemove, dispatchTblExpanded, dispatchTblResultsRemove} from '../TablesCntlr.js'; +import {dispatchTableRemove, dispatchTblExpanded, dispatchTblResultsRemove, dispatchTableSearch} from '../TablesCntlr.js'; import {TablePanelOptions} from './TablePanelOptions.jsx'; import {BasicTableView} from './BasicTableView.jsx'; import {TableConnector} from '../TableConnector.js'; @@ -130,7 +130,7 @@ export class TablePanel extends PureComponent { filterInfo, filterCount, sortInfo, data, bgStatus} = this.state; var {leftButtons, rightButtons} = this.state; - if (error) return
{error}
; + if (error) return ; if (isEmpty(columns)) return ; const selectInfoCls = SelectInfo.newInstance(selectInfo, startIdx); @@ -319,3 +319,18 @@ function Loading({showTitle, tbl_id, title, removable, bgStatus}) {
); } + +function TableError({error, tbl_id, message}) { + const {request} = TblUtil.getTblById(tbl_id); + const canReset = get(request, 'filters') || get(request, 'sortInfo'); + const reloadTable = () => { + const origRequest = omit(cloneDeep(request), 'filters', 'sortInfo'); + dispatchTableSearch(origRequest); + }; + return ( +
+
{message}
+ {canReset && } +
+ ); +} diff --git a/src/firefly/js/templates/lightcurve/LcPeriodogram.jsx b/src/firefly/js/templates/lightcurve/LcPeriodogram.jsx index eb430dc74c..a490f1950a 100644 --- a/src/firefly/js/templates/lightcurve/LcPeriodogram.jsx +++ b/src/firefly/js/templates/lightcurve/LcPeriodogram.jsx @@ -523,7 +523,7 @@ function periodogramSuccess(popupId, hideDropDown = false) { peaks: get(request, [pKeyDef.peaks.fkey]), table_name: LC.PEAK_TABLE, sortInfo: sortInfoString('SDE', false) // sort peak table by column SDE, descending - }, {tbl_id: LC.PEAK_TABLE, pageSize: parseInt(peak), inclCols : '"PEAK", "PERIOD", "POWER", "SDE"'}); // period and power are reserved words in sql.. put them in quotes + }, {tbl_id: LC.PEAK_TABLE, pageSize: parseInt(peak), inclCols : '"Peak", "Period", "Power", "SDE"'}); // period and power are reserved words in sql.. put them in quotes var tReq = makeTblRequest('LightCurveProcessor', LC.PERIODOGRAM_TABLE, { original_table: srcFile, @@ -538,7 +538,7 @@ function periodogramSuccess(popupId, hideDropDown = false) { table_name: LC.PERIODOGRAM_TABLE /* Should we do the same for Power column in Periodogram? */ /*sortInfo: sortInfoString('Power', false)*/ - }, {tbl_id: LC.PERIODOGRAM_TABLE, inclCols : '"PERIOD", "POWER"'}); + }, {tbl_id: LC.PERIODOGRAM_TABLE, inclCols : '"Period", "Power"'}); if (tReq !== null) { diff --git a/src/firefly/js/ui/TestQueriesPanel.jsx b/src/firefly/js/ui/TestQueriesPanel.jsx index 81ac4b5904..7541e92758 100644 --- a/src/firefly/js/ui/TestQueriesPanel.jsx +++ b/src/firefly/js/ui/TestQueriesPanel.jsx @@ -167,7 +167,7 @@ function renderPeriodogram(fields) { //'peaks' : 50 //'result_table': 'http://web.ipac.caltech.edu/staff/ejoliet/demo/vo-nexsci-result-sample.xml' }, - {inclCols : 'Power,Period'}); + {inclCols : '"Power","Period"'}); } else if (opt === 1) { tReq = makeTblRequest('PhaseFoldedProcessor', 'Phase folded', { 'period_days': ds, @@ -189,7 +189,7 @@ function renderPeriodogram(fields) { //'alg': 'ls', //There are three algorithms: ls (Lomb-Scargle), bls (Box-fitting Least Squares), and plav (Plavchan 2008). The default algorithm is Lomb-Scargle. 'peaks' : 57 //'result_table': 'http://web.ipac.caltech.edu/staff/ejoliet/demo/vo-nexsci-result-sample.xml' - }, {inclCols : 'Peak, Period, Power, SDE'}); + }, {inclCols : '"Peak", "Period", "Power", "SDE"'}); } console.log(ds); diff --git a/src/firefly/js/visualize/saga/CatalogWatcher.js b/src/firefly/js/visualize/saga/CatalogWatcher.js index c8f6d0c944..7f0af792a7 100644 --- a/src/firefly/js/visualize/saga/CatalogWatcher.js +++ b/src/firefly/js/visualize/saga/CatalogWatcher.js @@ -114,7 +114,7 @@ function handleCatalogUpdate(tbl_id) { const params= { startIdx : 0, pageSize : MAX_ROW, - inclCols : `${columns.lonCol},${columns.latCol},ROW_IDX` + inclCols : `"${columns.lonCol}","${columns.latCol}","ROW_IDX"` // column names should be in quotes }; let req = cloneRequest(sourceTable.request, params); diff --git a/src/firefly/js/visualize/saga/CoverageWatcher.js b/src/firefly/js/visualize/saga/CoverageWatcher.js index 18204d8a64..148573a731 100644 --- a/src/firefly/js/visualize/saga/CoverageWatcher.js +++ b/src/firefly/js/visualize/saga/CoverageWatcher.js @@ -520,11 +520,8 @@ function defaultCanDoCorners(table) {// eslint-disable-line no-unused-vars function getCovColumnsForQuery(options, table) { const cAry= [...options.getCornersColumns(table), options.getCenterColumns(table)]; - const base= cAry.reduce( (s,c,idx)=> { - s += (c ? `${idx > 0 ? ',' : ''}${c.lonCol},${c.latCol}` : ''); - return s; - }, ''); - return base+',ROW_IDX'; + const base = cAry.map( (c)=> `"${c.lonCol}","${c.latCol}"`).join(); // column names should be in quotes + return base+',"ROW_IDX"'; }