public final void readLong(long[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      pa[start + i] = readLong();
    }
  }

public final void readLong ( long [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { pa [ start + i ] = readLong ( ) ; } }

Read an array of longs

@param pa    read into this array
@param start starting at pa[start]
@param n     read this many elements
@throws IOException on read error


public final void readFloat(float[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      pa[start + i] = Float.intBitsToFloat(readInt());
    }
  }

public final void readFloat ( float [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { pa [ start + i ] = Float . intBitsToFloat ( readInt ( ) ) ; } }

Read an array of floats

@param pa    read into this array
@param start starting at pa[start]
@param n     read this many elements
@throws IOException on read error


public final void readDouble(double[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      pa[start + i] = Double.longBitsToDouble(readLong());
    }
  }

public final void readDouble ( double [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { pa [ start + i ] = Double . longBitsToDouble ( readLong ( ) ) ; } }

Read an array of doubles

@param pa    read into this array
@param start starting at pa[start]
@param n     read this many elements
@throws IOException on read error


public String readString(int nbytes) throws IOException {
    byte[] data = new byte[nbytes];
    readFully(data);
    return new String(data, CDM.utf8Charset);
  }

public String readString ( int nbytes ) throws IOException { byte [ ] data = new byte [ nbytes ] ; readFully ( data ) ; return new String ( data , CDM . utf8Charset ) ; }

Read a String of known length.

@param nbytes number of bytes to read
@return String wrapping the bytes.
@throws IOException if an I/O error occurs.


public String readStringMax(int nbytes) throws IOException {
    byte[] b = new byte[nbytes];
    readFully(b);
    int count;
    for (count = 0; count < nbytes; count++)
      if (b[count] == 0) break;
    return new String(b, 0, count, CDM.utf8Charset);
  }

public String readStringMax ( int nbytes ) throws IOException { byte [ ] b = new byte [ nbytes ] ; readFully ( b ) ; int count ; for ( count = 0 ; count < nbytes ; count ++ ) if ( b [ count ] == 0 ) break ; return new String ( b , 0 , count , CDM . utf8Charset ) ; }

Read a String of max length, zero terminate.

@param nbytes number of bytes to read
@return String wrapping the bytes.
@throws IOException if an I/O error occurs.

Read a String of max length zero terminate .


public final void writeBoolean(boolean[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeBoolean(pa[start + i]);
    }
  }

public final void writeBoolean ( boolean [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeBoolean ( pa [ start + i ] ) ; } }

Write an array of booleans

@param pa    write from this array
@param start starting with this element in the array
@param n     write this number of elements
@throws IOException on read error


public final void writeShort(short[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeShort(pa[start + i]);
    }
  }

public final void writeShort ( short [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeShort ( pa [ start + i ] ) ; } }

Write an array of shorts

@param pa    write from this array
@param start starting with this element in the array
@param n     this number of elements
@throws IOException on read error


public final void writeChar(char[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeChar(pa[start + i]);
    }
  }

public final void writeChar ( char [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeChar ( pa [ start + i ] ) ; } }

Write an array of chars

@param pa    write from this array
@param start starting with this element in the array
@param n     this number of elements
@throws IOException on read error


public final void writeInt(int[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeInt(pa[start + i]);
    }
  }

public final void writeInt ( int [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeInt ( pa [ start + i ] ) ; } }

Write an array of ints

@param pa    write from this array
@param start starting with this element in the array
@param n     write this number of elements
@throws IOException on read error


public final void writeLong(long[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeLong(pa[start + i]);
    }
  }

public final void writeLong ( long [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeLong ( pa [ start + i ] ) ; } }

Write an array of longs

@param pa    write from this array
@param start starting with this element in the array
@param n     write this number of elements
@throws IOException on read error


public final void writeFloat(float[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeFloat(pa[start + i]);
    }
  }

public final void writeFloat ( float [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeFloat ( pa [ start + i ] ) ; } }

Write an array of floats

@param pa    write from this array
@param start starting with this element in the array
@param n     write this number of elements
@throws IOException on read error


public final void writeDouble(double[] pa, int start, int n) throws IOException {
    for (int i = 0; i < n; i++) {
      writeDouble(pa[start + i]);
    }
  }

public final void writeDouble ( double [ ] pa , int start , int n ) throws IOException { for ( int i = 0 ; i < n ; i ++ ) { writeDouble ( pa [ start + i ] ) ; } }

Write an array of doubles

@param pa    write from this array
@param start starting with this element in the array
@param n     write this number of elements
@throws IOException on read error


public final void writeBytes(String s) throws IOException {
    int len = s.length();
    for (int i = 0; i < len; i++) {
      write((byte) s.charAt(i));
    }
  }

public final void writeBytes ( String s ) throws IOException { int len = s . length ( ) ; for ( int i = 0 ; i < len ; i ++ ) { write ( ( byte ) s . charAt ( i ) ) ; } }

Writes the string to the file as a sequence of bytes. Each
character in the string is written out, in sequence, by discarding
its high eight bits.

@param s a string of bytes to be written.
@throws IOException if an I/O error occurs.

Writes the string to the file as a sequence of bytes . Each character in the string is written out in sequence by discarding its high eight bits .


public final void writeBytes(char b[], int off, int len) throws IOException {
    for (int i = off; i < len; i++) {
      write((byte) b[i]);
    }
  }

public final void writeBytes ( char b [ ] , int off , int len ) throws IOException { for ( int i = off ; i < len ; i ++ ) { write ( ( byte ) b [ i ] ) ; } }

Writes the character array to the file as a sequence of bytes. Each
character in the string is written out, in sequence, by discarding
its high eight bits.

@param b   a character array of bytes to be written.
@param off the index of the first character to write.
@param len the number of characters to write.
@throws IOException if an I/O error occurs.

Writes the character array to the file as a sequence of bytes . Each character in the string is written out in sequence by discarding its high eight bits .


public boolean searchForward(KMPMatch match, int maxBytes) throws IOException {
    long start = getFilePointer();
    long last = (maxBytes < 0) ? length() : Math.min(length(), start + maxBytes);
    long needToScan = last - start;

    // check what ever is now in the buffer
    int bytesAvailable = (int) (dataEnd - filePosition);
    if (bytesAvailable < 1) {
      seek(filePosition); // read a new buffer
      bytesAvailable = (int) (dataEnd - filePosition);
    }
    int bufStart = (int) (filePosition - bufferStart);
    int scanBytes = (int) Math.min(bytesAvailable, needToScan);
    int pos = match.indexOf(buffer, bufStart, scanBytes);
    if (pos >= 0) {
      seek(bufferStart + pos);
      return true;
    }

    int matchLen = match.getMatchLength();
    needToScan -= scanBytes - matchLen;

    while (needToScan > matchLen) {
      readBuffer(dataEnd - matchLen); // force new buffer

      scanBytes = (int) Math.min(buffer.length, needToScan);
      pos = match.indexOf(buffer, 0, scanBytes);
      if (pos > 0) {
        seek(bufferStart + pos);
        return true;
      }

      needToScan -= scanBytes - matchLen;
    }

    // failure
    seek(last);
    return false;
  }

Search forward from the current pos, looking for a match.

@param match    the match to look for.
@param maxBytes maximum number of bytes to search. use -1 for all
@return true if found, file position will be at the start of the match.
@throws IOException on read error

Search forward from the current pos looking for a match .


public void appendQuery( StringBuffer sbuff, ArrayList values) {
    if (template != null)
      appendQueryFromTemplate( sbuff, values);
    else
      appendQueryFromParamValue( sbuff, values);
  }

public void appendQuery ( StringBuffer sbuff , ArrayList values ) { if ( template != null ) appendQueryFromTemplate ( sbuff , values ) ; else appendQueryFromParamValue ( sbuff , values ) ; }

Create the selector result string, and append.
@param sbuff append here
@param values list of selected values, each value is a pair (String, Object), where the
String is name of the value, and the Object is the value itself. We use the toString()
method on the object to get its String representation.

Create the selector result string and append .


static public MCollection factory(FeatureCollectionConfig config, Path topDir, boolean isTop, IndexReader indexReader, String suffix, org.slf4j.Logger logger) throws IOException {
    DirectoryBuilder builder = new DirectoryBuilder(config.collectionName, topDir.toString(), suffix);

    DirectoryPartition dpart = new DirectoryPartition(config, topDir, isTop, indexReader, suffix, logger);
    if (!builder.isLeaf(indexReader))  { // its a partition
      return dpart;
    }

    // its a collection
    boolean hasIndex = builder.findIndex();
    if (hasIndex) {
      return dpart.makeChildCollection(builder);
    } else {
      DirectoryCollection result = new DirectoryCollection(config.collectionName, topDir, isTop, config.olderThan, logger); // no index file
      return result;
    }
  }

static
public
MCollection
factory
(
FeatureCollectionConfig
config
,
Path
topDir
,
boolean
isTop
,
IndexReader
indexReader
,
String
suffix
,
org
.
slf4j
.
Logger
logger
)
throws
IOException
{
DirectoryBuilder
builder
=
new
DirectoryBuilder
(
config
.
collectionName
,
topDir
.
toString
(
)
,
suffix
)
;
DirectoryPartition
dpart
=
new
DirectoryPartition
(
config
,
topDir
,
isTop
,
indexReader
,
suffix
,
logger
)
;
if
(
!
builder
.
isLeaf
(
indexReader
)
)
{
// its a partition
return
dpart
;
}
// its a collection
boolean
hasIndex
=
builder
.
findIndex
(
)
;
if
(
hasIndex
)
{
return
dpart
.
makeChildCollection
(
builder
)
;
}
else
{
DirectoryCollection
result
=
new
DirectoryCollection
(
config
.
collectionName
,
topDir
,
isTop
,
config
.
olderThan
,
logger
)
;
// no index file
return
result
;
}
}

returns a DirectoryPartition or DirectoryCollection


public boolean findIndex() throws IOException {
    Path indexPath = Paths.get(dir.toString(), partitionName + suffix);
    if (Files.exists(indexPath)) {
      this.index = indexPath;
      BasicFileAttributes attr = Files.readAttributes(indexPath, BasicFileAttributes.class);
      this.indexLastModified = attr.lastModifiedTime();
      this.indexSize = attr.size();
      return true;
    }
    return false;
  }

public boolean findIndex ( ) throws IOException { Path indexPath = Paths . get ( dir . toString ( ) , partitionName + suffix ) ; if ( Files . exists ( indexPath ) ) { this . index = indexPath ; BasicFileAttributes attr = Files . readAttributes ( indexPath , BasicFileAttributes . class ) ; this . indexLastModified = attr . lastModifiedTime ( ) ; this . indexSize = attr . size ( ) ; return true ; } return false ; }

Find the index file, using its canonical name
@return true if found
@throws IOException

Find the index file using its canonical name


private boolean isLeaf(IndexReader indexReader) throws IOException {
    if (partitionStatus == PartitionStatus.unknown) {

        int countDir=0, countFile=0, count =0;
        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dir)) {
          Iterator<Path> iterator = dirStream.iterator();
          while (iterator.hasNext() && count++ < 100) {
            Path p = iterator.next();
            BasicFileAttributes attr = Files.readAttributes(p, BasicFileAttributes.class);
            if (attr.isDirectory()) countDir++;
            else countFile++;
          }
        }
      partitionStatus = (countFile > countDir) ? PartitionStatus.isLeaf : PartitionStatus.isDirectoryPartition;
    }

    return partitionStatus == PartitionStatus.isLeaf;
  }

private boolean isLeaf ( IndexReader indexReader ) throws IOException { if ( partitionStatus == PartitionStatus . unknown ) { int countDir = 0 , countFile = 0 , count = 0 ; try ( DirectoryStream < Path > dirStream = Files . newDirectoryStream ( dir ) ) { Iterator < Path > iterator = dirStream . iterator ( ) ; while ( iterator . hasNext ( ) && count ++ < 100 ) { Path p = iterator . next ( ) ; BasicFileAttributes attr = Files . readAttributes ( p , BasicFileAttributes . class ) ; if ( attr . isDirectory ( ) ) countDir ++ ; else countFile ++ ; } } partitionStatus = ( countFile > countDir ) ? PartitionStatus . isLeaf : PartitionStatus . isDirectoryPartition ; } return partitionStatus == PartitionStatus . isLeaf ; }

Scans first 100 files to decide if its a leaf. If so, it becomes a DirectoryCollection, else a PartitionCollection.
@param indexReader reads the index
@return true if partition, false if file collection
@throws IOException on IO error

Scans first 100 files to decide if its a leaf . If so it becomes a DirectoryCollection else a PartitionCollection .


public List<DirectoryBuilder> constructChildren(IndexReader indexReader, CollectionUpdateType forceCollection) throws IOException {
    if (childrenConstructed) return children;

    if (index != null && forceCollection == CollectionUpdateType.nocheck) { // use index if it exists
      constructChildrenFromIndex(indexReader, false);

    } else {
      scanForChildren();
    }

    //once we have found children, we know that this is a time partition
    partitionStatus = (children.size() > 0) ?  PartitionStatus.isDirectoryPartition : PartitionStatus.isLeaf;
    childrenConstructed = true;  // otherwise we are good

    return children;
  }

Find all children directories. Does not recurse.
We separate this from the constructor so it can be done on demand
Public for debugging.

Look for children by:

If index exists , use the children inside there./li>

(or) scan the directory for children partitions

@param indexReader  this reads the index, and calls AddChild.addchild() for each child
@return children, may be empty but not null
@throws IOException

Find all children directories . Does not recurse . We separate this from the constructor so it can be done on demand Public for debugging .


private void scanForChildren() {
    if (debug) System.out.printf("DirectoryBuilder.scanForChildren on %s ", dir);

    int count = 0;
    try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
      for (Path p : ds) {
        BasicFileAttributes attr = Files.readAttributes(p, BasicFileAttributes.class);
        if (attr.isDirectory()) {
          children.add(new DirectoryBuilder(topCollectionName, p, attr, suffix));
          if (debug && (++count % 10 == 0)) System.out.printf("%d ", count);
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (debug) System.out.printf("done=%d%n", count);
    childrenConstructed = true;
  }

Scan for subdirectories, make each into a DirectoryBuilder and add as a child

Scan for subdirectories make each into a DirectoryBuilder and add as a child


public List<MFile> readFilesFromIndex(IndexReader indexReader) throws IOException {
    List<MFile> result = new ArrayList<>(100);
    if (index == null) return result;

    indexReader.readMFiles(index, result);
    return result;
  }

public List < MFile > readFilesFromIndex ( IndexReader indexReader ) throws IOException { List < MFile > result = new ArrayList <> ( 100 ) ; if ( index == null ) return result ; indexReader . readMFiles ( index , result ) ; return result ; }


public List<ucar.nc2.dt.GridDataset.Gridset> getGridsets() {
    return new ArrayList<ucar.nc2.dt.GridDataset.Gridset>(gridsetHash.values());
  }

public List < ucar . nc2 . dt . GridDataset . Gridset > getGridsets ( ) { return new ArrayList < ucar . nc2 . dt . GridDataset . Gridset > ( gridsetHash . values ( ) ) ; }

Return GridDatatype objects grouped by GridCoordSys. All GridDatatype in a Gridset
have the same GridCoordSystem.

@return List of type ucar.nc2.dt.GridDataset.Gridset

Return GridDatatype objects grouped by GridCoordSys . All GridDatatype in a Gridset have the same GridCoordSystem .


public FileCacheable acquire(FileFactory factory, DatasetUrl durl, ucar.nc2.util.CancelTask cancelTask) throws IOException {
    return acquire(factory, durl.trueurl, durl, -1, cancelTask, null);
  }

public FileCacheable acquire ( FileFactory factory , DatasetUrl durl , ucar . nc2 . util . CancelTask cancelTask ) throws IOException { return acquire ( factory , durl . trueurl , durl , - 1 , cancelTask , null ) ; }

Acquire a FileCacheable, and lock it so no one else can use it.
call FileCacheable.close when done.

@param factory    use this factory to open the file; may not be null
@param durl   file location, also used as the cache name, will be passed to the NetcdfFileFactory
@param cancelTask user can cancel, ok to be null.
@return NetcdfFile corresponding to location.
@throws IOException on error

Acquire a FileCacheable and lock it so no one else can use it . call FileCacheable . close when done .


private void remove(CacheElement.CacheFile want) {
     want.remove();
     files.remove(want.ncfile);
     try {
       want.ncfile.setFileCache(null); // unhook the caching
       want.ncfile.close();
     } catch (IOException e) {
       log.error("close failed on "+want.ncfile.getLocation(), e);
     }
     want.ncfile = null;
  }

private
void
remove
(
CacheElement
.
CacheFile
want
)
{
want
.
remove
(
)
;
files
.
remove
(
want
.
ncfile
)
;
try
{
want
.
ncfile
.
setFileCache
(
)
;
// unhook the caching
want
.
ncfile
.
close
(
)
;
}
catch
(
IOException
e
)
{
log
.
error
(
"close failed on "
+
want
.
ncfile
.
getLocation
(
)
,
e
)
;
}
want
.
ncfile
=
;
}

LOOK should you remove the entire CacheElement ?


@Override
  public void eject(Object hashKey) {
     if (disabled.get()) return;

     // see if its in the cache
     CacheElement wantCacheElem = cache.get(hashKey);
     if (wantCacheElem == null) return;

     synchronized (wantCacheElem) { // synch in order to traverse the list
       for (CacheElement.CacheFile want : wantCacheElem.list) {
          // LOOK can we use remove(want);  ??
          files.remove(want.ncfile);
          try {
            want.ncfile.setFileCache(null); // unhook the caching
            want.ncfile.close();  // really close the file
            log.debug("close "+want.ncfile.getLocation());
          } catch (IOException e) {
            log.error("close failed on "+want.ncfile.getLocation(), e);
          }
          want.ncfile = null;
         if (debugPrint) System.out.println("  FileCache " + name + " eject " + hashKey);
       }
       wantCacheElem.list.clear();
     }
    cache.remove(hashKey);
   }

@
Override
public
void
eject
(
Object
hashKey
)
{
if
(
disabled
.
get
(
)
)
return
;
// see if its in the cache
CacheElement
wantCacheElem
=
cache
.
get
(
hashKey
)
;
if
(
wantCacheElem
==
)
return
;
synchronized
(
wantCacheElem
)
{
// synch in order to traverse the list
for
(
CacheElement
.
CacheFile
want
:
wantCacheElem
.
list
)
{
// LOOK can we use remove(want);  ??
files
.
remove
(
want
.
ncfile
)
;
try
{
want
.
ncfile
.
setFileCache
(
)
;
// unhook the caching
want
.
ncfile
.
close
(
)
;
// really close the file
log
.
debug
(
"close "
+
want
.
ncfile
.
getLocation
(
)
)
;
}
catch
(
IOException
e
)
{
log
.
error
(
"close failed on "
+
want
.
ncfile
.
getLocation
(
)
,
e
)
;
}
want
.
ncfile
=
;
if
(
debugPrint
)
System
.
out
.
println
(
"  FileCache "
+
name
+
" eject "
+
hashKey
)
;
}
wantCacheElem
.
list
.
clear
(
)
;
}
cache
.
remove
(
hashKey
)
;
}

Remove all instances of object from the cache
@param hashKey the object


@Override
  public boolean release(FileCacheable ncfile) throws IOException {
    if (ncfile == null) return false;

    if (disabled.get()) {
      ncfile.setFileCache(null); // prevent infinite loops
      ncfile.close();
      return false;
    }

    // find it in the file cache
    CacheElement.CacheFile file = files.get(ncfile); // using hashCode of the FileCacheable
    if (file != null) {
      if (!file.isLocked.get()) {
        cacheLog.warn("FileCache " + name + " release " + ncfile.getLocation() + " not locked; hash= "+ncfile.hashCode());
      }
      file.lastAccessed = System.currentTimeMillis();
      file.countAccessed++;
      file.isLocked.set(false);
      file.ncfile.release();

      if (cacheLog.isDebugEnabled()) cacheLog.debug("FileCache " + name + " release " + ncfile.getLocation()+"; hash= "+ncfile.hashCode());
      if (debugPrint) System.out.printf("  FileCache %s release %s lock=%s count=%d%n", name, ncfile.getLocation(), file.isLocked.get(), countLocked());
      return true;
    }
    return false;
    // throw new IOException("FileCache " + name + " release does not have file in cache = " + ncfile.getLocation());
  }

Release the file. This unlocks it, updates its lastAccessed date.
Normally applications need not call this, just close the file as usual.
The FileCacheable has to do tricky stuff.

@param ncfile release this file.
@return true if file was in cache, false if it was not

Release the file . This unlocks it updates its lastAccessed date . Normally applications need not call this just close the file as usual . The FileCacheable has to do tricky stuff .


private static int int4(int a, int b, int c, int d) {
    // all bits set to ones
    if (a == 0xff && b == 0xff && c == 0xff && d == 0xff)
      return UNDEFINED;

    return (1 - ((a & 128) >> 6)) * ((a & 127) << 24 | b << 16 | c << 8 | d);
  }

private
static
int
int4
(
int
a
,
int
b
,
int
c
,
int
d
)
{
// all bits set to ones
if
(
a
==
0xff
&&
b
==
0xff
&&
c
==
0xff
&&
d
==
0xff
)
return
UNDEFINED
;
return
(
1
(
(
a
&
128
)
>>
6
)
)
*
(
(
a
&
127
)
<<
24
|
b
<<
16
|
c
<<
8
|
d
)
;
}

Convert 4 bytes into a signed integer.

@param a
@param b
@param c
@param d
@return int


private CacheElement updateInCache(CacheElement elem) {
    if (shadowCache.firstKey() == elem) return elem;

    elem.updateAccessed();
    CacheElement prev = shadowCache.put(elem, elem); // faster if we could just insert at the top of the list. maybe we need to use LinkedList ?
    if (prev != null && (elem != prev)) {
      CacheElementComparator cc = new CacheElementComparator();
      System.out.printf("elem != prev compare=%d%n", cc.compare(elem, prev));
      System.out.printf("hash elem =%d prev=%d%n", elem.hashCode(), prev.hashCode());
    }
    return elem;
  }

get CacheElement specified by hashKey. If found, update lastUsed in shadowCache.

get CacheElement specified by hashKey . If found update lastUsed in shadowCache .


public synchronized void clearCache(boolean force) {
    List<CacheElement.CacheFile> deleteList = new ArrayList<>(2 * cache.size());

    if (force) {
      cache.clear(); // deletes everything from the cache
      deleteList.addAll(files.values());  // add everything to the delete list
      files.clear();
      // counter.set(0);

    } else {

      // add unlocked files to the delete list, remove from files hash
      Iterator<CacheElement.CacheFile> iter = files.values().iterator();
      while (iter.hasNext()) {
        CacheElement.CacheFile file = iter.next();
        if (file.isLocked.compareAndSet(false, true)) {
          file.remove(); // remove from the containing CacheElement
          deleteList.add(file);
          iter.remove();
        }
      }

      // remove empty cache elements
      for (CacheElement elem : cache.values()) {
        if (elem.list.size() == 0)
          cache.remove(elem.hashKey);
      }
    }

    // close all files in deleteList
    for (CacheElement.CacheFile file : deleteList) {
      if (force && file.isLocked.get())
        cacheLog.warn("FileCacheARC " + name + " force close locked file= " + file);
      //counter.decrementAndGet();

      if (file.ncfile == null) continue;

      try {
        file.ncfile.setFileCache(null);
        file.ncfile.close();
        file.ncfile = null; // help the gc
      } catch (IOException e) {
        log.error("FileCacheARC " + name + " close failed on " + file);
      }
    }
    if (cacheLog.isDebugEnabled())
      cacheLog.debug("*FileCacheARC " + name + " clearCache force= " + force + " deleted= " + deleteList.size() + " left=" + files.size());
    //System.out.println("\n*NetcdfFileCache.clearCache force= " + force + " deleted= " + deleteList.size() + " left=" + counter.get());
  }

Remove all cache entries.

@param force if true, remove them even if they are currently locked.


void makeVerticalTransform(GridDataset gds, Formatter parseInfo) {
    if (vt != null) return; // already done
    if (vCT == null) return;  // no vt

    vt = vCT.makeVerticalTransform(gds.getNetcdfDataset(), timeDim);

    if (vt == null) {
      if (parseInfo != null)
        parseInfo.format("  - ERR can't make VerticalTransform = %s%n", vCT.getVerticalTransformType());
    } else {
      if (parseInfo != null) parseInfo.format("  - VerticalTransform = %s%n", vCT.getVerticalTransformType());
    }
  }

we have to delay making these, since we dont identify the dimensions specifically until now

we have to delay making these since we dont identify the dimensions specifically until now


@Override
  public boolean isGlobalLon() {
    if (!isLatLon) return false;
    if (!(horizXaxis instanceof CoordinateAxis1D)) return false;
    CoordinateAxis1D lon = (CoordinateAxis1D) horizXaxis;
    double first = lon.getCoordEdge(0);
    double last = lon.getCoordEdge((int) lon.getSize());
    double min = Math.min(first, last);
    double max =  Math.max(first, last);
    return (max - min) >= 360;
  }

@ Override public boolean isGlobalLon ( ) { if ( ! isLatLon ) return false ; if ( ! ( horizXaxis instanceof CoordinateAxis1D ) ) return false ; CoordinateAxis1D lon = ( CoordinateAxis1D ) horizXaxis ; double first = lon . getCoordEdge ( 0 ) ; double last = lon . getCoordEdge ( ( int ) lon . getSize ( ) ) ; double min = Math . min ( first , last ) ; double max = Math . max ( first , last ) ; return ( max - min ) >= 360 ; }

Is this a global coverage over longitude ?
@return true if isLatLon and longitude wraps


@Override
  public boolean isZPositive() {
    if (vertZaxis == null) return false;
    if (vertZaxis.getPositive() != null) {
      return vertZaxis.getPositive().equalsIgnoreCase(ucar.nc2.constants.CF.POSITIVE_UP);
    }
    if (vertZaxis.getAxisType() == AxisType.Height) return true;
    return vertZaxis.getAxisType() != AxisType.Pressure;
  }

@ Override public boolean isZPositive ( ) { if ( vertZaxis == null ) return false ; if ( vertZaxis . getPositive ( ) != null ) { return vertZaxis . getPositive ( ) . equalsIgnoreCase ( ucar . nc2 . constants . CF . POSITIVE_UP ) ; } if ( vertZaxis . getAxisType ( ) == AxisType . Height ) return true ; return vertZaxis . getAxisType ( ) != AxisType . Pressure ; }

true if increasing z coordinate values means "up" in altitude

true if increasing z coordinate values means up in altitude


@Override
  public int[] findXYindexFromCoord(double x_coord, double y_coord, int[] result) {
    if (result == null)
      result = new int[2];

    if ((horizXaxis instanceof CoordinateAxis1D) && (horizYaxis instanceof CoordinateAxis1D)) {
      result[0] = ((CoordinateAxis1D) horizXaxis).findCoordElement(x_coord);
      result[1] = ((CoordinateAxis1D) horizYaxis).findCoordElement(y_coord);
      return result;

    } else if ((horizXaxis instanceof CoordinateAxis2D) && (horizYaxis instanceof CoordinateAxis2D)) {
      if (g2d == null)
        g2d = new GridCoordinate2D((CoordinateAxis2D) horizYaxis, (CoordinateAxis2D) horizXaxis);
      int[] result2 = new int[2];
      boolean found = g2d.findCoordElement(y_coord, x_coord, result2);
      if (found) {
        result[0] = result2[1];
        result[1] = result2[0];
      } else {
        result[0] = -1;
        result[1] = -1;
      }
      return result;
    }

    // cant happen
    throw new IllegalStateException("GridCoordSystem.findXYindexFromCoord");
  }

@
Override
public
int
[
]
findXYindexFromCoord
(
double
x_coord
,
double
y_coord
,
int
[
]
result
)
{
if
(
result
==
)
result
=
new
int
[
2
]
;
if
(
(
horizXaxis
instanceof
CoordinateAxis1D
)
&&
(
horizYaxis
instanceof
CoordinateAxis1D
)
)
{
result
[
0
]
=
(
(
CoordinateAxis1D
)
horizXaxis
)
.
findCoordElement
(
x_coord
)
;
result
[
1
]
=
(
(
CoordinateAxis1D
)
horizYaxis
)
.
findCoordElement
(
y_coord
)
;
return
result
;
}
else
if
(
(
horizXaxis
instanceof
CoordinateAxis2D
)
&&
(
horizYaxis
instanceof
CoordinateAxis2D
)
)
{
if
(
g2d
==
)
g2d
=
new
GridCoordinate2D
(
(
CoordinateAxis2D
)
horizYaxis
,
(
CoordinateAxis2D
)
horizXaxis
)
;
int
[
]
result2
=
new
int
[
2
]
;
boolean
found
=
g2d
.
findCoordElement
(
y_coord
,
x_coord
,
result2
)
;
if
(
found
)
{
result
[
0
]
=
result2
[
1
]
;
result
[
1
]
=
result2
[
0
]
;
}
else
{
result
[
0
]
=
1
;
result
[
1
]
=
1
;
}
return
result
;
}
// cant happen
throw
new
IllegalStateException
(
"GridCoordSystem.findXYindexFromCoord"
)
;
}

Given a point in x,y coordinate space, find the x,y index in the coordinate system.

@param x_coord position in x coordinate space.
@param y_coord position in y coordinate space.
@param result  put result (x,y) index in here, may be null
@return int[2], 0=x,1=y indices in the coordinate system of the point. These will be -1 if out of range.

Given a point in x y coordinate space find the x y index in the coordinate system .


@Override
  public int[] findXYindexFromCoordBounded(double x_coord, double y_coord, int[] result) {
    if (result == null)
      result = new int[2];

    if ((horizXaxis instanceof CoordinateAxis1D) && (horizYaxis instanceof CoordinateAxis1D)) {
      result[0] = ((CoordinateAxis1D) horizXaxis).findCoordElementBounded(x_coord);
      result[1] = ((CoordinateAxis1D) horizYaxis).findCoordElementBounded(y_coord);
      return result;

    } else if ((horizXaxis instanceof CoordinateAxis2D) && (horizYaxis instanceof CoordinateAxis2D)) {
      if (g2d == null)
        g2d = new GridCoordinate2D((CoordinateAxis2D) horizYaxis, (CoordinateAxis2D) horizXaxis);

      int[] result2 = new int[2];
      g2d.findCoordElement(y_coord, x_coord, result2); // returns best guess
      result[0] = result2[1];
      result[1] = result2[0];
      return result;
    }

    // cant happen
    throw new IllegalStateException("GridCoordSystem.findXYindexFromCoord");
  }

@
Override
public
int
[
]
findXYindexFromCoordBounded
(
double
x_coord
,
double
y_coord
,
int
[
]
result
)
{
if
(
result
==
)
result
=
new
int
[
2
]
;
if
(
(
horizXaxis
instanceof
CoordinateAxis1D
)
&&
(
horizYaxis
instanceof
CoordinateAxis1D
)
)
{
result
[
0
]
=
(
(
CoordinateAxis1D
)
horizXaxis
)
.
findCoordElementBounded
(
x_coord
)
;
result
[
1
]
=
(
(
CoordinateAxis1D
)
horizYaxis
)
.
findCoordElementBounded
(
y_coord
)
;
return
result
;
}
else
if
(
(
horizXaxis
instanceof
CoordinateAxis2D
)
&&
(
horizYaxis
instanceof
CoordinateAxis2D
)
)
{
if
(
g2d
==
)
g2d
=
new
GridCoordinate2D
(
(
CoordinateAxis2D
)
horizYaxis
,
(
CoordinateAxis2D
)
horizXaxis
)
;
int
[
]
result2
=
new
int
[
2
]
;
g2d
.
findCoordElement
(
y_coord
,
x_coord
,
result2
)
;
// returns best guess
result
[
0
]
=
result2
[
1
]
;
result
[
1
]
=
result2
[
0
]
;
return
result
;
}
// cant happen
throw
new
IllegalStateException
(
"GridCoordSystem.findXYindexFromCoord"
)
;
}

Given a point in x,y coordinate space, find the x,y index in the coordinate system.
If outside the range, the closest point is returned, eg, 0 or n-1 depending on if the coordinate is too small or too large.

@param x_coord position in x coordinate space.
@param y_coord position in y coordinate space.
@param result  put result in here, may be null
@return int[2], 0=x,1=y indices in the coordinate system of the point.

Given a point in x y coordinate space find the x y index in the coordinate system . If outside the range the closest point is returned eg 0 or n - 1 depending on if the coordinate is too small or too large .


@Override
  public int[] findXYindexFromLatLon(double lat, double lon, int[] result) {
    Projection dataProjection = getProjection();
    ProjectionPoint pp = dataProjection.latLonToProj(new LatLonPointImpl(lat, lon), new ProjectionPointImpl());

    return findXYindexFromCoord(pp.getX(), pp.getY(), result);
  }

@ Override public int [ ] findXYindexFromLatLon ( double lat , double lon , int [ ] result ) { Projection dataProjection = getProjection ( ) ; ProjectionPoint pp = dataProjection . latLonToProj ( new LatLonPointImpl ( lat , lon ) , new ProjectionPointImpl ( ) ) ; return findXYindexFromCoord ( pp . getX ( ) , pp . getY ( ) , result ) ; }

Given a lat,lon point, find the x,y index in the coordinate system.

@param lat    latitude position.
@param lon    longitude position.
@param result put result in here, may be null
@return int[2], 0=x,1=y indices in the coordinate system of the point. These will be -1 if out of range.

Given a lat lon point find the x y index in the coordinate system .


@Override
  public int[] findXYindexFromLatLonBounded(double lat, double lon, int[] result) {
    Projection dataProjection = getProjection();
    ProjectionPoint pp = dataProjection.latLonToProj(new LatLonPointImpl(lat, lon), new ProjectionPointImpl());

    return findXYindexFromCoordBounded(pp.getX(), pp.getY(), result);
  }

@ Override public int [ ] findXYindexFromLatLonBounded ( double lat , double lon , int [ ] result ) { Projection dataProjection = getProjection ( ) ; ProjectionPoint pp = dataProjection . latLonToProj ( new LatLonPointImpl ( lat , lon ) , new ProjectionPointImpl ( ) ) ; return findXYindexFromCoordBounded ( pp . getX ( ) , pp . getY ( ) , result ) ; }

Given a lat,lon point, find the x,y index in the coordinate system.
If outside the range, the closest point is returned

@param lat    latitude position.
@param lon    longitude position.
@param result put result in here, may be null
@return int[2], 0=x,1=y indices in the coordinate system of the point.

Given a lat lon point find the x y index in the coordinate system . If outside the range the closest point is returned


protected int getItemPos() {
      if (nitems < 1)
        return -arrow_size;   // dont show indicator
      else if (nitems == 1)
        return b.width/2;   // indicator in center

      int item = table.getSelectedRowIndex();  // selected item
      int eff_width = b.width - 2*arrow_size;   // effective width
      int pixel =  (item * eff_width)/(nitems-1);  // divided into n-1 intervals
      return pixel+arrow_size;
    }

protected
int
getItemPos
(
)
{
if
(
nitems
<
1
)
return
arrow_size
;
// dont show indicator
else
if
(
nitems
==
1
)
return
b
.
width
/
2
;
// indicator in center
int
item
=
table
.
getSelectedRowIndex
(
)
;
// selected item
int
eff_width
=
b
.
width
2
*
arrow_size
;
// effective width
int
pixel
=
(
item
*
eff_width
)
/
(
nitems
1
)
;
// divided into n-1 intervals
return
pixel
+
arrow_size
;
}

return slider indicator position for currently selected item


protected int getItem( int pixel) {
      if (nitems < 2)
        return 0;

      int eff_width = b.width - 2*arrow_size;   // effective width
      double fitem = ((double) (pixel-arrow_size)*(nitems-1)) / eff_width;
      int item =  (int)(fitem+.5);
      item = Math.max( Math.min(item, nitems-1), 0);
      return item;
    }

protected
int
getItem
(
int
pixel
)
{
if
(
nitems
<
2
)
return
0
;
int
eff_width
=
b
.
width
2
*
arrow_size
;
// effective width
double
fitem
=
(
(
double
)
(
pixel
arrow_size
)
*
(
nitems
1
)
)
/
eff_width
;
int
item
=
(
int
)
(
fitem
+
.5
)
;
item
=
Math
.
max
(
Math
.
min
(
item
,
nitems
1
)
,
0
)
;
return
item
;
}

return item selected by this pixel position


public void iterateOverMFileCollection(Visitor visit) throws IOException {
    if (debug) System.out.printf(" iterateOverMFileCollection %s ", collectionDir);
    int count = 0;
    try (DirectoryStream<Path> ds = Files.newDirectoryStream(collectionDir, new MyStreamFilter())) {
      for (Path p : ds) {
        try {
          BasicFileAttributes attr = Files.readAttributes(p, BasicFileAttributes.class);
          if (!attr.isDirectory())
            visit.consume(new MFileOS7(p));
          if (debug) System.out.printf("%d ", count++);
        } catch (IOException ioe) {
          // catch error and skip file
          logger.error("Failed to read attributes from file found in Files.newDirectoryStream ", ioe);
        }
      }
    }
    if (debug) System.out.printf("%d%n", count);
  }

this idiom keeps the iterator from escaping, so that we can use try-with-resource, and ensure DirectoryStream closes. like++

this idiom keeps the iterator from escaping so that we can use try - with - resource and ensure DirectoryStream closes . like ++


public void getRemoteFiles(final CancelTask _cancel) {
    this.cancel = _cancel;

    String urls = config.getServerPrefix() + "/thredds/admin/log/"+type+"/";
    ta.append(String.format("Download URL = %s%n", urls));

    String contents = null;
    try (HTTPMethod method = HTTPFactory.Get(session, urls)) {
        int statusCode = method.execute();
        if (statusCode == 200)
          contents = method.getResponseAsString();

      if ((contents == null) || (contents.length() == 0)) {
        ta.append(String.format("Failed to get logs at URL = %s%n%n", urls));
        return;
      } else {
        ta.append(String.format("Logs at URL = %s%n%s%n", urls, contents));
      }
    } catch (Throwable t) {
      ta.append(String.format("Failed to get logs at URL = %s error = %s%n%n", urls, t.getMessage()));
      t.printStackTrace();
      return;
    }

    // update text area in background  http://technobuz.com/2009/05/update-jtextarea-dynamically/
    final String list = contents;
    SwingWorker worker = new SwingWorker<String, Void>() {

      @Override
      protected String doInBackground() throws Exception {
        try {
          ta.append(String.format("Local log files stored in = %s%n%n", localDir));
          String[] lines = list.split("\n");
          for (String line : lines) {
            new RemoteLog(line.trim());
            if (cancel.isCancel()) {
              break;
            }
          }
        } catch (Throwable t) {
          t.printStackTrace();
        }

        return null;
      }

      public void done() {
        if (cancel.isCancel())
          ta.append(String.format("Download was cancelled for %s%n", type));
        else
          ta.append(String.format("Download complete for %s%n", type));
      }
    };

    // do in background
    worker.execute();
  }


@Override
  public String getSubCenterName(int center, int subcenter) {

    switch (subcenter) {
      case 0:
        return null;
      case 1:
        return "FSL/FRD Regional Analysis and Prediction Branch";
      case 2:
        return "FSL/FRD Local Analysis and Prediction Branch";
    }
    return super.getSubCenterName(center, subcenter);
  }

LOOK  maybe combine grib1, grib2 and bufr ??

LOOK maybe combine grib1 grib2 and bufr ??


public static CalendarPeriod.Field fromUnitString(String udunit) {
    udunit = udunit.trim();
    udunit = udunit.toLowerCase();

    if (udunit.equals("s")) return Field.Second;
    if (udunit.equals("ms")) return Field.Millisec;

      // eliminate plurals
    if (udunit.endsWith("s")) udunit = udunit.substring(0, udunit.length()-1);

    switch (udunit) {
      case "second":
      case "sec":
        return Field.Second;
      case "millisecond":
      case "millisec":
      case "msec":
        return Field.Millisec;
      case "minute":
      case "min":
        return Field.Minute;
      case "hour":
      case "hr":
      case "h":
        return Field.Hour;
      case "day":
      case "d":
        return Field.Day;
      case "month":
      case "mon":
        return Field.Month;
      case "year":
      case "yr":
        return Field.Year;
      default:
        throw new IllegalArgumentException("cant convert " + udunit + " to CalendarPeriod");
    }
  }

public
static
CalendarPeriod
.
Field
fromUnitString
(
String
udunit
)
{
udunit
=
udunit
.
trim
(
)
;
udunit
=
udunit
.
toLowerCase
(
)
;
if
(
udunit
.
equals
(
"s"
)
)
return
Field
.
Second
;
if
(
udunit
.
equals
(
"ms"
)
)
return
Field
.
Millisec
;
// eliminate plurals
if
(
udunit
.
endsWith
(
"s"
)
)
udunit
=
udunit
.
substring
(
0
,
udunit
.
length
(
)
1
)
;
switch
(
udunit
)
{
case
"second"
:
case
"sec"
:
return
Field
.
Second
;
case
"millisecond"
:
case
"millisec"
:
case
"msec"
:
return
Field
.
Millisec
;
case
"minute"
:
case
"min"
:
return
Field
.
Minute
;
case
"hour"
:
case
"hr"
:
case
"h"
:
return
Field
.
Hour
;
case
"day"
:
case
"d"
:
return
Field
.
Day
;
case
"month"
:
case
"mon"
:
return
Field
.
Month
;
case
"year"
:
case
"yr"
:
return
Field
.
Year
;
default
:
throw
new
IllegalArgumentException
(
"cant convert "
+
udunit
+
" to CalendarPeriod"
)
;
}
}

Convert a period string into a CalendarPeriod.Field.
@param udunit period string
@return CalendarPeriod.Field enum
@throws IllegalArgumentException if not valid format

Convert a period string into a CalendarPeriod . Field .


public static CalendarPeriod of(int value, Field field) {
    CalendarPeriod want = new CalendarPeriod(value, field);
    if (cache == null) return want;
    CalendarPeriod got = cache.getIfPresent(want);
    if (got != null) return got;
    cache.put(want, want);
    return want;
  }

public static CalendarPeriod of ( int value , Field field ) { CalendarPeriod want = new CalendarPeriod ( value , field ) ; if ( cache == null ) return want ; CalendarPeriod got = cache . getIfPresent ( want ) ; if ( got != null ) return got ; cache . put ( want , want ) ; return want ; }

minimize memory use by interning. wacko shit in GribPartitionBuilder TimeCoordinate, whoduhthunk?

minimize memory use by interning . wacko shit in GribPartitionBuilder TimeCoordinate whoduhthunk?


public static CalendarPeriod of(String udunit) {
    int value;
    String units;

    String[] split = StringUtil2.splitString(udunit);
    if (split.length == 1) {
      value = 1;
      units =  split[0];

    } else if (split.length == 2) {
      try {
        value = Integer.parseInt(split[0]);
      } catch (Throwable t) {
        return null;
      }
      units =  split[1];
    } else
      return null;

    CalendarPeriod.Field unit = CalendarPeriod.fromUnitString(units);
    return CalendarPeriod.of(value, unit);
  }

public static CalendarPeriod of ( String udunit ) { int value ; String units ; String [ ] split = StringUtil2 . splitString ( udunit ) ; if ( split . length == 1 ) { value = 1 ; units = split [ 0 ] ; } else if ( split . length == 2 ) { try { value = Integer . parseInt ( split [ 0 ] ) ; } catch ( Throwable t ) { return null ; } units = split [ 1 ] ; } else return null ; CalendarPeriod . Field unit = CalendarPeriod . fromUnitString ( units ) ; return CalendarPeriod . of ( value , unit ) ; }

Convert a udunit period string into a CalendarPeriod
@param udunit period string : "[val] unit"
@return CalendarPeriod or null if illegal


public int subtract(CalendarDate start, CalendarDate end) {
    long diff = end.getDifferenceInMsecs(start);
    int thislen = millisecs();
    if ((diff % thislen != 0))
      log.warn("roundoff error");
    return (int) (diff / thislen);
  }

public
int
subtract
(
CalendarDate
start
,
CalendarDate
end
)
{
long
diff
=
end
.
getDifferenceInMsecs
(
start
)
;
int
thislen
=
millisecs
(
)
;
if
(
(
diff
%
thislen
!=
0
)
)
log
.
warn
(
"roundoff error"
)
;
return
(
int
)
(
diff
/
thislen
)
;
}

Subtract two dates, return difference in units of this period.
If not even, will round down and log a warning
@param start start date
@param end   end date
@return  difference in units of this period

Subtract two dates return difference in units of this period . If not even will round down and log a warning


public double getConvertFactor(CalendarPeriod from) {
    if (field == CalendarPeriod.Field.Month || field == CalendarPeriod.Field.Year) {
      log.warn(" CalendarDate.convert on Month or Year");
    }

    return (double) from.millisecs() / millisecs();
  }

Get the conversion factor of the other CalendarPeriod to this one
@param from convert from this
@return conversion factor, so that getConvertFactor(from) * from = this


public double getValueInMillisecs() {
     if (field == CalendarPeriod.Field.Month)
       return 30.0 * 24.0 * 60.0 * 60.0 * 1000.0 * value;
     else if (field == CalendarPeriod.Field.Year)
       return 365.0 * 24.0 * 60.0 * 60.0 * 1000.0 * value;
     else return millisecs();
   }

public double getValueInMillisecs ( ) { if ( field == CalendarPeriod . Field . Month ) return 30.0 * 24.0 * 60.0 * 60.0 * 1000.0 * value ; else if ( field == CalendarPeriod . Field . Year ) return 365.0 * 24.0 * 60.0 * 60.0 * 1000.0 * value ; else return millisecs ( ) ; }

Get the duration in milliseconds                                               -+
@return the duration in seconds
@deprecated dont use because these are fixed length and thus approximate.


public int getOffset(CalendarDate start, CalendarDate end) {
    if (start.equals(end)) return 0;
    long start_millis = start.getDateTime().getMillis();
    long end_millis = end.getDateTime().getMillis();

    // 5 second slop
    Period p;
    if (start_millis < end_millis)
      p = new Period(start_millis, end_millis + 5000, getPeriodType());
    else
      p = new Period(start_millis+5000, end_millis, getPeriodType());

    return p.get(getDurationFieldType());
  }

public
int
getOffset
(
CalendarDate
start
,
CalendarDate
end
)
{
if
(
start
.
equals
(
end
)
)
return
0
;
long
start_millis
=
start
.
getDateTime
(
)
.
getMillis
(
)
;
long
end_millis
=
end
.
getDateTime
(
)
.
getMillis
(
)
;
// 5 second slop
Period
p
;
if
(
start_millis
<
end_millis
)
p
=
new
Period
(
start_millis
,
end_millis
+
5000
,
getPeriodType
(
)
)
;
else
p
=
new
Period
(
start_millis
+
5000
,
end_millis
,
getPeriodType
(
)
)
;
return
p
.
get
(
getDurationFieldType
(
)
)
;
}


public boolean sync() throws IOException {
    if ((gemreader.getInitFileSize() < raf.length()) && extendIndex) {
      gemreader.init(true);
      GridIndex index = gemreader.getGridIndex();
      // reconstruct the ncfile objects
      ncfile.empty();
      open(index, null);
      return true;
    }
    return false;
  }

public
boolean
sync
(
)
throws
IOException
{
if
(
(
gemreader
.
getInitFileSize
(
)
<
raf
.
length
(
)
)
&&
extendIndex
)
{
gemreader
.
init
(
true
)
;
GridIndex
index
=
gemreader
.
getGridIndex
(
)
;
// reconstruct the ncfile objects
ncfile
.
empty
(
)
;
open
(
index
,
)
;
return
true
;
}
return
false
;
}

Sync the file

@return true if needed to sync
@throws IOException problem synching the file


private void initTables() {
    try {
      GempakGridParameterTable.addParameters(
              "resources/nj22/tables/gempak/wmogrib3.tbl");
      GempakGridParameterTable.addParameters(
              "resources/nj22/tables/gempak/ncepgrib2.tbl");
    } catch (Exception e) {
      System.out.println("unable to init tables");
    }
  }


private boolean put(DataRootExt dateRootExt) {
    map.put(dateRootExt.getPath(), dateRootExt);
    return treeSet.add(dateRootExt.getPath());
  }

private boolean put ( DataRootExt dateRootExt ) { map . put ( dateRootExt . getPath ( ) , dateRootExt ) ; return treeSet . add ( dateRootExt . getPath ( ) ) ; }

Add a dataRootExt to in-memory tree.
@return true if not already exist


public String findLongestPathMatch( String reqPath) {
    SortedSet<String> tail = treeSet.tailSet(reqPath);
    if (tail.isEmpty()) return null;
    String after = tail.first();
    if (reqPath.startsWith( after)) // common case
      return tail.first();

    // have to check more, until no common starting chars
    for (String key : tail) {
      if (reqPath.startsWith(key))
        return key;

      // terminate when there's no match at all.
      if (StringUtil2.match(reqPath, key) == 0)
        break;
    }

    return null;
  }

Find the longest path match.
@param reqPath find object with longest match where reqPath.startsWith( key)
@return the value whose key is the longest that matches path, or null if none


public DataRoot findDataRoot( String reqPath) {
    String path =  findLongestPathMatch(reqPath);
    if (path == null) return null;
    DataRootExt dataRootExt = map.get(path);
    if (dataRootExt == null) {
      logger.error("DataRootPathMatcher found path {} but not in map", path);
      return null;
    }
    return convert2DataRoot(dataRootExt);
  }

Find the longest DataRoot match.
@param reqPath find object with longest match where reqPath.startsWith( key)
@return the value whose key is the longest that matches path, or null if none


public @Nonnull DataRoot convert2DataRoot(DataRootExt dataRootExt) {
    DataRoot dataRoot = dataRootExt.getDataRoot();
    if (dataRoot != null) return dataRoot;

    // otherwise must read the catalog that its in
    dataRoot = readDataRootFromCatalog(dataRootExt);
    dataRootExt.setDataRoot(dataRoot);
    return dataRoot;
  }


public CalendarDateRange getCalendarDateRange(Calendar cal) {
    if (dateRange == null) return null;
    if (cal.equals(Calendar.getDefault())) return dateRange;

    // otherwise must reparse
    return makeCalendarDateRange(cal);
  }

public
CalendarDateRange
getCalendarDateRange
(
Calendar
cal
)
{
if
(
dateRange
==
)
return
;
if
(
cal
.
equals
(
Calendar
.
getDefault
(
)
)
)
return
dateRange
;
// otherwise must reparse
return
makeCalendarDateRange
(
cal
)
;
}


public List<Integer> reindex(List<Coordinate> coords) {
     List<Integer> result = new ArrayList<>();
     for (Coordinate coord : coords) {
       Coordinate sub = swap.get(coord);
       Coordinate use = (sub == null) ? coord : sub;
       Integer idx = indexMap.get(use); // index into unionCoords
       if (idx == null) {
         throw new IllegalStateException();
       }
       result.add(idx);
     }
     return result;
   }

public
List
<
Integer
>
reindex
(
List
<
Coordinate
>
coords
)
{
List
<
Integer
>
result
=
new
ArrayList
<>
(
)
;
for
(
Coordinate
coord
:
coords
)
{
Coordinate
sub
=
swap
.
get
(
coord
)
;
Coordinate
use
=
(
sub
==
)
coord
:
sub
;
Integer
idx
=
indexMap
.
get
(
use
)
;
// index into unionCoords
if
(
idx
==
)
{
throw
new
IllegalStateException
(
)
;
}
result
.
add
(
idx
)
;
}
return
result
;
}

redo the variables against the shared coordinates


static public NetcdfFileWriter createNew(Version version, String location, Nc4Chunking chunker) throws IOException {
    return new NetcdfFileWriter(version, location, false, chunker);
  }

static public NetcdfFileWriter createNew ( Version version , String location , Nc4Chunking chunker ) throws IOException { return new NetcdfFileWriter ( version , location , false , chunker ) ; }

Create a new Netcdf file, with fill mode true.

@param version  netcdf-3 or 4
@param location name of new file to open; if it exists, will overwrite it.
@param chunker  used only for netcdf4, or null for default chunking algorithm
@return new NetcdfFileWriter
@throws IOException on I/O error

Create a new Netcdf file with fill mode true .


public Group addGroup(Group parent, String name) {
    if (!defineMode) throw new UnsupportedOperationException("not in define mode");
    if (parent == null) return ncfile.getRootGroup();

    Group result = new Group(ncfile, parent, name);
    parent.addGroup(result);
    return result;
  }

public
Group
addGroup
(
Group
parent
,
String
name
)
{
if
(
!
defineMode
)
throw
new
UnsupportedOperationException
(
"not in define mode"
)
;
if
(
parent
==
)
return
ncfile
.
getRootGroup
(
)
;
Group
result
=
new
Group
(
ncfile
,
parent
,
name
)
;
parent
.
addGroup
(
result
)
;
return
result
;
}

Add a Group to the file. Must be in define mode.
If pass in null as the parent then the root group is returned and the name is ignored.
This is how you get the root group. Note this is different from other uses of parent group.

@param parent the parent of this group, if null then returns the root group.
@param name   the name of this group, unique within parent
@return the created group

Add a Group to the file . Must be in define mode . If pass in null as the parent then the root group is returned and the name is ignored . This is how you get the root group . Note this is different from other uses of parent group .


public EnumTypedef addTypedef(Group g, EnumTypedef td) {
    if (!defineMode) throw new UnsupportedOperationException("not in define mode");
    if (!version.isExtendedModel())
      throw new IllegalArgumentException("Enum type only supported in extended model, this version is="+version);
    g.addEnumeration(td);
    return td;
  }

Add a EnumTypedef to the file. Must be in define mode.

@param g  the group to add to. if null, use root group
@param td the EnumTypedef.
@return the created attribute

Add a EnumTypedef to the file . Must be in define mode .


public Attribute deleteGroupAttribute(Group g, String attName) {
    if (!defineMode) throw new UnsupportedOperationException("not in define mode");
    if (g == null) g = ncfile.getRootGroup();
    Attribute att = g.findAttribute(attName);
    if (null == att) return null;
    g.remove(att);
    return att;
  }

public
Attribute
deleteGroupAttribute
(
Group
g
,
String
attName
)
{
if
(
!
defineMode
)
throw
new
UnsupportedOperationException
(
"not in define mode"
)
;
if
(
g
==
)
g
=
ncfile
.
getRootGroup
(
)
;
Attribute
att
=
g
.
findAttribute
(
attName
)
;
if
(
==
att
)
return
;
g
.
remove
(
att
)
;
return
att
;
}

Delete a group Attribute. Must be in define mode.

@param g       the group to add to. if null, use root group
@param attName existing Attribute has this name
@return deleted Attribute, or null if not found

Delete a group Attribute . Must be in define mode .


public Attribute renameGroupAttribute(Group g, String oldName, String newName) {
    if (!defineMode) throw new UnsupportedOperationException("not in define mode");

    if (!isValidObjectName(newName)) {
      String newnewName = createValidObjectName(newName);
      log.warn("illegal attribute name= " + newName + " change to " + newnewName);
      newName = newnewName;
    }

    if (g == null) g = ncfile.getRootGroup();
    Attribute att = g.findAttribute(oldName);
    if (null == att) return null;

    g.remove(att);
    att = new Attribute(newName, att.getValues());
    g.addAttribute(att);
    return att;
  }

public
Attribute
renameGroupAttribute
(
Group
g
,
String
oldName
,
String
newName
)
{
if
(
!
defineMode
)
throw
new
UnsupportedOperationException
(
"not in define mode"
)
;
if
(
!
isValidObjectName
(
newName
)
)
{
String
newnewName
=
createValidObjectName
(
newName
)
;
log
.
warn
(
"illegal attribute name= "
+
newName
+
" change to "
+
newnewName
)
;
newName
=
newnewName
;
}
if
(
g
==
)
g
=
ncfile
.
getRootGroup
(
)
;
Attribute
att
=
g
.
findAttribute
(
oldName
)
;
if
(
==
att
)
return
;
g
.
remove
(
att
)
;
att
=
new
Attribute
(
newName
,
att
.
getValues
(
)
)
;
g
.
addAttribute
(
att
)
;
return
att
;
}

Rename a group Attribute. Must be in define mode.

@param g       the group to add to. if null, use root group
@param oldName existing Attribute has this name
@param newName rename to this
@return renamed Attribute, or null if not found

Rename a group Attribute . Must be in define mode .


public Structure addRecordStructure() {
    if (version != Version.netcdf3) return null;
    boolean ok = (Boolean) ncfile.sendIospMessage(NetcdfFile.IOSP_MESSAGE_ADD_RECORD_STRUCTURE);
    if (!ok)
      throw new IllegalStateException("can't add record variable");
    return (Structure) ncfile.findVariable("record");
  }

public
Structure
addRecordStructure
(
)
{
if
(
version
!=
Version
.
netcdf3
)
return
;
boolean
ok
=
(
Boolean
)
ncfile
.
sendIospMessage
(
NetcdfFile
.
IOSP_MESSAGE_ADD_RECORD_STRUCTURE
)
;
if
(
!
ok
)
throw
new
IllegalStateException
(
"can't add record variable"
)
;
return
(
Structure
)
ncfile
.
findVariable
(
"record"
)
;
}

For netcdf3 only, take all unlimited variables and make them into a structure.
@return the record Structure, or null if not done.

For netcdf3 only take all unlimited variables and make them into a structure .


public void abort() throws java.io.IOException {
    if (spiw != null) {
      spiw.close();
      spiw = null;
    }
  }

public void abort ( ) throws java . io . IOException { if ( spiw != null ) { spiw . close ( ) ; spiw = null ; } }

Abort writing to this file. The file is closed.
@throws java.io.IOException

Abort writing to this file . The file is closed .


public void writeProperties(PrintWriter out) throws IOException {
    if (p == null) p = BeanParser.getParser( o.getClass());
    p.writeProperties(o, out);
  }

public void writeProperties ( PrintWriter out ) throws IOException { if ( p == null ) p = BeanParser . getParser ( o . getClass ( ) ) ; p . writeProperties ( o , out ) ; }

write XML using the bean properties of the contained object


public ThreddsMetadata extract(Dataset threddsDataset) throws IOException {
    ThreddsMetadata metadata = new ThreddsMetadata();
    Map<String, Object> flds = metadata.getFlds();

    try ( DataFactory.Result result = new DataFactory().openFeatureDataset(threddsDataset, null)) {
      if (result.fatalError) {
        logger.warn(" openFeatureDataset failed, errs=%s%n", result.errLog);
        return null;
      }

      if (result.featureType.isCoverageFeatureType()) {
        GridDataset gridDataset = (GridDataset) result.featureDataset; // LOOK wrong
        flds.put(Dataset.GeospatialCoverage, extractGeospatial(gridDataset));

        CalendarDateRange tc = extractCalendarDateRange(gridDataset);
        if (tc != null)
          flds.put(Dataset.TimeCoverage, tc);

        ThreddsMetadata.VariableGroup vars = extractVariables(threddsDataset.getDataFormatName(), gridDataset);
        if (vars != null)
          flds.put(Dataset.VariableGroups, vars);

      } else if (result.featureType.isPointFeatureType()) {
        PointDatasetImpl pobsDataset = (PointDatasetImpl) result.featureDataset;
        LatLonRect llbb = pobsDataset.getBoundingBox();
        if (null != llbb)
          flds.put(Dataset.GeospatialCoverage, new ThreddsMetadata.GeospatialCoverage(llbb, null, 0.0, 0.0));

        CalendarDateRange tc = extractCalendarDateRange(pobsDataset);
        if (tc != null)
          flds.put(Dataset.TimeCoverage, tc);

        ThreddsMetadata.VariableGroup vars = extractVariables(pobsDataset);
        if (vars != null)
          flds.put(Dataset.VariableGroups, vars);
      }

    } catch (IOException ioe) {
      logger.error("Error opening dataset " + threddsDataset.getName(), ioe);
    }

    return metadata;
  }

public
ThreddsMetadata
extract
(
Dataset
threddsDataset
)
throws
IOException
{
ThreddsMetadata
metadata
=
new
ThreddsMetadata
(
)
;
Map
<
String
,
Object
>
flds
=
metadata
.
getFlds
(
)
;
try
(
DataFactory
.
Result
result
=
new
DataFactory
(
)
.
openFeatureDataset
(
threddsDataset
,
)
)
{
if
(
result
.
fatalError
)
{
logger
.
warn
(
" openFeatureDataset failed, errs=%s%n"
,
result
.
errLog
)
;
return
;
}
if
(
result
.
featureType
.
isCoverageFeatureType
(
)
)
{
GridDataset
gridDataset
=
(
GridDataset
)
result
.
featureDataset
;
// LOOK wrong
flds
.
put
(
Dataset
.
GeospatialCoverage
,
extractGeospatial
(
gridDataset
)
)
;
CalendarDateRange
tc
=
extractCalendarDateRange
(
gridDataset
)
;
if
(
tc
!=
)
flds
.
put
(
Dataset
.
TimeCoverage
,
tc
)
;
ThreddsMetadata
.
VariableGroup
vars
=
extractVariables
(
threddsDataset
.
getDataFormatName
(
)
,
gridDataset
)
;
if
(
vars
!=
)
flds
.
put
(
Dataset
.
VariableGroups
,
vars
)
;
}
else
if
(
result
.
featureType
.
isPointFeatureType
(
)
)
{
PointDatasetImpl
pobsDataset
=
(
PointDatasetImpl
)
result
.
featureDataset
;
LatLonRect
llbb
=
pobsDataset
.
getBoundingBox
(
)
;
if
(
!=
llbb
)
flds
.
put
(
Dataset
.
GeospatialCoverage
,
new
ThreddsMetadata
.
GeospatialCoverage
(
llbb
,
,
0.0
,
0.0
)
)
;
CalendarDateRange
tc
=
extractCalendarDateRange
(
pobsDataset
)
;
if
(
tc
!=
)
flds
.
put
(
Dataset
.
TimeCoverage
,
tc
)
;
ThreddsMetadata
.
VariableGroup
vars
=
extractVariables
(
pobsDataset
)
;
if
(
vars
!=
)
flds
.
put
(
Dataset
.
VariableGroups
,
vars
)
;
}
}
catch
(
IOException
ioe
)
{
logger
.
error
(
"Error opening dataset "
+
threddsDataset
.
getName
(
)
,
ioe
)
;
}
return
metadata
;
}

extract info from underlying feature dataset
@param threddsDataset  call DataFactory().openFeatureDataset() to open it
@return results in ThreddsMetadata object
@throws IOException


@Override
    protected Unit myDivideInto(final Unit that) throws OperationException {
        return that instanceof OffsetUnit
                ? getUnit().divideInto(((OffsetUnit) that).getUnit())
                : getUnit().divideInto(that);
    }

@ Override protected Unit myDivideInto ( final Unit that ) throws OperationException { return that instanceof OffsetUnit ? getUnit ( ) . divideInto ( ( ( OffsetUnit ) that ) . getUnit ( ) ) : getUnit ( ) . divideInto ( that ) ; }

Divide this unit into another unit.

@param that
The unit to divide this unit into.
@return The quotient of that unit and this unit. The offset
of this unit will be ignored; thus, for example
"celsius.myDivideInto(day)" is equivalent to
"kelvin.myDivideInto(day)".
@throws OperationException
Can't divide these units.


public double toDerivedUnit(final double amount) throws ConversionException {
        if (!(_unit instanceof DerivableUnit)) {
            throw new ConversionException(this, getDerivedUnit());
        }
        return ((DerivableUnit) getUnit()).toDerivedUnit(amount + getOffset());
    }

public double toDerivedUnit ( final double amount ) throws ConversionException { if ( ! ( _unit instanceof DerivableUnit ) ) { throw new ConversionException ( this , getDerivedUnit ( ) ) ; } return ( ( DerivableUnit ) getUnit ( ) ) . toDerivedUnit ( amount + getOffset ( ) ) ; }

Converts a value in this unit to the equivalent value in the convertible
derived unit.

@param amount
The value in this unit.
@return The equivalent value in the convertible derived unit.
@throws ConversionException
Can't convert between units.

Converts a value in this unit to the equivalent value in the convertible derived unit .


public double fromDerivedUnit(final double amount)
            throws ConversionException {
        if (!(_unit instanceof DerivableUnit)) {
            throw new ConversionException(getDerivedUnit(), this);
        }
        return ((DerivableUnit) getUnit()).fromDerivedUnit(amount)
                - getOffset();
    }

public double fromDerivedUnit ( final double amount ) throws ConversionException { if ( ! ( _unit instanceof DerivableUnit ) ) { throw new ConversionException ( getDerivedUnit ( ) , this ) ; } return ( ( DerivableUnit ) getUnit ( ) ) . fromDerivedUnit ( amount ) - getOffset ( ) ; }

Converts a value in the convertible derived unit to the equivalent value
in this unit.

@param amount
The value in the convertible derived unit.
@return The equivalent value in this unit.
@throws ConversionException
Can't convert between units.

Converts a value in the convertible derived unit to the equivalent value in this unit .


public Array convertNestedVariable(ucar.nc2.Variable v, List<Range> section, DodsV dataV, boolean flatten) throws IOException, DAP2Exception {
    Array data = convertTopVariable(v, section, dataV);
    if (flatten) {
      ArrayStructure as = (ArrayStructure) data;

      // make list of names
      List<String> names = new ArrayList<>();
      Variable nested = v;
      while (nested.isMemberOfStructure()) {
        names.add( 0, nested.getShortName());
        nested = nested.getParentStructure();
      }

      StructureMembers.Member m = findNested(as, names, v.getShortName());
      Array mdata = m.getDataArray();
      if (mdata instanceof ArraySequenceNested) {
        // gotta unroll
        ArraySequenceNested arraySeq = (ArraySequenceNested) mdata;
        return arraySeq.flatten();
      }
      return mdata;
    }
    return data;
  }

public
Array
convertNestedVariable
(
ucar
.
nc2
.
Variable
v
,
List
<
Range
>
section
,
DodsV
dataV
,
boolean
flatten
)
throws
IOException
,
DAP2Exception
{
Array
data
=
convertTopVariable
(
v
,
section
,
dataV
)
;
if
(
flatten
)
{
ArrayStructure
as
=
(
ArrayStructure
)
data
;
// make list of names
List
<
String
>
names
=
new
ArrayList
<>
(
)
;
Variable
nested
=
v
;
while
(
nested
.
isMemberOfStructure
(
)
)
{
names
.
add
(
0
,
nested
.
getShortName
(
)
)
;
nested
=
nested
.
getParentStructure
(
)
;
}
StructureMembers
.
Member
m
=
findNested
(
as
,
names
,
v
.
getShortName
(
)
)
;
Array
mdata
=
m
.
getDataArray
(
)
;
if
(
mdata
instanceof
ArraySequenceNested
)
{
// gotta unroll
ArraySequenceNested
arraySeq
=
(
ArraySequenceNested
)
mdata
;
return
arraySeq
.
flatten
(
)
;
}
return
mdata
;
}
return
data
;
}

Convert a DataDDS into an Array for a Structure member variable.

@param v must be a member of a structure
@param section the requested variable section, as a List of type Range
@param dataV the dataDDS has been parsed into this dodsV, this is the top variable containing v
@param flatten if true, remove the StructureData "wrapper".
@return the data as as Array
@throws IOException on io error
@throws DAP2Exception on bad things happening

Convert a DataDDS into an Array for a Structure member variable .


public Array convertTopVariable(ucar.nc2.Variable v, List<Range> section, DodsV dataV) throws IOException, DAP2Exception {
    Array data = convert(dataV);

    // arrays
    if ((dataV.darray != null) && (dataV.bt instanceof DString)) {

      if (v.getDataType() == DataType.STRING)
        return convertStringArray(data, v);
      else if (v.getDataType() == DataType.CHAR)
        return convertStringArrayToChar(dataV.darray, v, section);
      else {
        String mess = "DODSVariable convertArray String invalid dataType= "+v.getDataType();
        logger.error(mess);
        throw new IllegalArgumentException( mess);
      }

    }

    if ((dataV.bt instanceof DString) && (v.getDataType() == DataType.CHAR)) {
        // special case: convert String back to CHAR
        return convertStringToChar(data, v);
    }

    return data;

    /* else { // the DGrid case comes here also
         // create the array, using  DODS internal array so there's no copying
        dods.dap.PrimitiveVector pv = dataV.darray.getPrimitiveVector();
        Object storage = pv.getInternalStorage();
        //storage = widenArray( pv, storage); // LOOK data conversion if needed
        int[] shape = (section == null) ? v.getShape() : Range.getShape(section);
        return Array.factory( v.getDataType().getPrimitiveClassType(), shape, storage);
      }   */
  }

Convert a DataDDS into an Array for a top level variable, ie not a Structure member variable.

@param v must be a top variable
@param section the requested variable section
@param dataV the dataDDS has been parsed into this dodsV
@return the data as as Array
@throws IOException on io error
@throws DAP2Exception on bad

Convert a DataDDS into an Array for a top level variable ie not a Structure member variable .


public Array convert(DodsV dataV) throws IOException, DAP2Exception {

    // scalars
    if (dataV.darray == null) {

      if (dataV.bt instanceof DStructure) {
        ArrayStructure structArray = makeArrayStructure( dataV);
        iconvertDataStructure( (DStructure) dataV.bt, structArray.getStructureMembers());
        return structArray;

      } else if (dataV.bt instanceof DGrid) {
        throw new IllegalStateException( "DGrid without a darray");

      } else if (dataV.bt instanceof DSequence) {
        ArrayStructure structArray = makeArrayStructure( dataV);
        iconvertDataSequenceArray( (DSequence) dataV.bt, structArray.getStructureMembers());
        return structArray;

      } else { // scalar
        DataType dtype = dataV.getDataType();
        Array scalarData = Array.factory(  dtype, new int[0]);
        IndexIterator scalarIndex = scalarData.getIndexIterator();
        iconvertDataPrimitiveScalar( dataV.bt, scalarIndex);
        return scalarData;
      }
    }

    // arrays
    if (dataV.darray != null) {

      if (dataV.bt instanceof DStructure) {
        ArrayStructure structArray = makeArrayStructure( dataV);
        iconvertDataStructureArray( dataV.darray, structArray.getStructureMembers());
        return structArray;

      } else if (dataV.bt instanceof DString) {
        return convertStringArray(dataV.darray);

      } else {
        // the DGrid case comes here also
        // create the array, using  DODS internal array so there's no copying
        opendap.dap.PrimitiveVector pv = dataV.darray.getPrimitiveVector();
        Object storage = pv.getInternalStorage();
        DataType dtype = dataV.getDataType();
        return Array.factory( dtype, makeShape( dataV.darray), storage);
      }
    }

    String mess = "Unknown baseType "+dataV.bt.getClass().getName()+" name="+ dataV.getEncodedName();
    logger.error(mess);
    throw new IllegalStateException(mess);
  }

Convert a DataDDS into an Array

@param dataV the dataDDS has been parsed into this dodsV
@return the data as as Array
@throws IOException on io error
@throws DAP2Exception on bad


static synchronized public void closeAll() {

    List<MetadataManager> closeDatabases = new ArrayList<>(openDatabases);
    for (MetadataManager mm : closeDatabases) {
      if (debug) System.out.println("  close database " + mm.collectionName);
      mm.close();
    }
    openDatabases = new ArrayList<>(); // empty

    if (myEnv != null) {
      try {
        // Finally, close the store and environment.
        myEnv.close();
        myEnv = null;
        logger.info("closed bdb caching");

      } catch (DatabaseException dbe) {
        logger.error("Error closing bdb: ", dbe);
      }
    }
  }

this is called on TDS shutdown and reinit


private synchronized void openDatabase() {
    if (database != null) return;
    DatabaseConfig dbConfig = new DatabaseConfig();
    dbConfig.setReadOnly(readOnly);
    dbConfig.setAllowCreate(!readOnly);
    if (!readOnly)
      dbConfig.setDeferredWrite(true);
    database = myEnv.openDatabase(null, collectionName, dbConfig);

    openDatabases.add(this);
  }

private synchronized void openDatabase ( ) { if ( database != null ) return ; DatabaseConfig dbConfig = new DatabaseConfig ( ) ; dbConfig . setReadOnly ( readOnly ) ; dbConfig . setAllowCreate ( ! readOnly ) ; if ( ! readOnly ) dbConfig . setDeferredWrite ( true ) ; database = myEnv . openDatabase ( null , collectionName , dbConfig ) ; openDatabases . add ( this ) ; }

assumes only one open at a time; could have MetadataManagers share open databases

assumes only one open at a time ; could have MetadataManagers share open databases


static org.joda.time.Period convertToPeriod(int value, String udunit) {
    if (udunit.endsWith("s")) udunit = udunit.substring(0, udunit.length()-1);

    switch (udunit) {
      case "msec":
        return Period.millis(value);
      case "sec":
        return Period.seconds(value);
      case "minute":
        return Period.minutes(value);
      case "hour":
      case "hr":
        return Period.hours(value);
      case "day":
        return Period.days(value);
      case "week":
        return Period.weeks(value);
      case "month":
        return Period.months(value);
      case "year":
        return Period.years(value);
    }

    throw new IllegalArgumentException("cant convert "+ udunit +" to Joda Period");
  }

static
org
.
joda
.
time
.
Period
convertToPeriod
(
int
value
,
String
udunit
)
{
if
(
udunit
.
endsWith
(
"s"
)
)
udunit
=
udunit
.
substring
(
0
,
udunit
.
length
(
)
1
)
;
switch
(
udunit
)
{
case
"msec"
:
return
Period
.
millis
(
value
)
;
case
"sec"
:
return
Period
.
seconds
(
value
)
;
case
"minute"
:
return
Period
.
minutes
(
value
)
;
case
"hour"
:
case
"hr"
:
return
Period
.
hours
(
value
)
;
case
"day"
:
return
Period
.
days
(
value
)
;
case
"week"
:
return
Period
.
weeks
(
value
)
;
case
"month"
:
return
Period
.
months
(
value
)
;
case
"year"
:
return
Period
.
years
(
value
)
;
}
throw
new
IllegalArgumentException
(
"cant convert "
+
udunit
+
" to Joda Period"
)
;
}

Convert a time udunit string
@param value number of units
@param udunit msec, sec, minute, hour, hr, day, week, month, year (plural form ok)
@return joda Period


public void ensureCapacity(long minCapacity) {
        if (array.length < minCapacity) {
            //ensure minCapacity is < Integer.MAX_VALUE
            ErddapMath2.ensureArraySizeOkay(minCapacity, "StringArray");

            //caller may know exact number needed, so don't double above 2x current size
            int newCapacity = (int)Math.min(Integer.MAX_VALUE - 1, array.length + (long)array.length);
            if (newCapacity < minCapacity)
                newCapacity = (int)minCapacity; //safe since checked above

            String[] newArray = new String[newCapacity];
            System.arraycopy(array, 0, newArray, 0, size);
            array = newArray; //do last to minimize concurrency problems
        }
    }

This ensures that the capacity is at least 'minCapacity'.

@param minCapacity the minimum acceptable capacity.
minCapacity is type long, but >= Integer.MAX_VALUE will throw exception.

This ensures that the capacity is at least minCapacity .


public String get(int index) {
        if (index >= size)
            throw new IllegalArgumentException(ErddapString2.ERROR + " in StringArray.get: index (" +
                index + ") >= size (" + size + ").");
        return array[index];
    }

public
String
get
(
int
index
)
{
if
(
index
>=
size
)
throw
new
IllegalArgumentException
(
ErddapString2
.
ERROR
+
" in StringArray.get: index ("
+
index
+
") >= size ("
+
size
+
")."
)
;
return
array
[
index
]
;
}

This gets a specified element.

@param index 0 ... size-1


public InvCatalogImpl makeCatalogForDirectory( String orgPath, URI catURI ) {

    if ( log.isDebugEnabled())
    {
      log.debug( "baseURI=" + catURI );
      log.debug( "orgPath=" + orgPath );
      log.debug( "rootPath=" + rootPath );
      log.debug( "scanLocation=" + scanLocation );
    }

    // Get the dataset path.
    String dsDirPath = translatePathToLocation( orgPath );
    if ( dsDirPath == null )
    {
      String tmpMsg = "makeCatalogForDirectory(): Requesting path <" + orgPath + "> must start with \"" + rootPath + "\".";
      log.error( tmpMsg );
      return null;
    }

    // Setup and create catalog builder.
    CatalogBuilder catBuilder = buildCatalogBuilder();
    if ( catBuilder == null )
      return null;

    // A very round about way to remove the filename (e.g., "catalog.xml").
    // Note: Gets around "path separator at end of path" issues that are CrDs implementation dependant.
    // Note: Does not check that CrDs is allowed by filters.
    String dsPath = dsDirPath.substring( scanLocationCrDs.getPath().length() );
    if ( dsPath.startsWith( "/" ))
      dsPath = dsPath.substring( 1 );
    CrawlableDataset reqCrDs = scanLocationCrDs.getDescendant( dsPath );
    CrawlableDataset parent = reqCrDs.getParentDataset();
    if (parent == null) {
      log.error( "makeCatalogForDirectory(): I/O error getting parent crDs level <" + dsDirPath + ">: ");
      return null;
    }
    dsDirPath = parent.getPath();

    // Get the CrawlableDataset for the desired catalog level (checks that allowed by filters).
    CrawlableDataset catalogCrDs;
    try
    {
      catalogCrDs = catBuilder.requestCrawlableDataset( dsDirPath );
    }
    catch ( IOException e )
    {
      log.error( "makeCatalogForDirectory(): I/O error getting catalog level <" + dsDirPath + ">: " + e.getMessage(), e );
      return null;
    }

    if ( catalogCrDs == null )
    {
      log.warn( "makeCatalogForDirectory(): requested catalog level <" + dsDirPath + "> not allowed (filtered out).");
      return null;
    }
    if ( ! catalogCrDs.isCollection() )
    {
      log.warn( "makeCatalogForDirectory(): requested catalog level <" + dsDirPath + "> is not a collection.");
      return null;
    }

    // Generate the desired catalog using the builder.
    InvCatalogImpl catalog;
    try
    {
      catalog = catBuilder.generateCatalog( catalogCrDs );
    }
    catch ( IOException e )
    {
      log.error( "makeCatalogForDirectory(): catalog generation failed <" + catalogCrDs.getPath() + ">: " + e.getMessage() );
      return null;
    }

    // Set the catalog base URI.
    if ( catalog != null )
      catalog.setBaseURI( catURI );

//    InvDatasetImpl top = (InvDatasetImpl) catalog.getDataset();
//    // if we name it carefully, can get catalogRef to useProxy == true (disappear top dataset)
//    if ( service.isRelativeBase()) {
//      pos = dataDir.lastIndexOf("/");
//      String lastDir = (pos > 0) ? dataDir.substring(pos+1) : dataDir;
//      String topName = lastDir.length() > 0 ? lastDir : getName();
//      top.setName( topName);
//    }

    return catalog;
  }

Try to build a catalog for the given path by scanning the location
associated with this InvDatasetScan. The given path must start with
the path of this InvDatasetScan.

@param orgPath the part of the baseURI that is the path
@param catURI the base URL for the catalog, used to resolve relative URLs.

@return the catalog for this path (uses version 1.1) or null if build unsuccessful.

Try to build a catalog for the given path by scanning the location associated with this InvDatasetScan . The given path must start with the path of this InvDatasetScan .


public InvCatalogImpl makeProxyDsResolverCatalog( String path, URI baseURI )
  {
    if ( path == null ) return null;
    if ( path.endsWith( "/")) return null;

    // Get the dataset path.
    String dsDirPath = translatePathToLocation( path );
    if ( dsDirPath == null )
    {
      log.error( "makeProxyDsResolverCatalog(): Requesting path <" + path + "> must start with \"" + rootPath + "\"." );
      return null;
    }

    // Split into parent path and dataset name.
    int pos = dsDirPath.lastIndexOf('/');
    if ( pos == -1 )
    {
      log.error( "makeProxyDsResolverCatalog(): Requesting path <" + path + "> must contain a slash (\"/\")." );
      return null;
    }
    String dsName = dsDirPath.substring( pos + 1 );
    dsDirPath = dsDirPath.substring( 0, pos );

    // Find matching ProxyDatasetHandler.
    ProxyDatasetHandler pdh = this.getProxyDatasetHandlers().get( dsName );
    if ( pdh == null )
    {
      log.error( "makeProxyDsResolverCatalog(): No matching proxy dataset handler found <" + dsName + ">." );
      return null;
    }

    // Setup and create catalog builder.
    CatalogBuilder catBuilder = buildCatalogBuilder();
    if ( catBuilder == null )
      return null;

    // Get the CrawlableDataset for the desired catalog level.
    CrawlableDataset catalogCrDs;
    try
    {
      catalogCrDs = catBuilder.requestCrawlableDataset( dsDirPath );
    }
    catch ( IOException e )
    {
      log.error( "makeProxyDsResolverCatalog(): failed to create CrawlableDataset for catalogLevel <" + dsDirPath + "> and class <" + crDsClassName + ">: " + e.getMessage(), e );
      return null;
    }
    if ( catalogCrDs == null )
    {
      log.warn( "makeProxyDsResolverCatalog(): requested catalog level <" + dsDirPath + "> not allowed (filtered out)." );
      return null;
    }
    if ( ! catalogCrDs.isCollection())
    {
      log.warn( "makeProxyDsResolverCatalog(): requested catalog level <" + dsDirPath + "> not a collection." );
      return null;
    }

    // Generate the desired catalog using the builder.
    InvCatalogImpl catalog;
    try
    {
      catalog = (InvCatalogImpl) catBuilder.generateProxyDsResolverCatalog( catalogCrDs, pdh );
    }
    catch ( IOException e )
    {
      log.error( "makeProxyDsResolverCatalog(): catalog generation failed <" + catalogCrDs.getPath() + ">: " + e.getMessage() );
      return null;
    }

    // Set the catalog base URI.
    if ( catalog != null )
      catalog.setBaseURI( baseURI );

    return catalog;
  }

Try to build a catalog for the given resolver path by scanning the
location associated with this InvDatasetScan. The given path must start
with the path of this InvDatasetScan and refer to a resolver
ProxyDatasetHandler that is part of this InvDatasetScan.

@param path the part of the baseURI that is the path
@param baseURI the base URL for the catalog, used to resolve relative URLs.

@return the resolver catalog for this path (uses version 1.1) or null if build unsuccessful.

Try to build a catalog for the given resolver path by scanning the location associated with this InvDatasetScan . The given path must start with the path of this InvDatasetScan and refer to a resolver ProxyDatasetHandler that is part of this InvDatasetScan .


private DataType getCoordinateType() {
    List<Dataset> nestedDatasets = getDatasets();
    DatasetOuterDimension first = (DatasetOuterDimension) nestedDatasets.get(0);
    return first.isStringValued ? DataType.STRING : DataType.DOUBLE;
  }

private DataType getCoordinateType ( ) { List < Dataset > nestedDatasets = getDatasets ( ) ; DatasetOuterDimension first = ( DatasetOuterDimension ) nestedDatasets . get ( 0 ) ; return first . isStringValued ? DataType . STRING : DataType . DOUBLE ; }

What is the data type of the aggregation coordinate ?

@return the data type of the aggregation coordinate


@Nullable
  public static Grib2Pds factory(int template, byte[] input) {
    switch (template) {
      case 0:
        return new Grib2Pds0(input);
      case 1:
        return new Grib2Pds1(input);
      case 2:
        return new Grib2Pds2(input);
      case 5:
        return new Grib2Pds5(input);
      case 6:
        return new Grib2Pds6(input);
      case 8:
        return new Grib2Pds8(input);
      case 9:
        return new Grib2Pds9(input);
      case 10:
        return new Grib2Pds10(input);
      case 11:
        return new Grib2Pds11(input);
      case 12:
        return new Grib2Pds12(input);
      case 15:
        return new Grib2Pds15(input);
      case 30:
        return new Grib2Pds30(input);
      case 31:
        return new Grib2Pds31(input);
      case 48:
          return new Grib2Pds48(input);
      case 61:
          return new Grib2Pds61(input);
      default:
        log.warn("Missing template " + template);
        return null;
    }
  }

@
Nullable
public
static
Grib2Pds
factory
(
int
template
,
byte
[
]
input
)
{
switch
(
template
)
{
case
0
:
return
new
Grib2Pds0
(
input
)
;
case
1
:
return
new
Grib2Pds1
(
input
)
;
case
2
:
return
new
Grib2Pds2
(
input
)
;
case
5
:
return
new
Grib2Pds5
(
input
)
;
case
6
:
return
new
Grib2Pds6
(
input
)
;
case
8
:
return
new
Grib2Pds8
(
input
)
;
case
9
:
return
new
Grib2Pds9
(
input
)
;
case
10
:
return
new
Grib2Pds10
(
input
)
;
case
11
:
return
new
Grib2Pds11
(
input
)
;
case
12
:
return
new
Grib2Pds12
(
input
)
;
case
15
:
return
new
Grib2Pds15
(
input
)
;
case
30
:
return
new
Grib2Pds30
(
input
)
;
case
31
:
return
new
Grib2Pds31
(
input
)
;
case
48
:
return
new
Grib2Pds48
(
input
)
;
case
61
:
return
new
Grib2Pds61
(
input
)
;
default
:
log
.
warn
(
"Missing template "
+
template
)
;
return
;
}
}

Factory for Grib2Pds

@param template pds template number
@param input   raw bytes
@return Grib2Pds or null on error


protected CalendarDate calcTime(int startIndex) {

    int year = GribNumbers.int2(getOctet(startIndex++), getOctet(startIndex++));
    int month = getOctet(startIndex++);
    int day = getOctet(startIndex++);
    int hour = getOctet(startIndex++);
    int minute = getOctet(startIndex++);
    int second = getOctet(startIndex++);

    if ((year == 0) && (month == 0) && (day == 0) && (hour == 0) && (minute == 0) && (second == 0))
      return CalendarDate.UNKNOWN;

   // href.t00z.prob.f36.grib2
     if (hour > 23) {
       day += (hour/24);
       hour = hour % 24;
     }

    return CalendarDate.of(null, year, month, day, hour, minute, second);
  }

protected
CalendarDate
calcTime
(
int
startIndex
)
{
int
year
=
GribNumbers
.
int2
(
getOctet
(
startIndex
++
)
,
getOctet
(
startIndex
++
)
)
;
int
month
=
getOctet
(
startIndex
++
)
;
int
day
=
getOctet
(
startIndex
++
)
;
int
hour
=
getOctet
(
startIndex
++
)
;
int
minute
=
getOctet
(
startIndex
++
)
;
int
second
=
getOctet
(
startIndex
++
)
;
if
(
(
year
==
0
)
&&
(
month
==
0
)
&&
(
day
==
0
)
&&
(
hour
==
0
)
&&
(
minute
==
0
)
&&
(
second
==
0
)
)
return
CalendarDate
.
UNKNOWN
;
// href.t00z.prob.f36.grib2
if
(
hour
>
23
)
{
day
+=
(
hour
/
24
)
;
hour
=
hour
%
24
;
}
return
CalendarDate
.
of
(
,
year
,
month
,
day
,
hour
,
minute
,
second
)
;
}


double applyScaleFactor(int scale, int value) {
    return ((scale == 0) || (scale == 255) || (value == 0)) ? value : value * Math.pow(10, -scale);
  }

double applyScaleFactor ( int scale , int value ) { return ( ( scale == 0 ) || ( scale == 255 ) || ( value == 0 ) ) ? value : value * Math . pow ( 10 , - scale ) ; }

Apply scale factor to value, return a double result.

@param scale signed scale factor
@param value apply to this value
@return   value ^ -scale

Apply scale factor to value return a double result .


private void parseLocalConcept(String filename, String conceptName) throws IOException {
      try (InputStream is = new FileInputStream(filename)) {
        addLocalConcept(is, conceptName);
      }
    }

private void parseLocalConcept ( String filename , String conceptName ) throws IOException { try ( InputStream is = new FileInputStream ( filename ) ) { addLocalConcept ( is , conceptName ) ; } }

Parse the localConcept files needed to create grib1 tables for use by the CDM.

Parse the localConcept files needed to create grib1 tables for use by the CDM .


private void addLocalConcept(InputStream is, String conceptName) throws IOException {
        /*
        example entry from name.def:

        #Total precipitation of at least 5 mm
        'Total precipitation of at least 5 mm' = {
             table2Version = 131 ;
             indicatorOfParameter = 61 ;
            }
         */

        try (BufferedReader br = new BufferedReader(new InputStreamReader(is, ENCODING))) {
            String line = br.readLine();

            while (!line.startsWith("#"))
                line = br.readLine(); // skip

            while (true) {
                HashMap<String, String> items = new HashMap<>();
                line = br.readLine();
                if (line == null) break; // done with the file
                if ((line.length() == 0) || line.startsWith("#")) continue;
                line = cleanLine(line);
                if (line.contains("{")) {
                    String paramName = line.split("=")[0].trim();
                    line = br.readLine();
                    if (line == null) break; // done with the file
                    line = cleanLine(line);
                    while (line.contains("=")) {
                        String[] kvp = line.split("=");
                        items.put(kvp[0].trim(), kvp[1].trim());
                        line = br.readLine();
                        if (line == null) break; // done with the file
                        line = cleanLine(line);                    }
                    String tableVersion = items.get(TABLE_VERSION_ID);
                    String parameterNumber = items.get(PARAM_NUM_ID);

                    storeConcept(tableVersion, parameterNumber, conceptName, paramName);
                }
            }
        }
    }

Add the information from a localConcept file to super HashMap localConcepts

@param is InputStream of the localConcept file
@param conceptName "type" of localConcept being added


private String cleanLine(String lineIn) {
        String lineOut;
        lineOut = lineIn.replaceAll("'", "");
        lineOut = lineOut.replaceAll("\t", "");
        lineOut = lineOut.replaceAll(";", "");

        return lineOut.trim();
    }

private String cleanLine ( String lineIn ) { String lineOut ; lineOut = lineIn . replaceAll ( "'" , "" ) ; lineOut = lineOut . replaceAll ( "\t" , "" ) ; lineOut = lineOut . replaceAll ( ";" , "" ) ; return lineOut . trim ( ) ; }

clean the string representation of a line in the localConcept
file. Basic removal of tabs, semicolons, single quotes, etc.
@param lineIn  line (String) to be cleaned
@return cleaned version of lineIn

clean the string representation of a line in the localConcept file . Basic removal of tabs semicolons single quotes etc .


private void storeConcept(String tableVersion, String parameterNumber, String key, String value) {

        HashMap<String, HashMap<String, String>> tmpTable;
        if (localConcepts.containsKey(tableVersion)) {
            tmpTable = localConcepts.get(tableVersion);
            if (tmpTable.containsKey(parameterNumber)) {
              HashMap<String, String> tmpParam = tmpTable.get(parameterNumber);
                if (!tmpParam.containsKey(key)) {
                     tmpParam.put(key, value);
                } else {
                    System.out.println("already has key value pair: " + key + ":" + value);
                }
            } else {
                HashMap<String, String> tmpParam = new HashMap<>(4);
                tmpParam.put(key, value);
                tmpTable.put(parameterNumber, tmpParam);
            }
        } else {
            tmpTable = new HashMap<>();
            HashMap<String, String> tmpParam = new HashMap<>(4);
            tmpParam.put(key, value);
            tmpTable.put(parameterNumber, tmpParam);
        }
        localConcepts.put(tableVersion, tmpTable);
    }

private
void
storeConcept
(
String
tableVersion
,
String
parameterNumber
,
String
key
,
String
value
)
{
HashMap
<
String
,
HashMap
<
String
,
String
>
>
tmpTable
;
if
(
localConcepts
.
containsKey
(
tableVersion
)
)
{
tmpTable
=
localConcepts
.
get
(
tableVersion
)
;
if
(
tmpTable
.
containsKey
(
parameterNumber
)
)
{
HashMap
<
String
,
String
>
tmpParam
=
tmpTable
.
get
(
parameterNumber
)
;
if
(
!
tmpParam
.
containsKey
(
key
)
)
{
tmpParam
.
put
(
key
,
value
)
;
}
else
{
System
.
out
.
println
(
"already has key value pair: "
+
key
+
":"
+
value
)
;
}
}
else
{
HashMap
<
String
,
String
>
tmpParam
=
new
HashMap
<>
(
4
)
;
tmpParam
.
put
(
key
,
value
)
;
tmpTable
.
put
(
parameterNumber
,
tmpParam
)
;
}
}
else
{
tmpTable
=
new
HashMap
<>
(
)
;
HashMap
<
String
,
String
>
tmpParam
=
new
HashMap
<>
(
4
)
;
tmpParam
.
put
(
key
,
value
)
;
tmpTable
.
put
(
parameterNumber
,
tmpParam
)
;
}
localConcepts
.
put
(
tableVersion
,
tmpTable
)
;
}

Store localConcept information in super HashMap localConcepts

@param tableVersion  - version of the table to add parameter to
@param parameterNumber  - parameter number
@param key Type of metadata to be added (shortName, Description, Units)
@param value Value of metadata


private void writeGrib1Tables() throws IOException {
        SimpleDateFormat dateFormat =
                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
        Calendar cal = Calendar.getInstance();
        String writeDate = dateFormat.format(cal.getTime());
        String grib1Info;
        List<String> tableNums = new ArrayList<>();
        HashMap<String, String> paramInfo;
        Path dir = Paths.get(ecmwfLocalConceptsLoc.replace("sources/", "resources/resources/grib1/"));
        for (String tableNum : localConcepts.keySet()) {
            tableNums.add(tableNum);
            String fileName = "2.98." + tableNum + ".table";
            System.out.println("Writing: " + fileName);
            Path newFile = dir.resolve(fileName);
            Files.deleteIfExists(newFile);
            Files.createFile(newFile);

            try (BufferedWriter writer = Files.newBufferedWriter(newFile, ENCODING)){
                writer.write("# Generated by " + this.getClass().getCanonicalName() + " on " + writeDate);
                writer.newLine();
                for(String paramNum : localConcepts.get(tableNum).keySet()){
                    paramInfo = localConcepts.get(tableNum).get(paramNum);

                    String shortName = paramInfo.get(SHORTNAME_ID);
                    String description = paramInfo.get(DESCRIPTION_ID);
                    String units = paramInfo.get(UNIT_ID);

                    grib1Info = paramNum + " " + shortName + " [" + description + "] (" + units + ")";

                    writer.write(grib1Info);
                    writer.newLine();
                }
            }
        }
        writeLookupTableFile(tableNums, dir, writeDate);
    }

private
void
writeGrib1Tables
(
)
throws
IOException
{
SimpleDateFormat
dateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ssz"
)
;
Calendar
cal
=
Calendar
.
getInstance
(
)
;
String
writeDate
=
dateFormat
.
format
(
cal
.
getTime
(
)
)
;
String
grib1Info
;
List
<
String
>
tableNums
=
new
ArrayList
<>
(
)
;
HashMap
<
String
,
String
>
paramInfo
;
Path
dir
=
Paths
.
get
(
ecmwfLocalConceptsLoc
.
replace
(
"sources/"
,
"resources/resources/grib1/"
)
)
;
for
(
String
tableNum
:
localConcepts
.
keySet
(
)
)
{
tableNums
.
add
(
tableNum
)
;
String
fileName
=
"2.98."
+
tableNum
+
".table"
;
System
.
out
.
println
(
"Writing: "
+
fileName
)
;
Path
newFile
=
dir
.
resolve
(
fileName
)
;
Files
.
deleteIfExists
(
newFile
)
;
Files
.
createFile
(
newFile
)
;
try
(
BufferedWriter
writer
=
Files
.
newBufferedWriter
(
newFile
,
ENCODING
)
)
{
writer
.
write
(
"# Generated by "
+
this
.
getClass
(
)
.
getCanonicalName
(
)
+
" on "
+
writeDate
)
;
writer
.
newLine
(
)
;
for
(
String
paramNum
:
localConcepts
.
get
(
tableNum
)
.
keySet
(
)
)
{
paramInfo
=
localConcepts
.
get
(
tableNum
)
.
get
(
paramNum
)
;
String
shortName
=
paramInfo
.
get
(
SHORTNAME_ID
)
;
String
description
=
paramInfo
.
get
(
DESCRIPTION_ID
)
;
String
units
=
paramInfo
.
get
(
UNIT_ID
)
;
grib1Info
=
paramNum
+
" "
+
shortName
+
" ["
+
description
+
"] ("
+
units
+
")"
;
writer
.
write
(
grib1Info
)
;
writer
.
newLine
(
)
;
}
}
}
writeLookupTableFile
(
tableNums
,
dir
,
writeDate
)
;
}

Write out grib1 tables based on localConcepts files - these are the tables
that the CDM will read.

Write out grib1 tables based on localConcepts files - these are the tables that the CDM will read .


private void writeLookupTableFile(List<String> tableNums, Path dir, String writeDate) throws IOException {

        System.out.println("Writing: lookupTables.txt");
        Collections.sort(tableNums);
        Path lookupTableReg = dir.resolve("lookupTables.txt");
        Files.deleteIfExists(lookupTableReg);
        Files.createFile(lookupTableReg);
        try (BufferedWriter writer = Files.newBufferedWriter(lookupTableReg, ENCODING)){
            writer.write("# Generated by " + this.getClass().getCanonicalName() + " on " + writeDate);
            writer.newLine();
            for(String tn : tableNums){
                String tableName = "2.98." + tn + ".table";
                String reg = "98:\t-1:\t" + tn + ":\t" + tableName;
                writer.write(reg);
                writer.newLine();
            }
        }
    }

private
void
writeLookupTableFile
(
List
<
String
>
tableNums
,
Path
dir
,
String
writeDate
)
throws
IOException
{
System
.
out
.
println
(
"Writing: lookupTables.txt"
)
;
Collections
.
sort
(
tableNums
)
;
Path
lookupTableReg
=
dir
.
resolve
(
"lookupTables.txt"
)
;
Files
.
deleteIfExists
(
lookupTableReg
)
;
Files
.
createFile
(
lookupTableReg
)
;
try
(
BufferedWriter
writer
=
Files
.
newBufferedWriter
(
lookupTableReg
,
ENCODING
)
)
{
writer
.
write
(
"# Generated by "
+
this
.
getClass
(
)
.
getCanonicalName
(
)
+
" on "
+
writeDate
)
;
writer
.
newLine
(
)
;
for
(
String
tn
:
tableNums
)
{
String
tableName
=
"2.98."
+
tn
+
".table"
;
String
reg
=
"98:\t-1:\t"
+
tn
+
":\t"
+
tableName
;
writer
.
write
(
reg
)
;
writer
.
newLine
(
)
;
}
}
}

Write the lookupTables.txt file, which basically registers all of the new grib1 tables
with the CDM

@param tableNums List of Table Numbers
@param dir Directory where the tables live
@param writeDate Date on which the main method of this class was run, resulting in new tables

Write the lookupTables . txt file which basically registers all of the new grib1 tables with the CDM


private void showLocalConcepts() {
        for (String tableNum : localConcepts.keySet()) {
            for (String paramNum : localConcepts.get(tableNum).keySet()) {
                for (String key :localConcepts.get(tableNum).get(paramNum).keySet()) {
                   System.out.println(key + ":" + localConcepts.get(tableNum).get(paramNum).get(key));
                }
            }
        }
    }

private void showLocalConcepts ( ) { for ( String tableNum : localConcepts . keySet ( ) ) { for ( String paramNum : localConcepts . get ( tableNum ) . keySet ( ) ) { for ( String key : localConcepts . get ( tableNum ) . get ( paramNum ) . keySet ( ) ) { System . out . println ( key + ":" + localConcepts . get ( tableNum ) . get ( paramNum ) . get ( key ) ) ; } } } }

Quick prinout to System.out of the different parameter metadata fields

Quick prinout to System . out of the different parameter metadata fields


public static void main(String[] args) {

        EcmwfLocalConcepts ec = new EcmwfLocalConcepts();
        try {
            ec.writeGrib1Tables();
            System.out.println("Finished!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

public static void main ( String [ ] args ) { EcmwfLocalConcepts ec = new EcmwfLocalConcepts ( ) ; try { ec . writeGrib1Tables ( ) ; System . out . println ( "Finished!" ) ; } catch ( IOException e ) { e . printStackTrace ( ) ; } }

Generate grib1 tables for the CDM based on the localConcept files from ECMWF GRIB-API

@param args None

Generate grib1 tables for the CDM based on the localConcept files from ECMWF GRIB - API