From 1aa8d304dfc33fd5e8d20aff2e7cca79b525c3bd Mon Sep 17 00:00:00 2001 From: Nate Jensen Date: Tue, 11 Dec 2012 09:29:31 -0600 Subject: [PATCH] Issue #1409 Initial implementation of hydro data access Change-Id: I309694f9477384446658520794e19ca9493473fb Former-commit-id: c236b4e1ad5dd07078672ccd26116669600873b8 [formerly 817717fe0aff3d2873ca76773a4c83db496c3b23] [formerly c236b4e1ad5dd07078672ccd26116669600873b8 [formerly 817717fe0aff3d2873ca76773a4c83db496c3b23] [formerly 85658e7e1d23c48e0b7fdb86c626ab34ef157956 [formerly ae7ac8a8bfc51d1c7dc3493c8fc036a87772f323]]] Former-commit-id: 85658e7e1d23c48e0b7fdb86c626ab34ef157956 Former-commit-id: 94b9d10c81e2048ff3f9feeefe94068c043d2733 [formerly 3c2865bbd76dcd4a51698a9bf038909b55c712cc] Former-commit-id: 13dca3b784c993a3553b07076b3b44598a6066bf --- .../feature.xml | 11 +- .../dataaccess/DataFactoryRegistry.java | 3 +- .../uf/common/dataaccess/grid/IGridData.java | 8 - .../META-INF/MANIFEST.MF | 8 +- .../build.properties | 3 +- .../component-deploy.xml | 8 - .../res/spring/hydro-common.xml | 13 + .../dataaccess/HydroGeometryFactory.java | 251 +++++++++++ .../hydro/dataaccess/HydroQueryAssembler.java | 407 ++++++++++++++++++ .../feature.xml | 11 +- 10 files changed, 697 insertions(+), 26 deletions(-) delete mode 100644 edexOsgi/com.raytheon.uf.common.hydro/component-deploy.xml create mode 100644 edexOsgi/com.raytheon.uf.common.hydro/res/spring/hydro-common.xml create mode 100644 edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java create mode 100644 edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroQueryAssembler.java diff --git a/cave/com.raytheon.uf.viz.common.core.feature/feature.xml b/cave/com.raytheon.uf.viz.common.core.feature/feature.xml index 929a26b48c..3efeb847df 100644 --- a/cave/com.raytheon.uf.viz.common.core.feature/feature.xml +++ b/cave/com.raytheon.uf.viz.common.core.feature/feature.xml @@ -82,7 +82,7 @@ download-size="0" install-size="0" version="0.0.0"/> - + - + + + diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/DataFactoryRegistry.java b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/DataFactoryRegistry.java index cc23dd2f2e..107c0e8c23 100644 --- a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/DataFactoryRegistry.java +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/DataFactoryRegistry.java @@ -85,6 +85,7 @@ public class DataFactoryRegistry { */ public IDataFactory register(String datatype, Class> requestType, IDataFactory factory) { + datatype = datatype.toLowerCase(); Map>, IDataFactory> requestTypeMap = datatypeMap .get(datatype); if (requestTypeMap == null) { @@ -109,7 +110,7 @@ public class DataFactoryRegistry { @SuppressWarnings("unchecked") public , D extends IData> IDataFactory getFactory( R request) { - String datatype = request.getDatatype(); + String datatype = request.getDatatype().toLowerCase(); if (datatype != null) { Map>, IDataFactory> requestTypeMap = datatypeMap .get(datatype); diff --git a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/grid/IGridData.java b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/grid/IGridData.java index fe8d210094..84186bd230 100644 --- a/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/grid/IGridData.java +++ b/edexOsgi/com.raytheon.uf.common.dataaccess/src/com/raytheon/uf/common/dataaccess/grid/IGridData.java @@ -24,7 +24,6 @@ import javax.measure.unit.Unit; import org.geotools.coverage.grid.GridGeometry2D; import com.raytheon.uf.common.dataaccess.IData; -import com.raytheon.uf.common.dataplugin.level.Level; import com.raytheon.uf.common.geospatial.interpolation.data.DataDestination; import com.raytheon.uf.common.geospatial.interpolation.data.UnitConvertingDataDestination; @@ -55,13 +54,6 @@ public interface IGridData extends IData { */ public String getParameter(); - /** - * Gets the level of the data - * - * @return the level of the data - */ - public Level getLevel(); - /** * Gets the GridGeometry of the data * diff --git a/edexOsgi/com.raytheon.uf.common.hydro/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.hydro/META-INF/MANIFEST.MF index 4658e8c9bc..ef3ff5fc43 100644 --- a/edexOsgi/com.raytheon.uf.common.hydro/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.hydro/META-INF/MANIFEST.MF @@ -4,11 +4,10 @@ Bundle-Name: Hydrocommon Plug-in Bundle-SymbolicName: com.raytheon.uf.common.hydro Bundle-Version: 1.12.1174.qualifier Bundle-Vendor: RAYTHEON -Require-Bundle: org.eclipse.ui, - org.eclipse.core.runtime, - org.geotools;bundle-version="2.5.2", +Require-Bundle: org.geotools;bundle-version="2.5.2", com.raytheon.uf.common.geospatial;bundle-version="1.11.9", - com.raytheon.edex.common;bundle-version="1.11.9" + com.raytheon.edex.common;bundle-version="1.11.9", + com.raytheon.uf.common.dataaccess Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: com.raytheon.uf.common.hydro.service, @@ -16,6 +15,7 @@ Export-Package: com.raytheon.uf.common.hydro.service, Import-Package: com.raytheon.uf.common.localization, com.raytheon.uf.common.menus, com.raytheon.uf.common.menus.xml, + com.raytheon.uf.common.message.response, com.raytheon.uf.common.ohd, com.raytheon.uf.common.serialization.comm, org.apache.commons.logging diff --git a/edexOsgi/com.raytheon.uf.common.hydro/build.properties b/edexOsgi/com.raytheon.uf.common.hydro/build.properties index 34d2e4d2da..5791d48d5f 100644 --- a/edexOsgi/com.raytheon.uf.common.hydro/build.properties +++ b/edexOsgi/com.raytheon.uf.common.hydro/build.properties @@ -1,4 +1,5 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ - . + .,\ + res/ diff --git a/edexOsgi/com.raytheon.uf.common.hydro/component-deploy.xml b/edexOsgi/com.raytheon.uf.common.hydro/component-deploy.xml deleted file mode 100644 index 2ed24bce13..0000000000 --- a/edexOsgi/com.raytheon.uf.common.hydro/component-deploy.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/edexOsgi/com.raytheon.uf.common.hydro/res/spring/hydro-common.xml b/edexOsgi/com.raytheon.uf.common.hydro/res/spring/hydro-common.xml new file mode 100644 index 0000000000..5b559d7c4d --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.hydro/res/spring/hydro-common.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + \ 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 new file mode 100644 index 0000000000..228c8a0066 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroGeometryFactory.java @@ -0,0 +1,251 @@ +/** + * 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.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.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; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; + +/** + * A data factory for getting data from the IHFS database. Requires that a + * request have a table identifier that corresponds to the table it should + * retrieve data from. Only works against tables that follow the SHEF PEDTSEP + * pattern. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 13, 2012            njensen     Initial creation
+ * 
+ * 
+ * + * @author njensen + * @version 1.0 + */ + +public class HydroGeometryFactory extends AbstractDataFactory implements + IGeometryDataFactory { + + // TODO always require at least one PE + // TODO possibly take care of it for them and add value + // TODO potentially limit big requests so that if too big of a result set, + // throw error to + // let the user know they need to reduce amount of data they request + // test out on live data how slow it gets to determine max number + // TODO add support for envelopes bounding the request + private static final String[] REQUIRED = { HydroQueryAssembler.TABLE }; + + private GeometryFactory gisFactory = new GeometryFactory(); + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.uf.common.dataaccess.IDataFactory#getAvailableTimes(com. + * raytheon.uf.common.dataaccess.IDataRequest) + */ + @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 { + return FactoryUtil.getAvailableTimes(this, request, binOffset); + } + + /* + * (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) { + validateRequest(request); + String query = HydroQueryAssembler.assembleGetData(request, times); + List result = sendServerRequest(query); + return makeGeometries(result, request.getParameters(), + request.getIdentifiers()); + } + + /* + * (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) { + validateRequest(request); + String query = HydroQueryAssembler.assembleGetData(request, timeRange); + List result = sendServerRequest(query); + return makeGeometries(result, request.getParameters(), + request.getIdentifiers()); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.uf.common.dataaccess.geom.IGeometryDataFactory# + * getAvailableLocationNames + * (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; + } + + @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]); + } +} diff --git a/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroQueryAssembler.java b/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroQueryAssembler.java new file mode 100644 index 0000000000..115e4cfe48 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.hydro/src/com/raytheon/uf/common/hydro/dataaccess/HydroQueryAssembler.java @@ -0,0 +1,407 @@ +/** + * 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.hydro.dataaccess; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.raytheon.uf.common.dataaccess.exception.IncompatibleRequestException; +import com.raytheon.uf.common.dataaccess.geom.IGeometryRequest; +import com.raytheon.uf.common.time.DataTime; +import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.common.time.util.TimeUtil; + +/** + * Utilities for assembling a SQL query based on an IGeometryRequest + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 15, 2012            njensen     Initial creation
+ * 
+ * 
+ * + * @author njensen + * @version 1.0 + */ + +public class HydroQueryAssembler { + + protected static final String TABLE = "table"; + + private static final String TIME_COL = "producttime"; + + private static final String LID_COL = "lid"; + + /** + * Don't allow instantiation + */ + private HydroQueryAssembler() { + + } + + /** + * Assembles a SQL query for data + * + * @param request + * the request for data + * @param times + * the times of data to request + * @return the SQL query + */ + public static String assembleGetData(IGeometryRequest request, + DataTime[] times) { + return assembleGetData(request, buildTimeConstraint(times)).toString(); + } + + /** + * Assembles a SQL query for data + * + * @param request + * the request for data + * @param timeRange + * the time range of data to request + * @return the SQL query + */ + public static String assembleGetData(IGeometryRequest request, + TimeRange timeRange) { + return assembleGetData(request, buildTimeConstraint(timeRange)) + .toString(); + } + + /** + * Assembles a SQL string to query corresponding to the request. + * + * @param request + * the request to transform to SQL + * @param timeConstraint + * a time constraint to apply to the where clause, if applicable. + * May be null. + * @return a SQL string that corresponds to the request + */ + private static CharSequence assembleGetData(IGeometryRequest request, + CharSequence timeConstraint) { + StringBuilder sb = new StringBuilder(); + // this method assembles a sql string such as: + // select d.lid, d.productttime, d.value, l.lat, l.lon from height d, + // location l where d.lid = 'ABRN1' and d.lid = l.lid; + // It is requesting the lat/lons of the location every time which + // could potentially be improved in efficiency. + + // select + sb.append(buildSelectParams(request)); + + // from table name + sb.append(buildFromWithLocation(request)); + + // where + CharSequence where = buildWhere(request, timeConstraint); + if (where.length() > 0) { + sb.append(where); + sb.append(" and d.lid = l.lid"); + } else { + sb.append("where d.lid = l.lid"); + } + sb.append(buildOrderByTime()); + sb.append(";"); + + // TODO do i need a safety check to limit it, like at 5000 rows or + // something like that? + return sb; + } + + /** + * Assembles a SQL query for available times that match the request + * + * @param request + * the request to find available times for + * @return the SQL query + */ + public static String assembleGetTimes(IGeometryRequest request) { + StringBuilder sb = new StringBuilder(); + + // select + sb.append("select distinct "); + sb.append(TIME_COL); + + // from + sb.append(buildFrom(request)); + + // where + sb.append(buildWhere(request, null)); + sb.append(buildOrderByTime()); + sb.append(";"); + + // TODO do i need a safety check to limit it, like at 5000 rows or + // something like that? + + return sb.toString(); + } + + /** + * Assembles a select statement of a query, such as + * "select d.lid, d.producttime, l.lat, l.lon, d.value" + * + * @param request + * the request to form a select statement on + * @return the select statement + */ + private static CharSequence buildSelectParams(IGeometryRequest request) { + StringBuilder sb = new StringBuilder(); + // always want the location name and time even if they didn't request it + // so that returned objects will have that information + sb.append("select d."); + sb.append(LID_COL); + sb.append(", d."); + sb.append(TIME_COL); + // request lat and lon for the returned geometry objects + sb.append(", l.lat, l.lon"); + + // request other columns + for (String param : request.getParameters()) { + sb.append(", d."); + sb.append(param); + } + + return sb; + } + + /** + * Assembles a from statement, such as "from height" + * + * @param request + * the request to determine the tablename from + * @return the from statement + */ + private static CharSequence buildFrom(IGeometryRequest request) { + return " from " + request.getIdentifiers().get(TABLE); + } + + /** + * Assembles a from statement with a location added, such as "from height, + * location l" + * + * @param request + * the request to determine the tablename from + * @return the from statement + */ + private static CharSequence buildFromWithLocation(IGeometryRequest request) { + StringBuilder sb = new StringBuilder(); + sb.append(buildFrom(request)); + sb.append(" d, location l"); + return sb; + } + + /** + * Assembles a SQL where clause based on the request + * + * @param request + * the request + * @param timeConstraint + * the time constraint String as produced by + * buildTimeConstraint(), or null + * @return the where clause + */ + private static CharSequence buildWhere(IGeometryRequest request, + CharSequence timeConstraint) { + StringBuilder sb = new StringBuilder(); + CharSequence locationConstraint = buildLocationConstraint(request + .getLocationNames()); + CharSequence extraConstraints = buildIdentifierConstraint(request + .getIdentifiers()); + if (locationConstraint != null || extraConstraints != null + || timeConstraint != null) { + sb.append(" where "); + if (locationConstraint != null) { + sb.append(locationConstraint); + if (extraConstraints != null || timeConstraint != null) { + sb.append(" and "); + } + } + if (extraConstraints != null) { + sb.append(extraConstraints); + if (timeConstraint != null) { + sb.append(" and "); + } + } + if (timeConstraint != null) { + sb.append(timeConstraint); + } + } + + return sb; + } + + /** + * Assembles a SQL string that can be used as part of a where clause to + * limit the locations returned. + * + * @param locationNames + * the names of hydro gages to limit on + * @return a SQL string based on lid, such as "lid = 'ABRN1'" or "lid in + * ('ARBN1','ARBN2')" + */ + private static CharSequence buildLocationConstraint(String[] locationNames) { + StringBuilder sb = null; + if (locationNames != null && locationNames.length > 0) { + sb = new StringBuilder(); + sb.append(LID_COL); + if (locationNames.length == 1) { + sb.append(" = '"); + sb.append(locationNames[0]); + sb.append("'"); + } else { + sb.append(" in ("); + for (int i = 0; i < locationNames.length; i++) { + sb.append("'"); + sb.append(locationNames[i]); + sb.append("'"); + if (i < locationNames.length - 1) { + sb.append(","); + } + } + sb.append(")"); + } + } + return sb; + } + + /** + * Assembles a SQL string that can be used as part of a where clause to + * limit the data returned. + * + * @param identifiers + * the constraints to use + * @return a SQL string based on the map, such as "ts = 'RG'" + */ + private static CharSequence buildIdentifierConstraint( + Map identifiers) { + StringBuilder sb = new StringBuilder(); + Map copy = new HashMap(identifiers); + copy.remove(TABLE); + Iterator> itr = copy.entrySet().iterator(); + while (itr.hasNext()) { + Map.Entry entry = itr.next(); + String key = entry.getKey(); + sb.append(entry.getKey()); + Object value = entry.getValue(); + if (value instanceof Number) { + sb.append(" = "); + sb.append(value); + } else if (value instanceof String) { + sb.append(" = "); + sb.append("'"); + sb.append(value); + sb.append("'"); + } else if (value instanceof List) { + sb.append(" in ("); + List list = (List) value; + Iterator itrList = list.iterator(); + while (itrList.hasNext()) { + sb.append("'"); + sb.append(itrList.next().toString()); + sb.append("'"); + if (itrList.hasNext()) { + sb.append(","); + } + } + sb.append(")"); + } else { + throw new IncompatibleRequestException( + "Unable to handle identifier " + key + " of type " + + value); + } + + if (itr.hasNext()) { + sb.append(" and "); + } + } + + return ((sb.length() > 0) ? sb : null); + } + + /** + * Assembles a SQL string that can be used as part of a where clause to + * limit the data to between the start and end of a time range. + * + * @param timeRange + * the time range to use to make the string + * @return a SQL between statement corresponding to the time range, such as + * "between '2012-09-29 09:00:00' and '2012-09-29 12:00:00'" + * + */ + private static CharSequence buildTimeConstraint(TimeRange timeRange) { + String result = null; + if (timeRange != null) { + result = TIME_COL + " between '" + + TimeUtil.formatToSqlTimestamp(timeRange.getStart()) + + "' and '" + + TimeUtil.formatToSqlTimestamp(timeRange.getEnd()) + "'"; + } + return result; + } + + /** + * Assembles a SQL string that can be used as part of a where clause to + * limit the data to a set of specific times. + * + * @param dataTimes + * the time to limit it to. + * @return a SQL in statement corresponding to the times as strings + */ + private static CharSequence buildTimeConstraint(DataTime[] dataTimes) { + StringBuilder sb = new StringBuilder(); + if (dataTimes != null && dataTimes.length > 0) { + sb.append(TIME_COL); + sb.append(" in ("); + for (int i = 0; i < dataTimes.length; i++) { + sb.append("'"); + sb.append(TimeUtil.formatToSqlTimestamp(dataTimes[i] + .getRefTime())); + sb.append("'"); + if (i < dataTimes.length - 1) { + sb.append(","); + } + } + sb.append(")"); + } + return ((sb.length() > 0) ? sb : null); + } + + /** + * Assembles a SQL string to order results by time, such as + * "order by producttime" + * + * @return a SQL statement that orders results by time + */ + private static CharSequence buildOrderByTime() { + StringBuilder sb = new StringBuilder(); + sb.append(" order by "); + sb.append(TIME_COL); + sb.append(" asc"); + return sb; + } + +} diff --git a/edexOsgi/com.raytheon.uf.edex.common.core.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.common.core.feature/feature.xml index de0bca7678..862a3abb21 100644 --- a/edexOsgi/com.raytheon.uf.edex.common.core.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.common.core.feature/feature.xml @@ -100,7 +100,7 @@ install-size="0" version="0.0.0" unpack="false"/> - + - + + +