diff --git a/cave/com.raytheon.uf.viz.core.feature/feature.xml b/cave/com.raytheon.uf.viz.core.feature/feature.xml index 888cdfab55..1208b117bd 100644 --- a/cave/com.raytheon.uf.viz.core.feature/feature.xml +++ b/cave/com.raytheon.uf.viz.core.feature/feature.xml @@ -187,6 +187,14 @@ install-size="0" version="0.0.0" unpack="false"/> + + + * @@ -64,47 +65,12 @@ public class DefaultDbMapQuery implements DbMapQuery { @Override public QueryResult queryWithinEnvelope(Envelope env, List columns, List additionalConstraints) throws VizException { - // add the geospatial constraint - if (env != null) { - // copy before modifying - if (additionalConstraints == null) { - additionalConstraints = new ArrayList(); - } else { - additionalConstraints = new ArrayList( - additionalConstraints); - } - // geospatial constraint will be first - additionalConstraints.add(0, String.format( - "%s && ST_SetSrid('BOX3D(%f %f, %f %f)'::box3d,4326)", - geomField, env.getMinX(), env.getMinY(), env.getMaxX(), - env.getMaxY())); - } - StringBuilder query = new StringBuilder("SELECT "); - if (columns != null && !columns.isEmpty()) { - Iterator iter = columns.iterator(); - query.append(iter.next()); - while (iter.hasNext()) { - query.append(", "); - query.append(iter.next()); - } - } - - query.append(" FROM "); - query.append(table); - - // add any additional constraints - if (additionalConstraints != null && !additionalConstraints.isEmpty()) { - query.append(" WHERE "); - Iterator iter = additionalConstraints.iterator(); - query.append(iter.next()); - while (iter.hasNext()) { - query.append(" AND "); - query.append(iter.next()); - } - } - - query.append(';'); + /* + * Build the query using the common method. + */ + final String query = MapsQueryUtil.assembleMapsTableQuery(env, columns, + additionalConstraints, this.table, this.geomField); return DirectDbQuery.executeMappedQuery(query.toString(), MAPS, QueryLanguage.SQL); diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.dataaccess/META-INF/MANIFEST.MF index 704b6e4b6b..b3f9ed9b15 100644 --- a/edexOsgi/com.raytheon.uf.common.dataaccess/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/META-INF/MANIFEST.MF @@ -14,7 +14,8 @@ Require-Bundle: com.raytheon.uf.common.time;visibility:=reexport, com.raytheon.uf.common.serialization;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" + com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", + com.raytheon.uf.common.message;bundle-version="1.12.1174" Export-Package: com.raytheon.uf.common.dataaccess, com.raytheon.uf.common.dataaccess.exception, com.raytheon.uf.common.dataaccess.geom, diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryDatabaseFactory.java b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryDatabaseFactory.java new file mode 100644 index 0000000000..9d1a8c3c23 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryDatabaseFactory.java @@ -0,0 +1,416 @@ +/** + * 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.Collections; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.sql.Timestamp; + +import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException; +import com.raytheon.uf.common.dataaccess.exception.TimeAgnosticDataException; +import com.raytheon.uf.common.dataaccess.geom.IGeometryData; +import com.raytheon.uf.common.dataaccess.geom.IGeometryDataFactory; +import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; +import com.raytheon.uf.common.dataaccess.util.DatabaseQueryUtil; +import com.raytheon.uf.common.dataaccess.util.DatabaseQueryUtil.QUERY_MODE; +import com.raytheon.uf.common.dataplugin.level.Level; +import com.raytheon.uf.common.time.BinOffset; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.TimeRange; +import com.vividsolutions.jts.geom.Geometry; + +/** + * Abstracts the retrieval of geometry data by running queries directly against + * the database. Maybe this class could also be further abstracted and extended + * to Grid data types? + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 29, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public abstract class AbstractGeometryDatabaseFactory extends + AbstractDataFactory implements IGeometryDataFactory { + + /* + * for now, we will assume that we will always be executing sql queries. If + * this assumption ever becomes invalid, the type of query that will be + * executed could be passed to the constructor or methods could be + * overridden. + */ + private static final QUERY_MODE queryMode = QUERY_MODE.MODE_SQLQUERY; + + private String databaseName; + + private String[] requiredIdentifiers; + + /** + * Constructor + * + * @param databaseName + * the name of the database to execute queries against + * @param requiredIdentifiers + * the identifiers that need to be included in the request + * (ifdef) + */ + public AbstractGeometryDatabaseFactory(String databaseName, + String[] requiredIdentifiers) { + this.databaseName = databaseName; + this.requiredIdentifiers = requiredIdentifiers; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. + * raytheon.uf.common.dataaccess.IDataRequest) + */ + @Override + public DataTime[] getAvailableTimes(IGeometryRequest request) + throws TimeAgnosticDataException { + this.validateRequest(request); + return this.executeTimeQuery(this.assembleGetTimes(request), request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. + * raytheon.uf.common.dataaccess.IDataRequest, + * com.raytheon.uf.common.time.BinOffset) + */ + @Override + public DataTime[] getAvailableTimes(IGeometryRequest request, + BinOffset binOffset) throws TimeAgnosticDataException { + this.validateRequest(request); + return this.executeTimeQuery(this.assembleGetTimes(request, binOffset), + request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf + * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.DataTime[]) + */ + @Override + public IGeometryData[] getData(IGeometryRequest request, DataTime... times) { + this.validateRequest(request); + return this.executeDataQuery(this.assembleGetData(request, times), + request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf + * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.TimeRange) + */ + @Override + public IGeometryData[] getData(IGeometryRequest request, TimeRange timeRange) { + this.validateRequest(request); + return this.executeDataQuery(this.assembleGetData(request, timeRange), + request); + } + + /** + * Runs a query to retrieve Data Times from the database. + * + * @param query + * the query to execute + * @param request + * the original request that we are processing + * @return an array of DataTimes + */ + protected final DataTime[] executeTimeQuery(String query, + IGeometryRequest request) { + List results = this.executeQuery(query, request); + List dataTimes = new ArrayList(); + for (Object[] objects : results) { + /* + * verify that the object is one of the data types we are expecting. + */ + if (objects[0] instanceof Timestamp) { + dataTimes.add(new DataTime((Timestamp) objects[0])); + } else if (objects[0] instanceof DataTime) { + dataTimes.add((DataTime) objects[0]); + } else { + throw new DataRetrievalException( + "Unrecognized temporal object: " + + objects[0].getClass().getName()); + } + } + + Collections.sort(dataTimes); + return dataTimes.toArray(new DataTime[dataTimes.size()]); + } + + /** + * Runs a query to retrieve IGeometryData from the database. + * + * @param query + * the query to execute + * @param request + * the original request that we are processing + * @return an array of IGeometryData + */ + protected final IGeometryData[] executeDataQuery(String query, + IGeometryRequest request) { + List results = this.executeQuery(query, request); + return this.makeGeometries(results, request.getParameters(), + request.getIdentifiers()); + } + + /** + * Runs a query to retrieve raw data from the database. + * + * @param query + * the query to execute + * @param request + * the original request that we are processing + * @return the raw data retrieved from the database + */ + protected final List executeQuery(String query, + IGeometryRequest request) { + return DatabaseQueryUtil.executeDatabaseQuery(queryMode, query, + this.databaseName, request.getDatatype()); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.common.dataaccess.geom.IGeometryDataFactory# + * getAvailableLocationNames + * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest) + */ + @Override + public String[] getAvailableLocationNames(IGeometryRequest request) { + this.validateRequest(request); + List results = this.executeQuery( + this.assembleGetAvailableLocationNames(request), request); + List locations = new ArrayList(); + for (Object[] objects : results) { + locations.add((String) objects[0]); + } + + Collections.sort(locations, String.CASE_INSENSITIVE_ORDER); + return locations.toArray(new String[locations.size()]); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.common.dataaccess.impl.AbstractDataFactory# + * getRequiredIdentifiers() + */ + @Override + public String[] getRequiredIdentifiers() { + return this.requiredIdentifiers; + } + + /* + * invoked to build the queries that will be executed. + */ + + /** + * Builds a query that will be used to retrieve time from the database based + * on the provided request. + * + * @param request + * the original request that we are processing + * @return the query + */ + protected abstract String assembleGetTimes(IGeometryRequest request); + + /** + * Builds a query that will be used to retrieve time from the database based + * on the provided request and the provided BinOffset. Necessary? + * + * @param request + * the original request that we are processing + * @param binOffset + * the BinOffset to apply to the retrieved DataTimes + * @return the query + */ + protected abstract String assembleGetTimes(IGeometryRequest request, + BinOffset binOffset); + + /** + * Builds a query used to retrieve data from the database based on the + * provided request and a list of DataTimes. + * + * @param request + * the original request that we are processing + * @param times + * DataTimes to use when building the query; will most likely + * manifest as constraints + * @return the query + */ + protected abstract String assembleGetData(IGeometryRequest request, + DataTime... times); + + /** + * Builds a query used to retrieve data from the database based on the + * provided request and the specified TimeRange. + * + * @param request + * the original request that we are processing + * @param timeRange + * a TimeRange to use when building the query; will most likely + * manifest as a BETWEEN constraint + * @return the query + */ + protected abstract String assembleGetData(IGeometryRequest request, + TimeRange timeRange); + + /** + * Builds a query used to retrieve location information from the database + * based on the provided request + * + * @param request + * the original request that we are processing + * @return the query + */ + protected abstract String assembleGetAvailableLocationNames( + IGeometryRequest request); + + /** + * Builds the data objects that will be returned by calls to getData() on + * the factory + * + * @param serverResult + * the results from the query run on the server + * @param paramNames + * the names of the parameters that were requested + * @param identifiers + * the identifiers from the data request + * @return the IGeometryData based on the results of the query + */ + protected IGeometryData[] makeGeometries(List serverResult, + String[] paramNames, Map identifiers) { + List resultList = new ArrayList(); + Map attrs = Collections.unmodifiableMap(identifiers); + + // loop over each db row + for (Object[] row : serverResult) { + resultList.add(this.makeGeometry(row, paramNames, attrs)); + } + + return resultList.toArray(new DefaultGeometryData[resultList.size()]); + } + + /** + * Constructs a single IGeometryData + * + * @param data + * the raw data associated with a single row retrieved from the + * database + * @param paramNames + * the parameters specified in the original IGeometryRequest + * @param attrs + * the identifiers specified in the original IGeometryRequest + * @return the constructed IGeometryData + */ + protected abstract IGeometryData makeGeometry(Object[] data, + String[] paramNames, Map attrs); + + /** + * Constructs a DefaultGeometryData based on the provided information + * + * @param time + * the provided DataTime + * @param level + * the provided Level + * @param geometry + * the provided Geometry + * @param locationName + * the provided Location + * @param attributes + * the identifiers specified in the original IGeometryRequest + * @param paramNames + * the parameters specified in the original IGeometryRequest + * @return the constructed DefaultGeometryData + */ + protected DefaultGeometryData buildGeometryData(DataTime time, Level level, + Geometry geometry, String locationName, + Map attributes, String[] paramNames) { + return this.buildGeometryData(time, level, geometry, locationName, + attributes, Integer.MAX_VALUE, null, paramNames); + } + + /** + * Constructs a DefaultGeometryData based on the provided information + * + * @param time + * the provided DataTime + * @param level + * the provided Level + * @param geometry + * the provided Geometry + * @param locationName + * the provided Location + * @param attributes + * identifiers specified in the original IGeometryRequest + * @param dataIndex + * a numerical index indicating where user-specified parameters + * may start in the provided row of raw data + * @param data + * a row of row data retrieved from the database; all + * user-specified parameters are extracted from it and added to + * the DefaultGeometryData using the addData method + * @param paramNames + * the parameters specified in the original IGeometryRequest + * @return the constructed DefaultGeometryData + */ + protected DefaultGeometryData buildGeometryData(DataTime time, Level level, + Geometry geometry, String locationName, + Map attributes, int dataIndex, Object[] data, + String[] paramNames) { + DefaultGeometryData geometryData = new DefaultGeometryData(); + geometryData.setDataTime(time); + geometryData.setLevel(level); + geometryData.setGeometry(geometry); + geometryData.setLocationName(locationName); + geometryData.setAttributes(attributes); + if ((data == null) == false && data.length > dataIndex) { + for (int i = dataIndex; i < data.length; i++) { + String name = paramNames[i - dataIndex]; + geometryData.addData(name, data[i]); + } + } + + return geometryData; + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryTimeAgnosticDatabaseFactory.java b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryTimeAgnosticDatabaseFactory.java new file mode 100644 index 0000000000..b584ece5c3 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/impl/AbstractGeometryTimeAgnosticDatabaseFactory.java @@ -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 com.raytheon.uf.common.dataaccess.exception.TimeAgnosticDataException; +import com.raytheon.uf.common.dataaccess.geom.IGeometryData; +import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; +import com.raytheon.uf.common.time.BinOffset; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.TimeRange; + +/** + * Abstracts the retrieval of time agnostic geometry data by building on and/or + * extending AbstractGeometryDatabaseFactory. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 29, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public abstract class AbstractGeometryTimeAgnosticDatabaseFactory extends + AbstractGeometryDatabaseFactory { + + /** + * Constructor + * + * @param databaseName + * the name of the database to execute queries against + * @param requiredIdentifiers + * the identifiers that need to be included in the request + * (ifdef) + */ + public AbstractGeometryTimeAgnosticDatabaseFactory(String databaseName, + String[] requiredIdentifiers) { + super(databaseName, requiredIdentifiers); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. + * raytheon.uf.common.dataaccess.IDataRequest) + */ + @Override + public DataTime[] getAvailableTimes(IGeometryRequest request) + throws TimeAgnosticDataException { + throw new TimeAgnosticDataException(this.buildExceptionMessage(request)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf + * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.DataTime[]) + */ + @Override + public IGeometryData[] getData(IGeometryRequest request, DataTime... times) { + return this.getData(request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf + * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.TimeRange) + */ + @Override + public IGeometryData[] getData(IGeometryRequest request, TimeRange timeRange) { + return this.getData(request); + } + + /** + * Retrieves data in a time agnostic way. + * + * @param request the original request that we are processing + * @return an array of IGeometryData + */ + protected IGeometryData[] getData(IGeometryRequest request) { + return super.executeDataQuery(this.assembleGetData(request), request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. + * raytheon.uf.common.dataaccess.IDataRequest, + * com.raytheon.uf.common.time.BinOffset) + */ + @Override + public DataTime[] getAvailableTimes(IGeometryRequest request, + BinOffset binOffset) throws TimeAgnosticDataException { + throw new TimeAgnosticDataException(this.buildExceptionMessage(request)); + } + + /** + * Constructs the message that will be included in the TimeAgnosticException + * + * @param request the original request that we are processing + * @return the constructed exception message + */ + private String buildExceptionMessage(IGeometryRequest request) { + StringBuilder stringBuilder = new StringBuilder( + "This operation is unsupported for data type: "); + stringBuilder.append(request.getDatatype()); + + return stringBuilder.toString(); + } + + /** + * Builds a time agnostic version of the query that will be used to retrieve data from the database. + * + * @param request the original request that we are processing + * @return the query + */ + protected abstract String assembleGetData(IGeometryRequest request); + + /** + * The following methods are no longer applicable to us. + * + * Should we be throwing an exception + */ + @Override + protected String assembleGetTimes(IGeometryRequest request) { + return null; + } + + @Override + protected String assembleGetTimes(IGeometryRequest request, + BinOffset binOffset) { + return null; + } + + @Override + protected String assembleGetData(IGeometryRequest request, + DataTime... times) { + return null; + } + + @Override + protected String assembleGetData(IGeometryRequest request, + TimeRange timeRange) { + return null; + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/util/DatabaseQueryUtil.java b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/util/DatabaseQueryUtil.java new file mode 100644 index 0000000000..70bb1e6065 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/util/DatabaseQueryUtil.java @@ -0,0 +1,136 @@ +/** + * 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.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException; +import com.raytheon.uf.common.dataquery.db.QueryResult; +import com.raytheon.uf.common.dataquery.db.QueryResultRow; +import com.raytheon.uf.common.dataquery.requests.QlServerRequest; +import com.raytheon.uf.common.dataquery.requests.RequestConstraint; +import com.raytheon.uf.common.message.response.AbstractResponseMessage; +import com.raytheon.uf.common.message.response.ResponseMessageError; +import com.raytheon.uf.common.message.response.ResponseMessageGeneric; +import com.raytheon.uf.common.serialization.comm.RequestRouter; + +/** + * A utility used to run queries against a specified database. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 29, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public class DatabaseQueryUtil { + /* + * should this enum actually be provided by the QlServerRequest? + */ + public static enum QUERY_MODE { + MODE_SQLQUERY("sqlquery"), MODE_HQLQUERY("hqlquery"), MODE_SQL_STATEMENT( + "sqlstatement"), MODE_HSQL_STATEMENT("hqlstatement"), MODE_SAVE_OR_UPDATE( + "saveOrUpdateObject"); + + private String modeText; + + QUERY_MODE(String modeText) { + this.modeText = modeText; + } + + protected String getModeText() { + return this.modeText; + } + } + + private static final String CONSTRAINT_QUERY = "query"; + + private static final String CONSTRAINT_DATABASE = "database"; + + private static final String CONSTRAINT_MODE = "mode"; + + /** + * Constructor + */ + private DatabaseQueryUtil() { + } + + /** + * Executes the provided query against the specified database and returns the results of the query execution. + * + * @param mode the request mode + * @param query the query to execute + * @param database the database to execute the query against + * @param dataType the Data Access Framework factory data type + * @return the information retrieved from the database + */ + public static List executeDatabaseQuery(QUERY_MODE mode, + String query, String database, String dataType) { + Map requestConstraintMap = new HashMap(); + requestConstraintMap + .put(CONSTRAINT_QUERY, new RequestConstraint(query)); + requestConstraintMap.put(CONSTRAINT_DATABASE, new RequestConstraint( + database)); + requestConstraintMap.put(CONSTRAINT_MODE, + new RequestConstraint(mode.getModeText())); + QlServerRequest serverRequest = new QlServerRequest( + requestConstraintMap); + + final String errorMessage = "Error retrieving " + dataType + " data"; + + // Execute the request. + AbstractResponseMessage response = null; + try { + response = (AbstractResponseMessage) RequestRouter + .route(serverRequest); + } catch (Exception e) { + throw new DataRetrievalException(errorMessage, e); + } + + QueryResult result = null; + if (response instanceof ResponseMessageError) { + throw new DataRetrievalException(errorMessage + ": " + + response.toString()); + } else if (response instanceof ResponseMessageGeneric) { + result = (QueryResult) ((ResponseMessageGeneric) response) + .getContents(); + } else { + throw new DataRetrievalException( + "Unable to process response of type" + response.getClass()); + } + + List unmappedResults = new ArrayList(); + for (QueryResultRow row : result.getRows()) { + unmappedResults.add(row.getColumnValues()); + } + return unmappedResults; + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.classpath b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.project b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.project new file mode 100644 index 0000000000..a741fa4514 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.dataplugin.maps + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..570db74296 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Mon Jan 28 15:41:42 CST 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..84a4bea125 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Common Maps Dataplugin +Bundle-SymbolicName: com.raytheon.uf.common.dataplugin.maps +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.apache.commons.lang;bundle-version="2.3.0", + com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174", + org.geotools;bundle-version="2.6.4", + com.raytheon.uf.common.dataaccess;bundle-version="1.0.0", + com.raytheon.uf.common.dataquery;bundle-version="1.0.0", + com.raytheon.uf.common.serialization;bundle-version="1.12.1174", + com.raytheon.uf.common.serialization.comm;bundle-version="1.12.1174", + com.raytheon.uf.common.message;bundle-version="1.12.1174" +Export-Package: com.raytheon.uf.common.dataplugin.maps.dataaccess.util diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/build.properties b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/build.properties new file mode 100644 index 0000000000..5791d48d5f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + res/ diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/res/spring/maps-dataplugin-common.xml b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/res/spring/maps-dataplugin-common.xml new file mode 100644 index 0000000000..138fc1113f --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/res/spring/maps-dataplugin-common.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsGeometryFactory.java b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsGeometryFactory.java new file mode 100644 index 0000000000..8cf9ee43d8 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsGeometryFactory.java @@ -0,0 +1,128 @@ +/** + * 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.maps.dataaccess; + +import java.util.Map; + +import com.vividsolutions.jts.geom.Geometry; + +import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException; +import com.raytheon.uf.common.dataaccess.geom.IGeometryData; +import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; +import com.raytheon.uf.common.dataaccess.impl.AbstractGeometryTimeAgnosticDatabaseFactory; +import com.vividsolutions.jts.io.ParseException; +import com.vividsolutions.jts.io.WKBReader; + +/** + * A data factory for retrieving data from the maps database. Currently, the + * name of the table to retrieve data from and the name of the geometry field of + * interest are required identifiers. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ +public class MapsGeometryFactory extends + AbstractGeometryTimeAgnosticDatabaseFactory { + private static final String[] REQUIRED_IDENTIFIERS = new String[] { + MapsQueryAssembler.REQUIRED_IDENTIFIERS.IDENTIFIER_TABLE, + MapsQueryAssembler.REQUIRED_IDENTIFIERS.IDENTIFIER_GEOM_FIELD }; + + private static final String MAPS_DATABASE = "maps"; + + private static final ThreadLocal wkbReaderWrapper = new ThreadLocal() { + @Override + protected WKBReader initialValue() { + return new WKBReader(); + } + }; + + /** + * Constructor + */ + public MapsGeometryFactory() { + super(MAPS_DATABASE, REQUIRED_IDENTIFIERS); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #makeGeometry(java.lang.Object[], java.lang.String[], java.util.Map) + */ + @Override + protected IGeometryData makeGeometry(Object[] data, String[] paramNames, + Map attrs) { + // order selected geom field, location, and other parameters + + // build the geometry + Geometry geometry = null; + Object object = data[0]; + if ((object instanceof byte[]) == false) { + throw new DataRetrievalException( + "Retrieved Geometry was not the expected type; was expecting byte[], received: " + + object.getClass().getName()); + } + try { + geometry = (wkbReaderWrapper.get()).read((byte[]) object); + } catch (ParseException e) { + throw new DataRetrievalException("Failed to parse the geometry.", e); + } + String location = (String) data[1]; + + return super.buildGeometryData(null, null, geometry, location, attrs, + 2, data, paramNames); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.common.dataaccess.impl. + * AbstractGeometryTimeAgnosticDatabaseFactory + * #assembleGetData(com.raytheon.uf.common.dataaccess.geom.IGeometryRequest) + */ + @Override + protected String assembleGetData(IGeometryRequest request) { + return MapsQueryAssembler.assembleGetData(request); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetAvailableLocationNames + * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest) + */ + @Override + protected String assembleGetAvailableLocationNames(IGeometryRequest request) { + return MapsQueryAssembler.assembleGetAvailableLocationNames(request); + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsQueryAssembler.java b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsQueryAssembler.java new file mode 100644 index 0000000000..5ac5347c21 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/MapsQueryAssembler.java @@ -0,0 +1,275 @@ +/** + * 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.maps.dataaccess; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Iterator; + +import org.apache.commons.lang.BooleanUtils; + +import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; +import com.raytheon.uf.common.dataplugin.maps.dataaccess.util.MapsQueryUtil; +import com.vividsolutions.jts.geom.Envelope; + +/** + * Constructs a query to retrieve information from the maps database based on + * the supplied information. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public class MapsQueryAssembler { + public static final class REQUIRED_IDENTIFIERS { + /* + * The table to retrieve the data from. + */ + public static final String IDENTIFIER_TABLE = "table"; + + /* + * The first field that will be selected - the geometry that we would + * like to retrieve. We will verify that it is not already in the column + * list. + */ + public static final String IDENTIFIER_GEOM_FIELD = "geomField"; + } + + /* + * Other common identifiers we may encounter. + */ + public static final class IDENTIFIERS { + /* + * Used to specify if the factory should look for information that is + * within the specified locations or information that excludes the + * specified locations. If this identifier is not specified, the default + * will be to look for information within the specified location. + */ + public static final String IDENTIFIER_IN_LOCATION = "inLocation"; + + /* + * The name of the location field, defaults to "name". + */ + public static final String IDENTIFIER_LOCATION_FIELD = "locationField"; + } + + private static final List RESERVED_IDENTIFIERS = Arrays.asList( + REQUIRED_IDENTIFIERS.IDENTIFIER_TABLE, + REQUIRED_IDENTIFIERS.IDENTIFIER_GEOM_FIELD, + IDENTIFIERS.IDENTIFIER_IN_LOCATION, + IDENTIFIERS.IDENTIFIER_LOCATION_FIELD); + + private static final String DEFAULT_LOCATION_FIELD = "name"; + + /** + * Constructor + */ + private MapsQueryAssembler() { + } + + /** + * Retrieves a named identifier from the request + * + * @param request + * the original request that we are processing + * @param identifierName + * the name of the identifier to extract + * @return the identifier + */ + public static String extractIdentifier(IGeometryRequest request, + String identifierName) { + return request.getIdentifiers().get(identifierName).toString(); + } + + /** + * Retrieves the table identifier + * + * @param request + * the original request that we are processing + * @return the table identifier + */ + public static String extractTable(IGeometryRequest request) { + return extractIdentifier(request, REQUIRED_IDENTIFIERS.IDENTIFIER_TABLE); + } + + /** + * Retrieves the geometry field identifier + * + * @param request + * the original request that we are processing + * @return the geometry identifier + */ + public static String extractGeomField(IGeometryRequest request) { + return extractIdentifier(request, + REQUIRED_IDENTIFIERS.IDENTIFIER_GEOM_FIELD); + } + + /** + * Constructs a query to retrieve data from the maps database + * + * @param request + * the original request that we are processing + * @return the query + */ + public static String assembleGetData(IGeometryRequest request) { + return assembleQuery(request, Boolean.FALSE); + } + + /** + * Constructs a query to retrieve locations from the database + * + * @param request + * the original request that we are processing + * @return the query + */ + public static String assembleGetAvailableLocationNames( + IGeometryRequest request) { + return assembleQuery(request, Boolean.TRUE); + } + + /** + * Constructs a query to retrieve information from the database + * + * @param request + * the original request that we are processing + * @param locationQuery + * indicates whether or not this query will be used to retrieve + * location information + * @return the query + */ + private static String assembleQuery(IGeometryRequest request, + boolean locationQuery) { + Envelope envelope = request.getEnvelope(); + String table = extractTable(request); + String geomField = extractGeomField(request); + String locationField = DEFAULT_LOCATION_FIELD; + if (request.getIdentifiers().containsKey( + IDENTIFIERS.IDENTIFIER_LOCATION_FIELD)) { + locationField = request.getIdentifiers() + .get(IDENTIFIERS.IDENTIFIER_LOCATION_FIELD).toString(); + } + + List columns = new ArrayList(); + if (locationQuery == false) { + // the first column will always be the geometry. + columns.add("AsBinary(" + geomField + ")"); + } + // the second column will always be the location name + columns.add(locationField); + if (locationQuery == false) { + // add any additional database columns the user has specified as + // parameters + // for additional information, refer to: http://tinyurl.com/arnayco + for (String parameter : request.getParameters()) { + columns.add(parameter); + } + } + List constraints = new ArrayList(); + // add location constraint (ifdef) + if ((request.getLocationNames() == null) == false + && request.getLocationNames().length > 0) { + boolean inLocation = Boolean.TRUE; + if (request.getIdentifiers().containsKey( + IDENTIFIERS.IDENTIFIER_IN_LOCATION)) { + inLocation = BooleanUtils.toBoolean(request.getIdentifiers() + .get(IDENTIFIERS.IDENTIFIER_IN_LOCATION).toString()); + } + + constraints.add(buildInConstraint(request.getLocationNames(), + locationField, inLocation)); + } + // add remaining identifiers to constraints (ifdef) + Iterator identifiersIterator = request.getIdentifiers() + .keySet().iterator(); + while (identifiersIterator.hasNext()) { + String identifierKey = identifiersIterator.next(); + if (RESERVED_IDENTIFIERS.contains(identifierKey)) { + continue; + } + constraints.add(buildEqualsConstraint(identifierKey, request + .getIdentifiers().get(identifierKey).toString())); + } + + return MapsQueryUtil.assembleMapsTableQuery(envelope, columns, + constraints, table, geomField); + } + + /** + * Constructs an equality constraint + * + * @param key + * the operand + * @param value + * the expected result + * @return the equality constraint + */ + private static String buildEqualsConstraint(String key, String value) { + StringBuilder stringBuilder = new StringBuilder(key); + stringBuilder.append(" = '"); + stringBuilder.append(value); + stringBuilder.append("'"); + + return stringBuilder.toString(); + } + + /** + * Constructs an IN or NOT IN constraint + * + * @param elements + * a list of elements to include in the constraint + * @param fieldName + * the database column name + * @param in + * indicates whether this is an IN constraint or a NOT IN + * constraint + * @return the constraint + */ + private static String buildInConstraint(Object[] elements, + String fieldName, boolean in) { + StringBuilder stringBuilder = new StringBuilder(fieldName); + if (in) { + stringBuilder.append(" IN ('"); + } else { + stringBuilder.append(" NOT IN ('"); + } + // add the 0th location + stringBuilder.append(elements[0]); + stringBuilder.append("'"); + for (int i = 1; i < elements.length; i++) { + stringBuilder.append(", '"); + stringBuilder.append(elements[i]); + stringBuilder.append("'"); + } + stringBuilder.append(")"); + + return stringBuilder.toString(); + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/util/MapsQueryUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/util/MapsQueryUtil.java new file mode 100644 index 0000000000..d87351dffb --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.maps/src/com/raytheon/uf/common/dataplugin/maps/dataaccess/util/MapsQueryUtil.java @@ -0,0 +1,119 @@ +/** + * 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.maps.dataaccess.util; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.vividsolutions.jts.geom.Envelope; + +/** + * A utility to construct a query that will be used to retrieve information from + * the maps table based on the supplied information. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            bkowal     Initial creation
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public class MapsQueryUtil { + + /** + * + */ + private MapsQueryUtil() { + } + + /** + * Builds a query that can be used to query the maps table based on the + * provided information. + * + * @param env + * used to limit the selected information to a certain + * geographical area + * @param columns + * the list of columns that will be included in the SELECT + * statement + * @param additionalConstraints + * the list of constraints that will become part of the AND + * statement + * @param table + * the table to select data from + * @param geomField + * the name of the geometry field of interest + * @return the query + */ + public static String assembleMapsTableQuery(Envelope env, + List columns, List additionalConstraints, + String table, String geomField) { + // add the geospatial constraint + if (env != null) { + // copy before modifying + if (additionalConstraints == null) { + additionalConstraints = new ArrayList(); + } else { + additionalConstraints = new ArrayList( + additionalConstraints); + } + // geospatial constraint will be first + additionalConstraints.add(0, String.format( + "%s && ST_SetSrid('BOX3D(%f %f, %f %f)'::box3d,4326)", + geomField, env.getMinX(), env.getMinY(), env.getMaxX(), + env.getMaxY())); + } + + StringBuilder query = new StringBuilder("SELECT "); + if (columns != null && !columns.isEmpty()) { + Iterator iter = columns.iterator(); + query.append(iter.next()); + while (iter.hasNext()) { + query.append(", "); + query.append(iter.next()); + } + } + + query.append(" FROM "); + query.append(table); + + // add any additional constraints + if (additionalConstraints != null && !additionalConstraints.isEmpty()) { + query.append(" WHERE "); + Iterator iter = additionalConstraints.iterator(); + query.append(iter.next()); + while (iter.hasNext()) { + query.append(" AND "); + query.append(iter.next()); + } + } + + query.append(';'); + return query.toString(); + } +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java b/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java index 228c8a0066..2148d19269 100644 --- a/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java +++ b/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java @@ -20,28 +20,13 @@ package com.raytheon.uf.common.hydro.dataaccess; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; -import com.raytheon.uf.common.dataaccess.exception.DataRetrievalException; import com.raytheon.uf.common.dataaccess.exception.TimeAgnosticDataException; import com.raytheon.uf.common.dataaccess.geom.IGeometryData; -import com.raytheon.uf.common.dataaccess.geom.IGeometryDataFactory; import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; -import com.raytheon.uf.common.dataaccess.impl.AbstractDataFactory; -import com.raytheon.uf.common.dataaccess.impl.DefaultGeometryData; +import com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory; import com.raytheon.uf.common.dataaccess.impl.FactoryUtil; -import com.raytheon.uf.common.dataquery.db.QueryResult; -import com.raytheon.uf.common.dataquery.db.QueryResultRow; -import com.raytheon.uf.common.dataquery.requests.QlServerRequest; -import com.raytheon.uf.common.dataquery.requests.RequestConstraint; -import com.raytheon.uf.common.message.response.AbstractResponseMessage; -import com.raytheon.uf.common.message.response.ResponseMessageError; -import com.raytheon.uf.common.message.response.ResponseMessageGeneric; -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; @@ -61,6 +46,7 @@ import com.vividsolutions.jts.geom.GeometryFactory; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 13, 2012 njensen Initial creation + * Jan 30, 2012 1551 bkowal Refactored * * * @@ -68,8 +54,7 @@ import com.vividsolutions.jts.geom.GeometryFactory; * @version 1.0 */ -public class HydroGeometryFactory extends AbstractDataFactory implements - IGeometryDataFactory { +public class HydroGeometryFactory extends AbstractGeometryDatabaseFactory { // TODO always require at least one PE // TODO possibly take care of it for them and add value @@ -82,26 +67,26 @@ public class HydroGeometryFactory extends AbstractDataFactory implements private GeometryFactory gisFactory = new GeometryFactory(); + private static final String IHFS_DATABASE = "ihfs"; + + public HydroGeometryFactory() { + super(IHFS_DATABASE, REQUIRED); + } + /* * (non-Javadoc) * * @see - * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. - * raytheon.uf.common.dataaccess.IDataRequest) + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #getAvailableTimes + * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest, + * com.raytheon.uf.common.time.BinOffset) + */ + /* + * For now this will remain as a method override; maybe this is the standard + * way to retrieve the times based on a BinOffset when the database is + * accessed directly? */ - @Override - public DataTime[] getAvailableTimes(IGeometryRequest request) - throws TimeAgnosticDataException { - validateRequest(request); - String query = HydroQueryAssembler.assembleGetTimes(request); - List result = sendServerRequest(query); - DataTime[] dts = new DataTime[result.size()]; - for (int i = 0; i < dts.length; i++) { - dts[i] = new DataTime((Timestamp) result.get(i)[0]); - } - return dts; - } - @Override public DataTime[] getAvailableTimes(IGeometryRequest request, BinOffset binOffset) throws TimeAgnosticDataException { @@ -112,140 +97,92 @@ public class HydroGeometryFactory extends AbstractDataFactory implements * (non-Javadoc) * * @see - * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf - * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.DataTime[]) + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #makeGeometry(java.lang.Object[], java.lang.String[], java.util.Map) */ @Override - public IGeometryData[] getData(IGeometryRequest request, DataTime... times) { - validateRequest(request); - String query = HydroQueryAssembler.assembleGetData(request, times); - List result = sendServerRequest(query); - return makeGeometries(result, request.getParameters(), - request.getIdentifiers()); + protected IGeometryData makeGeometry(Object[] data, String[] paramNames, + Map attrs) { + + // order is lid, producttime, lat, lon, other params + String lid = (String) data[0]; + Timestamp date = (Timestamp) data[1]; + double lat = (Double) data[2]; + double lon = (Double) data[3]; + + // intentionally setting level as null until hydrologists determine + // something better + return super.buildGeometryData(new DataTime(date), null, + gisFactory.createPoint(new Coordinate(lon, lat)), lid, attrs, + 4, data, paramNames); } /* * (non-Javadoc) * * @see - * com.raytheon.uf.common.dataaccess.IDataFactory#getData(com.raytheon.uf - * .common.dataaccess.IDataRequest, com.raytheon.uf.common.time.TimeRange) + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetTimes + * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest) */ @Override - public IGeometryData[] getData(IGeometryRequest request, TimeRange timeRange) { - validateRequest(request); - String query = HydroQueryAssembler.assembleGetData(request, timeRange); - List result = sendServerRequest(query); - return makeGeometries(result, request.getParameters(), - request.getIdentifiers()); + protected String assembleGetTimes(IGeometryRequest request) { + return HydroQueryAssembler.assembleGetTimes(request); } /* * (non-Javadoc) * - * @see com.raytheon.uf.common.dataaccess.geom.IGeometryDataFactory# - * getAvailableLocationNames + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetTimes + * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest, + * com.raytheon.uf.common.time.BinOffset) + */ + @Override + protected String assembleGetTimes(IGeometryRequest request, + BinOffset binOffset) { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetData(com.raytheon.uf.common.dataaccess.geom.IGeometryRequest, + * com.raytheon.uf.common.time.DataTime[]) + */ + @Override + protected String assembleGetData(IGeometryRequest request, + DataTime... times) { + return HydroQueryAssembler.assembleGetData(request, times); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetData(com.raytheon.uf.common.dataaccess.geom.IGeometryRequest, + * com.raytheon.uf.common.time.TimeRange) + */ + @Override + protected String assembleGetData(IGeometryRequest request, + TimeRange timeRange) { + return HydroQueryAssembler.assembleGetData(request, timeRange); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.impl.AbstractGeometryDatabaseFactory + * #assembleGetAvailableLocationNames * (com.raytheon.uf.common.dataaccess.geom.IGeometryRequest) */ @Override - public String[] getAvailableLocationNames(IGeometryRequest request) { - String query = "select lid from location;"; - List results = sendServerRequest(query); - int size = results.size(); - String[] locations = new String[size]; - for (int i = 0; i < size; i++) { - locations[i] = (String) results.get(i)[0]; - } - - return locations; + protected String assembleGetAvailableLocationNames(IGeometryRequest request) { + return "select lid from location;"; } - - @Override - public String[] getRequiredIdentifiers() { - return REQUIRED; - } - - /** - * Sends the query to the server and returns the results - * - * @param query - * the query to run - * @return the results of the query - */ - private List sendServerRequest(String query) { - Map rcMap = new HashMap(); - - rcMap.put("query", new RequestConstraint(query)); - rcMap.put("database", new RequestConstraint("ihfs")); - rcMap.put("mode", new RequestConstraint("sqlquery")); - QlServerRequest qsr = new QlServerRequest(rcMap); - AbstractResponseMessage response = null; - try { - response = (AbstractResponseMessage) RequestRouter.route(qsr); - } catch (Exception e) { - throw new DataRetrievalException("Error retrieving IHFS data", e); - } - - QueryResult result = null; - if (response instanceof ResponseMessageError) { - throw new DataRetrievalException("Error retrieving IHFS data: " - + response.toString()); - } else if (response instanceof ResponseMessageGeneric) { - result = (QueryResult) ((ResponseMessageGeneric) response) - .getContents(); - } else { - throw new DataRetrievalException( - "Unable to process response of type" + response.getClass()); - } - - List unmappedResults = new ArrayList(); - for (QueryResultRow row : result.getRows()) { - unmappedResults.add(row.getColumnValues()); - } - return unmappedResults; - } - - /** - * Builds the data objects that will be returned by calls to getData() on - * the factory - * - * @param serverResult - * the results from the query run on the server - * @param paramNames - * the names of the parameters that were requested - * @param identifiers - * the identifiers from the data request - * @return the IGeometryData based on the results of the query - */ - private IGeometryData[] makeGeometries(List serverResult, - String[] paramNames, Map identifiers) { - List resultList = new ArrayList(); - Map attrs = Collections.unmodifiableMap(identifiers); - - // loop over each db row - for (Object[] row : serverResult) { - DefaultGeometryData geom = new DefaultGeometryData(); - // order is lid, producttime, lat, lon, other params - String lid = (String) row[0]; - Timestamp date = (Timestamp) row[1]; - double lat = (Double) row[2]; - double lon = (Double) row[3]; - if (row.length > 4) { - for (int i = 4; i < row.length; i++) { - String name = paramNames[i - 4]; - geom.addData(name, row[i]); - } - } - geom.setLocationName(lid); - geom.setDataTime(new DataTime(date)); - // intentionally setting level as null until hydrologists determine - // something better - geom.setLevel(null); - geom.setGeometry(gisFactory.createPoint(new Coordinate(lon, lat))); - geom.setAttributes(attrs); - resultList.add(geom); - } - - return resultList.toArray(new DefaultGeometryData[0]); - } -} +} \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.edex.core.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.core.feature/feature.xml index 00aef65443..2ba20f3f64 100644 --- a/edexOsgi/com.raytheon.uf.edex.core.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.core.feature/feature.xml @@ -183,4 +183,11 @@ version="0.0.0" unpack="false"/> + +