diff --git a/data-discovery/src/main/java/search/DbObstap.java b/data-discovery/src/main/java/search/DbObstap.java index ea50b70d70bf19c4576ccbd13a0b2315c30f37c6..5c5f5571d55da156ce18f8b08343a3a284eac984 100644 --- a/data-discovery/src/main/java/search/DbObstap.java +++ b/data-discovery/src/main/java/search/DbObstap.java @@ -80,486 +80,515 @@ public class DbObstap } - - - public String[] queryOverlapingPubdid(QueryArgs qArgs) - throws Exception - { - LOGGER.fine("trace"); - - String inputRegion = toPgSphereSqlTypeString(qArgs.pos); - String dbRegion = toRegionColumnName(qArgs.pos.system); - - String theQuery = "SELECT obs_publisher_did FROM obscore WHERE ("+inputRegion+" && " + dbRegion + ")"; - - boolean vel_valid = (qArgs.band != null) && (qArgs.band.system != Band.System.NONE); - if(vel_valid) - { - String prefix = toSpecColumnNamePrefix(qArgs.band.system); - String vel_no_overlap - = "((" + prefix + "_min > " + Double.toString(qArgs.band.max) - + ") OR (" + prefix + "_max < " + Double.toString(qArgs.band.min) + "))"; - - theQuery += " AND ( ("+prefix+"_min is null) OR ("+prefix+"_max is null) OR (NOT " + vel_no_overlap + "))"; - /* NOTE '... OR (em_min is null)' statement causes to include 2D datasets if they overlap in sky - * It is the legacy-search behaviour - however is that useful ? - */ - } - - if(qArgs.collection != null) - { - String addColl = ""; - if(qArgs.collection.length() > 0) - addColl += "(obs_collection LIKE '%" + qArgs.collection + "%')"; - - if(addColl.length() > 0) theQuery += " AND (" + addColl + ")"; - } - - theQuery += appendIntervalConstraint(qArgs.fov, "s_fov"); - theQuery += appendIntervalConstraint(qArgs.spatres, "s_resolution"); - theQuery += appendIntervalConstraint(qArgs.specrp, "em_res_power"); - theQuery += appendIntervalConstraint(qArgs.exptime, "t_exptime"); - theQuery += appendIntervalConstraint(qArgs.timeres, "t_resolution"); - - theQuery += appendStringMatchConstraint(qArgs.id, "obs_publisher_did"); - theQuery += appendStringMatchConstraint(qArgs.facility, "facility_name"); - theQuery += appendStringMatchConstraint(qArgs.instrument, "instrument_name"); - theQuery += appendStringMatchConstraint(qArgs.dptype, "dataproduct_type"); - - theQuery += appendStringMatchConstraint(qArgs.target, "target_name"); - theQuery += appendStringMatchConstraint(qArgs.format, "access_format"); - - if(qArgs.calib != null) - theQuery += " AND (" + qArgs.calib + " = calib_level)"; - - if(qArgs.maxrec != null) - theQuery += " LIMIT " + qArgs.maxrec; - - LOGGER.fine(theQuery); - - List<String> pubdidList = new ArrayList<>(); - - LOGGER.fine("Connecting to: " + dbConnArgs.uri() + " with user: " + dbConnArgs.userName() ); - - try( - Connection conn = DriverManager.getConnection(dbConnArgs.uri(), dbConnArgs.userName(), dbConnArgs.password()); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery(theQuery);) - { - while (res.next()) - { - String pubdid_str = res.getString("obs_publisher_did"); - pubdidList.add(pubdid_str); - } - } - catch (SQLException se) - { - dbError(se); - // se.printStackTrace(); - throw new Exception(se.toString()); - } - - String[] pubdidArr = pubdidList.toArray(new String[0]); - - LOGGER.fine("pubdidArr[] length: " + pubdidArr.length); - - return pubdidArr; - } - - private String appendIntervalConstraint(Interval interval, String colName) - { - if(interval != null) - { - String no_overlap - = "((" + colName + " > " + Double.toString(interval.max) - + ") OR (" + colName + " < " + Double.toString(interval.min) + "))"; - - return " AND ( (" + colName + " is null) OR (NOT " + no_overlap + "))"; - } - else - { - return ""; - } - } - - private String appendStringMatchConstraint(String str, String colName) - { - if(str != null) - { - return " AND ( (" + colName + " is null) OR ('" + str.trim() + "' = " + colName + "))"; - } - else - { - return ""; - } - } - - - - public Obstap[] queryOutputData(String[] pubdidArr, Pos pos, Band band) + public int queryObstapRowCount() throws Exception - { - LOGGER.fine("trace"); - - String commaSepPubdids = String.join("\',\'", pubdidArr); - - String inputRegion = toPgSphereSqlTypeString(pos); - String dbRegion = toRegionColumnName(pos.system); - - String theQuery ="SELECT *," - + inputRegion + " && " + dbRegion + " AS inputOverlapsDb, " - + inputRegion + " <@ " + dbRegion + " AS inputInsideDb, " - + inputRegion + " @> " + dbRegion + " AS dbInsideInput FROM obscore WHERE (obs_publisher_did IN (\'" - +commaSepPubdids+"\'))"; - - List<Obstap> obstapList = new ArrayList<>(); - - LOGGER.fine(theQuery); - - LOGGER.fine("Connecting to: " + dbConnArgs.uri() - + " with optional user/pwd: " + dbConnArgs.userName() +" / "+ dbConnArgs.password() ); - try( - Connection conn = DriverManager.getConnection(dbConnArgs.uri(), dbConnArgs.userName(), dbConnArgs.password()); - Statement st = conn.createStatement(); - ResultSet res = st.executeQuery(theQuery);) - { - while (res.next()) - { - Obstap obstap = new Obstap(); - - obstap.dataproduct_type = this.getString(res,"dataproduct_type"); - obstap.calib_level = this.getInt(res,"calib_level"); - obstap.obs_collection = this.getString(res,"obs_collection"); - obstap.obs_title = this.getString(res,"obs_title"); - obstap.obs_id = this.getString(res,"obs_id"); - obstap.obs_publisher_did = this.getString(res,"obs_publisher_did"); - - obstap.bib_reference = this.getString(res,"bib_reference"); - obstap.data_rights = this.getString(res,"data_rights"); - - obstap.access_url = this.getString(res,"access_url"); - obstap.access_format = this.getString(res,"access_format"); - obstap.access_estsize = this.getLong(res,"access_estsize"); - - obstap.target_name = this.getString(res,"target_name"); - - obstap.s_ra = this.getDouble(res,"s_ra"); - obstap.s_dec = this.getDouble(res,"s_dec"); - obstap.s_fov = this.getDouble(res,"s_fov"); - obstap.s_region = this.getString(res,"s_region"); - obstap.s_xel1 = this.getLong(res,"s_xel1"); - obstap.s_xel2 = this.getLong(res,"s_xel2"); - obstap.s_resolution = this.getDouble(res,"s_resolution"); - - obstap.t_min = this.getDouble(res,"t_min"); - obstap.t_max = this.getDouble(res,"t_max"); - obstap.t_exptime = this.getDouble(res,"t_exptime"); - obstap.t_resolution = this.getDouble(res,"t_resolution"); - obstap.t_xel = this.getLong(res,"t_xel"); - - obstap.em_min = this.getDouble(res,"em_min"); - obstap.em_max = this.getDouble(res,"em_max"); - obstap.em_res_power = this.getDouble(res,"em_res_power"); - obstap.em_xel = this.getLong(res,"em_xel"); - - obstap.o_ucd = this.getString(res,"o_ucd"); - - obstap.pol_states = this.getString(res,"pol_states"); - obstap.pol_xel = this.getLong(res ,"pol_xel"); - - obstap.facility_name = this.getString(res,"facility_name"); - obstap.instrument_name = this.getString(res,"instrument_name"); - - // VLKB extension - - obstap.s_region_galactic = this.getString(res,"s_region_galactic"); - obstap.vel_min = this.getDouble(res,"vel_min"); - obstap.vel_max = this.getDouble(res,"vel_max"); - - boolean inputOverlapsDb = res.getBoolean("inputOverlapsDb"); - boolean inputInsideDb = res.getBoolean("inputInsideDb"); - boolean dbInsideInput = res.getBoolean("dbInsideInput"); - LOGGER.finest("inpOverlapsDb, inpInsideDb, dbInsideInp : " - + inputOverlapsDb + " " + inputInsideDb + " " + dbInsideInput); - - obstap.overlapCodeSky = convertToOverlapCodeSky(inputOverlapsDb, inputInsideDb, dbInsideInput); - - obstap.overlapCodeVel = convertToOverlapCodeVel(band, - obstap.em_min,obstap.em_max, - obstap.vel_min,obstap.vel_max ); - - obstap.overlapCode = convertToOverlapCode(obstap.overlapCodeSky, obstap.overlapCodeVel); - - - obstapList.add(obstap); - } - - LOGGER.fine("From DB collected # of Obstap : " + obstapList.size()); - } - catch (SQLException se) - { - dbError(se); - // se.printStackTrace(); - throw new Exception(se.toString()); - } - - Obstap[] cubes = obstapList.toArray(new Obstap[0]); - - return cubes; - } - - /* convert overlap codes (AST definition): - - "0 - The check could not be performed because the second Region could not be mapped into the coordinate system of the first Region.", - "1 - There is no overlap between the two Regions.", - "2 - The first Region is completely inside the second Region.", - "3 - The second Region is completely inside the first Region.", - "4 - There is partial overlap between the two Regions.", - "5 - The Regions are identical to within their uncertainties.", - "6 - The second Region is the exact negation of the first Region to within their uncertainties." - */ - private Integer convertToOverlapCodeSky(boolean inpOverlapsDb, boolean inpInDb, boolean dbInInp) - { - if(inpOverlapsDb) - { - if(!inpInDb && !dbInInp) return 4; - else if( inpInDb && !dbInInp) return 3; - else if(!inpInDb && dbInInp) return 2; - else return 5; - } - else - { - return 1; - } - } - - private boolean intervalOverlap(double amin, double amax, double bmin, double bmax) - { - boolean AoverB - = (amin <= bmin) && (bmin <= amax) - || (amin <= bmax) && (bmax <= amax); - - boolean BoverA - = (bmin <= amin) && (amin <= bmax) - || (bmin <= amax) && (amax <= bmax); - - return AoverB || BoverA; - } - - private Integer convertToOverlapCodeVel(Band band, - Double w_min, Double w_max, // WAVE - Double v_min, Double v_max) // VELO - { - if(band != null) - { - boolean v_valid = (v_min != null) && (v_max != null); - boolean w_valid = (w_min != null) && (w_max != null); - - if( v_valid && (band.system == Band.System.VELO_LSRK) ) - { - boolean overlap = intervalOverlap(band.min, band.max, v_min, v_max);; - - boolean dbInInp = (band.min <= v_min) && (v_min <= band.max) - && (band.min <= v_max) && (v_max <= band.max); - - boolean inpInDb = (v_min <= band.min) && (band.min <= v_max) - && (v_min <= band.max ) && (band.max <= v_max); - - // do as in Sky-overlap - return convertToOverlapCodeSky(overlap, inpInDb, dbInInp); - } - else if( w_valid && (band.system == Band.System.WAVE_Barycentric) ) - { - boolean overlap = intervalOverlap(band.min, band.max, w_min, w_max);; - - boolean dbInInp = (band.min <= w_min) && (w_min <= band.max) - && (band.min <= w_max) && (w_max <= band.max); - - boolean inpInDb = (w_min <= band.min) && (band.min <= w_max) - && (w_min <= band.max ) && (band.max <= w_max); - - // do as in Sky-overlap - return convertToOverlapCodeSky(overlap, inpInDb, dbInInp); - } - else - { - return null; - } - } - else - { - return null; - } - } - - private Integer convertToOverlapCode(Integer ovcSky, Integer ovcVel) - { - if(ovcSky == null) return ovcVel; // spectral images or both null - else if(ovcVel == null) return ovcSky; // 2D sky images or both null - else if((ovcSky != null) && (ovcVel != null)) - { - if((ovcSky == 1) || (ovcVel == 1) ) return 1; // no overlap - else if(ovcSky == ovcVel) return ovcSky; - else return 4; - } - else return null; // both null - } - - - /* conversions tolerate missing columns */ - - private Integer getInt(ResultSet res, String colLabel) - { - try - { - Integer value = res.getInt(colLabel); - return (res.wasNull() ? null : value); - } - catch(SQLException se) - { - dbError(se); - return null; - } - } - - private Long getLong(ResultSet res, String colLabel) - { - try - { - Long value = res.getLong(colLabel); - return (res.wasNull() ? null : value); - } - catch(SQLException se) - { - dbError(se); - return null; - } - } - - private Double getDouble(ResultSet res, String colLabel) - { - try - { - Double value = res.getDouble(colLabel); - return (res.wasNull() ? null : value); - } - catch(SQLException se) - { - dbError(se); - return null; - } - } - - private String getString(ResultSet res, String colLabel) - { - try - { - String value = res.getString(colLabel); - return (res.wasNull() ? null : value); - } - catch(SQLException se) - { - dbError(se); - return null; - } - } - - - - private String toPgSphereSqlTypeString(Pos pos) - { - double lon; - double lat; - double radius; - double dlon; - double dlat; - - String inputRegion = null; - - switch(pos.shape) - { - case CIRCLE: - lon = pos.circle.lon; - lat = pos.circle.lat; - radius = pos.circle.radius; - inputRegion = "scircle '<(" + Double.toString(lon) + "d," + Double.toString(lat) + "d)," - + Double.toString(radius) + "d>'"; - break; - - case RANGE: - lon = (pos.range.lon1 + pos.range.lon2)/2.0; - lat = (pos.range.lat1 + pos.range.lat2)/2.0; - dlon = (pos.range.lon2 - pos.range.lon1)/2.0; - dlat = (pos.range.lat2 - pos.range.lat1)/2.0; - - /* South-West and North-East corners of a box */ - String sw_lon = Double.toString(lon - dlon/2.0); - String sw_lat = Double.toString(lat - dlat/2.0); - String ne_lon = Double.toString(lon + dlon/2.0); - String ne_lat = Double.toString(lat + dlat/2.0); - - inputRegion = "sbox '( ("+ sw_lon + "d, " + sw_lat + "d), (" + ne_lon +"d, " + ne_lat + "d) )'"; - break; - - case POLYGON: - // FIXME redefine Polygon as point-array: - assert(pos.polygon.lon.length == pos.polygon.lat.length); - - // Polygon has at least 3 points - inputRegion = "spoly '( (" + pos.polygon.lon[0] + "d, " + pos.polygon.lat[0] + "d),"; - for(int ii=1; ii < pos.polygon.lon.length; ii++) - { - inputRegion += ", (" + pos.polygon.lon[ii] + "d, " + pos.polygon.lat[ii] + "d)"; - } - inputRegion += " )'"; - break; - - default: - throw new IllegalArgumentException("Pos::shape was: " + pos.shape.toString() - + " but valid is CIRCLE or RANGE or POLYGON"); - } - - return inputRegion; - } - - private String toRegionColumnName(Pos.System system) - { - String dbRegion; - switch(system) - { - case GALACTIC: - dbRegion = "polygon_region_galactic"; - break; - default: - dbRegion = "polygon_region"; - } - return dbRegion; - } - - private String toSpecColumnNamePrefix(Band.System system) - { - // vlkb-volib/Band.System: WAVE_Barycentric, VELO_LSRK, GRID, NONE - String prefix; - switch(system) - { - case VELO_LSRK: prefix = "vel"; break; - default: prefix = "em"; - } - return prefix; - } - - - private void dbError(SQLException se) - { - LOGGER.fine("SQLState : " + se.getSQLState()); - LOGGER.fine("ErrorCode: " + se.getErrorCode()); - LOGGER.warning("Message: " + se.getMessage()); - Throwable t = se.getCause(); - while(t != null) { - LOGGER.fine("Cause: " + t); - t = t.getCause(); - } - } + { + LOGGER.fine("trace"); + + String theQuery = "SELECT count(*) AS total FROM obscore"; + LOGGER.fine(theQuery); + LOGGER.fine("Connecting to: " + dbConnArgs.uri() + " with user: " + dbConnArgs.userName() ); + + int rowCount = -1; + try( + Connection conn = DriverManager.getConnection(dbConnArgs.uri(), dbConnArgs.userName(), dbConnArgs.password()); + Statement st = conn.createStatement(); + ResultSet res = st.executeQuery(theQuery);) + { + while (res.next()) + { + rowCount = res.getInt("total"); + } + } + catch (SQLException se) + { + dbError(se); + // se.printStackTrace(); + throw new Exception(se.toString()); + } + + return rowCount; + } + + + public String[] queryOverlapingPubdid(QueryArgs qArgs) + throws Exception + { + LOGGER.fine("trace"); + + String inputRegion = toPgSphereSqlTypeString(qArgs.pos); + String dbRegion = toRegionColumnName(qArgs.pos.system); + + String theQuery = "SELECT obs_publisher_did FROM obscore WHERE ("+inputRegion+" && " + dbRegion + ")"; + + boolean vel_valid = (qArgs.band != null) && (qArgs.band.system != Band.System.NONE); + if(vel_valid) + { + String prefix = toSpecColumnNamePrefix(qArgs.band.system); + String vel_no_overlap + = "((" + prefix + "_min > " + Double.toString(qArgs.band.max) + + ") OR (" + prefix + "_max < " + Double.toString(qArgs.band.min) + "))"; + + theQuery += " AND ( ("+prefix+"_min is null) OR ("+prefix+"_max is null) OR (NOT " + vel_no_overlap + "))"; + /* NOTE '... OR (em_min is null)' statement causes to include 2D datasets if they overlap in sky + * It is the legacy-search behaviour - however is that useful ? + */ + } + + if(qArgs.collection != null) + { + String addColl = ""; + if(qArgs.collection.length() > 0) + addColl += "(obs_collection LIKE '%" + qArgs.collection + "%')"; + + if(addColl.length() > 0) theQuery += " AND (" + addColl + ")"; + } + + theQuery += appendIntervalConstraint(qArgs.fov, "s_fov"); + theQuery += appendIntervalConstraint(qArgs.spatres, "s_resolution"); + theQuery += appendIntervalConstraint(qArgs.specrp, "em_res_power"); + theQuery += appendIntervalConstraint(qArgs.exptime, "t_exptime"); + theQuery += appendIntervalConstraint(qArgs.timeres, "t_resolution"); + + theQuery += appendStringMatchConstraint(qArgs.id, "obs_publisher_did"); + theQuery += appendStringMatchConstraint(qArgs.facility, "facility_name"); + theQuery += appendStringMatchConstraint(qArgs.instrument, "instrument_name"); + theQuery += appendStringMatchConstraint(qArgs.dptype, "dataproduct_type"); + + theQuery += appendStringMatchConstraint(qArgs.target, "target_name"); + theQuery += appendStringMatchConstraint(qArgs.format, "access_format"); + + if(qArgs.calib != null) + theQuery += " AND (" + qArgs.calib + " = calib_level)"; + + if(qArgs.maxrec != null) + theQuery += " LIMIT " + qArgs.maxrec; + + LOGGER.fine(theQuery); + + List<String> pubdidList = new ArrayList<>(); + + LOGGER.fine("Connecting to: " + dbConnArgs.uri() + " with user: " + dbConnArgs.userName() ); + + try( + Connection conn = DriverManager.getConnection(dbConnArgs.uri(), dbConnArgs.userName(), dbConnArgs.password()); + Statement st = conn.createStatement(); + ResultSet res = st.executeQuery(theQuery);) + { + while (res.next()) + { + String pubdid_str = res.getString("obs_publisher_did"); + pubdidList.add(pubdid_str); + } + } + catch (SQLException se) + { + dbError(se); + // se.printStackTrace(); + throw new Exception(se.toString()); + } + + String[] pubdidArr = pubdidList.toArray(new String[0]); + + LOGGER.fine("pubdidArr[] length: " + pubdidArr.length); + + return pubdidArr; + } + + private String appendIntervalConstraint(Interval interval, String colName) + { + if(interval != null) + { + String no_overlap + = "((" + colName + " > " + Double.toString(interval.max) + + ") OR (" + colName + " < " + Double.toString(interval.min) + "))"; + + return " AND ( (" + colName + " is null) OR (NOT " + no_overlap + "))"; + } + else + { + return ""; + } + } + + private String appendStringMatchConstraint(String str, String colName) + { + if(str != null) + { + return " AND ( (" + colName + " is null) OR ('" + str.trim() + "' = " + colName + "))"; + } + else + { + return ""; + } + } + + + + public Obstap[] queryOutputData(String[] pubdidArr, Pos pos, Band band) + throws Exception + { + LOGGER.fine("trace"); + + String commaSepPubdids = String.join("\',\'", pubdidArr); + + String inputRegion = toPgSphereSqlTypeString(pos); + String dbRegion = toRegionColumnName(pos.system); + + String theQuery ="SELECT *," + + inputRegion + " && " + dbRegion + " AS inputOverlapsDb, " + + inputRegion + " <@ " + dbRegion + " AS inputInsideDb, " + + inputRegion + " @> " + dbRegion + " AS dbInsideInput FROM obscore WHERE (obs_publisher_did IN (\'" + +commaSepPubdids+"\'))"; + + List<Obstap> obstapList = new ArrayList<>(); + + LOGGER.fine(theQuery); + + LOGGER.fine("Connecting to: " + dbConnArgs.uri() + + " with optional user/pwd: " + dbConnArgs.userName() +" / "+ dbConnArgs.password() ); + try( + Connection conn = DriverManager.getConnection(dbConnArgs.uri(), dbConnArgs.userName(), dbConnArgs.password()); + Statement st = conn.createStatement(); + ResultSet res = st.executeQuery(theQuery);) + { + while (res.next()) + { + Obstap obstap = new Obstap(); + + obstap.dataproduct_type = this.getString(res,"dataproduct_type"); + obstap.calib_level = this.getInt(res,"calib_level"); + obstap.obs_collection = this.getString(res,"obs_collection"); + obstap.obs_title = this.getString(res,"obs_title"); + obstap.obs_id = this.getString(res,"obs_id"); + obstap.obs_publisher_did = this.getString(res,"obs_publisher_did"); + + obstap.bib_reference = this.getString(res,"bib_reference"); + obstap.data_rights = this.getString(res,"data_rights"); + + obstap.access_url = this.getString(res,"access_url"); + obstap.access_format = this.getString(res,"access_format"); + obstap.access_estsize = this.getLong(res,"access_estsize"); + + obstap.target_name = this.getString(res,"target_name"); + + obstap.s_ra = this.getDouble(res,"s_ra"); + obstap.s_dec = this.getDouble(res,"s_dec"); + obstap.s_fov = this.getDouble(res,"s_fov"); + obstap.s_region = this.getString(res,"s_region"); + obstap.s_xel1 = this.getLong(res,"s_xel1"); + obstap.s_xel2 = this.getLong(res,"s_xel2"); + obstap.s_resolution = this.getDouble(res,"s_resolution"); + + obstap.t_min = this.getDouble(res,"t_min"); + obstap.t_max = this.getDouble(res,"t_max"); + obstap.t_exptime = this.getDouble(res,"t_exptime"); + obstap.t_resolution = this.getDouble(res,"t_resolution"); + obstap.t_xel = this.getLong(res,"t_xel"); + + obstap.em_min = this.getDouble(res,"em_min"); + obstap.em_max = this.getDouble(res,"em_max"); + obstap.em_res_power = this.getDouble(res,"em_res_power"); + obstap.em_xel = this.getLong(res,"em_xel"); + + obstap.o_ucd = this.getString(res,"o_ucd"); + + obstap.pol_states = this.getString(res,"pol_states"); + obstap.pol_xel = this.getLong(res ,"pol_xel"); + + obstap.facility_name = this.getString(res,"facility_name"); + obstap.instrument_name = this.getString(res,"instrument_name"); + + // VLKB extension + + obstap.s_region_galactic = this.getString(res,"s_region_galactic"); + obstap.vel_min = this.getDouble(res,"vel_min"); + obstap.vel_max = this.getDouble(res,"vel_max"); + + boolean inputOverlapsDb = res.getBoolean("inputOverlapsDb"); + boolean inputInsideDb = res.getBoolean("inputInsideDb"); + boolean dbInsideInput = res.getBoolean("dbInsideInput"); + LOGGER.finest("inpOverlapsDb, inpInsideDb, dbInsideInp : " + + inputOverlapsDb + " " + inputInsideDb + " " + dbInsideInput); + + obstap.overlapCodeSky = convertToOverlapCodeSky(inputOverlapsDb, inputInsideDb, dbInsideInput); + + obstap.overlapCodeVel = convertToOverlapCodeVel(band, + obstap.em_min,obstap.em_max, + obstap.vel_min,obstap.vel_max ); + + obstap.overlapCode = convertToOverlapCode(obstap.overlapCodeSky, obstap.overlapCodeVel); + + + obstapList.add(obstap); + } + + LOGGER.fine("From DB collected # of Obstap : " + obstapList.size()); + } + catch (SQLException se) + { + dbError(se); + // se.printStackTrace(); + throw new Exception(se.toString()); + } + + Obstap[] cubes = obstapList.toArray(new Obstap[0]); + + return cubes; + } + + /* convert overlap codes (AST definition): + + "0 - The check could not be performed because the second Region could not be mapped into the coordinate system of the first Region.", + "1 - There is no overlap between the two Regions.", + "2 - The first Region is completely inside the second Region.", + "3 - The second Region is completely inside the first Region.", + "4 - There is partial overlap between the two Regions.", + "5 - The Regions are identical to within their uncertainties.", + "6 - The second Region is the exact negation of the first Region to within their uncertainties." + */ + private Integer convertToOverlapCodeSky(boolean inpOverlapsDb, boolean inpInDb, boolean dbInInp) + { + if(inpOverlapsDb) + { + if(!inpInDb && !dbInInp) return 4; + else if( inpInDb && !dbInInp) return 3; + else if(!inpInDb && dbInInp) return 2; + else return 5; + } + else + { + return 1; + } + } + + private boolean intervalOverlap(double amin, double amax, double bmin, double bmax) + { + boolean AoverB + = (amin <= bmin) && (bmin <= amax) + || (amin <= bmax) && (bmax <= amax); + + boolean BoverA + = (bmin <= amin) && (amin <= bmax) + || (bmin <= amax) && (amax <= bmax); + + return AoverB || BoverA; + } + + private Integer convertToOverlapCodeVel(Band band, + Double w_min, Double w_max, // WAVE + Double v_min, Double v_max) // VELO + { + if(band != null) + { + boolean v_valid = (v_min != null) && (v_max != null); + boolean w_valid = (w_min != null) && (w_max != null); + + if( v_valid && (band.system == Band.System.VELO_LSRK) ) + { + boolean overlap = intervalOverlap(band.min, band.max, v_min, v_max);; + + boolean dbInInp = (band.min <= v_min) && (v_min <= band.max) + && (band.min <= v_max) && (v_max <= band.max); + + boolean inpInDb = (v_min <= band.min) && (band.min <= v_max) + && (v_min <= band.max ) && (band.max <= v_max); + + // do as in Sky-overlap + return convertToOverlapCodeSky(overlap, inpInDb, dbInInp); + } + else if( w_valid && (band.system == Band.System.WAVE_Barycentric) ) + { + boolean overlap = intervalOverlap(band.min, band.max, w_min, w_max);; + + boolean dbInInp = (band.min <= w_min) && (w_min <= band.max) + && (band.min <= w_max) && (w_max <= band.max); + + boolean inpInDb = (w_min <= band.min) && (band.min <= w_max) + && (w_min <= band.max ) && (band.max <= w_max); + + // do as in Sky-overlap + return convertToOverlapCodeSky(overlap, inpInDb, dbInInp); + } + else + { + return null; + } + } + else + { + return null; + } + } + + private Integer convertToOverlapCode(Integer ovcSky, Integer ovcVel) + { + if(ovcSky == null) return ovcVel; // spectral images or both null + else if(ovcVel == null) return ovcSky; // 2D sky images or both null + else if((ovcSky != null) && (ovcVel != null)) + { + if((ovcSky == 1) || (ovcVel == 1) ) return 1; // no overlap + else if(ovcSky == ovcVel) return ovcSky; + else return 4; + } + else return null; // both null + } + + + /* conversions tolerate missing columns */ + + private Integer getInt(ResultSet res, String colLabel) + { + try + { + Integer value = res.getInt(colLabel); + return (res.wasNull() ? null : value); + } + catch(SQLException se) + { + dbError(se); + return null; + } + } + + private Long getLong(ResultSet res, String colLabel) + { + try + { + Long value = res.getLong(colLabel); + return (res.wasNull() ? null : value); + } + catch(SQLException se) + { + dbError(se); + return null; + } + } + + private Double getDouble(ResultSet res, String colLabel) + { + try + { + Double value = res.getDouble(colLabel); + return (res.wasNull() ? null : value); + } + catch(SQLException se) + { + dbError(se); + return null; + } + } + + private String getString(ResultSet res, String colLabel) + { + try + { + String value = res.getString(colLabel); + return (res.wasNull() ? null : value); + } + catch(SQLException se) + { + dbError(se); + return null; + } + } + + + + private String toPgSphereSqlTypeString(Pos pos) + { + double lon; + double lat; + double radius; + double dlon; + double dlat; + + String inputRegion = null; + + switch(pos.shape) + { + case CIRCLE: + lon = pos.circle.lon; + lat = pos.circle.lat; + radius = pos.circle.radius; + inputRegion = "scircle '<(" + Double.toString(lon) + "d," + Double.toString(lat) + "d)," + + Double.toString(radius) + "d>'"; + break; + + case RANGE: + lon = (pos.range.lon1 + pos.range.lon2)/2.0; + lat = (pos.range.lat1 + pos.range.lat2)/2.0; + dlon = (pos.range.lon2 - pos.range.lon1)/2.0; + dlat = (pos.range.lat2 - pos.range.lat1)/2.0; + + /* South-West and North-East corners of a box */ + String sw_lon = Double.toString(lon - dlon/2.0); + String sw_lat = Double.toString(lat - dlat/2.0); + String ne_lon = Double.toString(lon + dlon/2.0); + String ne_lat = Double.toString(lat + dlat/2.0); + + inputRegion = "sbox '( ("+ sw_lon + "d, " + sw_lat + "d), (" + ne_lon +"d, " + ne_lat + "d) )'"; + break; + + case POLYGON: + // FIXME redefine Polygon as point-array: + assert(pos.polygon.lon.length == pos.polygon.lat.length); + + // Polygon has at least 3 points + inputRegion = "spoly '( (" + pos.polygon.lon[0] + "d, " + pos.polygon.lat[0] + "d),"; + for(int ii=1; ii < pos.polygon.lon.length; ii++) + { + inputRegion += ", (" + pos.polygon.lon[ii] + "d, " + pos.polygon.lat[ii] + "d)"; + } + inputRegion += " )'"; + break; + + default: + throw new IllegalArgumentException("Pos::shape was: " + pos.shape.toString() + + " but valid is CIRCLE or RANGE or POLYGON"); + } + + return inputRegion; + } + + private String toRegionColumnName(Pos.System system) + { + String dbRegion; + switch(system) + { + case GALACTIC: + dbRegion = "polygon_region_galactic"; + break; + default: + dbRegion = "polygon_region"; + } + return dbRegion; + } + + private String toSpecColumnNamePrefix(Band.System system) + { + // vlkb-volib/Band.System: WAVE_Barycentric, VELO_LSRK, GRID, NONE + String prefix; + switch(system) + { + case VELO_LSRK: prefix = "vel"; break; + default: prefix = "em"; + } + return prefix; + } + + + private void dbError(SQLException se) + { + LOGGER.fine("SQLState : " + se.getSQLState()); + LOGGER.fine("ErrorCode: " + se.getErrorCode()); + LOGGER.warning("Message: " + se.getMessage()); + Throwable t = se.getCause(); + while(t != null) { + LOGGER.fine("Cause: " + t); + t = t.getCause(); + } + } diff --git a/data-discovery/src/main/java/webapi/VosiServlet.java b/data-discovery/src/main/java/webapi/VosiServlet.java index 989a90ba1344874c78a632dc3584f6e6caeed48e..728e3d7eb270fae7df3e840e9e0f2141f2344264 100644 --- a/data-discovery/src/main/java/webapi/VosiServlet.java +++ b/data-discovery/src/main/java/webapi/VosiServlet.java @@ -27,123 +27,146 @@ import static java.nio.file.StandardCopyOption.*; public class VosiServlet extends javax.servlet.http.HttpServlet { - // for logs and debug - String className = this.getClass().getSimpleName(); + String className = this.getClass().getSimpleName(); + private static final SearchSettings settings = SearchSettings.getInstance("search.properties"); -// VOSI -// String accessURL = null; // FIXME now read from MERGEURL later introduce own param -// String funcName = "vlkb_cutout"; // FIXME read from config file - private static final String availStr = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<vosi:availability " - + " xmlns:vosi=\"http://www.ivoa.net/xml/VOSIAvailability/v1.0\">" - + " <vosi:available>true</vosi:available>" - + " <vosi:note>VLKB-SIAv2 " + Version.asString + " is accepting queries</vosi:note>" - + "</vosi:availability>"; + private String availString() + { + boolean available; + int obstapRowCount = -1; + DbObstap dbObstap; + String note; + try + { + synchronized(DbObstap.class) + { + dbObstap = new DbObstap(settings.dbConnArgs); + } + obstapRowCount = dbObstap.queryObstapRowCount(); + available = (obstapRowCount >= 0); + note = "Table obstap in " + settings.dbConnArgs.toString() + " has " + + String.valueOf(obstapRowCount) + " rows"; + } + catch(Exception ex) + { + note = "Accessing " + settings.dbConnArgs.toString() + + " failed with " + ex.toString(); + available = false; + } + String availStr = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<vosi:availability xmlns:vosi=\"http://www.ivoa.net/xml/VOSIAvailability/v1.0\">" + + "<vosi:available> "+ (available ? "true":"false") +" </vosi:available>" + + "<vosi:note> VLKB-SIAv2 "+ Version.asString +" is accepting queries </vosi:note>" + + "<vosi:note> " + note + " </vosi:note>" + + "</vosi:availability>"; + + return availStr; + } - private String capsStr = null; + private String capsStr = null; protected void SetCapsStr(String URL, String funcName) { if(URL != null) { - - String accessURL = stripTrailingSlash(URL); - - capsStr = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - - + "<vosi:capabilities " - + "xmlns:vosi=\"http://www.ivoa.net/xml/VOSICapabilities/v1.0\" " - + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " - + "xmlns:vod=\"http://www.ivoa.net/xml/VODataService/v1.1\">" - - + " <capability standardID=\"ivo://ivoa.net/std/VOSI#capabilities\">" - + " <interface xsi:type=\"vod:ParamHTTP\" version=\"1.0\">" - + " <accessURL use=\"full\">" - + accessURL + "/capabilities" - + " </accessURL>" - + " </interface>" - + " </capability>" - - + " <capability standardID=\"ivo://ivoa.net/std/VOSI#availability\">" - + " <interface xsi:type=\"vod:ParamHTTP\" version=\"1.0\">" - + " <accessURL use=\"full\">" - + accessURL + "/availability" - + " </accessURL>" - + " </interface>" - + " </capability>" - - + " <capability standardID=\"ivo://ivoa.net/std/SODA#sync-1.0\">" - + " <interface xsi:type=\"vod:ParamHTTP\" role=\"std\" version=\"1.0\">" - + " <accessURL use=\"full\">" - + accessURL + "/" + funcName - + " </accessURL>" - + " </interface>" - + " </capability>" - - + " <capability standardID=\"ivo://ivoa.net/std/SODA#async-1.0\">" - + " <interface xsi:type=\"vod:ParamHTTP\" role=\"std\" version=\"1.0\">" - + " <accessURL use=\"full\">" - + accessURL + "/" + funcName + "_uws/soda_cuts" - + " </accessURL>" - + " </interface>" - + " </capability>" - - + "</vosi:capabilities>"; + + String accessURL = stripTrailingSlash(URL); + + capsStr = + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + + "<vosi:capabilities " + + "xmlns:vosi=\"http://www.ivoa.net/xml/VOSICapabilities/v1.0\" " + + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + + "xmlns:vod=\"http://www.ivoa.net/xml/VODataService/v1.1\">" + + + " <capability standardID=\"ivo://ivoa.net/std/VOSI#capabilities\">" + + " <interface xsi:type=\"vod:ParamHTTP\" version=\"1.0\">" + + " <accessURL use=\"full\">" + + accessURL + "/capabilities" + + " </accessURL>" + + " </interface>" + + " </capability>" + + + " <capability standardID=\"ivo://ivoa.net/std/VOSI#availability\">" + + " <interface xsi:type=\"vod:ParamHTTP\" version=\"1.0\">" + + " <accessURL use=\"full\">" + + accessURL + "/availability" + + " </accessURL>" + + " </interface>" + + " </capability>" + + + " <capability standardID=\"ivo://ivoa.net/std/SODA#sync-1.0\">" + + " <interface xsi:type=\"vod:ParamHTTP\" role=\"std\" version=\"1.0\">" + + " <accessURL use=\"full\">" + + accessURL + "/" + funcName + + " </accessURL>" + + " </interface>" + + " </capability>" + + + " <capability standardID=\"ivo://ivoa.net/std/SODA#async-1.0\">" + + " <interface xsi:type=\"vod:ParamHTTP\" role=\"std\" version=\"1.0\">" + + " <accessURL use=\"full\">" + + accessURL + "/" + funcName + "_uws/soda_cuts" + + " </accessURL>" + + " </interface>" + + " </capability>" + + + "</vosi:capabilities>"; } } String stripTrailingSlash(String path) { - if (path.endsWith("/")) - return path.substring(0,path.length()-1); - else - return path; - } + if (path.endsWith("/")) + return path.substring(0,path.length()-1); + else + return path; + } - protected void doGet(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException { + protected void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { - doPost(request, response); - } + doPost(request, response); + } - protected void doPost(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException - { - StringBuffer requestURL = request.getRequestURL(); - - //System.out.println(className + " vlkb req from: " + request.getRemoteAddr() - // + " doGet: " + requestURL.toString()); - - PrintWriter writer = response.getWriter(); - response.setContentType("text/xml"); - - if(-1 != requestURL.lastIndexOf("/capabilities")) + protected void doPost(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { - String fullURL = request.getRequestURL().toString(); - String baseURL = fullURL.substring(0,requestURL.lastIndexOf("/")); + StringBuffer requestURL = request.getRequestURL(); - SetCapsStr(baseURL, "soda"); - writer.println(capsStr); + //System.out.println(className + " vlkb req from: " + request.getRemoteAddr() + // + " doGet: " + requestURL.toString()); + PrintWriter writer = response.getWriter(); + response.setContentType("text/xml"); + + if(-1 != requestURL.lastIndexOf("/capabilities")) + { + String fullURL = request.getRequestURL().toString(); + String baseURL = fullURL.substring(0,requestURL.lastIndexOf("/")); + + SetCapsStr(baseURL, "soda"); + writer.println(capsStr); + + } + else if(-1 != requestURL.lastIndexOf("/availability")) + { + writer.println(availString()); + } + // error FIXME what to do if none of above given ? e.g. misconfigured web.xml + + writer.close(); + return; } - else if(-1 != requestURL.lastIndexOf("/availability")) - { - writer.println(availStr); - } - // error FIXME what to do if none of above given ? e.g. misconfigured web.xml - - writer.close(); - return; - } }