/******************************************************************************* * Copyright (c) 2011 IRIS/DMC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * IRIS/DMC- initial API and implementation * * ACKNOWLEDGEMENT * This software was developed as part of a project supported by * Cooperative Agreement Number G10AC00533 from the United States * Geological Survey. Its contents are solely the responsibility of * the authors and the USGS is not responsible for the efficacy, * safety, or suitability of this software. ******************************************************************************/ import java.io.IOException; import java.io.OutputStream; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.annotation.PostConstruct; import org.apache.commons.collections.Predicate; import org.apache.commons.collections.PredicateUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; public class CacheImp implements Cache { private JdbcTemplate jdbcTemplate; private Store store = null; /* * This method seriously needs better search algorithm */ public void find(final Query query) throws IOException { long startTime = 0; String networkFilter = ""; String stationFilter = ""; String channelFilter = ""; String locationFilter = ""; String whereClause = ""; DriverManagerDataSource dataSource = new DriverManagerDataSource(); // dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver"); dataSource.setUrl("jdbc:oracle:thin:@ncdb2.geo.berkeley.edu:1521:dcucb"); dataSource.setUsername(""); dataSource.setPassword(""); jdbcTemplate = new JdbcTemplate(dataSource); //Add net, sta and chan filters to SQL.sql so the entire cache isn't generated for //each call of sml. networkFilter = buildFilter(query.getNetworks(), "network"); stationFilter = buildFilter(query.getStations(), "station"); channelFilter = buildFilter(query.getChannels(), "channel"); locationFilter = buildFilter(query.getLocations(), "location"); if (!networkFilter.isEmpty()){ whereClause = whereClause.concat(networkFilter); } if (!stationFilter.isEmpty()){ if (whereClause.length() > 0){ whereClause = whereClause.concat(" and " ); } whereClause = whereClause.concat(stationFilter); } if (!channelFilter.isEmpty()){ if (whereClause.length() > 0){ whereClause = whereClause.concat(" and "); } whereClause = whereClause.concat(channelFilter); } if (!whereClause.isEmpty()){ SQL.sql = SQL.sql.concat(" where " + whereClause); } //System.out.println("SQL.sql = " + SQL.sql); startTime = System.currentTimeMillis(); this.jdbcTemplate.execute("alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS'"); this.store = (Store)this.jdbcTemplate.query(SQL.sql, new CacheHandler()); List stationList = this.store.getStationList(); Predicate stationPredicate = null; Predicate stationEpochPredicate = null; Predicate channelPredicate = null; try { stationPredicate = buildStationPredicate(query); stationEpochPredicate = buildStationEpochPredicate(query); channelPredicate = buildChannelPredicate(query); } catch (StationRetrievalException e) { throw new NoStationFoundException(e.getMessage()); } XMLWriter writer = new XMLWriter(); PrintQueue printQueue = new PrintQueue(this.jdbcTemplate, writer, query); printQueue.SelectedNbStations = 0; // Retrieve number of sites for (Station station : stationList) { if (stationPredicate != null) { if (stationPredicate.evaluate(station)) { if (stationEpochPredicate != null) { for (StationEpoch stationEpoch : station.getEpochs()) { if (stationEpochPredicate.evaluate(stationEpoch)) { if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { int flag = 0; if (channelPredicate.evaluate(channel)) { flag = 1; } if (flag == 1) { printQueue.SelectedNbStations++; } } } else { printQueue.SelectedNbStations++; } } } } else { for (StationEpoch stationEpoch : station.getEpochs()) { if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { int flag = 0; if (channelPredicate.evaluate(channel)) { flag = 1; } if (flag == 1) { printQueue.SelectedNbStations++; } } } else { printQueue.SelectedNbStations++; } } } } } else { if (stationEpochPredicate != null) { for (StationEpoch stationEpoch : station.getEpochs()) { if (stationEpochPredicate.evaluate(stationEpoch)) { if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { int flag = 0; if (channelPredicate.evaluate(channel)) { flag = 1; } if (flag == 1) { printQueue.SelectedNbStations++; } } } else { printQueue.SelectedNbStations++; } } } } else { for (StationEpoch stationEpoch : station.getEpochs()) { if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { int flag = 0; if (channelPredicate.evaluate(channel)) { flag = 1; } if (flag == 1) { printQueue.SelectedNbStations++; } } } else { printQueue.SelectedNbStations++; } } } } } if (stationPredicate != null) { boolean addStation = false; for (Station station : stationList) {// Ready if (stationPredicate.evaluate(station)) { addStation = true; if (stationEpochPredicate != null) { boolean addStationEpoch = false; for (StationEpoch stationEpoch : station.getEpochs()) { if (stationEpochPredicate.evaluate(stationEpoch)) { addStationEpoch = true; if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { if (channelPredicate.evaluate(channel)) { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); addStationEpoch = false; } } if (query.getLevel() > Query.STATION_LEVEL) { printQueue.add(channel); } else { break; } } } } else { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } if (query.getLevel() > Query.STATION_LEVEL) { printQueue.add(stationEpoch.getChannels()); } break; } } } } else {// END stationEpochPredicate != null addStation = true; for (StationEpoch stationEpoch : station.getEpochs()) { boolean addStationEpoch = true; if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { if (channelPredicate.evaluate(channel)) { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } break; } else { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { printQueue.add(stationEpoch); addStationEpoch = false; } printQueue.add(channel); } } } } else { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } } else { if (addStation) { printQueue.add(station); addStation = false; } printQueue.add(stationEpoch); printQueue.add(stationEpoch.getChannels()); } } } } } }// /////ready } else {// END stationPredicate != null if (stationEpochPredicate != null) { for (Station station : stationList) { boolean addStation = true; for (StationEpoch stationEpoch : station.getEpochs()) { boolean addStationEpoch = true; if (stationEpochPredicate != null) { if (stationEpochPredicate.evaluate(stationEpoch)) { if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { if (channelPredicate.evaluate(channel)) { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } break; } else { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { printQueue.add(stationEpoch); addStationEpoch = false; } printQueue.add(channel); } } } } else { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } if (query.getLevel() > Query.STATION_LEVEL) { printQueue.add(stationEpoch.getChannels()); } } } } else {// End stationPredicate != null if (channelPredicate != null) { for (Node channel : stationEpoch.getChannels()) { if (channelPredicate.evaluate(channel)) { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } break; } else { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { printQueue.add(stationEpoch); addStationEpoch = false; } printQueue.add(channel); } } } } else { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } } else { if (addStation) { printQueue.add(station); addStation = false; } printQueue.add(stationEpoch); printQueue.add(stationEpoch.getChannels()); } } } } } } else { if (channelPredicate != null) { for (Station station : stationList) { boolean addStation = true; for (StationEpoch stationEpoch : station.getEpochs()) { boolean addStationEpoch = true; for (Node channel : stationEpoch.getChannels()) { if (channelPredicate.evaluate(channel)) { if (query.getLevel() < Query.CHANNEL_LEVEL) { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); addStationEpoch = false; } } break; } else { if (addStation) { printQueue.add(station); addStation = false; } if (addStationEpoch) { printQueue.add(stationEpoch); addStationEpoch = false; } printQueue.add(channel); } } } } } } else {// No filter, print all for (Station station : stationList) { printQueue.add(station); for (StationEpoch stationEpoch : station.getEpochs()) { if (query.getLevel() > Query.NETWORK_LEVEL) { printQueue.add(stationEpoch); } if (query.getLevel() > Query.STATION_LEVEL) { printQueue.add(stationEpoch.getChannels()); } } } } } } if (printQueue.isResultStreamed()) { printQueue.close(); } else { // throw new NoStationFoundException("No data found"); } } private String buildFilter(String[] listOfItems, String type){ String filter = ""; List wildcardMatches = null; String itemsCSV = ""; if (listOfItems != null && listOfItems.length > 0){ for (int i = 0; i < listOfItems.length; i++){ if (listOfItems[i].indexOf("?") != -1){ if (wildcardMatches == null){ wildcardMatches = new ArrayList(); } wildcardMatches.add(type + " like '" + listOfItems[i].replace("?","_") + "'"); } else if (listOfItems[i].indexOf("*") != -1){ if (wildcardMatches == null){ wildcardMatches = new ArrayList(); } wildcardMatches.add(type + " like '" + listOfItems[i].replace("*","%") + "'"); } else { if (!itemsCSV.isEmpty()){ itemsCSV = itemsCSV.concat(","); } itemsCSV = itemsCSV.concat("'" + listOfItems[i] + "'"); } } if (wildcardMatches != null){ for (int i=0; i stationPredicateList = new ArrayList(); List networkOrPredicate = new ArrayList(); final String[] networks = query.getNetworks(); if (networks != null) { // List netPredicates = new ArrayList(); if (networks.length > 1) { for (final String net : networks) { networkOrPredicate.add(new Predicate() { @Override public boolean evaluate(Object station) { if (net.contains("*") || net.contains("?")) { if (globMatches(net, ((Station) station).getNetCode())) { return true; } else { return false; } } else { if (net.equalsIgnoreCase(((Station) station).getNetCode())) { return true; } return false; } } }); } } else { networkOrPredicate.add(new Predicate() { @Override public boolean evaluate(Object station) { String net = networks[0]; if (net.contains("*") || net.contains("?")) { if (globMatches(net, ((Station) station).getNetCode())) { return true; } else { return false; } } else { if (net.equalsIgnoreCase(((Station) station).getNetCode())) { return true; } return false; } } }); } } // End networks if (networkOrPredicate != null && !networkOrPredicate.isEmpty()) { stationPredicateList.add(PredicateUtils.anyPredicate(networkOrPredicate)); } final String[] stations = query.getStations(); if (stations != null) { if (stations.length > 1) { List stationOrPredicate = new ArrayList(); for (final String sta : stations) { stationOrPredicate.add(new Predicate() { @Override public boolean evaluate(Object station) { if (sta.contains("*") || sta.contains("?")) { if (globMatches(sta, ((Station) station).getStaCode())) { return true; } else { return false; } } else { if (sta.equalsIgnoreCase(((Station) station).getStaCode())) { return true; } return false; } } }); } stationPredicateList.add(PredicateUtils.anyPredicate(stationOrPredicate)); } else { stationPredicateList.add(new Predicate() { @Override public boolean evaluate(Object station) { String sta = stations[0]; if (sta.contains("*") || sta.contains("?")) { if (globMatches(sta, ((Station) station).getStaCode())) { return true; } else { return false; } } else { if (stations[0].equalsIgnoreCase(((Station) station).getStaCode())) { return true; } return false; } } }); } } if (stationPredicateList.isEmpty()) { return null; } else { return PredicateUtils.allPredicate(stationPredicateList); } } private Predicate buildStationEpochPredicate(final Query query) { List epochPredicateList = new ArrayList(); if (query.getLat() != null && query.getLon() != null && query.getMaxRadius() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { StationEpoch stationEpoch = (StationEpoch) object; double distance = distance(query.getLat(), query.getLon(), stationEpoch.getLatitude(), stationEpoch.getLongitude(), 'K')/111.195; if (distance <= query.getMaxRadius() && distance >= query.getMinRadius()) { return true; } else { return false; } } }); } if (query.getMinLat() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getLatitude() >= query.getMinLat()) { return true; } else { return false; } } }); } if (query.getMaxLat() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getLatitude() <= query.getMaxLat()) { return true; } else { return false; } } }); } if (query.getMinLon() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getLongitude() >= query.getMinLon()) { return true; } else { return false; } } }); } if (query.getMaxLon() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getLongitude() <= query.getMaxLon()) { return true; } else { return false; } } }); } /* if (query.getStartAfter() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getStarted().isAfter( query.getStartAfter())) { return true; } return false; } }); } if (query.getStartBefore() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getStarted().isBefore(query.getStartBefore()) || ((StationEpoch) object).getStarted().isEqual(query.getStartBefore())) { return true; } return false; } }); } if (query.getEndAfter() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getEnded().isAfter( query.getEndAfter())) { return true; } return false; } }); } if (query.getEndBefore() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { if (((StationEpoch) object).getEnded().isBefore( query.getEndBefore())) { return true; } return false; } }); } if (query.getTimeWindow() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { StationEpoch station = (StationEpoch) object; if (station.getStarted().isBefore(query.getTimeWindow()[1]) && station.getEnded().isAfter( query.getTimeWindow()[0])) { return true; } return false; } }); } */ if (query.getUpdatedAfter() != null) { epochPredicateList.add(new Predicate() { @Override public boolean evaluate(Object object) { StationEpoch station = (StationEpoch) object; if (station.getLastModified().equals( query.getUpdatedAfter()) || station.getLastModified().isAfter( query.getUpdatedAfter())) { return true; } return false; } }); } if (epochPredicateList.size() > 0) return PredicateUtils.allPredicate(epochPredicateList); return null; } private double distance(double lat1, double lon1, double lat2, double lon2, char unit) { double theta = lon1 - lon2; double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta)); dist = Math.acos(dist); dist = rad2deg(dist); dist = dist * 60 * 1.1515; if (unit == 'K') { dist = dist * 1.609344; } else if (unit == 'N') { dist = dist * 0.8684; } return (dist); } /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ /* :: This function converts decimal degrees to radians : */ /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ private double deg2rad(double deg) { return (deg * Math.PI / 180.0); } /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ /* :: This function converts radians to decimal degrees : */ /* ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: */ private double rad2deg(double rad) { return (rad * 180 / Math.PI); } private Predicate buildChannelPredicate(final Query query) { List channelPredicateList = new ArrayList(); final String[] channels = query.getChannels(); if (channels != null) { if (channels.length == 0) { } else if (channels.length > 1) { List channelOrPredicate = new ArrayList(); for (final String chan : channels) { channelOrPredicate.add(new Predicate() { @Override public boolean evaluate(Object channel) { if (chan.contains("*") || chan.contains("?")) { if (globMatches(chan, ((Channel) channel).getCode())) { return true; } else { return false; } } else { if (chan.equalsIgnoreCase(((Channel) channel) .getCode())) { return true; } return false; } } }); } channelPredicateList.add(PredicateUtils .anyPredicate(channelOrPredicate)); } else { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { String chan = channels[0]; if (chan.contains("*") || chan.contains("?")) { if (globMatches(chan, ((Channel) channel).getCode())) { return true; } else { return false; } } else { if (chan.equalsIgnoreCase(((Channel) channel) .getCode())) { return true; } return false; } } }); } } final String[] locations = query.getLocations(); if (locations != null) { if (locations.length == 0) { } else if (locations.length > 1) { List locationOrPredicate = new ArrayList(); for (final String location : locations) { final String loc = location.replace("-", " "); locationOrPredicate.add(new Predicate() { @Override public boolean evaluate(Object channel) { if (loc.contains("*") || loc.contains("?")) { if (globMatches(loc, ((Channel) channel).getLocation())) { return true; } else { return false; } } else { if (loc.equalsIgnoreCase(((Channel) channel) .getLocation())) { return true; } return false; } } }); } channelPredicateList.add(PredicateUtils .anyPredicate(locationOrPredicate)); } else { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { String loc = locations[0].replace("-", " "); if (loc.contains("*") || loc.contains("?")) { if (globMatches(loc, ((Channel) channel).getLocation())) { return true; } else { return false; } } else { if (loc.equalsIgnoreCase(((Channel) channel) .getLocation())) { return true; } return false; } } }); } } if (query.getStartAfter() != null) { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { for (ChannelEpoch channelEpoch : ((Channel) channel).getEpochs()) { if (channelEpoch.getStarted().isAfter(query.getStartAfter())) { return true; } } return false; } }); } if (query.getStartBefore() != null) { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { for (ChannelEpoch channelEpoch : ((Channel) channel).getEpochs()) { if (channelEpoch.getStarted().isBefore(query.getStartBefore()) || channelEpoch.getStarted().isEqual(query.getStartBefore())) { return true; } } return false; } }); } if (query.getEndAfter() != null) { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { for (ChannelEpoch channelEpoch : ((Channel) channel).getEpochs()) { if (channelEpoch.getEnded().isAfter(query.getEndAfter())) { return true; } } return false; } }); } if (query.getEndBefore() != null) { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { for (ChannelEpoch channelEpoch : ((Channel) channel).getEpochs()) { if (channelEpoch.getEnded().isBefore(query.getEndBefore())) { return true; } } return false; } }); } if (query.getTimeWindow() != null) { channelPredicateList.add(new Predicate() { @Override public boolean evaluate(Object channel) { for (ChannelEpoch channelEpoch : ((Channel) channel).getEpochs()) { if (channelEpoch.getStarted().isBefore(query.getTimeWindow()[1]) && channelEpoch.getEnded().isAfter(query.getTimeWindow()[0])) { return true; } } return false; } }); } if (channelPredicateList.size() > 0){ return PredicateUtils.allPredicate(channelPredicateList); } return null; } private static boolean globMatches(String glob, String target) { Pattern p = Pattern.compile("(\\*+)|(\\?)|([^*?]+)"); Matcher m = p.matcher(glob); StringBuilder sb = new StringBuilder(); while (m.find()) { String star = m.group(1); String question = m.group(2); String text = m.group(3); if (star != null) { sb.append(".*"); } else if (question != null) { sb.append(".?"); } else { sb.append(Pattern.quote(text)); } } return target.matches(sb.toString()); } private boolean justStarted = true; }