Issue #1521 create grid data access factory and refactor satellite to share common functionality.

Change-Id: I54de0b41b60ccd058124eb79e6f032cb2ea9a3cf

Former-commit-id: a19b51cf2e [formerly a19b51cf2e [formerly 2133adac87eaa53977c26700ef656c304e81ee1b]]
Former-commit-id: 3032dc2189
Former-commit-id: 2e907f4a0e
This commit is contained in:
Ben Steffensmeier 2013-01-23 11:22:30 -06:00
parent 6964c16be7
commit fc7b0393c5
9 changed files with 816 additions and 339 deletions

View file

@ -24,6 +24,9 @@ import java.nio.Buffer;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.raytheon.uf.common.dataaccess.grid.IGridData;
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.IGraphicsTarget;
import com.raytheon.uf.viz.core.drawables.ColorMapLoader;
import com.raytheon.uf.viz.core.drawables.ColorMapParameters;
@ -34,9 +37,6 @@ import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.rsc.capabilities.ColorMapCapability;
import com.raytheon.uf.viz.core.style.level.SingleLevel;
import com.raytheon.uf.common.dataaccess.grid.IGridData;
import com.raytheon.uf.common.geospatial.interpolation.data.ByteBufferWrapper;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.viz.core.drawables.ColorMapParameterFactory;
import com.raytheon.viz.core.rsc.displays.GriddedImageDisplay2;
@ -128,9 +128,24 @@ public class GenericGridResource extends
public String getName() {
if (this.noData) {
return NODATA_LEGEND_TEXT;
}else if(this.dataTime == null){
return GENERIC_GRID_LEGEND_TEXT;
} else {
StringBuilder legend = new StringBuilder(GENERIC_GRID_LEGEND_TEXT);
IGridData gridData = resourceData.getGridData();
if (gridData != null) {
if (gridData.getParameter() != null) {
legend.append(" ");
legend.append(gridData.getParameter());
}
if (gridData.getLevel() != null) {
legend.append(" ");
legend.append(gridData.getLevel());
}
}
legend.append(this.dataTime.getLegendString());
return legend.toString();
}
return GENERIC_GRID_LEGEND_TEXT + this.dataTime.getLegendString();
}
@Override

View file

@ -12,7 +12,9 @@ Require-Bundle: com.raytheon.uf.common.time;visibility:=reexport,
com.raytheon.uf.common.dataplugin.level;visibility:=reexport,
com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174",
com.raytheon.uf.common.serialization;bundle-version="1.12.1174",
com.raytheon.uf.common.localization;bundle-version="1.12.1174"
com.raytheon.uf.common.localization;bundle-version="1.12.1174",
com.raytheon.uf.common.dataquery;bundle-version="1.0.0",
com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174"
Export-Package: com.raytheon.uf.common.dataaccess,
com.raytheon.uf.common.dataaccess.exception,
com.raytheon.uf.common.dataaccess.geom,

View file

