/* * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata * * Portions of this software were developed by the Unidata Program at the * University Corporation for Atmospheric Research. * * Access and use of this software shall impose the following obligations * and understandings on the user. The user is granted the right, without * any fee or cost, to use, copy, modify, alter, enhance and distribute * this software, and any derivative works thereof, and its supporting * documentation for any purpose whatsoever, provided that this entire * notice appears in all copies of the software, derivative works and * supporting documentation. Further, UCAR requests that the user credit * UCAR/Unidata in any publications that result from the use of this * software or in any product that includes this software. The names UCAR * and/or Unidata, however, may not be used in any advertising or publicity * to endorse or promote any products or commercial entity unless specific * written permission is obtained from UCAR/Unidata. The user also * understands that UCAR/Unidata is not obligated to provide the user with * any support, consulting, training or assistance of any kind with regard * to the use, operation and performance of this software nor to provide * the user with any updates, revisions, new versions or "bug fixes." * * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * User: rkambic * Date: Jan 14, 2010 * Time: 1:31:49 PM */ package thredds.server.radarServer; import java.io.File; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Maintains the Radar collection of stations and days for a Radar Dataset. The * purpose is to permit querying the collection by station. * */ public class RadarDatasetCollection { private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger( getClass() ); public static final Pattern p_yyyymmdd_hhmm = Pattern.compile("\\d{8}_(\\d{4})"); public static boolean debug = false; /** * Top Directory of dataset */ String tdir; /** * station/time type directory, typical level2 radar data * or * product/station/time */ boolean stnTime = true; /** * station/product/time type directory, typical Gempak radar data */ boolean stnProduct = false; /** * Radar product, for level II this is null */ String product = null; /** * Standard Product Naming ie Level2_KRLX_20100112_1324.ar2v */ boolean standardName = true; /** * isCasestudycollection */ boolean caseStudy = false; /** * directory in between station and products */ String inbetween = null; /** * Map of all the stations, ArrayList of yyyyddmm times */ HashMap<String, ArrayList<String>> yyyymmdd = new HashMap<>(); /** * Map key = stn + yyyymmdd, times or full unstandard names */ HashMap<String, ArrayList<String>> hhmm = new HashMap<>(); private static int daysToRead = 6; public int getDaysToRead() { return daysToRead; } public void setDaysToRead(int daysToRead) { this.daysToRead = daysToRead; } private final SimpleDateFormat dateFormat; /** * Creates a complete Dataset Collection using the current day and past stored days * @param tdir Location of dataset on disk * @param product if level3, then get product dataset */ public RadarDatasetCollection(String tdir, String product) { caseStudy = tdir.contains( "casestudies"); StringBuffer sb = new StringBuffer( tdir ); this.product = product; if( stnTime ) { if (product == null) { this.tdir = tdir; } else { this.tdir = sb.append( "/" ).append( product ).toString(); } } else { if (product == null) { this.tdir = tdir; } else { this.tdir = sb.append( "/" ).append( product ).append( "/" ).toString(); } } // Read in RadarDayCollections for this dataset File dir = new File(this.tdir); if ( !caseStudy && dir.exists() && dir.isDirectory()) { ArrayList<String> rdc = new ArrayList<>(); sb.setLength( 0 ); sb.append("In directory ").append(dir.getParent()).append("/").append(dir.getName()); log.debug( sb.toString() ); String[] children = dir.list(); for (String child : children) { if ( ! child.startsWith( ".2")) // LOOK WTF ?? these are directories look like ".20140514" that are some kind of serialized directory; // not sure who writes them, but they are owned by ldm. HAHAHAHAHAHAHA continue; rdc.add( child ); } Collections.sort(rdc, new CompareKeyDescend()); for (int i = 0; i < rdc.size() && i < daysToRead; i++) { readRadarDayCollection( rdc.get( i ) ); } } else { // casestudy collection adhoc station or station/product or this.tdir = tdir; ArrayList<String> stations = getStationsFromDir( tdir ); for (String stn : stations) { sb.setLength( 0 ); dir = new File( sb.append( tdir).append( "/").append( stn).toString()); if (dir.exists() && dir.isDirectory()) { File pdir = null; if( product != null ) { pdir = new File( sb.append("/").append(product).toString()); } else { pdir = new File( sb.toString()); // it's possible to have an extra directory in between the data String[] children = pdir.list(); if ( children.length > 0 ) { File btwn = new File( sb.append( "/").append( children[0]).toString()); if (btwn.exists() && btwn.isDirectory()) { pdir = btwn; inbetween = btwn.getName() +"/"; } } } if (pdir.exists() && pdir.isDirectory()) { String[] children = pdir.list(); ArrayList<String> times = new ArrayList<String>(); for (String child : children) { if ( child.startsWith( ".")) continue; if ( inbetween != null) { sb.setLength( 0 ); sb.append( inbetween ).append( child ); times.add( sb.toString() ); } else { times.add( child ); } } ArrayList<String> days = yyyymmdd.get( stn ); if ( days == null ) days = new ArrayList<>(); days.add( "all" ); yyyymmdd.put(stn, days); sb.setLength(0); sb.append( stn ).append("all"); Collections.sort(times, new CompareKeyDescend()); hhmm.put(sb.toString(), times); if (log.isDebugEnabled()) log.debug("RadarDayCollections {} added stn={} days={} hours={}", tdir, stn, days.size(), times.size()); // System.out.printf("RadarDayCollections %s added stn=%s days=%d hours=%d%n", tdir, stn, days.size(), times.size()); } } } } dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.US); dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); } /* * returns and ArrayList of stations from a directory */ private ArrayList<String> getStationsFromDir(String stnDir) { ArrayList<String> stations = new ArrayList<String>(); File dir = new File(stnDir); if (dir.exists() && dir.isDirectory()) { log.debug( "In directory " + dir.getParent() + "/" + dir.getName()); String[] children = dir.list(); for (String aChild : children) { File child = new File(dir, aChild); if (child.isDirectory()) { stations.add(aChild); } } } else { return null; } return stations; } /* * Read in a RadarDayCollection * @parm fileName * */ private Boolean readRadarDayCollection( String child ) { StringBuffer sb = new StringBuffer( tdir ); sb.append( "/").append( child ); RadarDayCollection dayCollection = new RadarDayCollection().read( sb.toString() ); //System.out.printf("readRadarDayCollection = %s%n", sb); if( dayCollection == null ) return false ; this.standardName = dayCollection.standardName; java.util.Set<String> stations = dayCollection.getStations(); for( String station : stations ) { ArrayList<String> days = yyyymmdd.get( station ); if ( days == null ) days = new ArrayList<>(); days.add( dayCollection.yyyymmdd ); yyyymmdd.put( station, days ); sb.setLength(0); sb.append( station ).append(dayCollection.yyyymmdd); hhmm.put( sb.toString(), dayCollection.getTimes( station ) ); } return true; } /* returns true if previous days data is now available, causes dataset reread */ public boolean previousDayNowAvailable() { if ( caseStudy ) // casestudy data is static return false; Calendar cal = Calendar.getInstance( java.util.TimeZone.getTimeZone("GMT")); // check for previous day cal.add( Calendar.DAY_OF_MONTH, -1 ); Date now = cal.getTime(); String previousDay = dateFormat.format( now ); StringBuffer sb = new StringBuffer(); // check if new day data is available java.util.Set<String> stations = yyyymmdd.keySet(); int count = 0; for( String station : stations ) { if( ++count == 10 ) // at most check 10 stations for previous day return false; ArrayList<String> days = yyyymmdd.get( station ); if( previousDay.equals( days.get( 0 ))) { return false; } else { // check if previous day available sb.setLength( 0 ); sb.append( tdir ).append( "/").append( '.' ).append( previousDay ); File dir = new File( sb.toString() ); if (dir.exists()) { return true; } } } return false; } /** * returns times for this station in the RadarStationCollection object * @param rsc RadarStationCollection * @return success boolean */ public boolean getStationTimes( RadarStationCollection rsc, String currentDay ) { // get today's times for station //Calendar cal = Calendar.getInstance( java.util.TimeZone.getTimeZone("GMT")); //Date now = cal.getTime(); //String currentDay = dateFormat.format( now ); StringBuffer sb = new StringBuffer( tdir ); sb.append( "/" ).append( rsc.stnName ).append( "/" ).append( currentDay ); File dir = new File( sb.toString() ); if (dir.exists() && dir.isDirectory()) { sb.insert( 0, "In directory "); log.debug( sb.toString() ); ArrayList<String> currenthhmm = new ArrayList<String>(); String[] children = dir.list(); Matcher m; for (String child : children) { if ( child.startsWith( ".")) continue; // Level2_KFTG_20100108_0654.ar2v m = p_yyyymmdd_hhmm.matcher(child); if (m.find()) { if (standardName ) currenthhmm.add(m.group(1)); else currenthhmm.add(child); } } if( currenthhmm.size() > 0 ) { Collections.sort(currenthhmm, new CompareKeyDescend()); rsc.yyyymmdd.add( currentDay ); rsc.hhmm.put( currentDay, currenthhmm ); } if ( log.isDebugEnabled() ) { for ( String hm : currenthhmm ) { sb.setLength( 0 ); sb.append( currentDay ).append( "_" ).append( hm ); log.debug( sb.toString() ); } } } ArrayList<String> dal = yyyymmdd.get( rsc.stnName ); if ( dal == null) return false; Collections.sort(dal, new CompareKeyDescend()); rsc.yyyymmdd.addAll( dal ); for ( String day : dal ) { sb.setLength( 0 ); sb.append( rsc.stnName ).append( day ); ArrayList<String> tal = hhmm.get( sb.toString() ); rsc.hhmm.put( day, tal ); if ( log.isDebugEnabled() ) { for ( String hm : tal ) { sb.setLength( 0 ); sb.append( day ).append( "_" ).append( hm ); log.debug( sb.toString() ); } } } return true; } public RadarStationCollection queryStation( String stnName, String currentDay ) { RadarStationCollection rsc = new RadarStationCollection( tdir, stnName, stnTime, product ); if (getStationTimes( rsc, currentDay ) ) return rsc; else return null; } public RadarStationCollection queryStation( String dir, String stnName, String product, String currentDay ) { RadarStationCollection rsc = new RadarStationCollection( dir, stnName, stnTime, product); getStationTimes( rsc, currentDay ); return rsc; } public String getTdir() { return tdir; } public boolean isStnTime() { return stnTime; } public boolean isStnProduct() { return stnProduct; } public String getProduct() { return product; } public boolean isStandardName() { return standardName; } public HashMap<String, ArrayList<String>> getYyyymmdd() { return yyyymmdd; } public boolean isCaseStudy() { return caseStudy; } public HashMap<String, ArrayList<String>> getHhmm() { return hhmm; } protected static class CompareKeyDescend implements Comparator<String> { public int compare(String s1, String s2) { return s2.compareTo(s1); } } }