From fe1a2a8ebcc5964cab8ec5cc8b7bc98c6b818c1a Mon Sep 17 00:00:00 2001 From: Ron Anderson Date: Wed, 4 Jun 2014 16:31:32 -0500 Subject: [PATCH] Omaha #3130 Fix thread safety issue in NetCDFFile. Change-Id: I99999c827507a565e1980fe2b686cef4d848fe7d Former-commit-id: 47bdee2a5855aec4ed7b2c72a389ece46a860420 [formerly 47bdee2a5855aec4ed7b2c72a389ece46a860420 [formerly 36f4c0f9b339dc91577cb231e2804d83f4f52706]] Former-commit-id: 68a0c42242d51c1a36f4b9ca4e5d22a0986db8c6 Former-commit-id: 3f4bdb73770984bcdd008c48077faac761205460 --- .../gfe/server/database/NetCDFFile.java | 200 ++++++++---------- 1 file changed, 85 insertions(+), 115 deletions(-) diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/NetCDFFile.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/NetCDFFile.java index 38ec2c3c3f..bbfe1bc034 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/NetCDFFile.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/database/NetCDFFile.java @@ -25,7 +25,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import ucar.ma2.ArrayChar; import ucar.ma2.ArrayFloat; @@ -54,7 +56,9 @@ import com.raytheon.uf.common.time.TimeRange; * * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- - * May 14, 2012 randerso Initial creation + * May 14, 2012 randerso Initial creation + * Jun 04, 2014 #3130 randerso Fix thread safety issues with NetcdfFile variable. + * General code cleanup * * * @@ -83,8 +87,6 @@ public class NetCDFFile { private List levelNames; - // private long possibleInventoryBits; - public ParmAtts() { maxVal = 0; minVal = 0; @@ -238,15 +240,13 @@ public class NetCDFFile { private String fname; - private NetcdfFile cdf; - private Date modelTime; private String modelName; private List availableTimes; - private List atts; + private Map atts; private ProjectionData projection; @@ -268,24 +268,34 @@ public class NetCDFFile { public NetCDFFile(String fname, String overrideModelName) { this.valid = false; this.fname = fname; - this.cdf = null; - - // NcError nce(NcError::silent_nonfatal); CHECK_STATE(setModelTime()); - CHECK_STATE(openCDF()); - if (overrideModelName == null || overrideModelName.length() > 0) { - this.modelName = overrideModelName; - } else { - CHECK_STATE(getModel()); + NetcdfFile cdf = null; + try { + cdf = NetcdfFile.open(this.fname); + if ((overrideModelName == null) || (overrideModelName.length() > 0)) { + this.modelName = overrideModelName; + } else { + CHECK_STATE(getModel(cdf)); + } + CHECK_STATE(getProj(cdf)); + CHECK_STATE(getTimes(cdf)); + getTPDurations(cdf); + CHECK_STATE(getNames(cdf)); + this.valid = true; + } catch (IOException e) { + statusHandler.error("Error opening NetCDF file: " + fname, e); + } finally { + if (cdf != null) { + try { + cdf.close(); + } catch (IOException e) { + statusHandler.handle(Priority.PROBLEM, + "Error closing netCDF file " + this.fname + ": " + + e.getLocalizedMessage(), e); + } + } } - CHECK_STATE(getProj()); - CHECK_STATE(getTimes()); - getTPDurations(); - CHECK_STATE(getNames()); - - closeCDF(); - this.valid = true; } private void CHECK_STATE(ServerResponse sr) { @@ -315,10 +325,6 @@ public class NetCDFFile { return availableTimes; } - public List getAtts() { - return atts; - } - public ProjectionData getProjection() { return projection; } @@ -337,7 +343,7 @@ public class NetCDFFile { private ServerResponse getFloatVarAtt(Variable var, String name) { ServerResponse sr = new ServerResponse(); Attribute att = var.findAttribute(name); - if (att == null || !att.getDataType().equals(DataType.FLOAT)) { + if ((att == null) || !att.getDataType().equals(DataType.FLOAT)) { sr.addMessage("Missing or invalid attribute: " + name); return sr; } @@ -361,7 +367,7 @@ public class NetCDFFile { private ServerResponse getStringVarAtt(Variable var, String name) { ServerResponse sr = new ServerResponse(); Attribute att = var.findAttribute(name); - if (att == null || !att.getDataType().equals(DataType.STRING)) { + if ((att == null) || !att.getDataType().equals(DataType.STRING)) { sr.addMessage("Missing or invalid attribute: " + name); return sr; } @@ -371,8 +377,8 @@ public class NetCDFFile { return sr; } - private ServerResponse getProj() { - ServerResponse sr = NetCDFUtils.getProj(this.cdf); + private ServerResponse getProj(NetcdfFile cdf) { + ServerResponse sr = NetCDFUtils.getProj(cdf); if (sr.isOkay()) { this.projection = sr.getPayload(); } @@ -383,10 +389,7 @@ public class NetCDFFile { * @return a list of parm names found in this netCDF file. */ public List getParmNames() { - List rval = new ArrayList(this.atts.size()); - for (int i = 0; i < atts.size(); i++) { - rval.add(atts.get(i).getName()); - } + List rval = new ArrayList(this.atts.keySet()); return rval; } @@ -421,7 +424,7 @@ public class NetCDFFile { * @param var * @return */ - private ServerResponse getParmAtts(Variable var) { + private ServerResponse getParmAtts(NetcdfFile cdf, Variable var) { ServerResponse sr = new ServerResponse(); String units, longname; @@ -450,7 +453,7 @@ public class NetCDFFile { if (!tsrmin.isOkay() || !tsrmax.isOkay()) { Attribute att = var.findAttribute("valid_range"); - if (att != null && att.getLength() == 2 + if ((att != null) && (att.getLength() == 2) && att.getDataType().equals(DataType.FLOAT)) { min = att.getNumericValue(0).floatValue(); max = att.getNumericValue(1).floatValue(); @@ -528,7 +531,7 @@ public class NetCDFFile { // Y coordinate = time, X coordinate = levels for (int y = 0; y < dims[0]; y++) { for (int x = 0; x < idims[1]; x++) { - char c = (char) dta.getByte(y * idims[1] + x); + char c = (char) dta.getByte((y * idims[1]) + x); byte b = (byte) (c == '1' ? 1 : 0); inventory.set(x, y, b); } @@ -582,11 +585,13 @@ public class NetCDFFile { * * @return */ - private ServerResponse getNames() { + private ServerResponse getNames(NetcdfFile cdf) { ServerResponse sr = new ServerResponse(); - this.atts = new ArrayList(); - for (Variable var : this.cdf.getVariables()) { + List variables = cdf.getVariables(); + this.atts = new HashMap(variables.size(), + 1.0f); + for (Variable var : variables) { if (var != null) { if (!var.getDataType().equals(DataType.FLOAT)) { continue; @@ -614,10 +619,11 @@ public class NetCDFFile { } } if (foundx && foundy) { - ServerResponse tsr = getParmAtts(var); + ServerResponse tsr = getParmAtts(cdf, var); sr.addMessages(tsr); if (tsr.isOkay()) { - this.atts.add(tsr.getPayload()); + ParmAtts parmAtts = tsr.getPayload(); + this.atts.put(parmAtts.getName(), parmAtts); } } } @@ -631,7 +637,7 @@ public class NetCDFFile { * model files. * */ - private void getTPDurations() { + private void getTPDurations(NetcdfFile cdf) { this.tpSubPrev = new ArrayList(getAvailableTimes().size()); for (int i = 0; i < getAvailableTimes().size(); i++) { this.tpSubPrev.add(false); @@ -640,8 +646,8 @@ public class NetCDFFile { long duration = (getAvailableTimes().get(1).getStart().getTime() - getAvailableTimes() .get(0).getStart().getTime()) / 1000; String s = String.format("_tp%d", (duration / 3600) * 2); - Variable tvar = this.cdf.findVariable(s); - if (tvar != null && tvar.getDataType().equals(DataType.FLOAT)) { + Variable tvar = cdf.findVariable(s); + if ((tvar != null) && tvar.getDataType().equals(DataType.FLOAT)) { Dimension d1 = tvar.getDimension(0); if (d1 != null) { try { @@ -665,10 +671,10 @@ public class NetCDFFile { * * @return ServerResponse */ - private ServerResponse getTimes() { + private ServerResponse getTimes(NetcdfFile cdf) { ServerResponse sr = new ServerResponse(); - Variable tvar = this.cdf.findVariable("valtimeMINUSreftime"); - if (tvar == null || !tvar.getDataType().equals(DataType.INT)) { + Variable tvar = cdf.findVariable("valtimeMINUSreftime"); + if ((tvar == null) || !tvar.getDataType().equals(DataType.INT)) { sr.addMessage("Missing or invalid 'valtimeMINUSreftime' var."); } else { Dimension d1 = tvar.getDimension(0); @@ -681,8 +687,9 @@ public class NetCDFFile { d1.getLength()); for (int i = 0; i < d1.getLength(); i++) { this.availableTimes.add(new TimeRange(new Date( - this.modelTime.getTime() + times.getInt(i) - * 1000L), 3600 * 1000)); + this.modelTime.getTime() + + (times.getInt(i) * 1000L)), + 3600 * 1000)); } } catch (IOException e) { statusHandler.handle( @@ -702,10 +709,10 @@ public class NetCDFFile { * * @return ServerResponse */ - private ServerResponse getModel() { + private ServerResponse getModel(NetcdfFile cdf) { ServerResponse sr = new ServerResponse(); - Variable mvar = this.cdf.findVariable("model"); - if (mvar == null || !mvar.getDataType().equals(DataType.CHAR)) { + Variable mvar = cdf.findVariable("model"); + if ((mvar == null) || !mvar.getDataType().equals(DataType.CHAR)) { sr.addMessage("Missing or invalid 'model' var."); } else { try { @@ -720,40 +727,6 @@ public class NetCDFFile { return sr; } - /** - * Attempts to open the netcdf file. If it can not be opened (or is not a - * valid cdf file) then an invalid ServerResponse is returned. - * - * @return ServerResponse - */ - private ServerResponse openCDF() { - ServerResponse sr = new ServerResponse(); - try { - this.cdf = NetcdfFile.open(this.fname); - if (this.cdf == null) { - sr.addMessage("Invalid NetCDF file: " + this.fname); - } - } catch (IOException e) { - statusHandler.handle(Priority.PROBLEM, "Error opening netCDF file " - + this.fname + ": " + e.getLocalizedMessage(), e); - } - return sr; - } - - /** - * Closes the netcdf file. - * - */ - private void closeCDF() { - try { - this.cdf.close(); - } catch (IOException e) { - statusHandler.handle(Priority.PROBLEM, "Error closing netCDF file " - + this.fname + ": " + e.getLocalizedMessage(), e); - } - this.cdf = null; - } - /** * Attempts to determine the models run time. If it fails, an invalid * ServerResponse will be returned. @@ -774,51 +747,48 @@ public class NetCDFFile { * @return the ParmAtts */ public ParmAtts getAtts(String parmName) { - for (ParmAtts a : this.atts) { - if (a.getName().equals(parmName)) { - return a; - } - } - return null; + return this.atts.get(parmName); } public Grid2DFloat getGrid(String parmName, int index, int level, Rectangle subdomain) { - ParmAtts atts = getAtts(parmName); - if (atts == null) { + if (!this.atts.containsKey(parmName)) { statusHandler.handle(Priority.PROBLEM, "Unknown parm name: " + parmName); return null; } - if (!openCDF().isOkay()) { - statusHandler.handle(Priority.PROBLEM, "Error opening CDF File: " - + this.fname); - this.valid = false; - return null; - } + NetcdfFile cdf = null; + try { + cdf = NetcdfFile.open(this.fname); - for (ParmAtts a : this.atts) { - if (parmName.equals(a.getName())) { - Grid2DFloat grid = null; - ServerResponse sr = NetCDFUtils.getFloatGrid( - this.cdf, parmName, index, level, subdomain); - if (!sr.isOkay()) { - closeCDF(); - statusHandler.handle(Priority.PROBLEM, sr.message()); - return null; - } else { - grid = sr.getPayload(); + Grid2DFloat grid = null; + ServerResponse sr = NetCDFUtils.getFloatGrid(cdf, + parmName, index, level, subdomain); + if (!sr.isOkay()) { + statusHandler.handle(Priority.PROBLEM, sr.message()); + return null; + } else { + grid = sr.getPayload(); + } + + return grid; + } catch (IOException e) { + statusHandler.error("Error opening NetCDF file: " + fname, e); + } finally { + if (cdf != null) { + try { + cdf.close(); + } catch (IOException e) { + statusHandler.handle(Priority.PROBLEM, + "Error closing netCDF file " + this.fname + ": " + + e.getLocalizedMessage(), e); } - - closeCDF(); - return grid; } } statusHandler .handle(Priority.PROBLEM, "unknown parm name: " + parmName); - closeCDF(); return null; }