@ -0,0 +1,233 @@
/**
* 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.dataaccess.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.raytheon.uf.common.dataaccess.IData;
import com.raytheon.uf.common.dataaccess.IDataRequest;
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
import com.raytheon.uf.common.dataaccess.exception.TimeAgnosticDataException;
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
import com.raytheon.uf.common.dataquery.requests.TimeQueryRequest;
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
import com.raytheon.uf.common.serialization.comm.RequestRouter;
import com.raytheon.uf.common.time.BinOffset;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
/**
* An abstract factory for getting data from plugins that use PluginDataObject.
* *
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 17, 2013 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class AbstractDataPluginFactory<R extends IDataRequest<D>, D extends IData>
extends AbstractDataFactory {
protected static final String FIELD_DATATIME = "dataTime";
protected static final String DBQUERY_PLUGIN_NAME_KEY = "pluginName";
public DataTime[] getAvailableTimes(R request)
throws TimeAgnosticDataException {
return this.getAvailableTimes(request, null);
}
@SuppressWarnings("unchecked")
public DataTime[] getAvailableTimes(R request,
BinOffset binOffset) throws TimeAgnosticDataException {
validateRequest(request);
TimeQueryRequest timeQueryRequest = this.buildTimeQueryRequest(request);
if ((binOffset == null) == false) {
timeQueryRequest.setBinOffset(binOffset);
}
List<Object> results = null;
try {
results = (List<Object>) RequestRouter.route(timeQueryRequest);
} catch (Exception e) {
throw new DataRetrievalException(
"Failed to retrieve available data times for plugin "
+ request.getDatatype() + " for request "
+ request.toString(), e);
}
List<DataTime> dataTimes = new ArrayList<DataTime>();
for (Object result : results) {
dataTimes.add((DataTime) result);
}
Collections.sort(dataTimes);
return dataTimes.toArray(new DataTime[dataTimes.size()]);
}
/**
* Builds a TimeQueryRequest that will be used to retrieve Data Times.
*
* @param request
* the original grid request
* @return a TimeQueryRequest to execute
*/
protected TimeQueryRequest buildTimeQueryRequest(R request) {
TimeQueryRequest timeQueryRequest = new TimeQueryRequest();
timeQueryRequest.setPluginName(request.getDatatype());
timeQueryRequest.setQueryTerms(this
.buildConstraintsFromRequest(request));
return timeQueryRequest;
}
public D[] getData(R request, DataTime... times) {
DbQueryRequest dbQueryRequest = this
.buildDbQueryRequest(request, times);
return this.getData(request, dbQueryRequest);
}
public D[] getData(R request, TimeRange timeRange) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request,
timeRange);
return this.getData(request, dbQueryRequest);
}
protected D[] getData(R request, DbQueryRequest dbQueryRequest) {
DbQueryResponse dbQueryResponse = executeDbQueryRequest(dbQueryRequest,
request.toString());
return getData(request, dbQueryResponse);
}
/**
* Executes the provided DbQueryRequest and returns a DbQueryResponse
*
* @param dbQueryRequest
* the DbQueryRequest to execute
* @param gridRequestString
* the original grid request for reporting purposes
* @return a DbQueryResponse
*/
protected DbQueryResponse executeDbQueryRequest(
DbQueryRequest dbQueryRequest, String gridRequestString) {
DbQueryResponse dbQueryResponse = null;
try {
dbQueryResponse = (DbQueryResponse) RequestRouter
.route(dbQueryRequest);
} catch (Exception e1) {
throw new DataRetrievalException(
"Unable to complete the DbQueryRequest for request: "
+ gridRequestString, e1);
}
return dbQueryResponse;
}
/**
* Constructs a db query request using the provided data times
*
* @param request
* the original grid request
* @param dataTimes
* the data times to include in the request (if any)
* @return a DbQueryRequest to execute
*/
protected DbQueryRequest buildDbQueryRequest(R request, DataTime[] dataTimes) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request);
if (dataTimes.length <= 0) {
return dbQueryRequest;
}
/* Add the DataTime Constraint */
RequestConstraint requestConstraint = new RequestConstraint();
requestConstraint.setConstraintType(ConstraintType.IN);
String[] dataTimeStrings = new String[dataTimes.length];
int index = 0;
for (DataTime dataTime : dataTimes) {
dataTimeStrings[index] = dataTime.toString();
++index;
}
requestConstraint.setConstraintValueList(dataTimeStrings);
dbQueryRequest.addConstraint(FIELD_DATATIME, requestConstraint);
return dbQueryRequest;
}
/**
* Constructs a db request using the provided time range
*
* @param request
* the original grid request
* @param timeRange
* the time range to include in the request
* @return a DbQueryRequest to execute
*/
protected DbQueryRequest buildDbQueryRequest(R request, TimeRange timeRange) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request);
/* Add the TimeRange Constraint */
RequestConstraint requestConstraint = new RequestConstraint();
requestConstraint.setConstraintType(ConstraintType.BETWEEN);
String[] dateTimeStrings = new String[] {
timeRange.getStart().toString(), timeRange.getEnd().toString() };
requestConstraint.setBetweenValueList(dateTimeStrings);
// TODO what should this do with forecast products?
dbQueryRequest.addConstraint(FIELD_DATATIME, requestConstraint);
return dbQueryRequest;
}
/**
* Constructs the base of a db query request using the supplied grid request
*
* @param request
* the original grid request
* @return the base DbQueryRequest
*/
protected DbQueryRequest buildDbQueryRequest(R request) {
DbQueryRequest dbQueryRequest = new DbQueryRequest();
Map<String, RequestConstraint> constraints = this
.buildConstraintsFromRequest(request);
constraints.put(DBQUERY_PLUGIN_NAME_KEY,
new RequestConstraint(request.getDatatype()));
dbQueryRequest.setConstraints(constraints);
return dbQueryRequest;
}
protected abstract Map<String, RequestConstraint> buildConstraintsFromRequest(
R request);
protected abstract D[] getData(R request, DbQueryResponse dbQueryResponse);
}

View file

@ -0,0 +1,174 @@
/**
* 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.dataaccess.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
import com.raytheon.uf.common.dataaccess.grid.IGridData;
import com.raytheon.uf.common.dataaccess.grid.IGridRequest;
import com.raytheon.uf.common.dataaccess.util.PDOUtil;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
import com.raytheon.uf.common.datastorage.Request;
import com.raytheon.uf.common.datastorage.Request.Type;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
/**
* An abstract factory for getting grid data from plugins that use
* PluginDataObject.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 17, 2013 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public abstract class AbstractGridDataPluginFactory extends
AbstractDataPluginFactory<IGridRequest, IGridData> {
/**
* Executes the provided DbQueryRequest and returns an array of IGridData
*
* @param request
* the original grid request
* @param dbQueryRequest
* the db query request to execute
* @return an array of IGridData
*/
protected IGridData[] getData(IGridRequest request,
DbQueryResponse dbQueryResponse) {
List<IGridData> gridData = new ArrayList<IGridData>();
for (Map<String, Object> resultMap : dbQueryResponse.getResults()) {
if (resultMap.containsKey(null) == false) {
throw new DataRetrievalException(
"The results of the DbQueryRequest do not consist of PluginDataObject objects as expected.");
}
if ((resultMap.get(null) instanceof PluginDataObject) == false) {
throw new DataRetrievalException(
"The PluginDataObject objects returned by the DbQueryRequest are not of type SatelliteRecord as expected.");
}
PluginDataObject pdo = (PluginDataObject) resultMap
.get(null);
IDataRecord dataRecord = null;
try {
dataRecord = PDOUtil.getDataRecords(pdo, "Data",
request.getStorageRequest());
} catch (Exception e) {
e.printStackTrace();
throw new DataRetrievalException(
"Failed to retrieve the IDataRecord for PluginDataObject: "
+ pdo.toString(), e);
}
/*
* Extract the grid geometry.
*/
GridGeometry2D gridGeometry = PDOUtil.retrieveGeometry(pdo);
gridGeometry = trimGridGeometryToRequest(gridGeometry,
request.getStorageRequest());
IGridData defaultGridData = null;
defaultGridData = this.constructGridDataResponse(request, pdo,
gridGeometry, dataRecord);
gridData.add(defaultGridData);
}
return gridData.toArray(new IGridData[gridData.size()]);
}
/**
* Given a full PDO grid geometry and the request used this will determine
* the geometry that describes the requested area. For null or ALL this
* returns the full geometry, for SLAB requests this will create a subset
* geometry describing the slab and for all other types of requests this
* returns null.
*
* @param gridGeom
* - full dataset geometry
* @param storageRequest
* @return for null or ALL this returns the full geometry, for SLAB requests
* this will create a subset geometry describing the slab and for
* all other types of requests this returns null.
*/
protected GridGeometry2D trimGridGeometryToRequest(GridGeometry2D gridGeom,
Request storageRequest) {
if (storageRequest == null || storageRequest.getType() == Type.ALL) {
return gridGeom;
} else if (storageRequest.getType() == Type.SLAB) {
int[] min = storageRequest.getMinIndexForSlab();
int[] max = storageRequest.getMaxIndexForSlab();
GridEnvelope2D range = new GridEnvelope2D(min[0], min[1], max[0]
- min[0], max[1] - min[1]);
try {
Envelope env = gridGeom.gridToWorld(range);
return new GridGeometry2D(range, env);
} catch (TransformException e) {
throw new DataRetrievalException(e);
}
} else {
// point, and line requests can't easily be described by a grid
// geometry. Theoretically if there is one point or if the lines are
// evenly spaced it might be possible or lines could be described by
// a nonlinear geometry, but as of now there are no plans to use the
// api for anything this exciting.
return null;
}
}
/**
* Builds an IGridData with the information that is supplied
*
* @param request
* the original grid request
* @param pdo
* a record that was retrieved from the database
* @param gridGeometry
* the geometry extracted from the pdo
* @param dataRecord
* the raw data
* @return the IGridData that was constructed
*/
protected abstract IGridData constructGridDataResponse(
IGridRequest request, PluginDataObject pdo,
GridGeometry2D gridGeometry, IDataRecord dataRecord);
}

View file

@ -29,10 +29,11 @@ import com.raytheon.uf.common.dataplugin.persist.IHDFFilePathProvider;
import com.raytheon.uf.common.dataplugin.persist.IPersistable;
import com.raytheon.uf.common.datastorage.DataStoreFactory;
import com.raytheon.uf.common.datastorage.IDataStore;
import com.raytheon.uf.common.datastorage.Request;
import com.raytheon.uf.common.datastorage.StorageException;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.geospatial.ISpatialEnabled;
import com.raytheon.uf.common.geospatial.MapUtil;
import com.raytheon.uf.common.localization.IPathManager;
/**
@ -64,6 +65,21 @@ public final class PDOUtil {
*/
private PDOUtil() {
}
private static IDataStore getDataStore(PluginDataObject pdo){
final String pluginName = pdo.getPluginName();
final IPersistable persistable = (IPersistable) pdo;
IHDFFilePathProvider pathProvider = pdo.getHDFPathProvider();
String satelliteHDF5Path = pathProvider.getHDFPath(pluginName,
persistable);
String satelliteHDF5File = pathProvider.getHDFFileName(pluginName,
persistable);
File file = new File(pluginName + IPathManager.SEPARATOR
+ satelliteHDF5Path + IPathManager.SEPARATOR
+ satelliteHDF5File);
return DataStoreFactory.getDataStore(file);
}
/**
* Retrieves the IDataRecords associated with the provided PluginDataObject.
@ -77,22 +93,17 @@ public final class PDOUtil {
*/
public static IDataRecord[] getDataRecords(PluginDataObject pdo)
throws FileNotFoundException, StorageException {
final String pluginName = pdo.getPluginName();
final IPersistable persistable = (IPersistable) pdo;
IHDFFilePathProvider pathProvider = pdo.getHDFPathProvider();
String satelliteHDF5Path = pathProvider.getHDFPath(pluginName,
persistable);
String satelliteHDF5File = pathProvider.getHDFFileName(pluginName,
persistable);
File file = new File(pluginName + IPathManager.SEPARATOR
+ satelliteHDF5Path + IPathManager.SEPARATOR
+ satelliteHDF5File);
IDataStore dataStore = DataStoreFactory.getDataStore(file);
IDataStore dataStore = getDataStore(pdo);
return dataStore.retrieve(pdo.getDataURI());
}
public static IDataRecord getDataRecords(PluginDataObject pdo,
String dataset, Request request)
throws FileNotFoundException, StorageException {
IDataStore dataStore = getDataStore(pdo);
return dataStore.retrieve(pdo.getDataURI(), dataset, request);
}
/**
* A utility method to extract and return the GridGeometry2D associated with
* the provided PluginDataObject.

View file

@ -39,4 +39,5 @@ Require-Bundle: javax.measure,
com.raytheon.uf.common.comm;bundle-version="1.12.1174",
com.raytheon.uf.common.dataquery;bundle-version="1.0.0",
com.raytheon.uf.common.dataplugin.level;bundle-version="1.12.1174",
com.raytheon.uf.common.util;bundle-version="1.12.1174"
com.raytheon.uf.common.util;bundle-version="1.12.1174",
com.raytheon.uf.common.dataaccess;bundle-version="1.0.0"

View file

@ -0,0 +1,13 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="gridDataAccessFactory" class="com.raytheon.uf.common.dataplugin.grid.dataaccess.GridDataAccessFactory" />
<bean factory-bean="dataAccessRegistry" factory-method="register">
<constructor-arg value="grid"/>
<constructor-arg value="com.raytheon.uf.common.dataaccess.grid.IGridRequest"/>
<constructor-arg ref="gridDataAccessFactory"/>
</bean>
</beans>

View file

@ -0,0 +1,299 @@
/**
* 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.dataplugin.grid.dataaccess;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.measure.unit.Unit;
import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.comm.CommunicationException;
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
import com.raytheon.uf.common.dataaccess.grid.IGridData;
import com.raytheon.uf.common.dataaccess.grid.IGridDataFactory;
import com.raytheon.uf.common.dataaccess.grid.IGridRequest;
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.grid.GridConstants;
import com.raytheon.uf.common.dataplugin.grid.GridRecord;
import com.raytheon.uf.common.dataplugin.grid.dataquery.GridQueryAssembler;
import com.raytheon.uf.common.dataplugin.grid.mapping.DatasetIdMapper;
import com.raytheon.uf.common.dataplugin.level.Level;
import com.raytheon.uf.common.dataplugin.level.mapping.LevelMapper;
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
import com.raytheon.uf.common.gridcoverage.GridCoverage;
import com.raytheon.uf.common.gridcoverage.lookup.GridCoverageLookup;
import com.raytheon.uf.common.parameter.mapping.ParameterMapper;
import com.raytheon.uf.common.util.mapping.Mapper;
/**
* Data access factory for accessing data from the Grid plugin as grid types.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 17, 2013 bsteffen Initial creation
*
* </pre>
*
* @author bsteffen
* @version 1.0
*/
public class GridDataAccessFactory extends AbstractGridDataPluginFactory
implements IGridDataFactory {
private static final String NAMESPACE = "namespace";
@Override
public GridGeometry2D getGeometry(IGridRequest request) {
Object locationId = null;
if (request.getIdentifiers().containsKey(GridConstants.LOCATION_ID)) {
locationId = request.getIdentifiers()
.get(GridConstants.LOCATION_ID);
} else {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request);
dbQueryRequest.setDistinct(Boolean.TRUE);
dbQueryRequest.addRequestField(GridConstants.LOCATION_ID);
DbQueryResponse dbQueryResponse = this.executeDbQueryRequest(
dbQueryRequest, request.toString());
if (dbQueryResponse.getResults().isEmpty()) {
return null;
}
if (dbQueryResponse.getResults().size() > 1) {
throw new DataRetrievalException(
"The provided request parameters refer to more than one geographical location.");
}
locationId = dbQueryResponse.getResults().get(0)
.get(GridConstants.LOCATION_ID);
}
GridCoverage cov = GridCoverageLookup.getInstance().getCoverage(
Integer.parseInt(locationId.toString()));
if (cov != null) {
return trimGridGeometryToRequest(cov.getGridGeometry(),
request.getStorageRequest());
} else {
return null;
}
}
@Override
public String[] getRequiredIdentifiers() {
// What is required? Technically it would be nice if you specified a
// datasetid, but some parameters are only in one model so maybe it's
// not required.
return null;
}
@Override
protected Map<String, RequestConstraint> buildConstraintsFromRequest(
IGridRequest request) {
Map<String, RequestConstraint> result = new HashMap<String, RequestConstraint>();
Map<String, Object> identifiers = request.getIdentifiers();
try {
GridQueryAssembler assembler = new GridQueryAssembler();
if (identifiers.containsKey(NAMESPACE)) {
assembler.setNamespace(identifiers.get(NAMESPACE).toString());
}
if (request.getParameters() != null) {
for (String parameter : request.getParameters()) {
assembler.setParameterAbbreviation(parameter);
mergeConstraintMaps(assembler.getConstraintMap(), result);
}
// clear fields so it doesn't merge the last one again.
assembler.setParameterAbbreviation(null);
}
if (request.getLevels() != null) {
for (Level level : request.getLevels()) {
assembler.setMasterLevelName(level.getMasterLevel()
.getName());
assembler.setLevelUnits(level.getMasterLevel()
.getUnitString());
assembler.setLevelOneValue(level.getLevelonevalue());
assembler.setLevelTwoValue(level.getLeveltwovalue());
// TODO Theoretically merging these could end badly if there
// are multiple master levels or if some levels have
// leveltwo and others don't. But for now pretend that never
// happens since it probably won't.
mergeConstraintMaps(assembler.getConstraintMap(), result);
}
// clear fields so it doesn't merge the last one again.
assembler.setMasterLevelName(null);
assembler.setLevelUnits(null);
assembler.setLevelOneValue(null);
assembler.setLevelTwoValue(null);
}
if (identifiers.containsKey(GridConstants.DATASET_ID)) {
assembler.setDatasetId(identifiers
.get(GridConstants.DATASET_ID).toString());
}
if (identifiers.containsKey(GridConstants.ENSEMBLE_ID)) {
assembler.setEnsembleId(identifiers.get(
GridConstants.ENSEMBLE_ID).toString());
}
if (identifiers.containsKey(GridConstants.SECONDARY_ID)) {
assembler.setSecondaryId(identifiers.get(
GridConstants.SECONDARY_ID).toString());
}
mergeConstraintMaps(assembler.getConstraintMap(), result);
} catch (CommunicationException e) {
throw new DataRetrievalException(e);
}
return result;
}
/**
* Copy all constraints from source to target. If target already contains a
* constraint for a key then merge the values into target.
*
* @param target
* @param source
*/
private void mergeConstraintMaps(Map<String, RequestConstraint> source,
Map<String, RequestConstraint> target) {
for (Entry<String, RequestConstraint> sourceEntry : source.entrySet()) {
String key = sourceEntry.getKey();
RequestConstraint sourceConstraint = sourceEntry.getValue();
RequestConstraint targetConstraint = target.get(sourceEntry
.getKey());
if (targetConstraint == null) {
target.put(key, sourceConstraint);
} else if (!sourceConstraint.equals(targetConstraint)) {
targetConstraint.setConstraintType(ConstraintType.IN);
// TODO we don't necessarily want to always add. This could
// result in something like IN MB,FHAG,MB,MB,MB, but we also
// don't want to parse the in list all the time.
targetConstraint.addToConstraintValueList(sourceConstraint
.getConstraintValue());
}
}
}
@Override
protected IGridData constructGridDataResponse(IGridRequest request,
PluginDataObject pdo, GridGeometry2D gridGeometry,
IDataRecord dataRecord) {
if (pdo instanceof GridRecord == false) {
throw new DataRetrievalException(this.getClass().getSimpleName()
+ " cannot handle " + pdo.getClass().getSimpleName());
}
GridRecord gridRecord = (GridRecord) pdo;
String parameter = gridRecord.getParameter().getAbbreviation();
String datasetId = gridRecord.getDatasetId();
Level level = gridRecord.getLevel();
if (request.getIdentifiers().containsKey(NAMESPACE)) {
// perform reverse mappings so the parameters and levels that are
// returned match exactly what was requested.
String namespace = request.getIdentifiers().get(NAMESPACE)
.toString();
List<String> requestParameters = Arrays.asList(request
.getParameters());
parameter = reverseResolveMapping(ParameterMapper.getInstance(),
parameter, namespace, requestParameters);
if (request.getIdentifiers().containsKey(GridConstants.DATASET_ID)) {
List<String> requestedDatasets = Arrays.asList(request
.getIdentifiers().get(GridConstants.DATASET_ID)
.toString());
datasetId = reverseResolveMapping(
DatasetIdMapper.getInstance(), datasetId, namespace,
requestedDatasets);
}
for (Level requestLevel : request.getLevels()) {
double levelone = requestLevel.getLevelonevalue();
double leveltwo = requestLevel.getLeveltwovalue();
String master = requestLevel.getMasterLevel().getName();
Unit<?> unit = requestLevel.getMasterLevel().getUnit();
try {
// instead of doing reverse mapping just do a forward
// mapping on everything they requested and compare to what
// they got.
Set<Level> levels = LevelMapper.getInstance().lookupLevels(
master, namespace, levelone, leveltwo, unit);
for (Level l : levels) {
if (level.equals(l)) {
level = requestLevel;
break;
}
}
} catch (CommunicationException e) {
throw new DataRetrievalException(e);
}
if (level == requestLevel) {
// we found one.
break;
}
}
}
DefaultGridData defaultGridData = new DefaultGridData(
DataWrapperUtil.constructArrayWrapper(dataRecord), gridGeometry);
defaultGridData.setDataTime(pdo.getDataTime());
defaultGridData.setParameter(parameter);
defaultGridData.setLevel(level);
defaultGridData.setUnit(gridRecord.getParameter().getUnit());
Map<String, Object> attributes = new HashMap<String, Object>(
request.getIdentifiers());
attributes.put(GridConstants.DATASET_ID, datasetId);
attributes.put(GridConstants.SECONDARY_ID, gridRecord.getSecondaryId());
attributes.put(GridConstants.ENSEMBLE_ID, gridRecord.getEnsembleId());
defaultGridData.setAttributes(attributes);
return defaultGridData;
}
private String reverseResolveMapping(Mapper mapper, String base,
String namespace, Collection<String> requested) {
// attempt to find a valid mapping that they requested.
for (String alias : mapper.lookupAliases(base, namespace)) {
if (requested.contains(alias)) {
return alias;
}
}
return base;
}
}

View file

@ -21,46 +21,36 @@ package com.raytheon.uf.common.dataplugin.satellite.dataaccess;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import org.geotools.coverage.grid.GridGeometry2D;
import javax.measure.unit.Unit;
import javax.measure.unit.UnitFormat;
import org.geotools.coverage.grid.GridGeometry2D;
import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException;
import com.raytheon.uf.common.dataaccess.exception.TimeAgnosticDataException;
import com.raytheon.uf.common.dataaccess.grid.IGridData;
import com.raytheon.uf.common.dataaccess.grid.IGridDataFactory;
import com.raytheon.uf.common.dataaccess.grid.IGridRequest;
import com.raytheon.uf.common.dataaccess.impl.AbstractDataFactory;
import com.raytheon.uf.common.dataaccess.impl.AbstractGridDataPluginFactory;
import com.raytheon.uf.common.dataaccess.impl.DefaultGridData;
import com.raytheon.uf.common.dataaccess.util.DataWrapperUtil;
import com.raytheon.uf.common.dataaccess.util.PDOUtil;
import com.raytheon.uf.common.dataplugin.satellite.units.SatelliteUnits;
import com.raytheon.uf.common.time.BinOffset;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.satellite.SatelliteRecord;
import com.raytheon.uf.common.dataplugin.satellite.units.SatelliteUnits;
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
import com.raytheon.uf.common.dataquery.requests.TimeQueryRequest;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType;
import com.raytheon.uf.common.dataquery.responses.DbQueryResponse;
import com.raytheon.uf.common.datastorage.records.IDataRecord;
import com.raytheon.uf.common.serialization.comm.RequestRouter;
import com.raytheon.uf.common.time.DataTime;
/**
* A data factory for getting satellite data from the metadata database. There
* are currently not any required identifiers.
*
* Note: This factory currently does not support Storage Requests even though
* they can be included in an IGridRequest.
*
* <pre>
*
* SOFTWARE HISTORY
@ -68,22 +58,20 @@ import com.raytheon.uf.common.serialization.comm.RequestRouter;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jan 02, 2012 bkowal Initial creation
* Jan 22, 2012 bsteffen Extract common functionality to AbstractGridDataPluginFactory
*
* </pre>
*
* @author bkowal
* @version 1.0
*/
public class SatelliteGridFactory extends AbstractDataFactory implements
IGridDataFactory {
private static final String FIELD_DATATIME = "dataTime.refTime";
public class SatelliteGridFactory extends AbstractGridDataPluginFactory
implements IGridDataFactory {
private static final String FIELD_PYHSICAL_ELEMENT = "physicalElement";
private static final String FIELD_SECTOR_ID = "sectorID";
public static final String DBQUERY_PLUGIN_NAME_KEY = "pluginName";
private Map<String, GridGeometry2D> sectorGeometryMapCache;
public SatelliteGridFactory() {
@ -91,85 +79,6 @@ public class SatelliteGridFactory extends AbstractDataFactory implements
SatelliteUnits.register();
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com.
* raytheon.uf.common.dataaccess.IDataRequest)
*/
@Override
public DataTime[] getAvailableTimes(IGridRequest request)
throws TimeAgnosticDataException {
return this.getAvailableTimes(request, null);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com.
* raytheon.uf.common.dataaccess.IDataRequest,
* com.raytheon.uf.common.time.BinOffset)
*/
@SuppressWarnings("unchecked")
@Override
public DataTime[] getAvailableTimes(IGridRequest request,
BinOffset binOffset) throws TimeAgnosticDataException {
TimeQueryRequest timeQueryRequest = this.buildTimeQueryRequest(request);
if ((binOffset == null) == false) {
timeQueryRequest.setBinOffset(binOffset);
}
List<Object> results = null;
try {
results = (List<Object>) RequestRouter.route(timeQueryRequest);
} catch (Exception e) {
throw new DataRetrievalException(
"Failed to retrieve available data times for plugin "
+ request.getDatatype() + " for request "
+ request.toString(), e);
}
List<DataTime> dataTimes = new ArrayList<DataTime>();
for (Object result : results) {
dataTimes.add((DataTime) result);
}
Collections.sort(dataTimes);
return dataTimes.toArray(new DataTime[dataTimes.size()]);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf
* .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.DataTime[])
*/
@Override
public IGridData[] getData(IGridRequest request, DataTime... times) {
DbQueryRequest dbQueryRequest = this
.buildDbQueryRequest(request, times);
return this.getData(request, dbQueryRequest);
}
/*
* (non-Javadoc)
*
* @see
* com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf
* .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.TimeRange)
*/
@Override
public IGridData[] getData(IGridRequest request, TimeRange timeRange) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request,
timeRange);
return this.getData(request, dbQueryRequest);
}
/*
* (non-Javadoc)
*
@ -185,6 +94,8 @@ public class SatelliteGridFactory extends AbstractDataFactory implements
return null;
}
GridGeometry2D geometry = null;
/*
* Has the Geometry for the sector id already been cached?
*/
@ -193,31 +104,33 @@ public class SatelliteGridFactory extends AbstractDataFactory implements
/*
* Return the Geometry from cache.
*/
return this.sectorGeometryMapCache.get(satelliteSectorID);
geometry = this.sectorGeometryMapCache.get(satelliteSectorID);
}
}
/*
* Retrieve the Geometry.
*/
IGridData[] records = this.getData(request, new DataTime[] {});
if (records.length <= 0) {
// No records were found
return null;
}
GridGeometry2D geometry = records[0].getGridGeometry();
if (geometry == null) {
/*
* Retrieve the Geometry.
*/
IGridData[] records = this.getData(request, new DataTime[] {});
if (records.length <= 0) {
// No records were found
return null;
}
geometry = records[0].getGridGeometry();
/*
* Cache the Geometry.
*/
synchronized (this.sectorGeometryMapCache) {
this.sectorGeometryMapCache.put(satelliteSectorID, geometry);
/*
* Cache the Geometry.
*/
synchronized (this.sectorGeometryMapCache) {
this.sectorGeometryMapCache.put(satelliteSectorID, geometry);
}
}
/*
* Return the Geometry.
*/
return geometry;
return trimGridGeometryToRequest(geometry, request.getStorageRequest());
}
/**
@ -276,214 +189,30 @@ public class SatelliteGridFactory extends AbstractDataFactory implements
return null;
}
/**
* Executes the provided DbQueryRequest and returns an array of IGridData
*
* @param request
* the original grid request
* @param dbQueryRequest
* the db query request to execute
* @return an array of IGridData
*/
/*
* TODO: add support for StorageRequest (included in the IGridRequest)
*/
private IGridData[] getData(IGridRequest request,
DbQueryRequest dbQueryRequest) {
DbQueryResponse dbQueryResponse = this.executeDbQueryRequest(
dbQueryRequest, request.toString());
List<IGridData> gridData = new ArrayList<IGridData>();
for (Map<String, Object> resultMap : dbQueryResponse.getResults()) {
if (resultMap.containsKey(null) == false) {
throw new DataRetrievalException(
"The results of the DbQueryRequest do not consist of PluginDataObject objects as expected.");
}
if ((resultMap.get(null) instanceof SatelliteRecord) == false) {
throw new DataRetrievalException(
"The PluginDataObject objects returned by the DbQueryRequest are not of type SatelliteRecord as expected.");
}
SatelliteRecord satelliteRecord = (SatelliteRecord) resultMap
.get(null);
IDataRecord[] dataRecords = null;
try {
dataRecords = PDOUtil.getDataRecords(satelliteRecord);
} catch (Exception e1) {
throw new DataRetrievalException(
"Failed to retrieve the IDataRecords for PluginDataObject: "
+ satelliteRecord.toString());
}
/*
* Extract the grid geometry.
*/
final GridGeometry2D gridGeometry = PDOUtil
.retrieveGeometry(satelliteRecord);
for (IDataRecord dataRecord : dataRecords) {
DefaultGridData defaultGridData = null;
try {
defaultGridData = this.constructGridDataResponse(request,
satelliteRecord, gridGeometry, dataRecord);
} catch (ParseException e) {
throw new DataRetrievalException(
"Failed to parse the Unit: "
+ satelliteRecord.getUnits(), e);
}
gridData.add(defaultGridData);
}
protected DefaultGridData constructGridDataResponse(IGridRequest request,
PluginDataObject pdo, GridGeometry2D gridGeometry,
IDataRecord dataRecord) {
if(pdo instanceof SatelliteRecord == false){
throw new DataRetrievalException(this.getClass().getSimpleName()
+ " cannot handle " + pdo.getClass().getSimpleName());
}
return gridData.toArray(new IGridData[gridData.size()]);
}
/**
* Executes the provided DbQueryRequest and returns a DbQueryResponse
*
* @param dbQueryRequest
* the DbQueryRequest to execute
* @param gridRequestString
* the original grid request for reporting purposes
* @return a DbQueryResponse
*/
private DbQueryResponse executeDbQueryRequest(
DbQueryRequest dbQueryRequest, String gridRequestString) {
DbQueryResponse dbQueryResponse = null;
try {
dbQueryResponse = (DbQueryResponse) RequestRouter
.route(dbQueryRequest);
} catch (Exception e1) {
throw new DataRetrievalException(
"Unable to complete the DbQueryRequest for request: "
+ gridRequestString, e1);
}
return dbQueryResponse;
}
/**
* Builds a TimeQueryRequest that will be used to retrieve Data Times.
*
* @param request
* the original grid request
* @return a TimeQueryRequest to execute
*/
/*
* TODO: maybe this method needs to be a util or a protected method in a
* superclass so that other data types that utilize a TimeQueryRequest will
* be able to use this logic?
*/
private TimeQueryRequest buildTimeQueryRequest(IGridRequest request) {
TimeQueryRequest timeQueryRequest = new TimeQueryRequest();
timeQueryRequest.setPluginName(request.getDatatype());
timeQueryRequest.setQueryTerms(this
.buildConstraintsFromRequest(request));
return timeQueryRequest;
}
/**
* Constructs a db query request using the provided data times
*
* @param request
* the original grid request
* @param dataTimes
* the data times to include in the request (if any)
* @return a DbQueryRequest to execute
*/
private DbQueryRequest buildDbQueryRequest(IGridRequest request,
DataTime[] dataTimes) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request);
if (dataTimes.length <= 0) {
return dbQueryRequest;
}
/* Add the DataTime Constraint */
RequestConstraint requestConstraint = new RequestConstraint();
requestConstraint.setConstraintType(ConstraintType.IN);
String[] dataTimeStrings = new String[dataTimes.length];
int index = 0;
for (DataTime dataTime : dataTimes) {
dataTimeStrings[index] = dataTime.toString();
++index;
}
requestConstraint.setConstraintValueList(dataTimeStrings);
dbQueryRequest.addConstraint(FIELD_DATATIME, requestConstraint);
return dbQueryRequest;
}
/**
* Constructs a db request using the provided time range
*
* @param request
* the original grid request
* @param timeRange
* the time range to include in the request
* @return a DbQueryRequest to execute
*/
private DbQueryRequest buildDbQueryRequest(IGridRequest request,
TimeRange timeRange) {
DbQueryRequest dbQueryRequest = this.buildDbQueryRequest(request);
/* Add the TimeRange Constraint */
RequestConstraint requestConstraint = new RequestConstraint();
requestConstraint.setConstraintType(ConstraintType.BETWEEN);
String[] dateTimeStrings = new String[] {
timeRange.getStart().toString(), timeRange.getEnd().toString() };
requestConstraint.setBetweenValueList(dateTimeStrings);
dbQueryRequest.addConstraint(FIELD_DATATIME, requestConstraint);
return dbQueryRequest;
}
/**
* Constructs the base of a db query request using the supplied grid request
*
* @param request
* the original grid request
* @return the base DbQueryRequest
*/
private DbQueryRequest buildDbQueryRequest(IGridRequest request) {
DbQueryRequest dbQueryRequest = new DbQueryRequest();
Map<String, RequestConstraint> constraints = this
.buildConstraintsFromRequest(request);
constraints.put(DBQUERY_PLUGIN_NAME_KEY,
new RequestConstraint(request.getDatatype()));
dbQueryRequest.setConstraints(constraints);
return dbQueryRequest;
}
/**
* Builds an IGridData with the information that is supplied
*
* @param request
* the original grid request
* @param satelliteRecord
* a record that was retrieved from the database
* @param gridGeometry
* the geometry extracted from the pdo
* @param dataRecord
* the raw data
* @return the IGridData that was constructed
* @throws ParseException
*/
private DefaultGridData constructGridDataResponse(IGridRequest request,
SatelliteRecord satelliteRecord, GridGeometry2D gridGeometry,
IDataRecord dataRecord) throws ParseException {
SatelliteRecord satelliteRecord = (SatelliteRecord) pdo;
DefaultGridData defaultGridData = new DefaultGridData(
DataWrapperUtil.constructArrayWrapper(dataRecord), gridGeometry);
defaultGridData.setDataTime(satelliteRecord.getDataTime());
defaultGridData.setDataTime(pdo.getDataTime());
defaultGridData.setParameter(satelliteRecord.getPhysicalElement());
defaultGridData.setLevel(null);
// unit
Unit<?> unit = null;
if ((satelliteRecord.getUnits() == null) == false) {
unit = UnitFormat.getUCUMInstance().parseSingleUnit(
satelliteRecord.getUnits(), new ParsePosition(0));
try {
unit = UnitFormat.getUCUMInstance().parseSingleUnit(
satelliteRecord.getUnits(), new ParsePosition(0));
} catch (ParseException e) {
throw new DataRetrievalException("Failed to parse the Unit: "
+ satelliteRecord.getUnits(), e);
}
}
defaultGridData.setUnit(unit);
defaultGridData.setAttributes(request.getIdentifiers());
@ -503,7 +232,7 @@ public class SatelliteGridFactory extends AbstractDataFactory implements
* multiple factories will be building a base constraint map using the same
* technique
*/
private Map<String, RequestConstraint> buildConstraintsFromRequest(
protected Map<String, RequestConstraint> buildConstraintsFromRequest(
IGridRequest request) {
Map<String, RequestConstraint> constraints = new HashMap<String, RequestConstraint>();
if ((request.getIdentifiers() == null) == false) {