Issue #2905 added ucar bufr parser
added netcdf 4.2 bufr library to ucar.nc2 foss added backported 4.3 bufr splitter library created a parser wrapper for ease of use Former-commit-id:78049d1e87
[formerly46513ea27c
] [formerly5b69e9b21c
] [formerly5b69e9b21c
[formerly199701def9
]] [formerly5348f0a29d
[formerly5b69e9b21c
[formerly199701def9
] [formerly5348f0a29d
[formerly 5ddf9be7105dbd8d1fb76ce28a4e6e3f03240974]]]] Former-commit-id:5348f0a29d
Former-commit-id: 277d0cc0113b99d8829eb2b3f507c2d995da98c4 [formerly a6b2df11d2b1e116738bfd3b8c4f5f2d90e354d4] [formerly420b48c8ea
[formerly0e11ca3cfe
]] Former-commit-id:420b48c8ea
Former-commit-id:6825bac664
This commit is contained in:
parent
16ca24f8ea
commit
60510fe32e
18 changed files with 837 additions and 3 deletions
7
cots/ucar.nc2.bufrsplitter/.classpath
Normal file
7
cots/ucar.nc2.bufrsplitter/.classpath
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="bufr-splitter-4.2.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
28
cots/ucar.nc2.bufrsplitter/.project
Normal file
28
cots/ucar.nc2.bufrsplitter/.project
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ucar.nc2.bufrsplitter</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
10
cots/ucar.nc2.bufrsplitter/META-INF/MANIFEST.MF
Normal file
10
cots/ucar.nc2.bufrsplitter/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,10 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Bufrsplitter
|
||||
Bundle-SymbolicName: ucar.nc2.bufrsplitter
|
||||
Bundle-Version: 4.2
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Require-Bundle: ucar.nc2,
|
||||
org.slf4j
|
||||
Bundle-ClassPath: bufr-splitter-4.2.jar
|
||||
Export-Package: ucar.nc2.iosp.bufr.writer
|
7
cots/ucar.nc2.bufrsplitter/README.txt
Normal file
7
cots/ucar.nc2.bufrsplitter/README.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
This contains the BUFR splitter classes from netcdf-java version 4.3.20.
|
||||
The classes have been modified to work with netcdf-java version 4.2. Modifications have
|
||||
been tagged with a comment containing the issue number related to the work (#2905).
|
||||
|
||||
This will not be needed if/when the ucar netcdf-java dependency is upgraded to 4.4.
|
||||
It is also recommended that the newer BufrSplitter2.java be used instead of BufrSPlitter.java.
|
||||
BufrSplitter2 has an improved interface that allows for use in other packages without modification.
|
BIN
cots/ucar.nc2.bufrsplitter/bufr-splitter-4.2.jar
Normal file
BIN
cots/ucar.nc2.bufrsplitter/bufr-splitter-4.2.jar
Normal file
Binary file not shown.
3
cots/ucar.nc2.bufrsplitter/build.properties
Normal file
3
cots/ucar.nc2.bufrsplitter/build.properties
Normal file
|
@ -0,0 +1,3 @@
|
|||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
bufr-splitter-4.2.jar
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="lib" path="bufr-3.0.jar"/>
|
||||
<classpathentry exported="true" kind="lib" path="grib-8.0.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
|
|
|
@ -2,9 +2,10 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Nc2
|
||||
Bundle-SymbolicName: ucar.nc2
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Version: 4.2
|
||||
Bundle-ClassPath: netcdf-4.2.jar,
|
||||
grib-8.0.jar
|
||||
grib-8.0.jar,
|
||||
bufr-3.0.jar
|
||||
Export-Package: net.jcip.annotations,
|
||||
thredds.catalog,
|
||||
thredds.catalog.crawl,
|
||||
|
@ -111,6 +112,9 @@ Export-Package: net.jcip.annotations,
|
|||
ucar.nc2.geotiff,
|
||||
ucar.nc2.iosp,
|
||||
ucar.nc2.iosp.adde,
|
||||
ucar.nc2.iosp.bufr,
|
||||
ucar.nc2.iosp.bufr.tables,
|
||||
ucar.nc2.iosp.bufr.writer,
|
||||
ucar.nc2.iosp.cinrad,
|
||||
ucar.nc2.iosp.dmsp,
|
||||
ucar.nc2.iosp.dorade,
|
||||
|
|
BIN
cots/ucar.nc2/bufr-3.0.jar
Normal file
BIN
cots/ucar.nc2/bufr-3.0.jar
Normal file
Binary file not shown.
|
@ -1,3 +1,4 @@
|
|||
bin.includes = META-INF/,\
|
||||
netcdf-4.2.jar,\
|
||||
grib-8.0.jar
|
||||
grib-8.0.jar,\
|
||||
bufr-3.0.jar
|
||||
|
|
7
edexOsgi/com.raytheon.uf.common.nc.bufr/.classpath
Normal file
7
edexOsgi/com.raytheon.uf.common.nc.bufr/.classpath
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
28
edexOsgi/com.raytheon.uf.common.nc.bufr/.project
Normal file
28
edexOsgi/com.raytheon.uf.common.nc.bufr/.project
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>com.raytheon.uf.common.nc.bufr</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
11
edexOsgi/com.raytheon.uf.common.nc.bufr/META-INF/MANIFEST.MF
Normal file
11
edexOsgi/com.raytheon.uf.common.nc.bufr/META-INF/MANIFEST.MF
Normal file
|
@ -0,0 +1,11 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: NetCDF Bufr
|
||||
Bundle-SymbolicName: com.raytheon.uf.common.nc.bufr
|
||||
Bundle-Version: 14.3
|
||||
Bundle-Vendor: RAYTHEON
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Require-Bundle: ucar.nc2,
|
||||
ucar.nc2.bufrsplitter,
|
||||
com.raytheon.uf.common.status
|
||||
Export-Package: com.raytheon.uf.common.nc.bufr
|
4
edexOsgi/com.raytheon.uf.common.nc.bufr/build.properties
Normal file
4
edexOsgi/com.raytheon.uf.common.nc.bufr/build.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
|
@ -0,0 +1,629 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.common.nc.bufr;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
|
||||
import ucar.ma2.Array;
|
||||
import ucar.ma2.ArraySequence;
|
||||
import ucar.ma2.DataType;
|
||||
import ucar.ma2.StructureData;
|
||||
import ucar.ma2.StructureMembers;
|
||||
import ucar.ma2.StructureMembers.Member;
|
||||
import ucar.nc2.NetcdfFile;
|
||||
import ucar.nc2.Structure;
|
||||
import ucar.nc2.Variable;
|
||||
import ucar.nc2.iosp.bufr.writer.BufrSplitter;
|
||||
import ucar.nc2.iosp.bufr.writer.BufrSplitter.Options;
|
||||
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
|
||||
/**
|
||||
* BUFR parser that utilizes the UCAR BUFR decoder that works with the Netcdf
|
||||
* Java API. The parser works as an event-based pull parser. The standard usage
|
||||
* involves an event loop that checks if hasNext() returns true then calls
|
||||
* next() for the current event type which can be acted upon.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Mar 18, 2014 2905 bclement Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bclement
|
||||
* @version 1.0
|
||||
*/
|
||||
public class BufrParser {
|
||||
|
||||
public static enum Event {
|
||||
START_FILE, START_STRUCTURE, FIELD, END_STRUCTURE, END_FILE
|
||||
}
|
||||
|
||||
private static final IUFStatusHandler log = UFStatus
|
||||
.getHandler(BufrParser.class);
|
||||
|
||||
private final static File DEFAULT_TMP_DIR;
|
||||
|
||||
static {
|
||||
final String edexHomeProp = "edex.home";
|
||||
String baseDir = System.getProperty(edexHomeProp);
|
||||
if (baseDir == null || baseDir.trim().isEmpty()){
|
||||
log.warn("Property '" + edexHomeProp + "' not set, defaulting to system tmp directory");
|
||||
DEFAULT_TMP_DIR = new File(System.getProperty("java.io.tmpdir"));
|
||||
} else {
|
||||
DEFAULT_TMP_DIR = new File(baseDir + File.separator + "data",
|
||||
"processing");
|
||||
}
|
||||
}
|
||||
|
||||
private final Options options;
|
||||
|
||||
private final File[] splitFiles;
|
||||
|
||||
private int fileIndex = 0;
|
||||
|
||||
private NetcdfFile currentNcfile;
|
||||
|
||||
private Iterator<Variable> varIter;
|
||||
|
||||
private Variable currentVar;
|
||||
|
||||
private StructIterator structIter;
|
||||
|
||||
private static class StructureLevel {
|
||||
public final StructureData structure;
|
||||
|
||||
public final Iterator<Member> memberIter;
|
||||
|
||||
public Member currentMember;
|
||||
|
||||
public StructureLevel(StructureData structure) {
|
||||
this(structure, structure.getStructureMembers());
|
||||
}
|
||||
|
||||
public StructureLevel(StructureData structure, StructureMembers members) {
|
||||
this.structure = structure;
|
||||
this.memberIter = members.getMembers().iterator();
|
||||
}
|
||||
}
|
||||
|
||||
private final Stack<StructureLevel> structStack = new Stack<BufrParser.StructureLevel>();
|
||||
|
||||
private Event lastEvent = null;
|
||||
|
||||
/**
|
||||
* @param bufrFile
|
||||
* BUFR file, may contain mixed message types
|
||||
* @throws IOException
|
||||
*/
|
||||
public BufrParser(final File bufrFile)
|
||||
throws IOException {
|
||||
this(bufrFile, DEFAULT_TMP_DIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bufrFile
|
||||
* BUFR file, may contain mixed message types
|
||||
* @param outputBaseDir
|
||||
* base directory for temporary storage of split files
|
||||
* @throws IOException
|
||||
*/
|
||||
public BufrParser(final File bufrFile, final File outputBaseDir)
|
||||
throws IOException {
|
||||
final String inputFile = bufrFile.getAbsolutePath();
|
||||
final File outputDir = getOutputDir(bufrFile.getName(), outputBaseDir);
|
||||
options = new Options() {
|
||||
|
||||
@Override
|
||||
public String getFileSpec() {
|
||||
return inputFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDirOut() {
|
||||
return outputDir.getAbsolutePath();
|
||||
}
|
||||
};
|
||||
|
||||
BufrSplitter splitter = new BufrSplitter(options);
|
||||
splitter.execute();
|
||||
|
||||
splitFiles = outputDir.listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".bufr");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temporary output directory based on the input file name
|
||||
*
|
||||
* @param inputName
|
||||
* @param outputBaseDir
|
||||
* @return
|
||||
*/
|
||||
private static File getOutputDir(final String inputName,
|
||||
final File outputBaseDir) {
|
||||
String name = inputName + "-" + System.currentTimeMillis() + "-split";
|
||||
File rval = new File(outputBaseDir, name);
|
||||
if (rval.exists()) {
|
||||
log.warn("BUFR splitter output directory already exists, is a file being processed twice?");
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if parser is not done parsing
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean hasNext() throws IOException {
|
||||
if (!structStack.isEmpty()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
if (level.memberIter != null && level.memberIter.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (structIter != null && structIter.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
if (varIter != null && varIter.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
if (fileIndex < splitFiles.length) {
|
||||
return true;
|
||||
}
|
||||
if (lastEvent != null && !lastEvent.equals(Event.END_FILE)) {
|
||||
/* only one more event left, the end of the last file */
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next parsing event. hasNext() must be called before this method
|
||||
* is called.
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public Event next() throws IOException {
|
||||
Event rval;
|
||||
if (!structStack.isEmpty()) {
|
||||
rval = nextMember();
|
||||
} else if (structIter != null && structIter.hasNext()) {
|
||||
/* in a variable with a sequence of structures, get the next one */
|
||||
rval = startStructure(structIter.next());
|
||||
} else if (structIter != null && !structIter.hasNext()) {
|
||||
/*
|
||||
* this happens if the variable had an empty structure iterator.
|
||||
* Structures are usually ended when there are no more members
|
||||
*/
|
||||
structIter = null;
|
||||
rval = Event.END_STRUCTURE;
|
||||
} else if (varIter != null) {
|
||||
if (varIter.hasNext()) {
|
||||
/* we are working through a bufr file, start the next variable */
|
||||
rval = startVariable();
|
||||
} else {
|
||||
/* no more variables, we are at the end of the bufr file */
|
||||
structIter = null;
|
||||
currentVar = null;
|
||||
varIter = null;
|
||||
rval = endFile();
|
||||
}
|
||||
} else if (fileIndex < splitFiles.length) {
|
||||
/* start the next bufr file */
|
||||
rval = startFile();
|
||||
} else if (lastEvent != null && !lastEvent.equals(Event.END_FILE)) {
|
||||
rval = endFile();
|
||||
} else {
|
||||
/* don't set rval to null so we preserve the correct lastEvent */
|
||||
return null;
|
||||
}
|
||||
lastEvent = rval;
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a member of the current structure. If the structure has no more
|
||||
* members, the structure is ended
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event nextMember() throws IOException {
|
||||
Event rval;
|
||||
StructureLevel level = structStack.peek();
|
||||
if (level.memberIter.hasNext()) {
|
||||
/* in a level of a structure, get the next member */
|
||||
Member m = level.memberIter.next();
|
||||
level.currentMember = m;
|
||||
DataType type = m.getDataType();
|
||||
if (type.equals(DataType.STRUCTURE)) {
|
||||
/* current member is a nested structure, start a new level */
|
||||
StructureData struct = (StructureData) level.structure
|
||||
.getScalarObject(m);
|
||||
rval = startStructure(struct);
|
||||
} else if (type.equals(DataType.SEQUENCE)) {
|
||||
/* current member is a sequence of members, start a new level */
|
||||
ArraySequence arr = level.structure.getArraySequence(m);
|
||||
return startStructure(new StructureLevel(level.structure,
|
||||
arr.getStructureMembers()));
|
||||
} else {
|
||||
/* current member is a field */
|
||||
rval = Event.FIELD;
|
||||
}
|
||||
} else {
|
||||
/* no more members of this structure level */
|
||||
rval = endStructure();
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing the next structure
|
||||
*
|
||||
* @param structure
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event startStructure(StructureData structure) throws IOException {
|
||||
StructureLevel level = new StructureLevel(structure);
|
||||
return startStructure(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing the next structure
|
||||
*
|
||||
* @param level
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event startStructure(StructureLevel level) throws IOException {
|
||||
structStack.push(level);
|
||||
return Event.START_STRUCTURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize processing for the current structure
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event endStructure() throws IOException {
|
||||
structStack.pop();
|
||||
if (structIter != null && !structIter.hasNext()) {
|
||||
structIter = null;
|
||||
}
|
||||
return Event.END_STRUCTURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing the next NetCDF variable
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event startVariable() throws IOException {
|
||||
Event rval;
|
||||
currentVar = varIter.next();
|
||||
if (currentVar instanceof Structure) {
|
||||
Structure s = (Structure) currentVar;
|
||||
structIter = new StructIterator(s.getStructureIterator(),
|
||||
s.getNumberOfMemberVariables());
|
||||
if (structIter.hasNext()) {
|
||||
rval = startStructure(structIter.next());
|
||||
} else {
|
||||
/*
|
||||
* start an event for an empty structure, next event will be an
|
||||
* end structure event
|
||||
*/
|
||||
rval = Event.START_STRUCTURE;
|
||||
}
|
||||
} else {
|
||||
rval = Event.FIELD;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing the next NetCDF file
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event startFile() throws IOException {
|
||||
File f = splitFiles[fileIndex];
|
||||
fileIndex += 1;
|
||||
currentNcfile = NetcdfFile.open(f.getAbsolutePath());
|
||||
varIter = currentNcfile.getVariables().iterator();
|
||||
return Event.START_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize processing of NetCDF file
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Event endFile() throws IOException {
|
||||
if (currentNcfile != null) {
|
||||
currentNcfile.close();
|
||||
currentNcfile = null;
|
||||
}
|
||||
return Event.END_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if no file is currently being processed
|
||||
*/
|
||||
public NetcdfFile getCurrentNcfile() {
|
||||
return currentNcfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if no file has started being processed
|
||||
*/
|
||||
public File getCurrentFile() {
|
||||
if (fileIndex < splitFiles.length) {
|
||||
return splitFiles[fileIndex];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if no variable is currently being processed
|
||||
*/
|
||||
public Variable getCurrentVar() {
|
||||
return currentVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if no events have happened
|
||||
*/
|
||||
public Event getLastEvent() {
|
||||
return lastEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the current field is a member of a structure (as opposed
|
||||
* to a variable field)
|
||||
*/
|
||||
private boolean fieldIsStructMember() {
|
||||
/* struct members are kept on the stack */
|
||||
return !structStack.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the current field is a scalar value
|
||||
*/
|
||||
public boolean fieldIsScalar() {
|
||||
boolean rval = false;
|
||||
if (fieldIsStructMember()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
Member m = level.currentMember;
|
||||
rval = m.isScalar();
|
||||
} else if (currentVar != null) {
|
||||
rval = currentVar.isScalar();
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return unit string for field, may be null
|
||||
*/
|
||||
public String getFieldUnits() {
|
||||
// TODO convert to standard edex units (javax.measure)?
|
||||
String rval = null;
|
||||
if (fieldIsStructMember()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
rval = level.currentMember.getUnitsString();
|
||||
} else if (currentVar != null) {
|
||||
rval = currentVar.getUnitsString();
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of current field
|
||||
*/
|
||||
public String getFieldName() {
|
||||
String rval = null;
|
||||
if (fieldIsStructMember()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
rval = level.currentMember.getName();
|
||||
} else if (currentVar != null) {
|
||||
rval = currentVar.getFullName();
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type of current field
|
||||
*/
|
||||
public Class<?> getFieldType() {
|
||||
DataType dtype = null;
|
||||
if (fieldIsStructMember()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
dtype = level.currentMember.getDataType();
|
||||
} else if (currentVar != null) {
|
||||
dtype = currentVar.getDataType();
|
||||
}
|
||||
/*
|
||||
* not using DataType.getClassType() because it returns primitive types,
|
||||
* we want to only work with objects
|
||||
*/
|
||||
switch (dtype) {
|
||||
case BOOLEAN:
|
||||
return Boolean.class;
|
||||
case BYTE:
|
||||
return Byte.class;
|
||||
case CHAR:
|
||||
return Character.class;
|
||||
case SHORT:
|
||||
return Short.class;
|
||||
case INT:
|
||||
return Integer.class;
|
||||
case LONG:
|
||||
return Long.class;
|
||||
case FLOAT:
|
||||
return Float.class;
|
||||
case DOUBLE:
|
||||
return Double.class;
|
||||
case STRING:
|
||||
return String.class;
|
||||
default:
|
||||
return dtype.getClassType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scalar value of field.
|
||||
*
|
||||
* @param fieldType
|
||||
* type retrieved from {@link BufrParser#getFieldType()}
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public <T> T getFieldScalarValue(Class<T> fieldType) throws IOException {
|
||||
return getFieldScalarValue(fieldType, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scalar value of field.
|
||||
*
|
||||
* @param fieldType
|
||||
* type retrieved from {@link BufrParser#getFieldType()}
|
||||
* @param charArrayAsString
|
||||
* if true, character array fields are converted to Strings
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getFieldScalarValue(Class<T> fieldType,
|
||||
boolean charArrayAsString) throws IOException {
|
||||
TypedArray typedArray = readFieldAsArray();
|
||||
if (typedArray == null) {
|
||||
return null;
|
||||
}
|
||||
Array array = typedArray.array;
|
||||
DataType type = typedArray.type;
|
||||
T rval;
|
||||
if (charArrayAsString && array.getSize() > 1
|
||||
&& type.equals(DataType.CHAR)) {
|
||||
int len = (int) array.getSize();
|
||||
StringBuilder builder = new StringBuilder(len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
builder.append(array.getChar(i));
|
||||
}
|
||||
rval = (T) builder.toString();
|
||||
} else {
|
||||
rval = (T) array.getObject(0);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field values as collection.
|
||||
*
|
||||
* @param fieldType
|
||||
* type retrieved from {@link BufrParser#getFieldType()}
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Collection<T> getFieldCollection(Class<T> fieldType)
|
||||
throws IOException {
|
||||
TypedArray typedArray = readFieldAsArray();
|
||||
if (typedArray == null) {
|
||||
return null;
|
||||
}
|
||||
Array array = typedArray.array;
|
||||
int len = (int) array.getSize();
|
||||
Collection<T> rval = new ArrayList<T>(len);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
rval.add((T) array.getObject(i));
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple return value wrapper to pair a datatype with an array
|
||||
*/
|
||||
private static class TypedArray {
|
||||
public final Array array;
|
||||
|
||||
public final DataType type;
|
||||
|
||||
public TypedArray(Array array, DataType type) {
|
||||
this.array = array;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field values as an array with the associated field datatype
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private TypedArray readFieldAsArray() throws IOException {
|
||||
TypedArray rval = null;
|
||||
if (fieldIsStructMember()) {
|
||||
StructureLevel level = structStack.peek();
|
||||
StructureData s = level.structure;
|
||||
Member m = level.currentMember;
|
||||
rval = new TypedArray(s.getArray(m), m.getDataType());
|
||||
} else if (currentVar != null) {
|
||||
rval = new TypedArray(currentVar.read(), currentVar.getDataType());
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* clean up temporary files
|
||||
*/
|
||||
public void clean(){
|
||||
for ( File f : splitFiles){
|
||||
if (!f.delete()){
|
||||
log.error("Unable to delete temporary file: " + f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
File outdir = new File(options.getDirOut());
|
||||
if (!outdir.delete()) {
|
||||
log.error("Unable to delete temporary directory: "
|
||||
+ outdir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.common.nc.bufr;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ucar.ma2.StructureData;
|
||||
import ucar.ma2.StructureDataIterator;
|
||||
|
||||
/**
|
||||
* Wrapper to fix {@link StructureDataIterator}. Needed because calling
|
||||
* {@link StructureDataIterator#hasNext()} when there is no more items throws an
|
||||
* exception.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Mar 19, 2014 2905 bclement Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author bclement
|
||||
* @version 1.0
|
||||
*/
|
||||
public class StructIterator {
|
||||
|
||||
private final StructureDataIterator iter;
|
||||
|
||||
private final int totalVariable;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
/**
|
||||
* @param iter
|
||||
* @param totalVariables
|
||||
* total number of items in iter
|
||||
*/
|
||||
public StructIterator(StructureDataIterator iter, int totalVariables) {
|
||||
this.iter = iter;
|
||||
this.totalVariable = totalVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there are more elements
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean hasNext() throws IOException {
|
||||
return count < totalVariable && iter.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return next element
|
||||
* @throws IOException
|
||||
*/
|
||||
public StructureData next() throws IOException {
|
||||
++count;
|
||||
return iter.next();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue