From 38a2e426d9324602707a0e8b6a6d7f380265c2ae Mon Sep 17 00:00:00 2001 From: James Korman Date: Fri, 13 Jul 2012 10:04:26 -0500 Subject: [PATCH] Issue #798 - Code review changes Issue #798 - Code review updates Change-Id: I5447574392a42c79fa4295ce4f9bb5ac295d06bb Former-commit-id: cb05a9f95384806537106dc804833331d6c7db48 --- .../viz/core/rsc/hdf5/FileBasedTileSet.java | 14 +- .../satellite/data/prep/SatDataRetriever.java | 25 +- .../viz/satellite/rsc/SatResource.java | 20 +- deltaScripts/goesr_deploy/convertSatURIs.py | 143 +++++ .../esb/bin/linux-x86-32/wrapper.conf | 1 + edexOsgi/build.edex/esb/bin/setup.env | 3 + edexOsgi/build.edex/esb/bin/wrapper.conf | 1 + .../plugin/satellite/SatelliteDecoder.java | 100 +-- .../satellite/dao/SatMapCoverageDao.java | 6 +- .../plugin/satellite/dao/SatelliteDao.java | 233 ++++++- .../util/satellite/SatSpatialFactory.java | 7 +- .../dataplugin/satellite/SatMapCoverage.java | 15 +- .../satellite/SatelliteMessageData.java | 98 ++- .../dataplugin/satellite/SatelliteRecord.java | 416 +++++++------ .../datastorage/hdf5/HDF5DataStore.java | 12 +- .../common/datastorage/DataStoreFactory.java | 211 +++++++ .../interpolation/data/ByteArrayWrapper.java | 116 ++++ .../com/raytheon/uf/common/util/FileUtil.java | 252 +++++++- .../uf/edex/database/plugin/PluginDao.java | 42 +- .../mcidas/McidasSatelliteDecoder.java | 203 ++++--- .../decoder/RegionalSatDecoder.java | 569 +++++++++--------- .../util/RegionalSatSpatialFactory.java | 9 +- 22 files changed, 1769 insertions(+), 727 deletions(-) create mode 100644 deltaScripts/goesr_deploy/convertSatURIs.py create mode 100644 edexOsgi/com.raytheon.uf.common.geospatial/src/com/raytheon/uf/common/geospatial/interpolation/data/ByteArrayWrapper.java diff --git a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/FileBasedTileSet.java b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/FileBasedTileSet.java index c12bcc09a8..afb1bd16a8 100644 --- a/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/FileBasedTileSet.java +++ b/cave/com.raytheon.viz.core/src/com/raytheon/viz/core/rsc/hdf5/FileBasedTileSet.java @@ -28,6 +28,7 @@ import org.apache.commons.collections.keyvalue.MultiKey; import org.geotools.coverage.grid.GridGeometry2D; import org.opengis.referencing.datum.PixelInCell; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.StorageException; import com.raytheon.uf.viz.core.IGraphicsTarget; import com.raytheon.uf.viz.core.data.IDataPreparer; @@ -53,7 +54,8 @@ import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Feb 15, 2007 chammack Initial Creation. - * + * - AWIPS2 Baseline Repository -------- + * Jul 18, 2012 798 jkorman Modified {@link #createTile} to remove hard-coded interpolation groups. * * * @author chammack @@ -97,7 +99,7 @@ public class FileBasedTileSet extends AbstractTileSet { this.dataset = dataset; } - /* + /** * (non-Javadoc) * * @see @@ -109,10 +111,10 @@ public class FileBasedTileSet extends AbstractTileSet { throws VizException { IImage raster = target.getExtension(IColormappedImageExtension.class) .initializeRaster( - new HDF5DataRetriever(new File(this.hdf5File), "/" - + this.group + "/" + this.dataset - + "-interpolated/" + level, this.tileSet - .getTile(level, i, j).getRectangle()), + new HDF5DataRetriever(new File(this.hdf5File), + DataStoreFactory.createDataSetName(group, + dataset, level), this.tileSet.getTile( + level, i, j).getRectangle()), rsc.getCapability(ColorMapCapability.class) .getColorMapParameters()); return raster; diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java index 1e24a137ab..bed5faa55d 100644 --- a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/data/prep/SatDataRetriever.java @@ -23,6 +23,7 @@ import java.awt.Rectangle; import java.nio.ByteBuffer; import com.raytheon.uf.common.dataplugin.PluginDataObject; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.Request; import com.raytheon.uf.common.datastorage.records.ByteDataRecord; import com.raytheon.uf.common.datastorage.records.IDataRecord; @@ -44,7 +45,8 @@ import com.raytheon.uf.viz.core.datastructure.VizDataCubeException; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Oct 28, 2009 mschenke Initial creation - * + * - AWIPS2 Baseline Repository -------- + * Jul 18, 2012 798 jkorman Modified constructor to remove hard-coded dataset name. * * * @author mschenke @@ -69,7 +71,9 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback { Rectangle dataSetBounds, boolean signed, ByteBuffer retreivedBuffer) { this.pdo = pdo; this.datasetBounds = dataSetBounds; - this.dataset = "Data" + "-interpolated/" + level; + + dataset = DataStoreFactory.createDataSetName(null, DataStoreFactory.DEF_DATASET_NAME, level); + this.signed = signed; this.retreivedBuffer = retreivedBuffer; } @@ -88,12 +92,7 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback { retreivedBuffer = null; } else { try { - byte[] data = getRawData(); - if (data != null) { - satBuffer = ByteBuffer.wrap(data); - } else { - System.out.println("Problem!"); - } + satBuffer = ByteBuffer.wrap(getRawData()); } catch (Exception e) { statusHandler.handle(Priority.SIGNIFICANT, "Error retrieving satellite data", e); @@ -108,6 +107,8 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback { } public byte[] getRawData() { + byte [] retData = null; + Request req = Request.buildSlab(new int[] { this.datasetBounds.x, this.datasetBounds.y }, new int[] { this.datasetBounds.x + this.datasetBounds.width, @@ -116,14 +117,14 @@ public class SatDataRetriever implements IColorMapDataRetrievalCallback { try { dataRecord = DataCubeContainer .getDataRecord(pdo, req, this.dataset); + if (dataRecord != null && dataRecord.length == 1) { + retData = ((ByteDataRecord) dataRecord[0]).getByteData(); + } } catch (VizDataCubeException e) { statusHandler.handle(Priority.SIGNIFICANT, "Error retrieving satellite data", e); } - if (dataRecord != null && dataRecord.length == 1) { - return ((ByteDataRecord) dataRecord[0]).getByteData(); - } - return null; + return retData; } /* diff --git a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java index b23f25a339..f8bbe023e4 100644 --- a/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java +++ b/cave/com.raytheon.viz.satellite/src/com/raytheon/viz/satellite/rsc/SatResource.java @@ -45,6 +45,7 @@ import com.raytheon.uf.common.dataplugin.satellite.units.counts.DerivedWVPixel; import com.raytheon.uf.common.dataplugin.satellite.units.generic.GenericPixel; import com.raytheon.uf.common.dataplugin.satellite.units.goes.PolarPrecipWaterPixel; import com.raytheon.uf.common.dataplugin.satellite.units.water.BlendedTPWPixel; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.geospatial.ISpatialObject; import com.raytheon.uf.common.geospatial.MapUtil; import com.raytheon.uf.common.geospatial.ReferencedCoordinate; @@ -94,7 +95,9 @@ import com.raytheon.viz.satellite.SatelliteConstants; * 03/25/2009 2086 jsanchez Mapped correct converter to parameter type. * Updated the call to ColormapParametersFactory.build * 03/30/2009 2169 jsanchez Updated numLevels handling. - * + * - AWIPS2 Baseline Repository -------- + * 07/17/2012 798 jkorman Use decimationLevels from SatelliteRecord. Removed hard-coded + * data set names. * * * @author chammack @@ -266,15 +269,8 @@ public class SatResource extends getCapability(ColorMapCapability.class).setColorMapParameters( colorMapParameters); - numLevels = 1; - int newSzX = record.getSpatialObject().getNx(); - int newSzY = record.getSpatialObject().getNy(); - while ((newSzX > 512 && newSzY > 512)) { - newSzX /= 2; - newSzY /= 2; - numLevels++; - } - + // number of interpolation levels plus the base level! + numLevels = record.getInterpolationLevels() + 1; } @Override @@ -490,13 +486,13 @@ public class SatResource extends } if (baseTile == null) { - tile = baseTile = new SatFileBasedTileSet(record, "Data", + tile = baseTile = new SatFileBasedTileSet(record, DataStoreFactory.DEF_DATASET_NAME, numLevels, 256, MapUtil.getGridGeometry(((SatelliteRecord) record) .getSpatialObject()), this, PixelInCell.CELL_CORNER, viewType); } else { - tile = new SatFileBasedTileSet(record, "Data", baseTile); + tile = new SatFileBasedTileSet(record, DataStoreFactory.DEF_DATASET_NAME, baseTile); } tile.addMeshCallback(this); tile.setMapDescriptor(this.descriptor); diff --git a/deltaScripts/goesr_deploy/convertSatURIs.py b/deltaScripts/goesr_deploy/convertSatURIs.py new file mode 100644 index 0000000000..ac6a6a79ac --- /dev/null +++ b/deltaScripts/goesr_deploy/convertSatURIs.py @@ -0,0 +1,143 @@ +#!/usr/bin/python +# +""" + Convert to append the coverageid to the satellite datauris, and + modify the associated satellite hdf5 group names to append the + coverageid. The new groups are added as an alias to the existing + datasets. + Date Ticket# Engineer Description + ------------ ---------- ----------- -------------------------- + 20120711 798 jkorman Initial Development +""" +from subprocess import Popen, PIPE +import sys +from time import time +import h5py + +POSTGRES_CMD = "psql -U awips -d metadata -t -q -A -c " +HDF5_LOC = "/awips2/edex/data/hdf5" +DATAURI_IDX = 1 +COVERAGE_IDX = 2 + +def update_satellite_table(): + """ + Add the interpolationLevels column to the satellite table. + """ + result = queryPostgres("select count(*) from information_schema.columns where table_name='satellite' and column_name='interpolationlevels';") + if(result[0][0] == '0'): + result = result = queryPostgres("alter table satellite add column interpolationlevels integer;") + print "Adding interpolationlevels column to satellite table" + +def formatFileTime(refTime): + """ + Extract and format the year (YYYY), month (MM), day (DD), and hour (HH) + from the reference time. The output is formatted as YYYY-MM-DD-HH + """ + return refTime[0:4] + "-" + refTime[5:7] + "-" + refTime[8:10] + "-" + refTime[11:13] + +def getFilename(refTime): + """ + Create the satellite data hdf filename corresponding to the given reference time. + """ + return "satellite-" + formatFileTime(refTime) + ".h5" + +def queryPostgres(sql): + """ + Extract and format the year (YYYY), month (MM), day (DD), and hour (HH) + from the reference time. The output is formatted as YYYY-MM-DD-HH + """ + result = Popen(POSTGRES_CMD + "\"" + sql + "\"", stdout=PIPE, shell=True) + retVal = [] + for line in result.stdout: + retVal.append(line.strip().split("|")) + return retVal + +def get_sectorids(): + """ + Get a list of unique sector identifiers from the satellite table. + """ + return queryPostgres("select distinct sectorid from satellite;") + +def get_satellite_rows(sectorid): + """ + Extract and format the year (YYYY), month (MM), day (DD), and hour (HH) + from the reference time. The output is formatted as YYYY-MM-DD-HH + """ + keys = {} + rows = queryPostgres("select id, dataURI, coverage_gid, sectorid, physicalelement, reftime from satellite where sectorid=" + repr(sectorid) + ";") + for row in rows: + # updateSql = "update satellite set datauri='" + row[DATAURI_IDX] + "/" + row[COVERAGE_IDX] + "' where id=" + row[0] + ";" + # queryPostgres(updateSql) + # create the key for this entry. + key = "/satellite/" + row[3] + "/" + row[4] + "/" + getFilename(row[5]) + # have we found this key already? + if(key in keys): + # if so, get the row list for this key + rowList = keys[key] + else: + # otherwise create an empty list to put the row in + rowList = [] + # add it to the collection + keys[key] = rowList + # and add the row to the list + rowList.append(row) + return keys + +def process_all_satellite(): + """ + Process all entries in the satellite table. + Do one sector id at a time. + """ + sectorids = get_sectorids() + if(sectorids): + for sectorid in sectorids: + print "Processing sector " + sectorid[0] + keys = get_satellite_rows(sectorid[0]) + if(keys): + for key in keys: + print "==========================================================" + print " Processing key = " + key + fname = HDF5_LOC + key + try: + f = h5py.File(fname,'r+') + for row in keys[key]: + newGroupName = row[DATAURI_IDX] + "/" + row[COVERAGE_IDX] + group = f.create_group(newGroupName) + group = f.create_group(newGroupName + "/Data-interpolated") + + oldds = row[DATAURI_IDX] + "/Data" + newds = newGroupName + "/Data" + # Link to the old data set + f[newds] = h5py.SoftLink(oldds) + + group = f[row[DATAURI_IDX] + "/Data-interpolated"] + numLevels = 1 + for n in group.keys(): + numLevels += 1 + newds = newGroupName + "/Data-interpolated/" + n + if (n == '0'): + # special case for this link. + # dataset /Data-interpolated/0 points to /Data + oldds = row[DATAURI_IDX] + "/Data" + else: + oldds = row[DATAURI_IDX] + "/Data-interpolated/" + n + f[newds] = h5py.SoftLink(oldds) + # now back up one for the Data,Data-interpolated/0 link + numLevels -= 1 + updateSql = "update satellite set datauri='" + row[DATAURI_IDX] + "/" + row[COVERAGE_IDX] + "'" + updateSql += ", interpolationlevels=" + repr(numLevels) + updateSql += " where id=" + row[0] + ";" + queryPostgres(updateSql) + f.close() + except: + print "Error occurred processing file " + fname + else: + print "No keys found for the sector id " + sectorid[0] + else: + print "No sector identifiers found in the satellite table" + +if __name__ == '__main__': + t = time() + update_satellite_table() + process_all_satellite() + print "Total Conversion time %ds" % (time() - t) diff --git a/edexOsgi/build.edex/esb/bin/linux-x86-32/wrapper.conf b/edexOsgi/build.edex/esb/bin/linux-x86-32/wrapper.conf index 99e6818f75..c9eff7aa67 100644 --- a/edexOsgi/build.edex/esb/bin/linux-x86-32/wrapper.conf +++ b/edexOsgi/build.edex/esb/bin/linux-x86-32/wrapper.conf @@ -23,3 +23,4 @@ # Java Library Path (location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=%EDEX_HOME%/bin/linux-x86-32/ + diff --git a/edexOsgi/build.edex/esb/bin/setup.env b/edexOsgi/build.edex/esb/bin/setup.env index ab51eefc0b..35f7a55d63 100644 --- a/edexOsgi/build.edex/esb/bin/setup.env +++ b/edexOsgi/build.edex/esb/bin/setup.env @@ -32,6 +32,9 @@ export RADAR_SERVER=tcp://localhost:8813 # set the AWIPS II shared directory export SHARE_DIR=/awips2/edex/data/share +# set the AWIPS II temporary directory +export TEMP_DIR=/awips2/edex/data/tmp + # set hydroapps directory path export apps_dir=${SHARE_DIR}/hydroapps # site identifier for hydroapps diff --git a/edexOsgi/build.edex/esb/bin/wrapper.conf b/edexOsgi/build.edex/esb/bin/wrapper.conf index ac62cf824c..125d07fa05 100644 --- a/edexOsgi/build.edex/esb/bin/wrapper.conf +++ b/edexOsgi/build.edex/esb/bin/wrapper.conf @@ -123,6 +123,7 @@ wrapper.java.additional.42=-Dweb.port=8080 wrapper.java.additional.43=-Dconfidential.port=8443 wrapper.java.additional.44=-Dhttp.port=%HTTP_PORT% wrapper.java.additional.45=-Dedex.arch=%EDEX_ARCH% +wrapper.java.additional.46=-Dedex.tmp=%TEMP_DIR% # Initial Java Heap Size (in MB) wrapper.java.initmemory=%INIT_MEM% diff --git a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/SatelliteDecoder.java b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/SatelliteDecoder.java index 00e8d8dbd1..c425c50b31 100644 --- a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/SatelliteDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/SatelliteDecoder.java @@ -38,7 +38,9 @@ import com.raytheon.edex.util.satellite.SatellitePosition; import com.raytheon.edex.util.satellite.SatelliteUnit; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.satellite.SatMapCoverage; +import com.raytheon.uf.common.dataplugin.satellite.SatelliteMessageData; import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; +import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.time.DataTime; import com.raytheon.uf.edex.decodertools.time.TimeTools; import com.raytheon.uf.edex.wmo.message.WMOHeader; @@ -50,7 +52,7 @@ import com.raytheon.uf.edex.wmo.message.WMOHeader; * * OFTWARE HISTORY * - * ate Ticket# Engineer Description + * Date Ticket# Engineer Description * ----------- ---------- ----------- -------------------------- * 006 garmenda Initial Creation * /14/2007 139 Phillippe Modified to follow refactored plugin pattern @@ -65,7 +67,8 @@ import com.raytheon.uf.edex.wmo.message.WMOHeader; * 02/05/2010 4120 jkorman Modified removeWmoHeader to handle WMOHeader in * various start locations. * 04/17/2012 14724 kshresth This is a temporary workaround - Projection off CONUS - * + * - AWIPS2 Baseline Repository -------- + * 06/27/2012 798 jkorman Using SatelliteMessageData to "carry" the decoded image. * * * @author bphillip @@ -242,10 +245,9 @@ public class SatelliteDecoder extends AbstractDecoder { SatellitePosition position = dao .getSatellitePosition(record.getCreatingEntity()); if (position == null) { - logger - .info("Unable to determine geostationary location of [" - + record.getCreatingEntity() - + "]. Zeroing out fields."); + logger.info("Unable to determine geostationary location of [" + + record.getCreatingEntity() + + "]. Zeroing out fields."); } else { record.setSatSubPointLat(position.getLatitude()); record.setSatSubPointLon(position.getLongitude()); @@ -265,7 +267,7 @@ public class SatelliteDecoder extends AbstractDecoder { /* * Rotate image if necessary */ - + // TODO: Can these numbers be an enum or constants? switch (scanMode) { case 1: Util.flipHoriz(tempBytes, ny, nx); @@ -280,8 +282,8 @@ public class SatelliteDecoder extends AbstractDecoder { default: break; } - - record.setMessageData(tempBytes); + SatelliteMessageData messageData = new SatelliteMessageData( + tempBytes, nx, ny); // get the latitude of the first point byteBuffer.position(20); @@ -315,7 +317,8 @@ public class SatelliteDecoder extends AbstractDecoder { float dx = 0.0f, dy = 0.0f, lov = 0.0f, lo2 = 0.0f, la2 = 0.0f; // Do specialized decoding and retrieve spatial data for Lambert // Conformal and Polar Stereographic projections - if ((mapProjection == 3) || (mapProjection == 5)) { + if ((mapProjection == SatMapCoverage.PROJ_LAMBERT) + || (mapProjection == SatMapCoverage.PROJ_POLAR_STEREO)) { byteBuffer.position(30); byteBuffer.get(threeBytesArray, 0, 3); dx = byteArrayToFloat(threeBytesArray) / 10; @@ -332,7 +335,7 @@ public class SatelliteDecoder extends AbstractDecoder { // Do specialized decoding and retrieve spatial data for // Mercator // projection - else if (mapProjection == 1) { + else if (mapProjection == SatMapCoverage.PROJ_MERCATOR) { dx = byteBuffer.getShort(33); dy = byteBuffer.getShort(35); @@ -352,31 +355,32 @@ public class SatelliteDecoder extends AbstractDecoder { SatMapCoverage mapCoverage = null; try { -/** - * This is a temporary workaround for DR14724, hopefully to be removed after NESDIS changes - * the product header - */ - if ((mapProjection == 3) - && (record.getPhysicalElement().equalsIgnoreCase("Imager 13 micron (IR)") ) - && (record.getSectorID().equalsIgnoreCase("West CONUS"))){ - nx = 1100; - ny = 1280; - dx = 4063.5f; - dy = 4063.5f; - la1 = 12.19f; - lo1 = -133.4588f; - } -/** - * End of DR14724 - */ + /** + * This is a temporary workaround for DR14724, hopefully to + * be removed after NESDIS changes the product header + */ + if ((mapProjection == SatMapCoverage.PROJ_LAMBERT) + && (record.getPhysicalElement() + .equalsIgnoreCase("Imager 13 micron (IR)")) + && (record.getSectorID() + .equalsIgnoreCase("West CONUS"))) { + nx = 1100; + ny = 1280; + dx = 4063.5f; + dy = 4063.5f; + la1 = 12.19f; + lo1 = -133.4588f; + } + /** + * End of DR14724 + */ mapCoverage = SatSpatialFactory.getInstance() .getMapCoverage(mapProjection, nx, ny, dx, dy, lov, latin, la1, lo1, la2, lo2); } catch (Exception e) { StringBuffer buf = new StringBuffer(); - buf - .append( - "Error getting or constructing SatMapCoverage for values: ") + buf.append( + "Error getting or constructing SatMapCoverage for values: ") .append("\n\t"); buf.append("mapProjection=" + mapProjection).append("\n\t"); buf.append("nx=" + nx).append("\n\t"); @@ -399,8 +403,11 @@ public class SatelliteDecoder extends AbstractDecoder { .getTime()); record.setPluginName("satellite"); record.constructDataURI(); + // Create the data record. + IDataRecord dataRec = messageData.getStorageRecord(record, + SatelliteRecord.SAT_DATASET_NAME); + record.setMessageData(dataRec); } - } } if (record == null) { @@ -435,26 +442,21 @@ public class SatelliteDecoder extends AbstractDecoder { } String msgStr = new String(message); Matcher matcher = null; - if (msgStr != null) { - matcher = Pattern.compile(WMOHeader.WMO_HEADER).matcher(msgStr); - if (matcher.find()) { - int headerStart = matcher.start(); - if (SAT_HDR_TT.equals(msgStr.substring(headerStart, - headerStart + 2))) { - int startOfSatellite = matcher.end(); - retMessage = new byte[messageData.length - startOfSatellite]; - System.arraycopy(messageData, startOfSatellite, retMessage, - 0, retMessage.length); - } else { - throw new DecoderException( - "First character of the WMO header must be 'T'"); - } + matcher = Pattern.compile(WMOHeader.WMO_HEADER).matcher(msgStr); + if (matcher.find()) { + int headerStart = matcher.start(); + if (SAT_HDR_TT.equals(msgStr + .substring(headerStart, headerStart + 2))) { + int startOfSatellite = matcher.end(); + retMessage = new byte[messageData.length - startOfSatellite]; + System.arraycopy(messageData, startOfSatellite, retMessage, 0, + retMessage.length); } else { - throw new DecoderException("Cannot decode an empty WMO header"); + throw new DecoderException( + "First character of the WMO header must be 'T'"); } } else { - throw new DecoderException( - "Could not create data for WMO header search"); + throw new DecoderException("Cannot decode an empty WMO header"); } return retMessage; diff --git a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatMapCoverageDao.java b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatMapCoverageDao.java index 0a8da339af..d846a3a309 100644 --- a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatMapCoverageDao.java +++ b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatMapCoverageDao.java @@ -40,6 +40,8 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 7/24/07 353 bphillip Initial Check in + * - AWIPS2 Baseline Repository -------- + * 06/27/2012 798 jkorman Corrected id query type. * * * @@ -64,7 +66,7 @@ public class SatMapCoverageDao extends CoreDao { * @return A SatelliteMapCoverage object with the corresponding ID. Null if * not found. */ - public SatMapCoverage queryByMapId(String mapId) { + public SatMapCoverage queryByMapId(Integer mapId) { return (SatMapCoverage) this.queryById(mapId); } @@ -152,7 +154,7 @@ public class SatMapCoverageDao extends CoreDao { query.addQueryParam("la1",la1); query.addQueryParam("lo1",lo1); - if (mapProjection == 1) { + if (mapProjection == SatMapCoverage.PROJ_MERCATOR) { query.addQueryParam("la2",la2); query.addQueryParam("lo2",lo2); } diff --git a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatelliteDao.java b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatelliteDao.java index 409f91a3af..a0d46e19de 100644 --- a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatelliteDao.java +++ b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/plugin/satellite/dao/SatelliteDao.java @@ -19,9 +19,13 @@ **/ package com.raytheon.edex.plugin.satellite.dao; +import java.awt.Rectangle; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; + +import org.opengis.referencing.operation.TransformException; import com.raytheon.edex.util.satellite.SatelliteCreatingEntity; import com.raytheon.edex.util.satellite.SatellitePhysicalElement; @@ -32,14 +36,23 @@ import com.raytheon.edex.util.satellite.SatelliteUnit; import com.raytheon.uf.common.dataplugin.PluginDataObject; import com.raytheon.uf.common.dataplugin.PluginException; import com.raytheon.uf.common.dataplugin.persist.IPersistable; +import com.raytheon.uf.common.dataplugin.satellite.SatMapCoverage; +import com.raytheon.uf.common.dataplugin.satellite.SatelliteMessageData; import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; import com.raytheon.uf.common.dataquery.db.QueryResult; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.datastorage.StorageException; import com.raytheon.uf.common.datastorage.StorageProperties; -import com.raytheon.uf.common.datastorage.records.AbstractStorageRecord; import com.raytheon.uf.common.datastorage.records.ByteDataRecord; import com.raytheon.uf.common.datastorage.records.IDataRecord; +import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +import com.raytheon.uf.common.geospatial.MapUtil; +import com.raytheon.uf.common.geospatial.interpolation.GridDownscaler; +import com.raytheon.uf.common.geospatial.interpolation.data.AbstractDataWrapper; +import com.raytheon.uf.common.geospatial.interpolation.data.ByteArrayWrapper; +import com.raytheon.uf.common.geospatial.interpolation.data.DataDestination; +import com.raytheon.uf.common.geospatial.interpolation.data.ShortArrayWrapper; import com.raytheon.uf.edex.core.dataplugin.PluginRegistry; import com.raytheon.uf.edex.database.DataAccessLayerException; import com.raytheon.uf.edex.database.plugin.PluginDao; @@ -55,7 +68,8 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Feb 11, 2009 bphillip Initial creation - * + * - AWIPS2 Baseline Repository -------- + * 07/09/2012 798 jkorman Modified datastore population. * * * @author bphillip @@ -99,31 +113,77 @@ public class SatelliteDao extends PluginDao { super(pluginName); } + /** + * Populated a given IDataStore object with the data record to be persisted. + * + * @param dataStore + * Storage object to be populated. + * @param record + * The persistable record containing the data to be persisted. + * @return The populated data storage object. + */ @Override protected IDataStore populateDataStore(IDataStore dataStore, IPersistable record) throws StorageException { SatelliteRecord satRecord = (SatelliteRecord) record; - AbstractStorageRecord storageRecord = null; - long nx = satRecord.getCoverage().getNx(); - long ny = satRecord.getCoverage().getNy(); + IDataRecord storageRecord = (IDataRecord) satRecord.getMessageData(); + if (storageRecord != null) { + StorageProperties props = new StorageProperties(); + String compression = PluginRegistry.getInstance() + .getRegisteredObject(pluginName).getCompression(); + if (compression != null) { + props.setCompression(StorageProperties.Compression + .valueOf(compression)); + } + props.setDownscaled(false); + storageRecord.setProperties(props); + storageRecord.setCorrelationObject(satRecord); + // Store the base record. + dataStore.addDataRecord(storageRecord); - long[] sizes = new long[] { nx, ny }; - storageRecord = new ByteDataRecord("Data", satRecord.getDataURI(), - (byte[]) satRecord.getMessageData(), 2, sizes); + Map attributes = storageRecord.getDataAttributes(); + + Float fillValue = getAttribute(attributes, + SatelliteRecord.SAT_FILL_VALUE, 0.0f); + + SatMapCoverage coverage = satRecord.getCoverage(); + GridDownscaler downScaler = createDownscaler(coverage, + storageRecord, fillValue); + + // How many interpolation levels do we need for this data? + // Subtract one for the base level data. + int levels = downScaler.getNumberOfDownscaleLevels() - 1; + // set the number of levels in the 'parent' satellite data. + satRecord.setInterpolationLevels(levels); + if (DataStoreFactory.isInterpolated(levels)) { + for (int downscaleLevel = 1; downscaleLevel <= levels; downscaleLevel++) { + Rectangle size = downScaler + .getDownscaleSize(downscaleLevel); + + AbstractDataWrapper dest = getDestination(storageRecord, + size); + dest.setFillValue(fillValue); + try { + downScaler.downscale(downscaleLevel, dest); + + IDataRecord dr = createDataRecord(satRecord, dest, + downscaleLevel, size); + // Set the attributes and properties from the parent + // data. + dr.setDataAttributes(attributes); + dr.setProperties(props); + dataStore.addDataRecord(dr); + + } catch (TransformException e) { + throw new StorageException( + "Error creating downscaled data", + storageRecord, e); + } + } + } - StorageProperties props = new StorageProperties(); - String compression = PluginRegistry.getInstance() - .getRegisteredObject(pluginName).getCompression(); - if (compression != null) { - props.setCompression(StorageProperties.Compression - .valueOf(compression)); } - props.setDownscaled(true); - - storageRecord.setProperties(props); - storageRecord.setCorrelationObject(satRecord); - dataStore.addDataRecord(storageRecord); return dataStore; } @@ -166,12 +226,13 @@ public class SatelliteDao extends PluginDao { query.addQueryParam("dataTime.refTime", theDate); query.addOrder("dataTime.refTime", true); try { - PluginDataObject[] pdos = this.getFullRecord(query, -1); + PluginDataObject[] pdos = this.getFullRecord(query, 0); for (int i = 0; i < pdos.length; i++) { satRecords.add((SatelliteRecord) pdos[i]); - satRecords.get(i).setMessageData( - (ByteDataRecord) ((IDataRecord[]) satRecords.get(i) - .getMessageData())[0]); + satRecords.get(i) + .setMessageData( + ((IDataRecord[]) satRecords.get(i) + .getMessageData())[0]); } } catch (Exception e) { throw new DataAccessLayerException( @@ -328,4 +389,130 @@ public class SatelliteDao extends PluginDao { this.positionDao = positionDao; } + /** + * Create an {@link AbstractDataWrapper} destination from the supplied + * {@link IDataRecord} with given dimensions. + * + * @param rec + * The record containing data to be wrapped. + * @param size + * A {@link Rectangle} containing the size of the input data. + * @return The wrapped data. + */ + private AbstractDataWrapper getDestination(IDataRecord rec, Rectangle size) { + AbstractDataWrapper dest = null; + + if (rec instanceof ByteDataRecord) { + dest = new ByteArrayWrapper(size.width, size.height); + } else if (rec instanceof ShortDataRecord) { + dest = new ShortArrayWrapper(size.width, size.height); + } + return dest; + } + + /** + * Create an {@link AbstractDataWrapper} source from the supplied + * {@link IDataRecord} with given dimensions. + * + * @param rec + * The record containing data to be wrapped. + * @param nx + * Number of items on the x axis. + * @param ny + * Number of items on the y axis. + * @return The wrapped data. + */ + private AbstractDataWrapper getSource(IDataRecord rec, int nx, int ny) { + AbstractDataWrapper source = null; + + if (rec instanceof ByteDataRecord) { + byte[] b = ((ByteDataRecord) rec).getByteData(); + source = new ByteArrayWrapper(b, nx, ny); + } else if (rec instanceof ShortDataRecord) { + short[] s = ((ShortDataRecord) rec).getShortData(); + source = new ShortArrayWrapper(s, nx, ny); + } + return source; + } + + /** + * Create the {@link IDataRecord} from the {@link DataDestination} using the + * original satellite data, size and + * + * @param satRec + * The original satellite data record. + * @param data + * The down-scaled data. + * @param downscaledLevel + * The level identifier for this data. + * @param size + * Size of the down-scaled data. + * @return The created data record to be stored. + */ + private IDataRecord createDataRecord(SatelliteRecord satRec, + DataDestination data, int downscaleLevel, Rectangle size) { + SatelliteMessageData msgData = null; + Object o = null; + if (data instanceof ByteArrayWrapper) { + o = ((ByteArrayWrapper) data).getArray(); + } else if (data instanceof ShortArrayWrapper) { + o = ((ShortArrayWrapper) data).getArray(); + } + if (o != null) { + msgData = new SatelliteMessageData(o, size.width, size.height); + } + IDataRecord rec = msgData.getStorageRecord(satRec, + String.valueOf(downscaleLevel)); + rec.setCorrelationObject(satRec); + rec.setGroup(DataStoreFactory.createGroupName(satRec.getDataURI(), + SatelliteRecord.SAT_DATASET_NAME, true)); + + return rec; + } + + /** + * Create a down scaler for the given data. + * + * @param coverage + * Satellite Map Coverage for the source data. + * @param rec + * The original data that will be down-scaled. + * @param fillValue + * The declared fill value for the data. + * @return + */ + private GridDownscaler createDownscaler(SatMapCoverage coverage, + IDataRecord rec, double fillValue) { + GridDownscaler downScaler = null; + + AbstractDataWrapper dataSource = getSource(rec, coverage.getNx(), + coverage.getNy()); + dataSource.setFillValue(fillValue); + + downScaler = new GridDownscaler(MapUtil.getGridGeometry(coverage), + dataSource); + + return downScaler; + } + + /** + * Get the value of an named attribute. + * + * @param attrs + * Attributes that contain the value. + * @param attrName + * Name of the attribute. + * @param defValue + * A default value. + * @return + */ + public static Float getAttribute(Map attrs, + String attrName, Float defValue) { + Float retValue = defValue; + if ((attrs != null) && (attrName != null)) { + retValue = (Float) attrs.get(attrName); + } + return retValue; + } + } diff --git a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/util/satellite/SatSpatialFactory.java b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/util/satellite/SatSpatialFactory.java index 4be3118c80..35c69076c6 100644 --- a/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/util/satellite/SatSpatialFactory.java +++ b/edexOsgi/com.raytheon.edex.plugin.satellite/src/com/raytheon/edex/util/satellite/SatSpatialFactory.java @@ -42,7 +42,8 @@ import com.vividsolutions.jts.io.WKTReader; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 12/19/07 439 bphillip Initial creation - * + * - AWIPS2 Baseline Repository -------- + * 07/12/2012 798 jkorman Changed projection "magic" numbers * * */ @@ -172,7 +173,7 @@ public class SatSpatialFactory { ProjectedCRS crs = null; // Get the correct CRS - if (mapProjection == 1) { + if (mapProjection == SatMapCoverage.PROJ_MERCATOR) { double cm = 0.0; if ((lo1 > 0.0) && (lo2 < 0.0)) { cm = 180.0; @@ -200,7 +201,7 @@ public class SatSpatialFactory { * Projection is Mercator. Determine corner points from la1,lo1,la2,lo2 * provided in the satellite file */ - if (mapProjection == 1) { + if (mapProjection == SatMapCoverage.PROJ_MERCATOR) { logger.debug("Determining corner points for Mercator projection"); corner1.x = lo1; corner1.y = la1; diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatMapCoverage.java b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatMapCoverage.java index 13649cc886..70297b4327 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatMapCoverage.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatMapCoverage.java @@ -21,6 +21,7 @@ package com.raytheon.uf.common.dataplugin.satellite; import javax.persistence.Column; +import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @@ -35,6 +36,7 @@ import org.hibernate.annotations.Type; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import com.raytheon.uf.common.dataplugin.annotations.DataURI; import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject; import com.raytheon.uf.common.geospatial.CRSCache; import com.raytheon.uf.common.geospatial.ISpatialObject; @@ -57,7 +59,8 @@ import com.vividsolutions.jts.geom.Polygon; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * 7/24/07 353 bphillip Initial Checkin - * + * - AWIPS2 Baseline Repository -------- + * 07/12/2012 798 jkorman Changed projection "magic" numbers * * */ @@ -65,13 +68,23 @@ import com.vividsolutions.jts.geom.Polygon; @Table(name = "satellite_spatial") @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize +@Embeddable public class SatMapCoverage extends PersistableDataObject implements ISpatialObject { private static final long serialVersionUID = 1L; + public static final int PROJ_MERCATOR = 1; + + public static final int PROJ_LAMBERT = 3; + + public static final int PROJ_POLAR_STEREO = 5; + + public static final int PROJ_CYLIN_EQUIDISTANT = 7; + @Id @DynamicSerializeElement + @DataURI(position = 0) private int gid; /** diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteMessageData.java b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteMessageData.java index eaae9f3960..a3b4da3016 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteMessageData.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteMessageData.java @@ -26,9 +26,13 @@ import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; import com.raytheon.uf.common.datastorage.records.ByteDataRecord; import com.raytheon.uf.common.datastorage.records.IDataRecord; import com.raytheon.uf.common.datastorage.records.ShortDataRecord; +import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; +import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; /** - * TODO Add Description + * Encapsulate satellite image data as well as the dimensions of + * the image grid. Attributes about the data may also be added. As an + * example these attributes could include "scale factor" and/or "fill_value". * *
  * 
@@ -36,31 +40,39 @@ import com.raytheon.uf.common.datastorage.records.ShortDataRecord;
  * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Jun 27, 2012            jkorman     Initial creation
+ * Jun 27, 2012        798     jkorman Initial creation
  * 
  * 
* * @author jkorman * @version 1.0 */ - +@DynamicSerialize public class SatelliteMessageData { private static final int DATA_DIMS = 2; + // Number of columns in the image data + @DynamicSerializeElement private int nx; + // Number of rows in the image data + @DynamicSerializeElement private int ny; + // The image grid data - Usually some type (T []) + @DynamicSerializeElement private Object messageData; + @DynamicSerializeElement private Map dataAttributes; /** - * - * @param messageData - * @param numCols - * @param numRows + * Create a message object containing the gridded image data as well as + * its dimensions. + * @param messageData The image grid data - Usually some type (T []) + * @param numCols Number of columns in the image grid. + * @param numRows Number of rows in the image grid. */ public SatelliteMessageData(Object messageData, int numCols, int numRows) { this.messageData = messageData; @@ -69,7 +81,8 @@ public class SatelliteMessageData { } /** - * + * Set the gridded image data. + * @param data The image grid data - Usually some type (T []) * @see com.raytheon.uf.common.dataplugin.satellite.SatelliteMessageData#setMessageData(java.lang.Object) */ public void setMessageData(Object data) { @@ -77,7 +90,9 @@ public class SatelliteMessageData { } /** - * + * Set an attribute associated with the image data. + * @param key Name to store the information against. + * @param value The value to store against the given key. */ public void setDataAttribute(String key, Object value) { if (dataAttributes == null) { @@ -87,7 +102,9 @@ public class SatelliteMessageData { } /** - * + * Set the dimensions of the data. + * @param nx Number of columns in the image grid. + * @param ny Number of rows in the image grid. * @see com.raytheon.uf.common.dataplugin.satellite.SatelliteMessageData#setDimensions(int, * int) */ @@ -97,7 +114,11 @@ public class SatelliteMessageData { } /** - * + * Create a data record that encapsulates the data in this class. + * @param dataRec A satellite record that will supply the information needed to + * populate the data record being built. + * @param dataSetName The name that will be used to identify the data set. + * @return The created data record. * @see com.raytheon.uf.common.dataplugin.satellite.SatelliteMessageData#getStorageRecord() */ public IDataRecord getStorageRecord(SatelliteRecord dataRec, String dataSetName) { @@ -120,4 +141,59 @@ public class SatelliteMessageData { return storageRecord; } + /** + * Get the number of columns in the image grid. + * @return The number of columns in the image grid. + */ + public int getNx() { + return nx; + } + + /** + * Set the number of columns in the image grid. + * @param nx Number of columns in the image grid. + */ + public void setNx(int nx) { + this.nx = nx; + } + + /** + * Get the number of rows in the image grid. + * @return The number of rows in the image grid. + */ + public int getNy() { + return ny; + } + + /** + * Set the number of rows in the image grid. + * @param ny Number of rows in the image grid. + */ + public void setNy(int ny) { + this.ny = ny; + } + + /** + * Get the data attributes. + * @return The data attributes. + */ + public Map getDataAttributes() { + return dataAttributes; + } + + /** + * Set the data attributes. + * @param dataAttributes The data attributes. + */ + public void setDataAttributes(Map dataAttributes) { + this.dataAttributes = dataAttributes; + } + + /** + * Get the underlying message data object. + * @return The underlying message data object. + */ + public Object getMessageData() { + return messageData; + } } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteRecord.java b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteRecord.java index cf8f78850e..f8fbc6cce9 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteRecord.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.satellite/src/com/raytheon/uf/common/dataplugin/satellite/SatelliteRecord.java @@ -35,6 +35,7 @@ import javax.xml.bind.annotation.XmlRootElement; import com.raytheon.uf.common.dataplugin.IDecoderGettable; import com.raytheon.uf.common.dataplugin.annotations.DataURI; import com.raytheon.uf.common.dataplugin.persist.ServerSpecificPersistablePluginDataObject; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.geospatial.ISpatialEnabled; import com.raytheon.uf.common.serialization.annotations.DynamicSerialize; import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @@ -65,239 +66,276 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @XmlAccessorType(XmlAccessType.NONE) @DynamicSerialize public class SatelliteRecord extends ServerSpecificPersistablePluginDataObject - implements ISpatialEnabled { + implements ISpatialEnabled { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /** - * The source of the data - NESDIS - */ - @Column(length = 31) - @DataURI(position = 1) - @XmlAttribute - @DynamicSerializeElement - private String source; + public static final String SAT_DATASET_NAME = DataStoreFactory.DEF_DATASET_NAME; + + public static final String SAT_FILL_VALUE = "FILL_VALUE"; - /** The creating entity. See table 4.5 of GINI satellite ICD */ - @Column(length = 63) - @DataURI(position = 2) - @XmlAttribute - @DynamicSerializeElement - private String creatingEntity; + public static final String SAT_ADD_OFFSET = "ADD_OFFSET"; - /** The sector ID. See table 4.6 of the GINI satellite ICD */ - @Column(length = 63) - @DataURI(position = 3) - @XmlAttribute - @DynamicSerializeElement - private String sectorID; + public static final String SAT_SCALE_FACTOR = "SCALE_FACTOR"; - /** The physical Element. See table 4.7 of the GINI satellite ICD */ - @Column(length = 63) - @DataURI(position = 4) - @XmlAttribute - @DynamicSerializeElement - private String physicalElement; + /** + * The source of the data - NESDIS + */ + @Column(length = 31) + @DataURI(position = 1) + @XmlAttribute + @DynamicSerializeElement + private String source; - /** - * Number of logical records in the product. See tables 4.9, 4.11, 4.12, - * 4.13, 4.14, 4.16 of the GINI satellite ICD - */ - @Column - @XmlAttribute - @DynamicSerializeElement - private Integer numRecords; + /** The creating entity. See table 4.5 of GINI satellite ICD */ + @Column(length = 63) + @DataURI(position = 2) + @XmlAttribute + @DynamicSerializeElement + private String creatingEntity; - /** - * Size of logical records in bytes for product. See tables 4.9, 4.11, 4.12, - * 4.13, 4.14, 4.16 of the GINI satellite ICD - */ - @Column - @XmlAttribute - @DynamicSerializeElement - private Integer sizeRecords; + /** The sector ID. See table 4.6 of the GINI satellite ICD */ + @Column(length = 63) + @DataURI(position = 3) + @XmlAttribute + @DynamicSerializeElement + private String sectorID; - /** The latitude directly beneath the satellite */ - @Column - @DynamicSerializeElement - private Float satSubPointLat; + /** The physical Element. See table 4.7 of the GINI satellite ICD */ + @Column(length = 63) + @DataURI(position = 4) + @XmlAttribute + @DynamicSerializeElement + private String physicalElement; - /** The longitude directly beneath the satellite */ - @Column - @DynamicSerializeElement - private Float satSubPointLon; + /** + * Number of logical records in the product. See tables 4.9, 4.11, 4.12, + * 4.13, 4.14, 4.16 of the GINI satellite ICD + */ + @Column + @XmlAttribute + @DynamicSerializeElement + private Integer numRecords; - /** The upper right hand latitude */ - @Column - @DynamicSerializeElement - private Float upperRightLat; + /** + * Size of logical records in bytes for product. See tables 4.9, 4.11, 4.12, + * 4.13, 4.14, 4.16 of the GINI satellite ICD + */ + @Column + @XmlAttribute + @DynamicSerializeElement + private Integer sizeRecords; - /** The upper right hand longitude */ - @Column - @DynamicSerializeElement - private Float upperRightLon; + /** The latitude directly beneath the satellite */ + @Column + @DynamicSerializeElement + private Float satSubPointLat; - /** Height of the satellite in km */ - @Column - @DynamicSerializeElement - private Integer satHeight; + /** The longitude directly beneath the satellite */ + @Column + @DynamicSerializeElement + private Float satSubPointLon; - /** Units of the satellite data * */ - @Column(length = 26) - @XmlAttribute - @DynamicSerializeElement - private String units; + /** The upper right hand latitude */ + @Column + @DynamicSerializeElement + private Float upperRightLat; - @ManyToOne - @PrimaryKeyJoinColumn - @XmlElement - @DynamicSerializeElement - private SatMapCoverage coverage; + /** The upper right hand longitude */ + @Column + @DynamicSerializeElement + private Float upperRightLon; - @Override - public SatMapCoverage getSpatialObject() { - return coverage; - } + /** Height of the satellite in km */ + @Column + @DynamicSerializeElement + private Integer satHeight; - public SatMapCoverage getCoverage() { - return coverage; - } + /** Units of the satellite data * */ + @Column(length = 26) + @XmlAttribute + @DynamicSerializeElement + private String units; - public void setCoverage(SatMapCoverage coverage) { - this.coverage = coverage; - } + /** Number of interpolation levels in the data store */ + @Column + @XmlAttribute + @DynamicSerializeElement + private Integer interpolationLevels; + + @DataURI(position = 5, embedded=true) + @ManyToOne + @PrimaryKeyJoinColumn + @XmlElement + @DynamicSerializeElement + private SatMapCoverage coverage; - public Float getSatSubPointLat() { - return satSubPointLat; - } + @Override + public SatMapCoverage getSpatialObject() { + return coverage; + } - public void setSatSubPointLat(Float satSubPointLat) { - this.satSubPointLat = satSubPointLat; - } + public SatMapCoverage getCoverage() { + return coverage; + } - public Float getSatSubPointLon() { - return satSubPointLon; - } + public void setCoverage(SatMapCoverage coverage) { + this.coverage = coverage; + } - public void setSatSubPointLon(Float satSubPointLon) { - this.satSubPointLon = satSubPointLon; - } + public Float getSatSubPointLat() { + return satSubPointLat; + } - public Float getUpperRightLat() { - return upperRightLat; - } + public void setSatSubPointLat(Float satSubPointLat) { + this.satSubPointLat = satSubPointLat; + } - public void setUpperRightLat(Float upperRightLat) { - this.upperRightLat = upperRightLat; - } + public Float getSatSubPointLon() { + return satSubPointLon; + } - public Float getUpperRightLon() { - return upperRightLon; - } + public void setSatSubPointLon(Float satSubPointLon) { + this.satSubPointLon = satSubPointLon; + } - public void setUpperRightLon(Float upperRightLon) { - this.upperRightLon = upperRightLon; - } + public Float getUpperRightLat() { + return upperRightLat; + } - /** - * No-arg constructor. - */ - public SatelliteRecord() { + public void setUpperRightLat(Float upperRightLat) { + this.upperRightLat = upperRightLat; + } - } + public Float getUpperRightLon() { + return upperRightLon; + } - /** - * Constructs a satellite record from a dataURI - * - * @param uri - * The dataURI - * @param tableDef - * The table definition associated with this class - */ - public SatelliteRecord(String uri) { - super(uri); - } + public void setUpperRightLon(Float upperRightLon) { + this.upperRightLon = upperRightLon; + } - public Integer getNumRecords() { - return numRecords; - } + /** + * No-arg constructor. + */ + public SatelliteRecord() { - public void setNumRecords(Integer numRecords) { - this.numRecords = numRecords; - } + } - public Integer getSizeRecords() { - return sizeRecords; - } + /** + * Constructs a satellite record from a dataURI + * + * @param uri + * The dataURI + * @param tableDef + * The table definition associated with this class + */ + public SatelliteRecord(String uri) { + super(uri); + } - public void setSizeRecords(Integer sizeRecords) { - this.sizeRecords = sizeRecords; - } + public Integer getNumRecords() { + return numRecords; + } - public Integer getSatHeight() { - return satHeight; - } + public void setNumRecords(Integer numRecords) { + this.numRecords = numRecords; + } - public void setSatHeight(Integer satHeight) { - this.satHeight = satHeight; - } + public Integer getSizeRecords() { + return sizeRecords; + } - /** - * @return the units - */ - public String getUnits() { - return units; - } + public void setSizeRecords(Integer sizeRecords) { + this.sizeRecords = sizeRecords; + } - /** - * @param units - * the units to set - */ - public void setUnits(String units) { - this.units = units; - } + public Integer getSatHeight() { + return satHeight; + } - /** - * Get the IDecoderGettable reference for this record. - * - * @return The IDecoderGettable reference for this record. Null for this - * class. - */ - @Override - public IDecoderGettable getDecoderGettable() { - return null; - } + public void setSatHeight(Integer satHeight) { + this.satHeight = satHeight; + } - public String getSource() { - return source; - } + /** + * @return the units + */ + public String getUnits() { + return units; + } - public void setSource(String source) { - this.source = source; - } + /** + * @param units + * the units to set + */ + public void setUnits(String units) { + this.units = units; + } - public String getCreatingEntity() { - return creatingEntity; - } + /** + * Get the IDecoderGettable reference for this record. + * + * @return The IDecoderGettable reference for this record. Null for this + * class. + */ + @Override + public IDecoderGettable getDecoderGettable() { + return null; + } - public void setCreatingEntity(String creatingEntity) { - this.creatingEntity = creatingEntity; - } + public String getSource() { + return source; + } - public String getSectorID() { - return sectorID; - } + public void setSource(String source) { + this.source = source; + } - public void setSectorID(String sectorID) { - this.sectorID = sectorID; - } + public String getCreatingEntity() { + return creatingEntity; + } - public String getPhysicalElement() { - return physicalElement; - } + public void setCreatingEntity(String creatingEntity) { + this.creatingEntity = creatingEntity; + } - public void setPhysicalElement(String physicalElement) { - this.physicalElement = physicalElement; - } + public String getSectorID() { + return sectorID; + } + public void setSectorID(String sectorID) { + this.sectorID = sectorID; + } + + public String getPhysicalElement() { + return physicalElement; + } + + public void setPhysicalElement(String physicalElement) { + this.physicalElement = physicalElement; + } + + /** + * Get the number of interpolation levels in the data store. + * @return The number of interpolation levels. Data that is not interpolated + * should return a value of 0. + */ + public Integer getInterpolationLevels() { + return interpolationLevels; + } + + /** + * Set the number of interpolation levels in the data store. If the data + * are not interpolated a value of 0 should be used. + * @param levels The number of interpolation levels in the data. Any value less than + * zero is set to zero. + */ + public void setInterpolationLevels(Integer levels) { + if(!DataStoreFactory.isInterpolated(levels)) { + levels = 0; + } + interpolationLevels = levels; + } + } diff --git a/edexOsgi/com.raytheon.uf.common.datastorage.hdf5/src/com/raytheon/uf/common/datastorage/hdf5/HDF5DataStore.java b/edexOsgi/com.raytheon.uf.common.datastorage.hdf5/src/com/raytheon/uf/common/datastorage/hdf5/HDF5DataStore.java index 79312bce50..92d377be28 100644 --- a/edexOsgi/com.raytheon.uf.common.datastorage.hdf5/src/com/raytheon/uf/common/datastorage/hdf5/HDF5DataStore.java +++ b/edexOsgi/com.raytheon.uf.common.datastorage.hdf5/src/com/raytheon/uf/common/datastorage/hdf5/HDF5DataStore.java @@ -58,6 +58,7 @@ import ncsa.hdf.hdf5lib.exceptions.HDF5Exception; import ncsa.hdf.hdf5lib.exceptions.HDF5LibraryException; import ncsa.hdf.hdf5lib.exceptions.HDF5SymbolTableException; +import com.raytheon.uf.common.datastorage.DataStoreFactory; import com.raytheon.uf.common.datastorage.DuplicateRecordStorageException; import com.raytheon.uf.common.datastorage.IDataStore; import com.raytheon.uf.common.datastorage.Request; @@ -90,6 +91,8 @@ import com.raytheon.uf.common.util.FileUtil; * Sep 25, 2007 chammack Added replace record functionality * Apr 01, 2008 1041 chammack Added delete functionality * Jun 30, 2008 2538 jsanchez Update readProperties for Strings. + * - AWIPS2 Baseline Repository -------- + * Jul 18, 2012 798 jkorman Removed some hard-coded interpolation code/constants. * * * @author chammack @@ -438,7 +441,7 @@ public class HDF5DataStore implements IDataStore { String[] datasets = getDatasets(group); for (String ds : datasets) { - if (includeInterpolated && ds.endsWith("-interpolated")) { + if (includeInterpolated && ds.endsWith(DataStoreFactory.DEF_INTERPOLATED_GROUP)) { IDataRecord[] subresults; subresults = this.retrieve(group + "/" + ds, false); @@ -447,7 +450,7 @@ public class HDF5DataStore implements IDataStore { records.add(result); } } - } else if (!ds.endsWith("-interpolated")) { + } else if (!ds.endsWith(DataStoreFactory.DEF_INTERPOLATED_GROUP)) { IDataRecord record = this.retrieve(group, ds, Request.ALL); records.add(record); } @@ -1626,9 +1629,8 @@ public class HDF5DataStore implements IDataStore { .getData()); } - rec.setName("" + level); - rec.setGroup(originalGroup + "/" + originalDatasetName - + "-interpolated"); + rec.setName(String.valueOf(level)); + rec.setGroup(DataStoreFactory.createGroupName(originalGroup, originalDatasetName, true)); rec.setSizes(new long[] { w / 2, h / 2 }); diff --git a/edexOsgi/com.raytheon.uf.common.datastorage/src/com/raytheon/uf/common/datastorage/DataStoreFactory.java b/edexOsgi/com.raytheon.uf.common.datastorage/src/com/raytheon/uf/common/datastorage/DataStoreFactory.java index f5861f7747..8f4021cbf3 100644 --- a/edexOsgi/com.raytheon.uf.common.datastorage/src/com/raytheon/uf/common/datastorage/DataStoreFactory.java +++ b/edexOsgi/com.raytheon.uf.common.datastorage/src/com/raytheon/uf/common/datastorage/DataStoreFactory.java @@ -43,6 +43,9 @@ import com.raytheon.uf.common.datastorage.records.StringDataRecord; * Feb 12, 2007 chammack Initial Creation. * 20070914 379 jkorman Added createStorageRecord factory methods. * Refactored from HDFDataStore. + * - AWIPS2 Baseline Repository -------- + * Jul 18, 2012 798 jkorman Extracted methods {@link #createDataSetName}, {@link #createGroupName}, and + * {@link #isInterpolated} from various classes. * * * @author chammack @@ -50,6 +53,28 @@ import com.raytheon.uf.common.datastorage.records.StringDataRecord; */ public class DataStoreFactory { + /** + * Default data set name; {@value #DEF_DATASET_NAME}. + */ + public static final String DEF_DATASET_NAME = "Data"; + + /** + * Default interpolation suffix ({@value #DEF_INTERPOLATED_GROUP}) for + * interpolated groups. + */ + public static final String DEF_INTERPOLATED_GROUP = "-interpolated"; + + /** + * Default group element separator; {@value #DEF_SEPARATOR}. + */ + public static final String DEF_SEPARATOR = "/"; + + /** + * Base interpolation level. Any interpolation level greater than this value + * ({@value #BASE_LEVEL}) is considered to be a valid interpolation level. + */ + public static final int BASE_LEVEL = 0; + private static final DataStoreFactory instance = new DataStoreFactory(); private IDataStoreFactory underlyingFactory; @@ -160,4 +185,190 @@ public class DataStoreFactory { return record; } + /** + * Create a storage dataset name using the group and data set name and an + * interpolation level. Any interpolation level less than or equal to zero + * generates the base dataset name with no interpolation. Any interpolation + * levels greater than zero are considered to be decimated levels of the + * original data. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
base groupdatasetinterpolationresult
nullnull-1/Data
nullnull0/Data
nullnull4/Data-interpolated/4
/data/groupnull0/data/group/Data
/data/groupnull3/data/group/Data-interpolated/3
/data/groupdsname-1/data/group/dsname
/data/groupdsname2/data/group/dsname-interpolated/2
+ * + * @param groupName + * The group name this data set belongs to. If null, an empty + * group name is generated. + * @param baseDataSet + * Data set name The dataset name. This name and the + * {@link DEF_INTERPOLATED_GROUP} are used to create the + * interpolated suffix for the group name. If null and + * interpolation is requested, a default value + * {@link DEF_DATASET_NAME} will be used. + * @param interpolatedLevel + * The interpolation level data set numeric identifier. + * @return The generated fully qualified dataset name. + */ + public static String createDataSetName(String groupName, + String baseDataSet, int interpolatedLevel) { + boolean interpolated = isInterpolated(interpolatedLevel); + StringBuilder interpolatedGroup = new StringBuilder(createGroupName( + groupName, baseDataSet, interpolated)); + + interpolatedGroup.append(DEF_SEPARATOR); + if (interpolated) { + interpolatedGroup.append(String.valueOf(interpolatedLevel)); + } else { + if (baseDataSet != null) { + interpolatedGroup.append(baseDataSet); + } else { + interpolatedGroup.append(DEF_DATASET_NAME); + } + } + return interpolatedGroup.toString(); + } + + /** + * Create a hierarchical group name, given a base group name, a dataset name + * and if interpolated levels are being created. If interpolation is not + * requested then the base group name is returned unchanged or if null an + * empty string is returned. When interpolation is requested, the dataset + * name is appended with an interpolation identifer to create an + * interpolation level group name. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
base groupdatasetinterpolationresult
nullnullfalsezero length string
nullnulltrue/Data-interpolated
/data/groupnullfalse/data/group
/data/groupnulltrue/data/group/Data-interpolated
/data/groupdsnamefalse/data/group
/data/groupdsnametrue/data/group/dsname-interpolated
+ * + * @param groupName + * The base group name. + * @param baseDataSet + * Data set name The dataset name. This name and the + * {@link #DEF_INTERPOLATED_GROUP} are used to create the + * interpolated suffix for the group name. If null and + * interpolation is requested, a default value + * {@link #DEF_DATASET_NAME} will be used. + * @param interpolatedLevel + * Create an interpolated group name. + * @return The generated group name. + */ + public static String createGroupName(String groupName, String baseDataSet, + boolean interpolated) { + StringBuilder interpolatedGroup = new StringBuilder(); + if (groupName != null) { + interpolatedGroup.append(groupName); + } + if (interpolated) { + interpolatedGroup.append(DEF_SEPARATOR); + if (baseDataSet != null) { + if (baseDataSet.length() > BASE_LEVEL) { + interpolatedGroup.append(baseDataSet); + } else { + interpolatedGroup.append(DEF_DATASET_NAME); + } + } else { + interpolatedGroup.append(DEF_DATASET_NAME); + } + interpolatedGroup.append(DEF_INTERPOLATED_GROUP); + } + return interpolatedGroup.toString(); + } + + /** + * Is the specified interpolation greater than the {@link BASE_LEVEL}? + * + * @param interpolatedLevel + * An interpolation level. + * @return + */ + public static boolean isInterpolated(int interpolatedLevel) { + return (interpolatedLevel > BASE_LEVEL); + } } diff --git a/edexOsgi/com.raytheon.uf.common.geospatial/src/com/raytheon/uf/common/geospatial/interpolation/data/ByteArrayWrapper.java b/edexOsgi/com.raytheon.uf.common.geospatial/src/com/raytheon/uf/common/geospatial/interpolation/data/ByteArrayWrapper.java new file mode 100644 index 0000000000..6fa57e1541 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.geospatial/src/com/raytheon/uf/common/geospatial/interpolation/data/ByteArrayWrapper.java @@ -0,0 +1,116 @@ +/** + * 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.geospatial.interpolation.data; + +import org.geotools.coverage.grid.GeneralGridGeometry; + +/** + * {@link AbstractDataWrapper} implementation for byte array data. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 13, 2012            jkorman     Initial creation
+ * 
+ * 
+ * + * @author jkorman + * @version 1.0 + */ + +public class ByteArrayWrapper extends DataWrapper1D { + + // The wrapped byte array data. + protected final byte[] array; + + /** + * Wrap a byte array using a specified geometry. + * @param array Byte array data to be wrapped. + * @param geometry A {@link GeneralGridGeometry} that will be used to discover + * the shape of the input data. + */ + public ByteArrayWrapper(byte[] array, GeneralGridGeometry geometry) { + super(geometry); + this.array = array; + } + + /** + * Wrap a byte array using given x and y axis dimensions. + * @param array Byte array data to be wrapped. + * @param nx Number of elements on the x axis. + * @param ny Number of elements on the y axis. + */ + public ByteArrayWrapper(byte[] array, int nx, int ny) { + super(nx, ny); + this.array = array; + } + + /** + * Create an instance with a byte array using given x and y axis dimensions. + * @param nx Number of elements on the x axis. + * @param ny Number of elements on the y axis. + */ + public ByteArrayWrapper(int nx, int ny) { + this(new byte[nx * ny], nx, ny); + } + + /** + * Create an instance with a byte array using a specified geometry. + * @param geometry A {@link GeneralGridGeometry} that will be used to discover + * the shape of the input data. + */ + public ByteArrayWrapper(GeneralGridGeometry geometry) { + // assume this is going to be a destination and avoid passing + // geometry to super to save time on checking for wrapping. + this(geometry.getGridRange().getSpan(0), geometry.getGridRange() + .getSpan(1)); + } + + /** + * Get a reference to the internal wrapped data. + * @return The internal byte array data. + */ + public byte[] getArray() { + return array; + } + + /** + * Get the value of the internal data at a specified position. + * @param index Position within the internal data to get. + * @return The value of the internal data. + */ + @Override + protected double getDataValueInternal(int index) { + return array[index]; + } + + /** + * Set the value of the internal data at a specified position. + * @param dataValue A value to set at the given index. + * @param index Position within the internal data to set. + */ + @Override + public void setDataValueInternal(double dataValue, int index) { + array[index] = (byte) dataValue; + } +} diff --git a/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/FileUtil.java b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/FileUtil.java index 6bce385cec..d96e390326 100644 --- a/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/FileUtil.java +++ b/edexOsgi/com.raytheon.uf.common.util/src/com/raytheon/uf/common/util/FileUtil.java @@ -21,6 +21,7 @@ package com.raytheon.uf.common.util; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -28,6 +29,7 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -47,6 +49,9 @@ import java.util.zip.GZIPOutputStream; * return false when unable to * obtain directory listing. * Sep 16, 2008 1250 jelkins Added join function + * - AWIPS2 Baseline Repository -------- + * Jul 06, 2012 798 jkorman Added more robust {@link #copyFile}. Added methods + * to create temporary directories and files. * * * @@ -311,29 +316,23 @@ public class FileUtil { return unmangled.toString(); } + /** + * Copy a file to a another file. + * + * @param fileToCopy + * The source file. This file reference must exist. + * @param outputFile + * The destination file. This file may exist, if so it will be + * overwritten. + * @throws IOException + * An error occurred while copying the data. + * @throws NullPointerException + * Either the source or target file references are null. + */ public static void copyFile(File fileToCopy, File outputFile) throws IOException { - - FileInputStream fis = null; - FileOutputStream fos = null; - try { - fis = new FileInputStream(fileToCopy); - outputFile.getParentFile().mkdirs(); - fos = new FileOutputStream(outputFile); - byte[] bytes = new byte[2048]; - int len = fis.read(bytes); - while (len > -1) { - fos.write(bytes, 0, len); - len = fis.read(bytes); - } - } finally { - if (fos != null) { - fos.close(); - } - if (fis != null) { - fis.close(); - } - } + // Copy the entire file. + copyFile(fileToCopy, outputFile, 0); } public static String file2String(File file) throws IOException { @@ -621,4 +620,215 @@ public class FileUtil { return VALID_FILENAME.matcher(fileName).matches(); } + /** + * Copy a file from one location to another. The file copy may begin at some + * specified position within the source file. + * + * @param source + * The source file. This file reference must exist. + * @param target + * The destination file. This file may exist, if so it will be + * overwritten. + * @param position + * The start position within the source file where the copy + * operation will begin. The position must be greater than or + * equal to zero, and less than the file length of the source. + * @return Was the required data copied to the target file. + * @throws IOException + * An error occurred while copying the data. + * @throws IllegalArgumentException + * The position is less than zero or greater than the length of + * the source file or either of the source, target files are null. + */ + public static boolean copyFile(File source, File target, int position) + throws IOException { + boolean status = false; + if (source != null) { + if (target != null) { + if ((position >= 0) && (position < source.length())) { + + FileInputStream fis = null; + FileOutputStream fos = null; + try { + fis = new FileInputStream(source); + FileChannel fci = fis.getChannel(); + + fos = new FileOutputStream(target); + FileChannel fco = fos.getChannel(); + + long count = source.length() - position; + + long transfered = fci.transferTo(position, count, fco); + // ensure we copied all of the data. + status = (transfered == count); + } finally { + String cause = null; + try { + close(fis); + } catch (IOException e) { + cause = String.format( + "copyFile.source.close[%s][%s]", e + .getClass().getName(), e + .getMessage()); + } + try { + close(fos); + } catch (IOException e) { + if (cause == null) { + cause = String.format( + "copyFile.target.close[%s][%s]", e + .getClass().getName(), e + .getMessage()); + } else { + cause = String.format( + "%s copyFile.target.close[%s][%s]", + cause, e.getClass().getName(), + e.getMessage()); + } + } + // One or more closes failed. Construct and throw an + // exception. + if (cause != null) { + throw new IOException(cause); + } + } + } else { + String msg = String.format( + "position [%d] is out of range. Max is [%d]", + position, source.length()); + throw new IllegalArgumentException(msg); + } + } else { + throw new IllegalArgumentException("target file reference is null"); + } + } else { + throw new IllegalArgumentException("source file reference is null"); + } + return status; + } + + /** + * Attempt to create a temporary directory under a given base directory for + * temporary directories. If the directory already exists it is returned, + * otherwise it is created. + * + * @param tempPath + * The base path for temporary directories. + * @param componentName + * The component requesting a temporary directory. If this is + * null the tempPath will be used. + * @return The file reference to the created or existing temporary + * directory. + * @throws IOException + * The attempt to create the temporary directory failed. + * @throws IllegalArgumentException + * The temporary directory path is null. + */ + public static File createTempDir(String tempPath, String componentName) + throws IOException { + File tempDir = null; + if (tempPath != null) { + if (componentName == null) { + tempDir = new File(tempPath); + } else { + tempDir = new File(tempPath, componentName); + } + try { + // Check if the directory already exists... + if (!tempDir.exists()) { + // it doesn't, so create it. + if (!tempDir.mkdirs()) { + throw new IOException( + "Could not create temporary directory " + + tempDir.getAbsolutePath()); + } + } else { + if (!tempDir.isDirectory()) { + String msg = String + .format("Path [%s] is not a directory, cannot create temporary directory", + tempDir.getAbsolutePath()); + throw new IOException(msg); + } + } + } catch (SecurityException se) { + throw new IOException("Could not create temporary directory " + + tempDir.getAbsolutePath(), se); + } + } else { + throw new IllegalArgumentException("Temporary path is null"); + } + return tempDir; + } + + /** + * Create an empty temporary file. The file is created in the directory + * referenced by tempPath. The file created will be named + * + *
+     * tempPath / namePrefix_tempFileUniquePart.nameSuffix
+     * 
+ * + * @param tempPath + * Base path to the temporary directory. + * @param namePrefix + * The temporary filename prefix. If this is null a default + * prefix of "tempFile" will be used. + * @param nameSuffix + * The temporary filename suffix. If this is null the default + * suffix ".tmp" will be used. + * @return The File reference to the created temporary file. + * @throws IOException + * The tempPath does not exist and could not be created or an + * error occurred while creating the temporary file. + * @throws IllegalArgumentException + * The temporary path was null. + */ + public static File createTempFile(File tempPath, String namePrefix, + String nameSuffix) throws IOException { + String defaultPrefix = "tempFile"; + String prefixFiller = "xxx"; + File tempFile = null; + + if (tempPath != null) { + if (!tempPath.exists()) { + if (!tempPath.mkdirs()) { + throw new IOException( + "Could not create temporary directory " + + tempPath.getAbsolutePath()); + } + } + // isDirectory will not work until we actually have a path that + // exists! + if (!tempPath.isDirectory()) { + String msg = String + .format("Path [%s] is not a directory, cannot create temporary file", + tempPath.getAbsolutePath()); + throw new IOException(msg); + } + if (namePrefix == null) { + namePrefix = defaultPrefix; + } else if (namePrefix.length() < 3) { + namePrefix += prefixFiller; + } + namePrefix += "_"; + tempFile = File.createTempFile(namePrefix, nameSuffix, tempPath); + } else { + throw new IllegalArgumentException("Temporary path is null"); + } + return tempFile; + } + + /** + * Attempt to close a {@link Closeable} object. + * + * @param c + * An object that needs to be closed. + * @throws IOException + * An error occurred attempting to close the object. + */ + public static void close(Closeable c) throws IOException { + if (c != null) { + c.close(); + } + } } diff --git a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java index bf653ccf92..3b59bd4214 100644 --- a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java +++ b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java @@ -344,7 +344,8 @@ public abstract class PluginDao extends CoreDao { * @param objects * The objects to retrieve the HDF5 component for * @param tileSet - * The tile set to retrieve. Currently unimplemented + * The tile set to retrieve. Any value less than or equal + * to zero returns the "base" data only. * @return The HDF5 data records * @throws StorageException * If problems occur while interacting with HDF5 data stores @@ -355,32 +356,29 @@ public abstract class PluginDao extends CoreDao { List retVal = new ArrayList(); for (PluginDataObject obj : objects) { - IDataRecord[] record = null; if (obj instanceof IPersistable) { /* connect to the data store and retrieve the data */ IDataStore dataStore = getDataStore((IPersistable) obj); - if (tileSet != -1) { - record = new IDataRecord[tileSet + 1]; - for (int i = 0; i <= tileSet; i++) { - try { - record[i] = dataStore.retrieve(obj.getDataURI() - + File.separator + "Data-interpolated" - + File.separator, String.valueOf(tileSet), - Request.ALL); - } catch (Exception e) { - throw new PluginException( - "Error getting HDF5 data", e); - } - } - } else { - record = new IDataRecord[1]; - try { - record[0] = dataStore.retrieve(obj.getDataURI(), - "Data", Request.ALL); - } catch (Exception e) { - throw new PluginException("Error getting HDF5 data", e); + boolean interpolated = DataStoreFactory.isInterpolated(tileSet); + if(!interpolated) { + tileSet = 0; + } + IDataRecord[] record = new IDataRecord[tileSet + 1]; + try { + String group = DataStoreFactory.createGroupName( + obj.getDataURI(), + DataStoreFactory.DEF_DATASET_NAME, interpolated); + // Retrieve the base record. + record[0] = dataStore.retrieve(obj.getDataURI(), + DataStoreFactory.DEF_DATASET_NAME, Request.ALL); + // Now get the interpolated data, if any! + for (int tile = 1; tile < record.length; tile++) { + record[tile] = dataStore.retrieve(group, + String.valueOf(tile), Request.ALL); } + } catch (Exception e) { + throw new PluginException("Error getting HDF5 data", e); } retVal.add(record); } diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.satellite.mcidas/src/com/raytheon/uf/edex/plugin/satellite/mcidas/McidasSatelliteDecoder.java b/edexOsgi/com.raytheon.uf.edex.plugin.satellite.mcidas/src/com/raytheon/uf/edex/plugin/satellite/mcidas/McidasSatelliteDecoder.java index b7aaa9426b..b8b4ee9f50 100644 --- a/edexOsgi/com.raytheon.uf.edex.plugin.satellite.mcidas/src/com/raytheon/uf/edex/plugin/satellite/mcidas/McidasSatelliteDecoder.java +++ b/edexOsgi/com.raytheon.uf.edex.plugin.satellite.mcidas/src/com/raytheon/uf/edex/plugin/satellite/mcidas/McidasSatelliteDecoder.java @@ -40,9 +40,11 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools; import com.raytheon.uf.edex.plugin.satellite.mcidas.util.McidasSatelliteLookups; import com.raytheon.uf.edex.plugin.satellite.mcidas.util.McidasSatelliteLookups.PhysicalElementValue; -/** McIDAS AREA Decoder +/** + * McIDAS AREA Decoder * - *

Implemented: + *

+ * Implemented: *

    *
  • Mercator projection
  • *
  • Multiple bands
  • @@ -55,32 +57,53 @@ import com.raytheon.uf.edex.plugin.satellite.mcidas.util.McidasSatelliteLookups. *
  • Calibration block
  • *
  • Non-byte data types
  • *
+ *
+ * 
+ * OFTWARE HISTORY
+ *                   
+ * Date         Ticket#     Engineer    Description
+ * -----------  ----------  ----------- --------------------------
+ * No previous history
+ * - AWIPS2 Baseline Repository --------
+ * 07/12/2012    798        jkorman     Changed projection "magic" numbers 
+ * 
+ * + * @author + * @version */ public class McidasSatelliteDecoder { - + private static final IUFStatusHandler theHandler = UFStatus - .getHandler(McidasSatelliteDecoder.class); + .getHandler(McidasSatelliteDecoder.class); + private static final String UNEXPECTED_HEADER_VALUE = "Unexpected value in format"; + private static final int EXPECTED_IMAGE_TYPE_LE = 4; + private static final int EXPECTED_IMAGE_TYPE_BE = 0x04000000; - - private static final double HALFPI = Math.PI/2.; - private static final double RTD = 180./Math.PI; - private static final double DTR = Math.PI/180.; - + + private static final double HALFPI = Math.PI / 2.; + + private static final double RTD = 180. / Math.PI; + + private static final double DTR = Math.PI / 180.; + private SatelliteDao dao; + private String traceId; - + public McidasSatelliteDecoder() { - + } - - public PluginDataObject[] decode(byte[] data, Headers headers) throws Exception { + + public PluginDataObject[] decode(byte[] data, Headers headers) + throws Exception { traceId = (String) headers.get("traceId"); try { return decodeMcidasArea(data); } catch (DecoderException e) { - // Any DecoderExceptions throw by this decoder do not need a stack trace + // Any DecoderExceptions throw by this decoder do not need a stack + // trace theHandler.error(e.getMessage(), e); return new PluginDataObject[0]; } @@ -89,8 +112,8 @@ public class McidasSatelliteDecoder { /** * References:
*
    - *
  • http://www.ssec.wisc.edu/mcidas/doc/prog_man/2006/formats-1.html
  • - *
  • http://www.ssec.wisc.edu/mcidas/doc/misc_doc/area2.html
  • + *
  • http://www.ssec.wisc.edu/mcidas/doc/prog_man/2006/formats-1.html
  • + *
  • http://www.ssec.wisc.edu/mcidas/doc/misc_doc/area2.html
  • *
* * @param data @@ -100,7 +123,7 @@ public class McidasSatelliteDecoder { private PluginDataObject[] decodeMcidasArea(byte[] data) throws Exception { ByteBuffer buf = ByteBuffer.wrap(data); buf.order(ByteOrder.LITTLE_ENDIAN); - + // Decode the directory block if (buf.getInt() != 0) formatError(UNEXPECTED_HEADER_VALUE); @@ -152,37 +175,36 @@ public class McidasSatelliteDecoder { buf.getInt(); // reserved /* int calibrationOffset = */buf.getInt(); buf.getInt(); // comment cards - + long bandBits = ((long) bandMap33to64 << 32) | bandMap1to32; if (nBands != Long.bitCount(bandBits)) formatError("Specified number of bands does not match number of bits in band map"); // Decode the navigation block buf.position(navBlockOffset); - SatMapCoverage coverage = decodeNavigation(elementResolution, lineResolution, - ulImageElement, ulImageLine, - nElementsPerLine, nLines, buf); - - // Decode the data block, creating a SatelliteRecord for each band. + SatMapCoverage coverage = decodeNavigation(elementResolution, + lineResolution, ulImageElement, ulImageLine, nElementsPerLine, + nLines, buf); + + // Decode the data block, creating a SatelliteRecord for each band. PluginDataObject[] result = new PluginDataObject[nBands]; int bitIndex = 0; - RECORD: - for (int ri = 0; ri < nBands; ++ri) { + RECORD: for (int ri = 0; ri < nBands; ++ri) { while ((bandBits & (1L << bitIndex)) == 0) if (++bitIndex >= 64) break RECORD; // shouldn't happen - + SatelliteRecord rec = new SatelliteRecord(); rec.setDataTime(new DataTime(unpackTime(yyyddd, hhmmss))); rec.setSource("McIDAS"); rec.setCreatingEntity(getCreatingEntity(sensorSourceNumber)); - PhysicalElementValue pev = getPhysicalElement(sensorSourceNumber, - bitIndex + 1); + PhysicalElementValue pev = getPhysicalElement(sensorSourceNumber, + bitIndex + 1); rec.setPhysicalElement(pev.name); rec.setUnits(pev.units); rec.setSectorID(getAreaName(areaNumber)); rec.setCoverage(coverage); - + // TODO: Line pad if not a multiple of four bytes if (linePrefixLength == 0 && nBytesPerElement == 1 && nBands == 1) { byte[] imageBytes = new byte[nLines * nElementsPerLine]; @@ -202,8 +224,8 @@ public class McidasSatelliteDecoder { } } } else - unimplemented("non-byte elements"); - + unimplemented("non-byte elements"); + rec.setTraceId(traceId); rec.setPersistenceTime(TimeTools.getSystemCalendar().getTime()); rec.setPluginName("satellite"); @@ -214,14 +236,14 @@ public class McidasSatelliteDecoder { return result; } - + /** - * Reference: http://www.ssec.wisc.edu/mcidas/doc/prog_man/2006/formats-13a.html + * Reference: + * http://www.ssec.wisc.edu/mcidas/doc/prog_man/2006/formats-13a.html * */ - private SatMapCoverage decodeNavigation(int xImgRes, int yImgRes, - int ulX, int ulY, - int nx, int ny, ByteBuffer buf) throws Exception { + private SatMapCoverage decodeNavigation(int xImgRes, int yImgRes, int ulX, + int ulY, int nx, int ny, ByteBuffer buf) throws Exception { SatMapCoverage result = new SatMapCoverage(); String navType = get4cc(buf); if (navType.equals("MERC")) { @@ -231,121 +253,127 @@ public class McidasSatelliteDecoder { int spacingAtStdLatInMeters = buf.getInt(); int nrmlLonDDMMSS = buf.getInt(); - // NOTE: We do not check the following for compatibility with WGS84. + // NOTE: We do not check the following for compatibility with WGS84. int radiusInMeters = buf.getInt(); - /*int eccentricity = */buf.getInt(); - /*boolean geodetic = */buf.getInt()/* >= 0*/; - + /* int eccentricity = */buf.getInt(); + /* boolean geodetic = */buf.getInt()/* >= 0 */; + boolean westPositive = buf.getInt() >= 0; float la1, lo1, la2, lo2; - - /* The following is based on - * gov.noaa.nws.ncep.edex.plugin.mcidas/src/gov/noaa/nws/ncep/edex/plugin/mcidas/decoder/McidasDecoder.java + + /* + * The following is based on + * gov.noaa.nws.ncep.edex.plugin.mcidas/src + * /gov/noaa/nws/ncep/edex/plugin/mcidas/decoder/McidasDecoder.java */ - + double clon = flipLon(unpackDdmmss(nrmlLonDDMMSS), westPositive); double clat = unpackDdmmss(stdLatDDMMSS); double dx = spacingAtStdLatInMeters * xImgRes; double dy = spacingAtStdLatInMeters * yImgRes; - + { double phi0r = clat * DTR; double rxp = ((double) (elementOfEquator - ulX) / xImgRes + 1.); double ryp = (ny - (double) (lineOfEquator - ulY) / yImgRes); - + double dxp = 1. - rxp; double dyp = 1. - ryp; double rm = dx * dyp; double rcos = radiusInMeters * Math.cos(phi0r); - double arg = Math.exp(rm/rcos); - la1 = (float) ((2. * Math.atan(arg) - HALFPI ) * RTD); - lo1 = (float) prnlon ((clon + ((dx * dxp) / rcos) * RTD)); - dxp = nx -rxp; - dyp = ny -ryp; + double arg = Math.exp(rm / rcos); + la1 = (float) ((2. * Math.atan(arg) - HALFPI) * RTD); + lo1 = (float) prnlon((clon + ((dx * dxp) / rcos) * RTD)); + dxp = nx - rxp; + dyp = ny - ryp; rm = dx * dyp; arg = Math.exp(rm / rcos); - la2 = (float) ((2. * Math.atan(arg) - HALFPI ) * RTD); - lo2 = (float) prnlon ((clon + ((dx * dxp) / rcos) * RTD)); - lo2 = (float) prnlon (lo2); + la2 = (float) ((2. * Math.atan(arg) - HALFPI) * RTD); + lo2 = (float) prnlon((clon + ((dx * dxp) / rcos) * RTD)); + lo2 = (float) prnlon(lo2); } - - result = SatSpatialFactory.getInstance().getMapCoverage(1, nx, ny, - (float) dx, (float) dy, (float) clon, (float) clat, - la1, lo1, la2, lo2); + + result = SatSpatialFactory.getInstance().getMapCoverage( + SatMapCoverage.PROJ_MERCATOR, nx, ny, (float) dx, + (float) dy, (float) clon, (float) clat, la1, lo1, la2, lo2); } else unimplemented(String.format("navigation type \"%s\"", navType)); - + return result; } - - private static double prnlon (double lon) { - double dlon = lon - (int)(lon / 360.f) * 360.f; + + private static double prnlon(double lon) { + double dlon = lon - (int) (lon / 360.f) * 360.f; if (lon < -180.) { dlon = lon + 360.f; - } - else if (lon > 180.) { + } else if (lon > 180.) { dlon = (double) (lon - 360.); } return dlon; } - + private static Calendar unpackTime(int yyyddd, int hhmmss) { Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); cal.setTimeInMillis(0); - cal.set(Calendar.YEAR, + 1900 + yyyddd / 1000); - cal.set(Calendar.DAY_OF_YEAR, yyyddd % 1000); - + cal.set(Calendar.YEAR, +1900 + yyyddd / 1000); + cal.set(Calendar.DAY_OF_YEAR, yyyddd % 1000); + int hh = hhmmss / 10000; cal.set(Calendar.HOUR_OF_DAY, hh); cal.set(Calendar.MINUTE, (hhmmss - hh * 10000) / 100); - cal.set(Calendar.SECOND, hhmmss % 100); - + cal.set(Calendar.SECOND, hhmmss % 100); + return cal; } - + private static double unpackDdmmss(int ddmmss) { int dd = ddmmss / 10000; int mm = (ddmmss - dd * 10000) / 100; int ss = ddmmss % 100; - return dd + mm/60.0 + ss/3600.0; + return dd + mm / 60.0 + ss / 3600.0; } - + private static double flipLon(double lon, boolean flip) { - return flip ? - lon : lon; + return flip ? -lon : lon; } - + private static String get4cc(ByteBuffer buf) { byte[] bytes = new byte[4]; buf.get(bytes); return new String(bytes, Charset.forName("ISO-8859-1")); } - + private String getCreatingEntity(int sensorSourceNumber) { - String value = McidasSatelliteLookups.getInstance().getCreatingEntity(sensorSourceNumber); - return value != null ? value : String.format("Unknown-%d", sensorSourceNumber); + String value = McidasSatelliteLookups.getInstance().getCreatingEntity( + sensorSourceNumber); + return value != null ? value : String.format("Unknown-%d", + sensorSourceNumber); } private PhysicalElementValue getPhysicalElement(int ssn, int bandIndex) { - PhysicalElementValue value = McidasSatelliteLookups.getInstance().getPhysicalElement(ssn, bandIndex); - return value != null ? value : - new PhysicalElementValue(String.format("Unknown-%d", bandIndex), null); + PhysicalElementValue value = McidasSatelliteLookups.getInstance() + .getPhysicalElement(ssn, bandIndex); + return value != null ? value : new PhysicalElementValue(String.format( + "Unknown-%d", bandIndex), null); } - + private String getAreaName(int areaNumber) { - String value = McidasSatelliteLookups.getInstance().getAreaName(areaNumber); + String value = McidasSatelliteLookups.getInstance().getAreaName( + areaNumber); return value != null ? value : String.format("AREA%04d", areaNumber); } - + private void formatError(String message) throws DecoderException { throw new DecoderException(String.format("%s: %s", traceId, message)); } protected void unimplemented(String feature) throws DecoderException { - throw new DecoderException(String.format("%s: unimplemented: %s", traceId, feature)); + throw new DecoderException(String.format("%s: unimplemented: %s", + traceId, feature)); } - /** + /** * @return the dao */ public SatelliteDao getDao() { @@ -353,7 +381,8 @@ public class McidasSatelliteDecoder { } /** - * @param dao the dao to set + * @param dao + * the dao to set */ public void setDao(SatelliteDao dao) { this.dao = dao; diff --git a/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/decoder/RegionalSatDecoder.java b/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/decoder/RegionalSatDecoder.java index 3d300863fe..c81e206028 100644 --- a/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/decoder/RegionalSatDecoder.java +++ b/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/decoder/RegionalSatDecoder.java @@ -29,38 +29,23 @@ import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord; import ucar.nc2.Attribute; import ucar.nc2.NetcdfFile; - /** - * Decoder implementation for alaska and regional satellite plugin. - * This decoder ingests netcdf3 files generated by the Alaska Region and GOES-R Proving Ground - * for their satellite data. + * Decoder implementation for alaska and regional satellite plugin. This decoder + * ingests netcdf3 files generated by the Alaska Region and GOES-R Proving + * Ground for their satellite data. * - * The following are the relevant elements in the netcdf3 files being used by the decoder - * dimensions: - * y = 1024 ; - * x = 1280 ; - * - * variables: - * byte image(y, x) ; - * double validTime ; - * validTime:units = "seconds since 1970-1-1 00:00:00.00 0:00" ; - * validTime:long_name = "Valid Time" ; + * The following are the relevant elements in the netcdf3 files being used by + * the decoder dimensions: y = 1024 ; x = 1280 ; * - * global attributes: - * :channel = "0.58 - 0.68 micron VISL" ; - * :depictorName = "AkSec1a1" ; - * :satelliteName = "HRPT" ; - * :projName = "STEREOGRAPHIC" ; - * :centralLat = 90.f ; - * :centralLon = -156.f ; - * :lat00 = 62.057667f ; - * :lon00 = -168.81633f ; - * :latNxNy = 52.910168f ; - * :lonNxNy = -146.53101f ; - * :dxKm = 1.0164f ; - * :dyKm = 1.0164f ; - * :latDxDy = 58.f ; - * :lonDxDy = -156.f ; + * variables: byte image(y, x) ; double validTime ; validTime:units = + * "seconds since 1970-1-1 00:00:00.00 0:00" ; validTime:long_name = + * "Valid Time" ; + * + * global attributes: :channel = "0.58 - 0.68 micron VISL" ; :depictorName = + * "AkSec1a1" ; :satelliteName = "HRPT" ; :projName = "STEREOGRAPHIC" ; + * :centralLat = 90.f ; :centralLon = -156.f ; :lat00 = 62.057667f ; :lon00 = + * -168.81633f ; :latNxNy = 52.910168f ; :lonNxNy = -146.53101f ; :dxKm = + * 1.0164f ; :dyKm = 1.0164f ; :latDxDy = 58.f ; :lonDxDy = -156.f ; * *
  * 
@@ -68,8 +53,9 @@ import ucar.nc2.NetcdfFile;
  *                   
  * date          Ticket#     Engineer    Description
  * -----------  ----------  ----------- --------------------------
- * 7/15/11                      tk    	Initial Creation                          
- * 
+ * 7/15/11                      tk    	Initial Creation
+ * - AWIPS2 Baseline Repository --------
+ * 07/12/2012    798        jkorman     Changed projection "magic" numbers 
  * 
* * @author tk @@ -78,309 +64,332 @@ import ucar.nc2.NetcdfFile; public class RegionalSatDecoder extends AbstractDecoder { - private String traceId = ""; + private String traceId = ""; - private SatelliteDao dao; - - private String source; - - private String filename; - - /** - * The decoder method uses the NetcdfFile API to retrieve the attributes and satellite image data - * from the Alaska Region and GOES-R Proving Ground netcdf3 files. These netcdf3 files are generated - * for use in Alaska and the metadata and data are specified by the requirements for the Alaska Region. - * Once the netcdf3 file is decoded, the metadata is stored in the Satellite table in Postgres and - * the image data is stored in the HDF5 repository as Satellite records. The GIS map metadata is stored - * in the satellite_spatial table by creating a SatMapCoverage object. - * - * The following parameters are set in the spring configuraiton file alaskasat-ingest.xml and the - * dao and source members are set when the RegionalSatDecoder instance is initialized: - * - * * @param dao the data access object for satellite records - * * @param source the source of the satellite images (Alaska Region) - */ - public PluginDataObject[] decode(byte[] data) throws Exception { + private SatelliteDao dao; - PluginDataObject[] retData = null; + private String source; - SatelliteRecord record = null; + private String filename; - NetcdfFile netCdfFile = null; + /** + * The decoder method uses the NetcdfFile API to retrieve the attributes and + * satellite image data from the Alaska Region and GOES-R Proving Ground + * netcdf3 files. These netcdf3 files are generated for use in Alaska and + * the metadata and data are specified by the requirements for the Alaska + * Region. Once the netcdf3 file is decoded, the metadata is stored in the + * Satellite table in Postgres and the image data is stored in the HDF5 + * repository as Satellite records. The GIS map metadata is stored in the + * satellite_spatial table by creating a SatMapCoverage object. + * + * The following parameters are set in the spring configuraiton file + * alaskasat-ingest.xml and the dao and source members are set when the + * RegionalSatDecoder instance is initialized: + * + * * @param dao the data access object for satellite records * @param source + * the source of the satellite images (Alaska Region) + */ + public PluginDataObject[] decode(byte[] data) throws Exception { - if ((data != null) && (data.length > 0)) { + PluginDataObject[] retData = null; - Calendar calendar = Calendar.getInstance(TimeZone - .getTimeZone("GMT")); + SatelliteRecord record = null; - record = new SatelliteRecord(); + NetcdfFile netCdfFile = null; - //String filename = "alaska_netcdf3"; // dummy filename; TODO: get filename from camel context? - netCdfFile = NetcdfFile.openInMemory(filename,data); + if ((data != null) && (data.length > 0)) { - - // set the source; Alaska Region - if (source == null) { - source = "Source"; // use to look up source value; default of Source - } - record.setSource(getSource(source)); // lookup source value - - // set the creating entity + Calendar calendar = Calendar.getInstance(TimeZone + .getTimeZone("GMT")); + + record = new SatelliteRecord(); + + // String filename = "alaska_netcdf3"; // dummy filename; TODO: get + // filename from camel context? + netCdfFile = NetcdfFile.openInMemory(filename, data); + + // set the source; Alaska Region + if (source == null) { + source = "Source"; // use to look up source value; default of + // Source + } + record.setSource(getSource(source)); // lookup source value + + // set the creating entity Attribute satName = netCdfFile.findGlobalAttribute("satelliteName"); - - String entity = null; //"HRPT"; "GOESR-PG"; "Blended2"; + + String entity = null; // "HRPT"; "GOESR-PG"; "Blended2"; if (satName != null) { - entity = satName.getStringValue(); + entity = satName.getStringValue(); } - + if (entity != null) { - String parsed = getCreatingEntity(entity); - if (parsed != null && parsed.length() > 0) { - record.setCreatingEntity(parsed); - } - else { - record.setCreatingEntity(entity); - } - } - else { - record.setCreatingEntity("Unknown"); + String parsed = getCreatingEntity(entity); + if (parsed != null && parsed.length() > 0) { + record.setCreatingEntity(parsed); + } else { + record.setCreatingEntity(entity); + } + } else { + record.setCreatingEntity("Unknown"); } // end of error block - // read the sector ID, may need to change to use satelliteSector attribute? - String sector = netCdfFile.findGlobalAttribute("depictorName").getStringValue().trim(); - record.setSectorID(sector); + // read the sector ID, may need to change to use satelliteSector + // attribute? + String sector = netCdfFile.findGlobalAttribute("depictorName") + .getStringValue().trim(); + record.setSectorID(sector); - // read and set the physical element - PhysicalElementValue pev = null; - Attribute chan = netCdfFile.findGlobalAttribute("channel"); - if(chan != null) { - String channel = chan.getStringValue().trim(); + // read and set the physical element + PhysicalElementValue pev = null; + Attribute chan = netCdfFile.findGlobalAttribute("channel"); + if (chan != null) { + String channel = chan.getStringValue().trim(); - pev = getPhysicalElement(entity, channel); - String element = pev.name; - if (pev.name != null) { - record.setPhysicalElement(element); - } else { - record.setPhysicalElement(channel); - } - } else { - record.setPhysicalElement("Imager Visible"); - } - - // read and set the units (IRPixel, GenericPixel, ...) - // defined in physicalElements.xml lookup file - if(pev != null) - { - String units = pev.units; - if (pev.units != null) { - record.setUnits(units); - } - } - - // read the number of records - int numRecords = netCdfFile.findDimension("y").getLength(); + pev = getPhysicalElement(entity, channel); + String element = pev.name; + if (pev.name != null) { + record.setPhysicalElement(element); + } else { + record.setPhysicalElement(channel); + } + } else { + record.setPhysicalElement("Imager Visible"); + } - record.setNumRecords(numRecords); + // read and set the units (IRPixel, GenericPixel, ...) + // defined in physicalElements.xml lookup file + if (pev != null) { + String units = pev.units; + if (pev.units != null) { + record.setUnits(units); + } + } - // read the size of each record - int recordSize = netCdfFile.findDimension("x").getLength(); - record.setSizeRecords(recordSize); + // read the number of records + int numRecords = netCdfFile.findDimension("y").getLength(); - // read the valid time in seconds and store the time in milliseconds - long time = netCdfFile.findVariable("validTime").readScalarLong(); // time in seconds - calendar.setTimeInMillis(time * 1000); // need to convert seconds to milliseconds - - /* - Date date = new Date(); // used for setting the test data time - long time = date.getTime(); - calendar.setTimeInMillis(time); // need to convert seconds to millisconds - */ - - record.setDataTime(new DataTime(calendar)); + record.setNumRecords(numRecords); - // set lov to central lon - float lov = netCdfFile.findGlobalAttribute("centralLon").getNumericValue().floatValue(); + // read the size of each record + int recordSize = netCdfFile.findDimension("x").getLength(); + record.setSizeRecords(recordSize); - int mapProjection = 5; // STEREOGRAPHIC projection default - float latin = 0.0f; // set to zero for Stereographic projections - float rotation = 0.0f; - - // read the projection - String projection = netCdfFile.findGlobalAttribute("projName").getStringValue().trim(); - if(!projection.equalsIgnoreCase("STEREOGRAPHIC")) - { - // get latin for projection from data - latin = netCdfFile.findGlobalAttribute("centralLat").getNumericValue().floatValue(); - if(projection.equalsIgnoreCase("LAMBERT") || projection.equalsIgnoreCase("LAMBERT_CONFORMAL")) - { - mapProjection = 3; - } - else if(projection.equalsIgnoreCase("MERCATOR")) - { - mapProjection = 1; - } - else if(projection.equalsIgnoreCase("CYLINDRICAL_EQUIDISTANT")) - { - mapProjection = 7; - } - - } else { - Attribute rot = netCdfFile.findGlobalAttribute("rotation"); - if (rot != null) { - rotation = rot.getNumericValue().floatValue(); - // STEREOGRAPHIC projection add rotation to lov - lov += rotation; - } - } // end of if projection block + // read the valid time in seconds and store the time in milliseconds + long time = netCdfFile.findVariable("validTime").readScalarLong(); // time + // in + // seconds + calendar.setTimeInMillis(time * 1000); // need to convert seconds to + // milliseconds - // declare and initialize - float dx = 0.0f, dy = 0.0f, lo1 = 0.0f, la1 = 0.0f, lo2 = 0.0f, la2 = 0.0f; - int nx = 0, ny = 0; - - // Do specialized decoding and retrieve spatial data for projections - if ((mapProjection == 3) || (mapProjection == 5) || (mapProjection == 1) || (mapProjection == 7)) { + /* + * Date date = new Date(); // used for setting the test data time + * long time = date.getTime(); calendar.setTimeInMillis(time); // + * need to convert seconds to millisconds + */ - // set number of points along x-axis - nx = recordSize; - // set number of points along y-axis - ny = numRecords; + record.setDataTime(new DataTime(calendar)); - // read the image as byte data and store as byte array - record.setMessageData((byte []) netCdfFile.readSection("image").get1DJavaArray(Class.forName("java.lang.Byte"))); + // set lov to central lon + float lov = netCdfFile.findGlobalAttribute("centralLon") + .getNumericValue().floatValue(); - // get the latitude of the first point, upper left corner - la1 = netCdfFile.findGlobalAttribute("lat00").getNumericValue().floatValue(); + int mapProjection = SatMapCoverage.PROJ_POLAR_STEREO; // STEREOGRAPHIC + // projection + // default + float latin = 0.0f; // set to zero for Stereographic projections + float rotation = 0.0f; - // get longitude of the first point, upper left corner - lo1 = (netCdfFile.findGlobalAttribute("lon00").getNumericValue().floatValue()); + // read the projection + String projection = netCdfFile.findGlobalAttribute("projName") + .getStringValue().trim(); + if (!projection.equalsIgnoreCase("STEREOGRAPHIC")) { + // get latin for projection from data + latin = netCdfFile.findGlobalAttribute("centralLat") + .getNumericValue().floatValue(); + if (projection.equalsIgnoreCase("LAMBERT") + || projection.equalsIgnoreCase("LAMBERT_CONFORMAL")) { + mapProjection = SatMapCoverage.PROJ_LAMBERT; + } else if (projection.equalsIgnoreCase("MERCATOR")) { + mapProjection = SatMapCoverage.PROJ_MERCATOR; + } else if (projection + .equalsIgnoreCase("CYLINDRICAL_EQUIDISTANT")) { + mapProjection = SatMapCoverage.PROJ_CYLIN_EQUIDISTANT; + } - // get the pixel spacing - dx = netCdfFile.findGlobalAttribute("dxKm").getNumericValue().floatValue(); - dx *= 1000f; // convert to meters from km - dy = netCdfFile.findGlobalAttribute("dyKm").getNumericValue().floatValue(); - dy *= 1000f; // convert to meters from km + } else { + Attribute rot = netCdfFile.findGlobalAttribute("rotation"); + if (rot != null) { + rotation = rot.getNumericValue().floatValue(); + // STEREOGRAPHIC projection add rotation to lov + lov += rotation; + } + } // end of if projection block - la2 = netCdfFile.findGlobalAttribute("latNxNy").getNumericValue().floatValue(); - lo2 = netCdfFile.findGlobalAttribute("lonNxNy").getNumericValue().floatValue(); - } else { - throw new DecoderException( - "Unable to decode Satellite: Encountered Unknown projection"); - } // end of if map projection block + // declare and initialize + float dx = 0.0f, dy = 0.0f, lo1 = 0.0f, la1 = 0.0f, lo2 = 0.0f, la2 = 0.0f; + int nx = 0, ny = 0; - // Get latitude of upper right hand corner - float urLat = 0; // not used so set to zero, if required get and set value - record.setUpperRightLat(urLat); + // Do specialized decoding and retrieve spatial data for projections + if ((mapProjection == SatMapCoverage.PROJ_MERCATOR) + || (mapProjection == SatMapCoverage.PROJ_LAMBERT) + || (mapProjection == SatMapCoverage.PROJ_POLAR_STEREO) + || (mapProjection == SatMapCoverage.PROJ_CYLIN_EQUIDISTANT)) { - // Get longitude of upper right hand corner - float urLon = 0; // not used so set to zero, if required get and set value - record.setUpperRightLon(urLon); + // set number of points along x-axis + nx = recordSize; + // set number of points along y-axis + ny = numRecords; - SatMapCoverage mapCoverage = null; + // read the image as byte data and store as byte array + record.setMessageData((byte[]) netCdfFile.readSection("image") + .get1DJavaArray(Class.forName("java.lang.Byte"))); - try { - mapCoverage = RegionalSatSpatialFactory.getInstance() - .getMapCoverage(mapProjection, nx, ny, dx, dy, lov, - latin, la1, lo1, la2, lo2); - } catch (Exception e) { - StringBuffer buf = new StringBuffer(); - buf - .append( - "Error getting or constructing SatMapCoverage for values: ") - .append("\n\t"); - buf.append("mapProjection=" + mapProjection).append("\n\t"); - buf.append("nx=" + nx).append("\n\t"); - buf.append("ny=" + ny).append("\n\t"); - buf.append("dx=" + dx).append("\n\t"); - buf.append("dy=" + dy).append("\n\t"); - buf.append("lov=" + lov).append("\n\t"); - buf.append("latin=" + latin).append("\n\t"); - buf.append("la1=" + la1).append("\n\t"); - buf.append("lo1=" + lo1).append("\n\t"); - buf.append("la2=" + la2).append("\n\t"); - buf.append("lo2=" + lo2).append("\n"); - throw new DecoderException(buf.toString(), e); - } // end of catch block - - if (record != null) { - record.setTraceId(traceId); - record.setCoverage(mapCoverage); - record.setPersistenceTime(TimeTools.getSystemCalendar() - .getTime()); - record.setPluginName("satellite"); - record.constructDataURI(); - } // end of if statement + // get the latitude of the first point, upper left corner + la1 = netCdfFile.findGlobalAttribute("lat00").getNumericValue() + .floatValue(); - } // end of if data not empty statement + // get longitude of the first point, upper left corner + lo1 = (netCdfFile.findGlobalAttribute("lon00") + .getNumericValue().floatValue()); - if (record == null) { - retData = new PluginDataObject[0]; - } else { - retData = new PluginDataObject[] { record }; - } - return retData; - } + // get the pixel spacing + dx = netCdfFile.findGlobalAttribute("dxKm").getNumericValue() + .floatValue(); + dx *= 1000f; // convert to meters from km + dy = netCdfFile.findGlobalAttribute("dyKm").getNumericValue() + .floatValue(); + dy *= 1000f; // convert to meters from km - // uses lookup map instead of database to store creating entity parameter configuration - private String getCreatingEntity(String name) { - String value = RegionalSatLookups.getInstance().getCreatingEntity(name); - return value != null ? value : String.format("Unknown-%s", name); - } + la2 = netCdfFile.findGlobalAttribute("latNxNy") + .getNumericValue().floatValue(); + lo2 = netCdfFile.findGlobalAttribute("lonNxNy") + .getNumericValue().floatValue(); + } else { + throw new DecoderException( + "Unable to decode Satellite: Encountered Unknown projection"); + } // end of if map projection block - // uses lookup map instead of database to store physical element parameter configuration - private PhysicalElementValue getPhysicalElement(String satName, String channel) { - PhysicalElementValue value = RegionalSatLookups.getInstance().getPhysicalElement(satName, channel); - return value != null ? value : - new PhysicalElementValue(String.format("Unknown-%s", channel), null); - } + // Get latitude of upper right hand corner + float urLat = 0; // not used so set to zero, if required get and set + // value + record.setUpperRightLat(urLat); - // uses lookup map instead of database to store source parameter configuration - private String getSource(String name) { - String value = RegionalSatLookups.getInstance().getSource(name); - return value != null ? value : String.format("Unknown-%s", name); - } + // Get longitude of upper right hand corner + float urLon = 0; // not used so set to zero, if required get and set + // value + record.setUpperRightLon(urLon); - /** + SatMapCoverage mapCoverage = null; + + try { + mapCoverage = RegionalSatSpatialFactory.getInstance() + .getMapCoverage(mapProjection, nx, ny, dx, dy, lov, + latin, la1, lo1, la2, lo2); + } catch (Exception e) { + StringBuffer buf = new StringBuffer(); + buf.append( + "Error getting or constructing SatMapCoverage for values: ") + .append("\n\t"); + buf.append("mapProjection=" + mapProjection).append("\n\t"); + buf.append("nx=" + nx).append("\n\t"); + buf.append("ny=" + ny).append("\n\t"); + buf.append("dx=" + dx).append("\n\t"); + buf.append("dy=" + dy).append("\n\t"); + buf.append("lov=" + lov).append("\n\t"); + buf.append("latin=" + latin).append("\n\t"); + buf.append("la1=" + la1).append("\n\t"); + buf.append("lo1=" + lo1).append("\n\t"); + buf.append("la2=" + la2).append("\n\t"); + buf.append("lo2=" + lo2).append("\n"); + throw new DecoderException(buf.toString(), e); + } // end of catch block + + if (record != null) { + record.setTraceId(traceId); + record.setCoverage(mapCoverage); + record.setPersistenceTime(TimeTools.getSystemCalendar() + .getTime()); + record.setPluginName("satellite"); + record.constructDataURI(); + } // end of if statement + + } // end of if data not empty statement + + if (record == null) { + retData = new PluginDataObject[0]; + } else { + retData = new PluginDataObject[] { record }; + } + return retData; + } + + // uses lookup map instead of database to store creating entity parameter + // configuration + private String getCreatingEntity(String name) { + String value = RegionalSatLookups.getInstance().getCreatingEntity(name); + return value != null ? value : String.format("Unknown-%s", name); + } + + // uses lookup map instead of database to store physical element parameter + // configuration + private PhysicalElementValue getPhysicalElement(String satName, + String channel) { + PhysicalElementValue value = RegionalSatLookups.getInstance() + .getPhysicalElement(satName, channel); + return value != null ? value : new PhysicalElementValue(String.format( + "Unknown-%s", channel), null); + } + + // uses lookup map instead of database to store source parameter + // configuration + private String getSource(String name) { + String value = RegionalSatLookups.getInstance().getSource(name); + return value != null ? value : String.format("Unknown-%s", name); + } + + /** * @return dao the data access object for satellite records */ - public SatelliteDao getDao() { - return dao; - } + public SatelliteDao getDao() { + return dao; + } - /** + /** * @param dao * the data access object for satellite records */ - public void setDao(SatelliteDao dao) { - this.dao = dao; - } + public void setDao(SatelliteDao dao) { + this.dao = dao; + } - /** + /** * @return the source */ - public String getSource() { - return source; - } - - /** + public String getSource() { + return source; + } + + /** * @param source * the source of the satellite images (Alaska Region) */ - public void setSource(String source) { - this.source = source; - } - - /** + public void setSource(String source) { + this.source = source; + } + + /** * @return the filename */ - public String getFilename() { - return filename; - } - - /** + public String getFilename() { + return filename; + } + + /** * @param filename * the filename of the netcdf3 file */ - public void setFilename(String file) { - this.filename = file; - } + public void setFilename(String file) { + this.filename = file; + } } diff --git a/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/util/RegionalSatSpatialFactory.java b/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/util/RegionalSatSpatialFactory.java index 0bf1d2996a..b810f27892 100644 --- a/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/util/RegionalSatSpatialFactory.java +++ b/ost/gov.noaa.nws.ost.edex.plugin.regionalsat/src/gov/noaa/nws/ost/edex/plugin/regionalsat/util/RegionalSatSpatialFactory.java @@ -37,7 +37,8 @@ import com.vividsolutions.jts.io.WKTReader; * date Ticket# Engineer Description * ----------- ---------- ----------- -------------------------- * 7/15/11 tk Initial Creation - * + * - AWIPS2 Baseline Repository -------- + * 07/12/2012 798 jkorman Changed projection "magic" numbers * * * @author tk @@ -179,13 +180,13 @@ public class RegionalSatSpatialFactory { ProjectedCRS crs = null; // Get the correct CRS - if (mapProjection == 1) { + if (mapProjection == SatMapCoverage.PROJ_MERCATOR) { crs = MapUtil.constructMercator(MapUtil.AWIPS_EARTH_RADIUS, MapUtil.AWIPS_EARTH_RADIUS, latin, lov); - } else if (mapProjection == 3) { + } else if (mapProjection == SatMapCoverage.PROJ_LAMBERT) { crs = MapUtil.constructLambertConformal(MapUtil.AWIPS_EARTH_RADIUS, MapUtil.AWIPS_EARTH_RADIUS, latin, latin, lov); - } else if (mapProjection == 7) { + } else if (mapProjection == SatMapCoverage.PROJ_CYLIN_EQUIDISTANT) { crs = MapUtil.constructEquidistantCylindrical(MapUtil.AWIPS_EARTH_RADIUS, MapUtil.AWIPS_EARTH_RADIUS, lov, latin); } else {