Merge "Issue #227 enhanced caching of maps for thin client" into 4-Thin_Client
Former-commit-id:6a49a1bec3
[formerly0608677c67
] [formerly6a49a1bec3
[formerly0608677c67
] [formerlyb1810ddd3f
[formerly 825ddae7e604056e254530e225118f92d88d4b5c]]] Former-commit-id:b1810ddd3f
Former-commit-id:84aa8509e4
[formerly8a0c505bac
] Former-commit-id:f7541736f7
This commit is contained in:
commit
5071f2fd79
12 changed files with 1045 additions and 493 deletions
|
@ -19,7 +19,6 @@
|
||||||
**/
|
**/
|
||||||
package com.raytheon.uf.viz.core.maps.rsc;
|
package com.raytheon.uf.viz.core.maps.rsc;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
import org.opengis.referencing.crs.CoordinateReferenceSystem;
|
||||||
|
@ -29,7 +28,6 @@ import com.raytheon.uf.common.status.UFStatus;
|
||||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||||
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||||
import com.raytheon.uf.viz.core.PixelExtent;
|
import com.raytheon.uf.viz.core.PixelExtent;
|
||||||
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
|
||||||
import com.raytheon.uf.viz.core.drawables.IFont;
|
import com.raytheon.uf.viz.core.drawables.IFont;
|
||||||
import com.raytheon.uf.viz.core.exception.VizException;
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||||
|
@ -152,25 +150,10 @@ public abstract class AbstractDbMapResource<T extends AbstractDbMapResourceData,
|
||||||
*/
|
*/
|
||||||
public List<String> getLabelFields() {
|
public List<String> getLabelFields() {
|
||||||
if (this.labelFields == null) {
|
if (this.labelFields == null) {
|
||||||
List<String> labelFields = new ArrayList<String>();
|
|
||||||
try {
|
try {
|
||||||
int p = resourceData.getTable().indexOf('.');
|
this.labelFields = DbMapQueryFactory.getMapQuery(
|
||||||
String schema = resourceData.getTable().substring(0, p);
|
resourceData.getTable(), resourceData.getGeomField())
|
||||||
String table = resourceData.getTable().substring(p + 1);
|
.getColumnNamesWithoutGeometries();
|
||||||
|
|
||||||
StringBuilder query = new StringBuilder(
|
|
||||||
"SELECT column_name FROM information_schema.columns WHERE table_schema = '");
|
|
||||||
query.append(schema);
|
|
||||||
query.append("' AND table_name='");
|
|
||||||
query.append(table);
|
|
||||||
query.append("' AND udt_name != 'geometry' ORDER BY ordinal_position;");
|
|
||||||
List<Object[]> results = MapQueryCache.executeQuery(
|
|
||||||
query.toString(), "maps", QueryLanguage.SQL);
|
|
||||||
|
|
||||||
for (Object[] obj : results) {
|
|
||||||
labelFields.add(obj[0].toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnDefinition[] columns = resourceData.getColumns();
|
ColumnDefinition[] columns = resourceData.getColumns();
|
||||||
if (columns != null) {
|
if (columns != null) {
|
||||||
for (ColumnDefinition col : columns) {
|
for (ColumnDefinition col : columns) {
|
||||||
|
@ -181,7 +164,6 @@ public abstract class AbstractDbMapResource<T extends AbstractDbMapResourceData,
|
||||||
statusHandler.handle(Priority.PROBLEM,
|
statusHandler.handle(Priority.PROBLEM,
|
||||||
"Error querying available label fields", e);
|
"Error querying available label fields", e);
|
||||||
}
|
}
|
||||||
this.labelFields = labelFields;
|
|
||||||
}
|
}
|
||||||
return this.labelFields;
|
return this.labelFields;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* 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.viz.core.maps.rsc;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
||||||
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
import com.vividsolutions.jts.geom.Envelope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Add Description
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* Dec 9, 2011 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DbMapQueryFactory {
|
||||||
|
|
||||||
|
public interface DbMapQuery {
|
||||||
|
public QueryResult queryWithinEnvelope(Envelope env,
|
||||||
|
List<String> columns, List<String> additionalConstraints)
|
||||||
|
throws VizException;
|
||||||
|
|
||||||
|
public List<String> getColumnNamesWithoutGeometries()
|
||||||
|
throws VizException;
|
||||||
|
|
||||||
|
public String getGeometryType() throws VizException;
|
||||||
|
|
||||||
|
public List<Double> getLevels() throws VizException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DbMapQueryFactory instance;
|
||||||
|
|
||||||
|
public static DbMapQuery getMapQuery(String table, String geomField) {
|
||||||
|
return getInstance().getMapQueryInternal(table, geomField);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static DbMapQueryFactory getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new DbMapQueryFactory();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void setCustomInstance(DbMapQueryFactory factory) {
|
||||||
|
instance = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DbMapQueryFactory() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DbMapQuery getMapQueryInternal(String table, String geomField) {
|
||||||
|
return new DefaultDbMapQuery(table, geomField);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -53,6 +53,7 @@ import com.raytheon.uf.viz.core.IGraphicsTarget;
|
||||||
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
|
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
|
||||||
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
|
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
|
||||||
import com.raytheon.uf.viz.core.PixelExtent;
|
import com.raytheon.uf.viz.core.PixelExtent;
|
||||||
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery;
|
||||||
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
||||||
import com.raytheon.uf.viz.core.drawables.IShadedShape;
|
import com.raytheon.uf.viz.core.drawables.IShadedShape;
|
||||||
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
|
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
|
||||||
|
@ -161,18 +162,18 @@ public class DbMapResource extends
|
||||||
|
|
||||||
String shadingField;
|
String shadingField;
|
||||||
|
|
||||||
String query;
|
Envelope envelope;
|
||||||
|
|
||||||
Map<Object, RGB> colorMap;
|
Map<Object, RGB> colorMap;
|
||||||
|
|
||||||
Request(IGraphicsTarget target, IMapDescriptor descriptor,
|
Request(IGraphicsTarget target, IMapDescriptor descriptor,
|
||||||
DbMapResource rsc, String query, String geomField,
|
DbMapResource rsc, Envelope envelope, String geomField,
|
||||||
String labelField, String shadingField,
|
String labelField, String shadingField,
|
||||||
Map<Object, RGB> colorMap) {
|
Map<Object, RGB> colorMap) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.rsc = rsc;
|
this.rsc = rsc;
|
||||||
this.query = query;
|
this.envelope = envelope;
|
||||||
this.geomField = geomField;
|
this.geomField = geomField;
|
||||||
this.labelField = labelField;
|
this.labelField = labelField;
|
||||||
this.shadingField = shadingField;
|
this.shadingField = shadingField;
|
||||||
|
@ -207,9 +208,9 @@ public class DbMapResource extends
|
||||||
|
|
||||||
public Throwable cause;
|
public Throwable cause;
|
||||||
|
|
||||||
public String query;
|
public Envelope query;
|
||||||
|
|
||||||
private Result(String query) {
|
private Result(Envelope query) {
|
||||||
this.query = query;
|
this.query = query;
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +229,7 @@ public class DbMapResource extends
|
||||||
}
|
}
|
||||||
|
|
||||||
public void request(IGraphicsTarget target, IMapDescriptor descriptor,
|
public void request(IGraphicsTarget target, IMapDescriptor descriptor,
|
||||||
DbMapResource rsc, String query, String geomField,
|
DbMapResource rsc, Envelope query, String geomField,
|
||||||
String labelField, String shadingField,
|
String labelField, String shadingField,
|
||||||
Map<Object, RGB> colorMap) {
|
Map<Object, RGB> colorMap) {
|
||||||
if (requestQueue.size() == QUEUE_LIMIT) {
|
if (requestQueue.size() == QUEUE_LIMIT) {
|
||||||
|
@ -255,7 +256,7 @@ public class DbMapResource extends
|
||||||
protected IStatus run(IProgressMonitor monitor) {
|
protected IStatus run(IProgressMonitor monitor) {
|
||||||
Request req = requestQueue.poll();
|
Request req = requestQueue.poll();
|
||||||
while (req != null) {
|
while (req != null) {
|
||||||
Result result = new Result(req.query);
|
Result result = new Result(req.envelope);
|
||||||
try {
|
try {
|
||||||
String table = resourceData.getTable();
|
String table = resourceData.getTable();
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
|
@ -263,10 +264,35 @@ public class DbMapResource extends
|
||||||
result = null;
|
result = null;
|
||||||
return Status.CANCEL_STATUS;
|
return Status.CANCEL_STATUS;
|
||||||
}
|
}
|
||||||
QueryResult mappedResult = MapQueryCache
|
List<String> constraints = new ArrayList<String>();
|
||||||
.executeMappedQuery(req.query, "maps",
|
if (resourceData.getConstraints() != null) {
|
||||||
QueryLanguage.SQL);
|
constraints.addAll(Arrays.asList(resourceData
|
||||||
|
.getConstraints()));
|
||||||
|
}
|
||||||
|
List<String> fields = new ArrayList<String>();
|
||||||
|
fields.add(GID);
|
||||||
|
if (req.labelField != null
|
||||||
|
&& !fields.contains(req.labelField)) {
|
||||||
|
fields.add(req.labelField);
|
||||||
|
}
|
||||||
|
if (req.shadingField != null
|
||||||
|
&& !fields.contains(req.shadingField)) {
|
||||||
|
fields.add(req.shadingField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceData.getColumns() != null) {
|
||||||
|
for (ColumnDefinition column : resourceData
|
||||||
|
.getColumns()) {
|
||||||
|
if (fields.contains(column.getName())) {
|
||||||
|
fields.remove(column.getName());
|
||||||
|
}
|
||||||
|
fields.add(column.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QueryResult mappedResult = DbMapQueryFactory.getMapQuery(
|
||||||
|
resourceData.getTable(),
|
||||||
|
resourceData.getGeomField()).queryWithinEnvelope(
|
||||||
|
req.envelope, fields, constraints);
|
||||||
Map<Integer, Geometry> gidMap = new HashMap<Integer, Geometry>(
|
Map<Integer, Geometry> gidMap = new HashMap<Integer, Geometry>(
|
||||||
mappedResult.getResultCount() * 2);
|
mappedResult.getResultCount() * 2);
|
||||||
List<Integer> toRequest = new ArrayList<Integer>(
|
List<Integer> toRequest = new ArrayList<Integer>(
|
||||||
|
@ -309,7 +335,7 @@ public class DbMapResource extends
|
||||||
result = null;
|
result = null;
|
||||||
return Status.CANCEL_STATUS;
|
return Status.CANCEL_STATUS;
|
||||||
}
|
}
|
||||||
QueryResult geomResults = MapQueryCache
|
QueryResult geomResults = DirectDbQuery
|
||||||
.executeMappedQuery(geomQuery.toString(),
|
.executeMappedQuery(geomQuery.toString(),
|
||||||
"maps", QueryLanguage.SQL);
|
"maps", QueryLanguage.SQL);
|
||||||
for (int i = 0; i < geomResults.getResultCount(); ++i) {
|
for (int i = 0; i < geomResults.getResultCount(); ++i) {
|
||||||
|
@ -330,7 +356,7 @@ public class DbMapResource extends
|
||||||
"Expected byte[] received "
|
"Expected byte[] received "
|
||||||
+ obj.getClass().getName()
|
+ obj.getClass().getName()
|
||||||
+ ": " + obj.toString()
|
+ ": " + obj.toString()
|
||||||
+ "\n query=\"" + req.query
|
+ "\n query=\"" + req.envelope
|
||||||
+ "\"");
|
+ "\"");
|
||||||
}
|
}
|
||||||
gidMap.put(gid, g);
|
gidMap.put(gid, g);
|
||||||
|
@ -525,7 +551,7 @@ public class DbMapResource extends
|
||||||
getLabelFields().toArray(new String[0]));
|
getLabelFields().toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildQuery(PixelExtent extent) throws VizException {
|
private Envelope buildEnvelope(PixelExtent extent) throws VizException {
|
||||||
Envelope env = null;
|
Envelope env = null;
|
||||||
try {
|
try {
|
||||||
Envelope e = descriptor.pixelToWorld(extent, descriptor.getCRS());
|
Envelope e = descriptor.pixelToWorld(extent, descriptor.getCRS());
|
||||||
|
@ -535,60 +561,7 @@ public class DbMapResource extends
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new VizException("Error transforming extent", e);
|
throw new VizException("Error transforming extent", e);
|
||||||
}
|
}
|
||||||
|
return env;
|
||||||
double[] levels = getLevels();
|
|
||||||
String geometryField = getGeomField(levels[levels.length - 1]);
|
|
||||||
|
|
||||||
// get the geometry field
|
|
||||||
StringBuilder query = new StringBuilder("SELECT ");
|
|
||||||
query.append(GID);
|
|
||||||
|
|
||||||
// add any additional columns
|
|
||||||
List<String> additionalColumns = new ArrayList<String>();
|
|
||||||
if (resourceData.getColumns() != null) {
|
|
||||||
for (ColumnDefinition column : resourceData.getColumns()) {
|
|
||||||
query.append(", ");
|
|
||||||
query.append(column);
|
|
||||||
|
|
||||||
additionalColumns.add(column.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the label field
|
|
||||||
String labelField = getCapability(LabelableCapability.class)
|
|
||||||
.getLabelField();
|
|
||||||
if (labelField != null && !additionalColumns.contains(labelField)) {
|
|
||||||
query.append(", ");
|
|
||||||
query.append(labelField);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the shading field
|
|
||||||
String shadingField = getCapability(ShadeableCapability.class)
|
|
||||||
.getShadingField();
|
|
||||||
if (shadingField != null && !additionalColumns.contains(shadingField)) {
|
|
||||||
query.append(", ");
|
|
||||||
query.append(shadingField);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the geometry table
|
|
||||||
query.append(" FROM ");
|
|
||||||
query.append(resourceData.getTable());
|
|
||||||
|
|
||||||
// add the geospatial constraint
|
|
||||||
query.append(" WHERE ");
|
|
||||||
query.append(getGeospatialConstraint(geometryField, env));
|
|
||||||
|
|
||||||
// add any additional constraints
|
|
||||||
if (resourceData.getConstraints() != null) {
|
|
||||||
for (String constraint : resourceData.getConstraints()) {
|
|
||||||
query.append(" AND ");
|
|
||||||
query.append(constraint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query.append(';');
|
|
||||||
|
|
||||||
return query.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getGeomField(double simpLev) {
|
protected String getGeomField(double simpLev) {
|
||||||
|
@ -599,18 +572,6 @@ public class DbMapResource extends
|
||||||
return resourceData.getGeomField() + suffix;
|
return resourceData.getGeomField() + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
protected Object getGeospatialConstraint(String geometryField, Envelope env) {
|
|
||||||
// create the geospatial constraint from the envelope
|
|
||||||
String geoConstraint = String.format(
|
|
||||||
"%s && ST_SetSrid('BOX3D(%f %f, %f %f)'::box3d,4326)",
|
|
||||||
geometryField, env.getMinX(), env.getMinY(), env.getMaxX(),
|
|
||||||
env.getMaxY());
|
|
||||||
return geoConstraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dpp
|
* @param dpp
|
||||||
* @return
|
* @return
|
||||||
|
@ -665,7 +626,7 @@ public class DbMapResource extends
|
||||||
clipToProjExtent(screenExtent).getEnvelope())) {
|
clipToProjExtent(screenExtent).getEnvelope())) {
|
||||||
if (!paintProps.isZooming()) {
|
if (!paintProps.isZooming()) {
|
||||||
PixelExtent expandedExtent = getExpandedExtent(screenExtent);
|
PixelExtent expandedExtent = getExpandedExtent(screenExtent);
|
||||||
String query = buildQuery(expandedExtent);
|
Envelope query = buildEnvelope(expandedExtent);
|
||||||
queryJob.request(aTarget, descriptor, this, query,
|
queryJob.request(aTarget, descriptor, this, query,
|
||||||
getGeomField(simpLev), labelField, shadingField,
|
getGeomField(simpLev), labelField, shadingField,
|
||||||
colorMap);
|
colorMap);
|
||||||
|
@ -856,27 +817,13 @@ public class DbMapResource extends
|
||||||
protected double[] getLevels() {
|
protected double[] getLevels() {
|
||||||
if (levels == null) {
|
if (levels == null) {
|
||||||
try {
|
try {
|
||||||
int p = resourceData.getTable().indexOf('.');
|
List<Double> results = DbMapQueryFactory.getMapQuery(
|
||||||
String schema = resourceData.getTable().substring(0, p);
|
resourceData.getTable(), resourceData.getGeomField())
|
||||||
String table = resourceData.getTable().substring(p + 1);
|
.getLevels();
|
||||||
StringBuilder query = new StringBuilder(
|
|
||||||
"SELECT f_geometry_column FROM public.geometry_columns WHERE f_table_schema='");
|
|
||||||
query.append(schema);
|
|
||||||
query.append("' AND f_table_name='");
|
|
||||||
query.append(table);
|
|
||||||
query.append("' AND f_geometry_column LIKE '");
|
|
||||||
query.append(resourceData.getGeomField());
|
|
||||||
query.append("_%';");
|
|
||||||
List<Object[]> results = MapQueryCache.executeQuery(
|
|
||||||
query.toString(), "maps", QueryLanguage.SQL);
|
|
||||||
|
|
||||||
levels = new double[results.size()];
|
levels = new double[results.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Object[] objs : results) {
|
for (Double d : results) {
|
||||||
String s = ((String) objs[0]).substring(
|
levels[i++] = d;
|
||||||
resourceData.getGeomField().length() + 1).replace(
|
|
||||||
'_', '.');
|
|
||||||
levels[i++] = Double.parseDouble(s);
|
|
||||||
}
|
}
|
||||||
Arrays.sort(levels);
|
Arrays.sort(levels);
|
||||||
} catch (VizException e) {
|
} catch (VizException e) {
|
||||||
|
@ -891,19 +838,9 @@ public class DbMapResource extends
|
||||||
protected String getGeometryType() {
|
protected String getGeometryType() {
|
||||||
if (geometryType == null) {
|
if (geometryType == null) {
|
||||||
try {
|
try {
|
||||||
int p = resourceData.getTable().indexOf('.');
|
geometryType = DbMapQueryFactory.getMapQuery(
|
||||||
String schema = resourceData.getTable().substring(0, p);
|
resourceData.getTable(), resourceData.getGeomField())
|
||||||
String table = resourceData.getTable().substring(p + 1);
|
.getGeometryType();
|
||||||
StringBuilder query = new StringBuilder(
|
|
||||||
"SELECT type FROM geometry_columns WHERE f_table_schema='");
|
|
||||||
query.append(schema);
|
|
||||||
query.append("' AND f_table_name='");
|
|
||||||
query.append(table);
|
|
||||||
query.append("' LIMIT 1;");
|
|
||||||
List<Object[]> results = MapQueryCache.executeQuery(
|
|
||||||
query.toString(), "maps", QueryLanguage.SQL);
|
|
||||||
|
|
||||||
geometryType = (String) results.get(0)[0];
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
statusHandler.handle(Priority.PROBLEM,
|
statusHandler.handle(Priority.PROBLEM,
|
||||||
"Error querying geometry type", e);
|
"Error querying geometry type", e);
|
||||||
|
|
|
@ -22,6 +22,7 @@ package com.raytheon.uf.viz.core.maps.rsc;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ import org.eclipse.core.runtime.jobs.Job;
|
||||||
import org.eclipse.swt.graphics.RGB;
|
import org.eclipse.swt.graphics.RGB;
|
||||||
import org.geotools.geometry.jts.ReferencedEnvelope;
|
import org.geotools.geometry.jts.ReferencedEnvelope;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
||||||
import com.raytheon.uf.common.geospatial.MapUtil;
|
import com.raytheon.uf.common.geospatial.MapUtil;
|
||||||
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
import com.raytheon.uf.common.geospatial.ReferencedCoordinate;
|
||||||
import com.raytheon.uf.common.pointdata.vadriver.VA_Advanced;
|
import com.raytheon.uf.common.pointdata.vadriver.VA_Advanced;
|
||||||
|
@ -45,7 +47,6 @@ import com.raytheon.uf.viz.core.IGraphicsTarget.PointStyle;
|
||||||
import com.raytheon.uf.viz.core.IGraphicsTarget.TextStyle;
|
import com.raytheon.uf.viz.core.IGraphicsTarget.TextStyle;
|
||||||
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
|
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
|
||||||
import com.raytheon.uf.viz.core.PixelExtent;
|
import com.raytheon.uf.viz.core.PixelExtent;
|
||||||
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
|
||||||
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||||
import com.raytheon.uf.viz.core.exception.VizException;
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
import com.raytheon.uf.viz.core.map.MapDescriptor;
|
import com.raytheon.uf.viz.core.map.MapDescriptor;
|
||||||
|
@ -158,18 +159,19 @@ public class DbPointMapResource extends
|
||||||
private class Request {
|
private class Request {
|
||||||
DbPointMapResource rsc;
|
DbPointMapResource rsc;
|
||||||
|
|
||||||
boolean labeled;
|
String labelField;
|
||||||
|
|
||||||
boolean useGoodness;
|
String goodnessField;
|
||||||
|
|
||||||
String query;
|
Envelope env;
|
||||||
|
|
||||||
Request(DbPointMapResource rsc, String query, boolean labeled,
|
public Request(DbPointMapResource rsc, String labelField,
|
||||||
boolean useGoodness) {
|
String goodnessField, Envelope env) {
|
||||||
|
super();
|
||||||
this.rsc = rsc;
|
this.rsc = rsc;
|
||||||
this.query = query;
|
this.labelField = labelField;
|
||||||
this.labeled = labeled;
|
this.goodnessField = goodnessField;
|
||||||
this.useGoodness = useGoodness;
|
this.env = env;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -200,11 +202,12 @@ public class DbPointMapResource extends
|
||||||
}
|
}
|
||||||
|
|
||||||
public void request(IGraphicsTarget target, DbPointMapResource rsc,
|
public void request(IGraphicsTarget target, DbPointMapResource rsc,
|
||||||
String query, boolean labeled, boolean useGoodness) {
|
Envelope envelope, String labelField, String goodnessField) {
|
||||||
if (requestQueue.size() == QUEUE_LIMIT) {
|
if (requestQueue.size() == QUEUE_LIMIT) {
|
||||||
requestQueue.poll();
|
requestQueue.poll();
|
||||||
}
|
}
|
||||||
requestQueue.add(new Request(rsc, query, labeled, useGoodness));
|
requestQueue.add(new Request(rsc, labelField, goodnessField,
|
||||||
|
envelope));
|
||||||
|
|
||||||
this.cancel();
|
this.cancel();
|
||||||
this.schedule();
|
this.schedule();
|
||||||
|
@ -226,10 +229,37 @@ public class DbPointMapResource extends
|
||||||
while (req != null) {
|
while (req != null) {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
try {
|
try {
|
||||||
System.out.println(req.query);
|
|
||||||
long t0 = System.currentTimeMillis();
|
long t0 = System.currentTimeMillis();
|
||||||
List<Object[]> results = MapQueryCache.executeQuery(
|
List<String> columns = new ArrayList<String>();
|
||||||
req.query, "maps", QueryLanguage.SQL);
|
if (req.labelField != null) {
|
||||||
|
columns.add(req.labelField);
|
||||||
|
}
|
||||||
|
if (req.goodnessField != null
|
||||||
|
&& req.goodnessField != req.labelField) {
|
||||||
|
columns.add(req.goodnessField);
|
||||||
|
}
|
||||||
|
if (resourceData.getColumns() != null) {
|
||||||
|
for (ColumnDefinition column : resourceData
|
||||||
|
.getColumns()) {
|
||||||
|
if (columns.contains(column.getName())) {
|
||||||
|
columns.remove(column.getName());
|
||||||
|
}
|
||||||
|
columns.add(column.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columns.add("AsBinary(" + resourceData.getGeomField()
|
||||||
|
+ ") as " + resourceData.getGeomField());
|
||||||
|
|
||||||
|
List<String> constraints = null;
|
||||||
|
if (resourceData.getConstraints() != null) {
|
||||||
|
constraints = Arrays.asList(resourceData
|
||||||
|
.getConstraints());
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult results = DbMapQueryFactory.getMapQuery(
|
||||||
|
resourceData.getTable(),
|
||||||
|
resourceData.getGeomField()).queryWithinEnvelope(
|
||||||
|
req.env, columns, constraints);
|
||||||
|
|
||||||
long t1 = System.currentTimeMillis();
|
long t1 = System.currentTimeMillis();
|
||||||
System.out.println("Maps DB query took: " + (t1 - t0)
|
System.out.println("Maps DB query took: " + (t1 - t0)
|
||||||
|
@ -238,41 +268,48 @@ public class DbPointMapResource extends
|
||||||
List<LabelNode> newLabels = new ArrayList<LabelNode>();
|
List<LabelNode> newLabels = new ArrayList<LabelNode>();
|
||||||
|
|
||||||
WKBReader wkbReader = new WKBReader();
|
WKBReader wkbReader = new WKBReader();
|
||||||
for (Object[] r : results) {
|
for (int c = 0; c < results.getResultCount(); c++) {
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
canceled = false;
|
canceled = false;
|
||||||
result = null;
|
result = null;
|
||||||
// System.out.println("MapQueryJob Canceled.");
|
// System.out.println("MapQueryJob Canceled.");
|
||||||
return Status.CANCEL_STATUS;
|
return Status.CANCEL_STATUS;
|
||||||
}
|
}
|
||||||
int i = 0;
|
|
||||||
Geometry g = null;
|
Geometry g = null;
|
||||||
if (r[i] instanceof byte[]) {
|
Object geomObj = results.getRowColumnValue(c,
|
||||||
byte[] wkb = (byte[]) r[i++];
|
resourceData.getGeomField());
|
||||||
|
if (geomObj instanceof byte[]) {
|
||||||
|
byte[] wkb = (byte[]) geomObj;
|
||||||
g = wkbReader.read(wkb);
|
g = wkbReader.read(wkb);
|
||||||
} else {
|
} else {
|
||||||
statusHandler.handle(Priority.ERROR,
|
statusHandler.handle(Priority.ERROR,
|
||||||
"Expected byte[] received "
|
"Expected byte[] received "
|
||||||
+ r[i].getClass().getName() + ": "
|
+ geomObj.getClass().getName()
|
||||||
+ r[i].toString() + "\n query=\""
|
+ ": " + geomObj.toString()
|
||||||
+ req.query + "\"");
|
+ "\n query=\"" + req.env + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g != null) {
|
if (g != null) {
|
||||||
String label = "";
|
String label = "";
|
||||||
if (req.labeled && r[i] != null) {
|
if (req.labelField != null
|
||||||
if (r[i] instanceof BigDecimal) {
|
&& results.getRowColumnValue(c,
|
||||||
label = Double.toString(((Number) r[i++])
|
req.labelField) != null) {
|
||||||
|
Object r = results.getRowColumnValue(c,
|
||||||
|
req.labelField);
|
||||||
|
if (r instanceof BigDecimal) {
|
||||||
|
label = Double.toString(((Number) r)
|
||||||
.doubleValue());
|
.doubleValue());
|
||||||
} else {
|
} else {
|
||||||
label = r[i++].toString();
|
label = r.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LabelNode node = new LabelNode(label,
|
LabelNode node = new LabelNode(label,
|
||||||
g.getCentroid());
|
g.getCentroid());
|
||||||
|
|
||||||
if (req.useGoodness) {
|
if (req.goodnessField != null) {
|
||||||
node.setGoodness(((Number) r[i++]).intValue());
|
node.setGoodness(((Number) results
|
||||||
|
.getRowColumnValue(c, req.goodnessField))
|
||||||
|
.intValue());
|
||||||
}
|
}
|
||||||
newLabels.add(node);
|
newLabels.add(node);
|
||||||
}
|
}
|
||||||
|
@ -293,7 +330,7 @@ public class DbPointMapResource extends
|
||||||
}
|
}
|
||||||
Double[] distances;
|
Double[] distances;
|
||||||
|
|
||||||
if (req.useGoodness) {
|
if (req.goodnessField != null) {
|
||||||
distances = distanceCalc.getVaAdvanced(coords,
|
distances = distanceCalc.getVaAdvanced(coords,
|
||||||
goodness, dst);
|
goodness, dst);
|
||||||
} else {
|
} else {
|
||||||
|
@ -358,7 +395,7 @@ public class DbPointMapResource extends
|
||||||
queryJob = new MapQueryJob();
|
queryJob = new MapQueryJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildQuery(IGraphicsTarget target, PixelExtent extent)
|
private void requestData(IGraphicsTarget target, PixelExtent extent)
|
||||||
throws VizException {
|
throws VizException {
|
||||||
|
|
||||||
Envelope env = null;
|
Envelope env = null;
|
||||||
|
@ -370,62 +407,13 @@ public class DbPointMapResource extends
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new VizException("Error transforming extent", e);
|
throw new VizException("Error transforming extent", e);
|
||||||
}
|
}
|
||||||
// System.out.println(env);
|
|
||||||
|
|
||||||
String geometryField = resourceData.getGeomField();
|
|
||||||
|
|
||||||
// create the geospatial constraint from the envelope
|
|
||||||
String geoConstraint = String.format(
|
|
||||||
"%s && ST_SetSrid('BOX3D(%f %f, %f %f)'::box3d,4326)",
|
|
||||||
geometryField, env.getMinX(), env.getMinY(), env.getMaxX(),
|
|
||||||
env.getMaxY());
|
|
||||||
|
|
||||||
// get the geometry field
|
|
||||||
StringBuilder query = new StringBuilder("SELECT AsBinary(");
|
|
||||||
query.append(geometryField);
|
|
||||||
query.append(")");
|
|
||||||
|
|
||||||
// add the label field
|
// add the label field
|
||||||
String labelField = getCapability(LabelableCapability.class)
|
String labelField = getCapability(LabelableCapability.class)
|
||||||
.getLabelField();
|
.getLabelField();
|
||||||
if (labelField != null) {
|
|
||||||
query.append(", ");
|
|
||||||
query.append(labelField);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the goodness field
|
queryJob.request(target, this, env, labelField,
|
||||||
if (resourceData.getGoodnessField() != null) {
|
resourceData.getGoodnessField());
|
||||||
query.append(", ");
|
|
||||||
query.append(resourceData.getGoodnessField());
|
|
||||||
}
|
|
||||||
|
|
||||||
// add any additional columns
|
|
||||||
if (resourceData.getColumns() != null) {
|
|
||||||
for (ColumnDefinition column : resourceData.getColumns()) {
|
|
||||||
query.append(", ");
|
|
||||||
query.append(column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the geometry table
|
|
||||||
query.append(" FROM ");
|
|
||||||
query.append(resourceData.getTable());
|
|
||||||
|
|
||||||
// add the geo constraint
|
|
||||||
query.append(" WHERE ");
|
|
||||||
query.append(geoConstraint);
|
|
||||||
|
|
||||||
// add any addtional constraints
|
|
||||||
if (resourceData.getConstraints() != null) {
|
|
||||||
for (String constraint : resourceData.getConstraints()) {
|
|
||||||
query.append(" AND ");
|
|
||||||
query.append(constraint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query.append(';');
|
|
||||||
|
|
||||||
return query.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -454,9 +442,7 @@ public class DbPointMapResource extends
|
||||||
clipToProjExtent(screenExtent).getEnvelope())) {
|
clipToProjExtent(screenExtent).getEnvelope())) {
|
||||||
if (!paintProps.isZooming()) {
|
if (!paintProps.isZooming()) {
|
||||||
PixelExtent expandedExtent = getExpandedExtent(screenExtent);
|
PixelExtent expandedExtent = getExpandedExtent(screenExtent);
|
||||||
String query = buildQuery(aTarget, expandedExtent);
|
requestData(aTarget, expandedExtent);
|
||||||
queryJob.request(aTarget, this, query, isLabeled,
|
|
||||||
resourceData.getGoodnessField() != null);
|
|
||||||
lastExtent = expandedExtent;
|
lastExtent = expandedExtent;
|
||||||
lastLabelField = labelField;
|
lastLabelField = labelField;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
/**
|
||||||
|
* 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.viz.core.maps.rsc;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
||||||
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery;
|
||||||
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
||||||
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
import com.raytheon.uf.viz.core.maps.rsc.DbMapQueryFactory.DbMapQuery;
|
||||||
|
import com.vividsolutions.jts.geom.Envelope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Add Description
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* Dec 9, 2011 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DefaultDbMapQuery implements DbMapQuery {
|
||||||
|
|
||||||
|
protected static final String MAPS = "maps";
|
||||||
|
|
||||||
|
protected final String table;
|
||||||
|
|
||||||
|
protected final String geomField;
|
||||||
|
|
||||||
|
protected DefaultDbMapQuery(String table, String geomField) {
|
||||||
|
this.table = table;
|
||||||
|
this.geomField = geomField;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult queryWithinEnvelope(Envelope env, List<String> columns,
|
||||||
|
List<String> additionalConstraints) throws VizException {
|
||||||
|
// add the geospatial constraint
|
||||||
|
if (env != null) {
|
||||||
|
// copy before modifying
|
||||||
|
if (additionalConstraints == null) {
|
||||||
|
additionalConstraints = new ArrayList<String>();
|
||||||
|
} else {
|
||||||
|
additionalConstraints = new ArrayList<String>(
|
||||||
|
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<String> 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<String> iter = additionalConstraints.iterator();
|
||||||
|
query.append(iter.next());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
query.append(" AND ");
|
||||||
|
query.append(iter.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query.append(';');
|
||||||
|
|
||||||
|
return DirectDbQuery.executeMappedQuery(query.toString(), MAPS,
|
||||||
|
QueryLanguage.SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getColumnNamesWithoutGeometries() throws VizException {
|
||||||
|
List<String> labelFields = new ArrayList<String>();
|
||||||
|
int p = table.indexOf('.');
|
||||||
|
String schema = table.substring(0, p);
|
||||||
|
String table = this.table.substring(p + 1);
|
||||||
|
|
||||||
|
StringBuilder query = new StringBuilder(
|
||||||
|
"SELECT column_name FROM information_schema.columns WHERE table_schema = '");
|
||||||
|
query.append(schema);
|
||||||
|
query.append("' AND table_name='");
|
||||||
|
query.append(table);
|
||||||
|
query.append("' ");
|
||||||
|
query.append("AND udt_name != 'geometry' ");
|
||||||
|
query.append("ORDER BY ordinal_position;");
|
||||||
|
List<Object[]> results = DirectDbQuery.executeQuery(query.toString(),
|
||||||
|
MAPS, QueryLanguage.SQL);
|
||||||
|
|
||||||
|
for (Object[] obj : results) {
|
||||||
|
labelFields.add(obj[0].toString());
|
||||||
|
}
|
||||||
|
return labelFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getGeometryType() throws VizException {
|
||||||
|
int p = table.indexOf('.');
|
||||||
|
String schema = table.substring(0, p);
|
||||||
|
String table = this.table.substring(p + 1);
|
||||||
|
StringBuilder query = new StringBuilder(
|
||||||
|
"SELECT type FROM geometry_columns WHERE f_table_schema='");
|
||||||
|
query.append(schema);
|
||||||
|
query.append("' AND f_table_name='");
|
||||||
|
query.append(table);
|
||||||
|
query.append("' LIMIT 1;");
|
||||||
|
List<Object[]> results = DirectDbQuery.executeQuery(query.toString(),
|
||||||
|
MAPS, QueryLanguage.SQL);
|
||||||
|
|
||||||
|
return (String) results.get(0)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Double> getLevels() throws VizException {
|
||||||
|
int p = table.indexOf('.');
|
||||||
|
String schema = table.substring(0, p);
|
||||||
|
String table = this.table.substring(p + 1);
|
||||||
|
StringBuilder query = new StringBuilder(
|
||||||
|
"SELECT f_geometry_column FROM public.geometry_columns WHERE f_table_schema='");
|
||||||
|
query.append(schema);
|
||||||
|
query.append("' AND f_table_name='");
|
||||||
|
query.append(table);
|
||||||
|
query.append("' AND f_geometry_column LIKE '");
|
||||||
|
query.append(geomField);
|
||||||
|
query.append("_%';");
|
||||||
|
List<Object[]> results = DirectDbQuery.executeQuery(query.toString(),
|
||||||
|
MAPS, QueryLanguage.SQL);
|
||||||
|
|
||||||
|
List<Double> levels = new ArrayList<Double>(results.size());
|
||||||
|
for (Object[] objs : results) {
|
||||||
|
String s = (String) objs[0];
|
||||||
|
s = s.replace(geomField + "_", "");
|
||||||
|
s = s.replace('_', '.');
|
||||||
|
levels.add(Double.parseDouble(s));
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,269 +0,0 @@
|
||||||
/**
|
|
||||||
* 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.viz.core.maps.rsc;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
|
||||||
import com.raytheon.uf.common.dataquery.db.QueryResultRow;
|
|
||||||
import com.raytheon.uf.common.localization.FileLocker;
|
|
||||||
import com.raytheon.uf.common.localization.FileLocker.Type;
|
|
||||||
import com.raytheon.uf.common.serialization.DynamicSerializationManager;
|
|
||||||
import com.raytheon.uf.common.serialization.DynamicSerializationManager.SerializationType;
|
|
||||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
|
||||||
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
|
||||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
|
||||||
import com.raytheon.uf.common.status.UFStatus;
|
|
||||||
import com.raytheon.uf.common.util.cache.ICacheObject;
|
|
||||||
import com.raytheon.uf.common.util.cache.LRUCache;
|
|
||||||
import com.raytheon.uf.viz.core.catalog.DirectDbQuery;
|
|
||||||
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
|
||||||
import com.raytheon.uf.viz.core.exception.VizException;
|
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.MapQueryCache.QueryCacheable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map query caching derived from Erik Magnuson's code changes to DirectDbQuery
|
|
||||||
* to keep map results around on the client and not waste time/bandwidth
|
|
||||||
* querying.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
*
|
|
||||||
* SOFTWARE HISTORY
|
|
||||||
*
|
|
||||||
* Date Ticket# Engineer Description
|
|
||||||
* ------------ ---------- ----------- --------------------------
|
|
||||||
* Nov 9, 2011 njensen Initial creation
|
|
||||||
*
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author njensen
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class MapQueryCache extends LRUCache<String, QueryCacheable> {
|
|
||||||
|
|
||||||
private static final transient IUFStatusHandler statusHandler = UFStatus
|
|
||||||
.getHandler(MapQueryCache.class);
|
|
||||||
|
|
||||||
private static MapQueryCache mapQueryCache = new MapQueryCache(
|
|
||||||
64 * 1024 * 1024);
|
|
||||||
|
|
||||||
private static boolean cache = false;
|
|
||||||
|
|
||||||
@DynamicSerialize
|
|
||||||
protected static class QueryCacheable implements ICacheObject {
|
|
||||||
|
|
||||||
@DynamicSerializeElement
|
|
||||||
QueryResult queryResult;
|
|
||||||
|
|
||||||
public QueryCacheable() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected QueryCacheable(QueryResult result) {
|
|
||||||
queryResult = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSize() {
|
|
||||||
// TODO get better number or move this off LRU
|
|
||||||
return queryResult.getColumnCount() * queryResult.getRows().length
|
|
||||||
* 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryResult getQueryResult() {
|
|
||||||
return queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQueryResult(QueryResult queryResult) {
|
|
||||||
this.queryResult = queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@DynamicSerialize
|
|
||||||
protected static class CachePair {
|
|
||||||
|
|
||||||
@DynamicSerializeElement
|
|
||||||
String queryKey;
|
|
||||||
|
|
||||||
@DynamicSerializeElement
|
|
||||||
QueryCacheable cacheable;
|
|
||||||
|
|
||||||
public CachePair() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CachePair(String key, QueryCacheable obj) {
|
|
||||||
this.queryKey = key;
|
|
||||||
this.cacheable = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getQueryKey() {
|
|
||||||
return queryKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQueryKey(String queryKey) {
|
|
||||||
this.queryKey = queryKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueryCacheable getCacheable() {
|
|
||||||
return cacheable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCacheable(QueryCacheable cacheable) {
|
|
||||||
this.cacheable = cacheable;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private constructor
|
|
||||||
*
|
|
||||||
* @param maxSize
|
|
||||||
*/
|
|
||||||
private MapQueryCache(long maxSize) {
|
|
||||||
super(maxSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a mapped query against DirectDbQuery API. If cache is enabled
|
|
||||||
* will check the cache before sending a query and if sending a query, will
|
|
||||||
* store the result in the cache.
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param database
|
|
||||||
* @param language
|
|
||||||
* @return
|
|
||||||
* @throws VizException
|
|
||||||
*/
|
|
||||||
public static QueryResult executeMappedQuery(String query, String database,
|
|
||||||
QueryLanguage language) throws VizException {
|
|
||||||
QueryResult queryResult = null;
|
|
||||||
String key = query + database + language;
|
|
||||||
|
|
||||||
if (cache) {
|
|
||||||
QueryCacheable cacheResult = mapQueryCache.get(key);
|
|
||||||
if (cacheResult != null) {
|
|
||||||
queryResult = cacheResult.queryResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryResult == null) {
|
|
||||||
// either cache was disabled, it wasn't in cache, or reading cache
|
|
||||||
// failed, so send the query
|
|
||||||
queryResult = DirectDbQuery.executeMappedQuery(query, database,
|
|
||||||
language);
|
|
||||||
if (cache) {
|
|
||||||
mapQueryCache.put(key, new QueryCacheable(queryResult));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a query against DirectDbQuery API. If cache is enabled will
|
|
||||||
* check the cache before sending a query and if sending a query, will store
|
|
||||||
* the result in the cache.
|
|
||||||
*
|
|
||||||
* @param query
|
|
||||||
* @param database
|
|
||||||
* @param language
|
|
||||||
* @return
|
|
||||||
* @throws VizException
|
|
||||||
*/
|
|
||||||
public static List<Object[]> executeQuery(String query, String database,
|
|
||||||
QueryLanguage language) throws VizException {
|
|
||||||
QueryResult result = executeMappedQuery(query, database, language);
|
|
||||||
List<Object[]> unmappedResults = new ArrayList<Object[]>();
|
|
||||||
|
|
||||||
for (QueryResultRow row : result.getRows()) {
|
|
||||||
unmappedResults.add(row.getColumnValues());
|
|
||||||
}
|
|
||||||
return unmappedResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setCaching(boolean caching) {
|
|
||||||
cache = caching;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<CachePair> getCacheables() {
|
|
||||||
List<CachePair> pairs = new ArrayList<CachePair>(lruMap.size());
|
|
||||||
synchronized (this) {
|
|
||||||
for (Entry<String, Item> entry : lruMap.entrySet()) {
|
|
||||||
pairs.add(new CachePair(entry.getKey(), entry.getValue().value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCacheables(Collection<CachePair> pairs) {
|
|
||||||
for (CachePair pair : pairs) {
|
|
||||||
put(pair.queryKey, pair.cacheable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore the geometry cache from the file system
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static synchronized void restoreCache(File cacheFile) {
|
|
||||||
try {
|
|
||||||
FileLocker.lock(MapQueryCache.class, cacheFile, Type.READ);
|
|
||||||
if (cacheFile.exists() && cacheFile.length() > 0) {
|
|
||||||
FileInputStream fin = new FileInputStream(cacheFile);
|
|
||||||
Collection<CachePair> pairs = (Collection<CachePair>) DynamicSerializationManager
|
|
||||||
.getManager(SerializationType.Thrift).deserialize(fin);
|
|
||||||
mapQueryCache.setCacheables(pairs);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
statusHandler.error("Error restoring cache from file system", e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
FileLocker.unlock(MapQueryCache.class, cacheFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the geometry cache to the file system
|
|
||||||
*/
|
|
||||||
public static synchronized void storeCache(File cacheFile) {
|
|
||||||
try {
|
|
||||||
FileLocker.lock(MapQueryCache.class, cacheFile, Type.WRITE);
|
|
||||||
FileOutputStream out = new FileOutputStream(cacheFile);
|
|
||||||
DynamicSerializationManager.getManager(SerializationType.Thrift)
|
|
||||||
.serialize(mapQueryCache.getCacheables(), out);
|
|
||||||
out.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
statusHandler.error("Error storing cache to file system", e);
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
FileLocker.unlock(MapQueryCache.class, cacheFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -17,6 +17,10 @@ Require-Bundle: com.raytheon.uf.viz.core,
|
||||||
Import-Package: com.raytheon.uf.common.comm,
|
Import-Package: com.raytheon.uf.common.comm,
|
||||||
com.raytheon.uf.common.datastorage,
|
com.raytheon.uf.common.datastorage,
|
||||||
com.raytheon.uf.viz.core.maps.rsc,
|
com.raytheon.uf.viz.core.maps.rsc,
|
||||||
|
com.vividsolutions.jts.geom,
|
||||||
|
com.vividsolutions.jts.index.strtree,
|
||||||
|
com.vividsolutions.jts.io,
|
||||||
javax.jms
|
javax.jms
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
|
Export-Package: com.raytheon.uf.viz.thinclient.cave.cache.map
|
||||||
|
|
|
@ -21,8 +21,8 @@ package com.raytheon.uf.viz.thinclient.cave.cache;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.MapQueryCache;
|
|
||||||
import com.raytheon.uf.viz.thinclient.cache.AbstractCachePersistance;
|
import com.raytheon.uf.viz.thinclient.cache.AbstractCachePersistance;
|
||||||
|
import com.raytheon.uf.viz.thinclient.cave.cache.map.CacheDbMapQueryFactory;
|
||||||
import com.raytheon.uf.viz.thinclient.preferences.ThinClientPreferenceConstants;
|
import com.raytheon.uf.viz.thinclient.preferences.ThinClientPreferenceConstants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +57,8 @@ public class MapQueryCachePersistence extends AbstractCachePersistance {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void store(File cacheFile) {
|
public void store(File cacheFile) {
|
||||||
MapQueryCache.storeCache(cacheFile);
|
CacheDbMapQueryFactory.storeCache(cacheFile);
|
||||||
|
// MapQueryCache.storeCache(cacheFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -69,7 +70,8 @@ public class MapQueryCachePersistence extends AbstractCachePersistance {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void restore(File cacheFile) {
|
public void restore(File cacheFile) {
|
||||||
MapQueryCache.restoreCache(cacheFile);
|
CacheDbMapQueryFactory.restoreCache(cacheFile);
|
||||||
|
// MapQueryCache.restoreCache(cacheFile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ public class MapQueryCachePersistence extends AbstractCachePersistance {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void enable() {
|
protected void enable() {
|
||||||
MapQueryCache.setCaching(true);
|
CacheDbMapQueryFactory.setEnableCaching(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -92,7 +94,7 @@ public class MapQueryCachePersistence extends AbstractCachePersistance {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void disable() {
|
protected void disable() {
|
||||||
MapQueryCache.setCaching(false);
|
CacheDbMapQueryFactory.setEnableCaching(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,327 @@
|
||||||
|
/**
|
||||||
|
* 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.viz.thinclient.cave.cache.map;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResultRow;
|
||||||
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery;
|
||||||
|
import com.raytheon.uf.viz.core.catalog.DirectDbQuery.QueryLanguage;
|
||||||
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
|
import com.raytheon.uf.viz.core.maps.rsc.DefaultDbMapQuery;
|
||||||
|
import com.vividsolutions.jts.geom.Envelope;
|
||||||
|
import com.vividsolutions.jts.geom.Geometry;
|
||||||
|
import com.vividsolutions.jts.index.strtree.STRtree;
|
||||||
|
import com.vividsolutions.jts.io.ParseException;
|
||||||
|
import com.vividsolutions.jts.io.WKBReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Add Description
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* Dec 9, 2011 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CacheDbMapQuery extends DefaultDbMapQuery {
|
||||||
|
|
||||||
|
private static final String GID = "gid";
|
||||||
|
|
||||||
|
private static final String GEOM_ENV = "geom_env";
|
||||||
|
|
||||||
|
// Used for spatial lookups, returns a list of indexes into the data
|
||||||
|
private STRtree tree;
|
||||||
|
|
||||||
|
// all database columns for every row, this is the primary cached data.
|
||||||
|
private QueryResult data = null;
|
||||||
|
|
||||||
|
// a specific list of indexes which are returned for any given constraint
|
||||||
|
private Map<String, List<Integer>> constraint2indices = new HashMap<String, List<Integer>>();
|
||||||
|
|
||||||
|
// The column names available without any geometry columns.
|
||||||
|
private List<String> columnNames = null;
|
||||||
|
|
||||||
|
// the geometry type
|
||||||
|
private String geometryType = null;;
|
||||||
|
|
||||||
|
// all levels for a the geometry
|
||||||
|
private List<Double> levels = null;
|
||||||
|
|
||||||
|
private Object columnNamesLock = new Object();
|
||||||
|
|
||||||
|
private Object geometryTypeLock = new Object();
|
||||||
|
|
||||||
|
private Object levelsLock = new Object();
|
||||||
|
|
||||||
|
protected CacheDbMapQuery(String table, String geomField) {
|
||||||
|
super(table, geomField);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheDbMapQuery(CacheDbMapQuerySerializeable s)
|
||||||
|
throws VizException {
|
||||||
|
super(s.getTable(), s.getGeomField());
|
||||||
|
geometryType = s.getGeometryType();
|
||||||
|
columnNames = s.getColumnNames();
|
||||||
|
levels = s.getLevels();
|
||||||
|
constraint2indices = s.getConstraint2indices();
|
||||||
|
data = s.getData();
|
||||||
|
if (data != null) {
|
||||||
|
createTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryResult queryWithinEnvelope(Envelope env, List<String> columns,
|
||||||
|
List<String> additionalConstraints) throws VizException {
|
||||||
|
fillCache(geomField, columns);
|
||||||
|
List<?> items = tree.query(env);
|
||||||
|
List<Integer> validGIDs = null;
|
||||||
|
if (additionalConstraints != null) {
|
||||||
|
for (String constraint : additionalConstraints) {
|
||||||
|
items.retainAll(getIndices(constraint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<QueryResultRow> rows = new ArrayList<QueryResultRow>();
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
int rowNumber = (Integer) items.get(i);
|
||||||
|
if (validGIDs != null
|
||||||
|
&& !validGIDs.contains(data.getRowColumnValue(rowNumber,
|
||||||
|
GID))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Object[] columnValues = new Object[columns.size()];
|
||||||
|
for (int j = 0; j < columns.size(); j++) {
|
||||||
|
columnValues[j] = data.getRowColumnValue(rowNumber,
|
||||||
|
columns.get(j));
|
||||||
|
}
|
||||||
|
rows.add(new QueryResultRow(columnValues));
|
||||||
|
}
|
||||||
|
Map<String, Integer> columnNames = new HashMap<String, Integer>();
|
||||||
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
|
columnNames.put(doAs(columns.get(i)), i);
|
||||||
|
}
|
||||||
|
return new QueryResult(columnNames, rows.toArray(new QueryResultRow[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getIndices(String constraint) throws VizException {
|
||||||
|
synchronized (constraint2indices) {
|
||||||
|
List<Integer> indices = constraint2indices.get(constraint);
|
||||||
|
if (indices != null) {
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
StringBuilder query = new StringBuilder("SELECT ");
|
||||||
|
query.append(GID);
|
||||||
|
query.append(" FROM ");
|
||||||
|
query.append(table);
|
||||||
|
query.append(" WHERE ");
|
||||||
|
query.append(constraint);
|
||||||
|
query.append(";");
|
||||||
|
|
||||||
|
List<Object[]> results = DirectDbQuery.executeQuery(
|
||||||
|
query.toString(), MAPS, QueryLanguage.SQL);
|
||||||
|
ArrayList<Integer> gids = new ArrayList<Integer>(results.size());
|
||||||
|
for (Object[] result : results) {
|
||||||
|
gids.add((Integer) result[0]);
|
||||||
|
}
|
||||||
|
indices = new ArrayList<Integer>(gids.size());
|
||||||
|
for (int i = 0; i < data.getResultCount(); ++i) {
|
||||||
|
int gid = (Integer) data.getRowColumnValue(i, "gid");
|
||||||
|
if (gids.contains(gid)) {
|
||||||
|
indices.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constraint2indices.put(constraint, indices);
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryResult getColumns(List<String> columns) throws VizException {
|
||||||
|
StringBuilder query = new StringBuilder("SELECT ");
|
||||||
|
Iterator<String> iter = columns.iterator();
|
||||||
|
query.append(iter.next());
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
query.append(", ");
|
||||||
|
query.append(iter.next());
|
||||||
|
}
|
||||||
|
query.append(" from ");
|
||||||
|
query.append(table);
|
||||||
|
query.append(";");
|
||||||
|
QueryResult result = DirectDbQuery.executeMappedQuery(query.toString(),
|
||||||
|
MAPS, QueryLanguage.SQL);
|
||||||
|
for (String column : columns) {
|
||||||
|
String as = doAs(column);
|
||||||
|
if (as.equals(column)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (GEOM_ENV.equals(as)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int index = result.getColumnNames().remove(doAs(column));
|
||||||
|
result.getColumnNames().put(column, index);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void fillCache(String geomField, List<String> columns)
|
||||||
|
throws VizException {
|
||||||
|
columns = new ArrayList<String>(columns);
|
||||||
|
if (data != null) {
|
||||||
|
for (String column : data.getColumnNames().keySet()) {
|
||||||
|
columns.remove(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (columns.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// we correlate data based off gid so make sure it is in there.
|
||||||
|
if (!columns.contains("gid")) {
|
||||||
|
columns.add("gid");
|
||||||
|
}
|
||||||
|
if (tree == null) {
|
||||||
|
// request the envelope
|
||||||
|
String envColumn = "AsBinary(ST_Envelope(" + geomField + ")) as "
|
||||||
|
+ GEOM_ENV;
|
||||||
|
columns.add(envColumn);
|
||||||
|
QueryResult result = getColumns(columns);
|
||||||
|
columns.remove(envColumn);
|
||||||
|
data = result;
|
||||||
|
createTree();
|
||||||
|
} else {
|
||||||
|
QueryResult result = getColumns(columns);
|
||||||
|
// gid should already be in the result set.
|
||||||
|
columns.remove("gid");
|
||||||
|
Map<Integer, QueryResultRow> gid2row = new HashMap<Integer, QueryResultRow>();
|
||||||
|
for (int i = 0; i < result.getResultCount(); ++i) {
|
||||||
|
int gid = (Integer) result.getRowColumnValue(i, "gid");
|
||||||
|
gid2row.put(gid, result.getRows()[i]);
|
||||||
|
}
|
||||||
|
int index = data.getColumnNames().size();
|
||||||
|
for (String column : columns) {
|
||||||
|
data.getColumnNames().put(column, index++);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < data.getResultCount(); ++i) {
|
||||||
|
int gid = (Integer) data.getRowColumnValue(i, "gid");
|
||||||
|
QueryResultRow existRow = data.getRows()[i];
|
||||||
|
QueryResultRow resultRow = gid2row.get(gid);
|
||||||
|
Object[] columnValues = existRow.getColumnValues();
|
||||||
|
columnValues = Arrays.copyOf(columnValues, columnValues.length
|
||||||
|
+ columns.size());
|
||||||
|
for (String column : columns) {
|
||||||
|
int resultIndex = result.getColumnNames().get(column);
|
||||||
|
int newIndex = data.getColumnNames().get(column);
|
||||||
|
columnValues[newIndex] = resultRow.getColumn(resultIndex);
|
||||||
|
}
|
||||||
|
existRow.setColumnValues(columnValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTree() throws VizException {
|
||||||
|
WKBReader wkbReader = new WKBReader();
|
||||||
|
tree = new STRtree();
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < data.getResultCount(); ++i) {
|
||||||
|
Object obj = data.getRowColumnValue(i, GEOM_ENV);
|
||||||
|
if (obj instanceof byte[]) {
|
||||||
|
byte[] wkb = (byte[]) obj;
|
||||||
|
Geometry g = wkbReader.read(wkb);
|
||||||
|
Envelope e = g.getEnvelopeInternal();
|
||||||
|
tree.insert(e, i);
|
||||||
|
} else {
|
||||||
|
throw new VizException("Error populating GID Cache.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new VizException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String doAs(String string) {
|
||||||
|
String[] split = string.split("\\s[aA][sS]\\s");
|
||||||
|
return split[split.length - 1].trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getColumnNamesWithoutGeometries() throws VizException {
|
||||||
|
synchronized (columnNamesLock) {
|
||||||
|
if (columnNames == null) {
|
||||||
|
columnNames = super.getColumnNamesWithoutGeometries();
|
||||||
|
}
|
||||||
|
return new ArrayList<String>(columnNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getGeometryType() throws VizException {
|
||||||
|
synchronized (geometryTypeLock) {
|
||||||
|
if (geometryType == null) {
|
||||||
|
geometryType = super.getGeometryType();
|
||||||
|
}
|
||||||
|
return geometryType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Double> getLevels() throws VizException {
|
||||||
|
synchronized (levelsLock) {
|
||||||
|
if (levels == null) {
|
||||||
|
levels = super.getLevels();
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheDbMapQuerySerializeable getSerializeable() {
|
||||||
|
CacheDbMapQuerySerializeable s = new CacheDbMapQuerySerializeable();
|
||||||
|
s.setTable(table);
|
||||||
|
s.setGeomField(geomField);
|
||||||
|
s.setGeometryType(geometryType);
|
||||||
|
s.setColumnNames(columnNames);
|
||||||
|
s.setLevels(levels);
|
||||||
|
s.setConstraint2indices(constraint2indices);
|
||||||
|
s.setData(data);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getGeomField() {
|
||||||
|
return geomField;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* 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.viz.thinclient.cave.cache.map;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.localization.FileLocker;
|
||||||
|
import com.raytheon.uf.common.localization.FileLocker.Type;
|
||||||
|
import com.raytheon.uf.common.serialization.DynamicSerializationManager;
|
||||||
|
import com.raytheon.uf.common.serialization.DynamicSerializationManager.SerializationType;
|
||||||
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||||
|
import com.raytheon.uf.common.status.UFStatus;
|
||||||
|
import com.raytheon.uf.viz.core.maps.rsc.DbMapQueryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Add Description
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* Dec 9, 2011 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CacheDbMapQueryFactory extends DbMapQueryFactory {
|
||||||
|
|
||||||
|
private static final transient IUFStatusHandler statusHandler = UFStatus
|
||||||
|
.getHandler(CacheDbMapQueryFactory.class);
|
||||||
|
|
||||||
|
private static CacheDbMapQueryFactory instance;
|
||||||
|
|
||||||
|
private Map<String, CacheDbMapQuery> cache = new HashMap<String, CacheDbMapQuery>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CacheDbMapQuery getMapQueryInternal(String table, String geomField) {
|
||||||
|
String key = table + ":::" + geomField;
|
||||||
|
synchronized (cache) {
|
||||||
|
CacheDbMapQuery query = cache.get(key);
|
||||||
|
if (query == null) {
|
||||||
|
query = new CacheDbMapQuery(table, geomField);
|
||||||
|
cache.put(key, query);
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void setEnableCaching(boolean enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new CacheDbMapQueryFactory();
|
||||||
|
}
|
||||||
|
setCustomInstance(instance);
|
||||||
|
} else {
|
||||||
|
setCustomInstance(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void restoreCache(File cacheFile) {
|
||||||
|
if (instance == null) {
|
||||||
|
setCustomInstance(instance = new CacheDbMapQueryFactory());
|
||||||
|
}
|
||||||
|
synchronized (instance.cache) {
|
||||||
|
try {
|
||||||
|
FileLocker.lock(CacheDbMapQuery.class, cacheFile, Type.READ);
|
||||||
|
if (cacheFile.exists() && cacheFile.length() > 0) {
|
||||||
|
FileInputStream fin = new FileInputStream(cacheFile);
|
||||||
|
List<CacheDbMapQuerySerializeable> list = (List<CacheDbMapQuerySerializeable>) DynamicSerializationManager
|
||||||
|
.getManager(SerializationType.Thrift).deserialize(
|
||||||
|
fin);
|
||||||
|
for (CacheDbMapQuerySerializeable s : list) {
|
||||||
|
CacheDbMapQuery c = new CacheDbMapQuery(s);
|
||||||
|
String key = c.getTable() + ":::" + c.getGeomField();
|
||||||
|
instance.cache.put(key, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
statusHandler
|
||||||
|
.error("Error restoring cache from file system", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
FileLocker.unlock(CacheDbMapQuery.class, cacheFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the geometry cache to the file system
|
||||||
|
*/
|
||||||
|
public static synchronized void storeCache(File cacheFile) {
|
||||||
|
if (instance == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (instance.cache) {
|
||||||
|
try {
|
||||||
|
FileLocker.lock(CacheDbMapQuery.class, cacheFile, Type.WRITE);
|
||||||
|
FileOutputStream out = new FileOutputStream(cacheFile);
|
||||||
|
List<CacheDbMapQuerySerializeable> list = new ArrayList<CacheDbMapQuerySerializeable>(
|
||||||
|
instance.cache.size());
|
||||||
|
for (CacheDbMapQuery value : instance.cache.values()) {
|
||||||
|
list.add(value.getSerializeable());
|
||||||
|
}
|
||||||
|
DynamicSerializationManager
|
||||||
|
.getManager(SerializationType.Thrift).serialize(list,
|
||||||
|
out);
|
||||||
|
out.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
statusHandler.error("Error storing cache to file system", e);
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
FileLocker.unlock(CacheDbMapQuery.class, cacheFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/**
|
||||||
|
* 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.viz.thinclient.cave.cache.map;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.raytheon.uf.common.dataquery.db.QueryResult;
|
||||||
|
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
|
||||||
|
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Add Description
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* SOFTWARE HISTORY
|
||||||
|
*
|
||||||
|
* Date Ticket# Engineer Description
|
||||||
|
* ------------ ---------- ----------- --------------------------
|
||||||
|
* Dec 9, 2011 bsteffen Initial creation
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author bsteffen
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@DynamicSerialize
|
||||||
|
public class CacheDbMapQuerySerializeable {
|
||||||
|
|
||||||
|
@DynamicSerialize
|
||||||
|
public static class ConstraintAndIndices {
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private String constraint;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private List<Integer> indices;
|
||||||
|
|
||||||
|
public String getConstraint() {
|
||||||
|
return constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstraint(String constraint) {
|
||||||
|
this.constraint = constraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getIndices() {
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndices(List<Integer> indices) {
|
||||||
|
this.indices = indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private String table;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private String geomField;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private QueryResult data;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private List<ConstraintAndIndices> constraintAndIndices;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private List<String> columnNames;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private String geometryType;;
|
||||||
|
|
||||||
|
@DynamicSerializeElement
|
||||||
|
private List<Double> levels;
|
||||||
|
|
||||||
|
public String getTable() {
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTable(String table) {
|
||||||
|
this.table = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGeomField() {
|
||||||
|
return geomField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGeomField(String geomField) {
|
||||||
|
this.geomField = geomField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryResult getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(QueryResult data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<Integer>> getConstraint2indices() {
|
||||||
|
Map<String, List<Integer>> m = new HashMap<String, List<Integer>>();
|
||||||
|
for (ConstraintAndIndices c : constraintAndIndices) {
|
||||||
|
m.put(c.getConstraint(), c.getIndices());
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstraint2indices(
|
||||||
|
Map<String, List<Integer>> constraint2indices) {
|
||||||
|
constraintAndIndices = new ArrayList<ConstraintAndIndices>(
|
||||||
|
constraint2indices.size());
|
||||||
|
for (Entry<String, List<Integer>> entry : constraint2indices.entrySet()) {
|
||||||
|
ConstraintAndIndices c = new ConstraintAndIndices();
|
||||||
|
c.setConstraint(entry.getKey());
|
||||||
|
c.setIndices(entry.getValue());
|
||||||
|
constraintAndIndices.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConstraintAndIndices> getConstraintAndIndices() {
|
||||||
|
return constraintAndIndices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstraintAndIndices(
|
||||||
|
List<ConstraintAndIndices> constraintAndIndices) {
|
||||||
|
this.constraintAndIndices = constraintAndIndices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getColumnNames() {
|
||||||
|
return columnNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumnNames(List<String> columnNames) {
|
||||||
|
this.columnNames = columnNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGeometryType() {
|
||||||
|
return geometryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGeometryType(String geometryType) {
|
||||||
|
this.geometryType = geometryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Double> getLevels() {
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevels(List<Double> levels) {
|
||||||
|
this.levels = levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -60,7 +60,6 @@ import com.raytheon.uf.viz.core.drawables.PaintProperties;
|
||||||
import com.raytheon.uf.viz.core.exception.VizException;
|
import com.raytheon.uf.viz.core.exception.VizException;
|
||||||
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
import com.raytheon.uf.viz.core.map.IMapDescriptor;
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.AbstractDbMapResourceData.ColumnDefinition;
|
import com.raytheon.uf.viz.core.maps.rsc.AbstractDbMapResourceData.ColumnDefinition;
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.MapQueryCache;
|
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.DbMapResource;
|
import com.raytheon.uf.viz.core.maps.rsc.DbMapResource;
|
||||||
import com.raytheon.uf.viz.core.maps.rsc.DbMapResourceData;
|
import com.raytheon.uf.viz.core.maps.rsc.DbMapResourceData;
|
||||||
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
import com.raytheon.uf.viz.core.rsc.LoadProperties;
|
||||||
|
@ -203,7 +202,7 @@ public class ZoneSelectorResource extends DbMapResource {
|
||||||
|
|
||||||
// System.out.println(req.query);
|
// System.out.println(req.query);
|
||||||
// long t0 = System.currentTimeMillis();
|
// long t0 = System.currentTimeMillis();
|
||||||
QueryResult mappedResult = MapQueryCache
|
QueryResult mappedResult = DirectDbQuery
|
||||||
.executeMappedQuery(req.query, "maps",
|
.executeMappedQuery(req.query, "maps",
|
||||||
QueryLanguage.SQL);
|
QueryLanguage.SQL);
|
||||||
|
|
||||||
|
@ -984,7 +983,6 @@ public class ZoneSelectorResource extends DbMapResource {
|
||||||
return zoneNames;
|
return zoneNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getGeospatialConstraint(String geometryField, Envelope env) {
|
protected String getGeospatialConstraint(String geometryField, Envelope env) {
|
||||||
StringBuilder constraint = new StringBuilder();
|
StringBuilder constraint = new StringBuilder();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue