diff --git a/cots/ucar.nc2.bufrsplitter/.classpath b/cots/ucar.nc2.bufrsplitter/.classpath new file mode 100644 index 0000000000..22d5ebaced --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/cots/ucar.nc2.bufrsplitter/.project b/cots/ucar.nc2.bufrsplitter/.project new file mode 100644 index 0000000000..0495849428 --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/.project @@ -0,0 +1,28 @@ + + + ucar.nc2.bufrsplitter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/cots/ucar.nc2.bufrsplitter/.settings/org.eclipse.jdt.core.prefs b/cots/ucar.nc2.bufrsplitter/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/.settings/org.eclipse.jdt.core.prefs @@ -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 diff --git a/cots/ucar.nc2.bufrsplitter/META-INF/MANIFEST.MF b/cots/ucar.nc2.bufrsplitter/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..597847b9e5 --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/META-INF/MANIFEST.MF @@ -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 diff --git a/cots/ucar.nc2.bufrsplitter/README.txt b/cots/ucar.nc2.bufrsplitter/README.txt new file mode 100644 index 0000000000..e76a5e6ded --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/README.txt @@ -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. \ No newline at end of file diff --git a/cots/ucar.nc2.bufrsplitter/bufr-splitter-4.2.jar b/cots/ucar.nc2.bufrsplitter/bufr-splitter-4.2.jar new file mode 100644 index 0000000000..37f4fa95a5 Binary files /dev/null and b/cots/ucar.nc2.bufrsplitter/bufr-splitter-4.2.jar differ diff --git a/cots/ucar.nc2.bufrsplitter/build.properties b/cots/ucar.nc2.bufrsplitter/build.properties new file mode 100644 index 0000000000..6139413b47 --- /dev/null +++ b/cots/ucar.nc2.bufrsplitter/build.properties @@ -0,0 +1,3 @@ +bin.includes = META-INF/,\ + .,\ + bufr-splitter-4.2.jar diff --git a/cots/ucar.nc2/.classpath b/cots/ucar.nc2/.classpath index ae868eb4a0..bda560fe52 100644 --- a/cots/ucar.nc2/.classpath +++ b/cots/ucar.nc2/.classpath @@ -1,5 +1,6 @@ + diff --git a/cots/ucar.nc2/META-INF/MANIFEST.MF b/cots/ucar.nc2/META-INF/MANIFEST.MF index e693653a73..7cabcdf48b 100644 --- a/cots/ucar.nc2/META-INF/MANIFEST.MF +++ b/cots/ucar.nc2/META-INF/MANIFEST.MF @@ -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, diff --git a/cots/ucar.nc2/bufr-3.0.jar b/cots/ucar.nc2/bufr-3.0.jar new file mode 100644 index 0000000000..775be6ee62 Binary files /dev/null and b/cots/ucar.nc2/bufr-3.0.jar differ diff --git a/cots/ucar.nc2/build.properties b/cots/ucar.nc2/build.properties index c8b34d35bb..9faafcc1ed 100644 --- a/cots/ucar.nc2/build.properties +++ b/cots/ucar.nc2/build.properties @@ -1,3 +1,4 @@ bin.includes = META-INF/,\ netcdf-4.2.jar,\ - grib-8.0.jar + grib-8.0.jar,\ + bufr-3.0.jar diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/.classpath b/edexOsgi/com.raytheon.uf.common.nc.bufr/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/.project b/edexOsgi/com.raytheon.uf.common.nc.bufr/.project new file mode 100644 index 0000000000..b9bda084f7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.nc.bufr + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.nc.bufr/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/.settings/org.eclipse.jdt.core.prefs @@ -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 diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.nc.bufr/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..45e9ad1aa7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/META-INF/MANIFEST.MF @@ -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 diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/build.properties b/edexOsgi/com.raytheon.uf.common.nc.bufr/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/BufrParser.java b/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/BufrParser.java new file mode 100644 index 0000000000..969d2c63a0 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/BufrParser.java @@ -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. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 18, 2014 2905       bclement     Initial creation
+ * 
+ * 
+ * + * @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 varIter; + + private Variable currentVar; + + private StructIterator structIter; + + private static class StructureLevel { + public final StructureData structure; + + public final Iterator 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 structStack = new Stack(); + + 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 getFieldScalarValue(Class 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 getFieldScalarValue(Class 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 Collection getFieldCollection(Class fieldType) + throws IOException { + TypedArray typedArray = readFieldAsArray(); + if (typedArray == null) { + return null; + } + Array array = typedArray.array; + int len = (int) array.getSize(); + Collection rval = new ArrayList(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()); + } + } +} diff --git a/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/StructIterator.java b/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/StructIterator.java new file mode 100644 index 0000000000..a13d26350b --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.nc.bufr/src/com/raytheon/uf/common/nc/bufr/StructIterator.java @@ -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. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 19, 2014 2905       bclement     Initial creation
+ * 
+ * 
+ * + * @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(); + } + +}