/layers-store/src/main/java/org/ala/layers/dao/ObjectDAOImpl.java

http://alageospatialportal.googlecode.com/ · Java · 811 lines · 631 code · 96 blank · 84 comment · 114 complexity · fa6e5a341847a757453a6d13e1ea979e MD5 · raw file

  1. /**************************************************************************
  2. * Copyright (C) 2010 Atlas of Living Australia
  3. * All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public
  6. * License Version 1.1 (the "License"); you may not use this file
  7. * except in compliance with the License. You may obtain a copy of
  8. * the License at http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS
  11. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  12. * implied. See the License for the specific language governing
  13. * rights and limitations under the License.
  14. ***************************************************************************/
  15. package org.ala.layers.dao;
  16. import java.io.BufferedInputStream;
  17. import java.io.ByteArrayOutputStream;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.IOException;
  21. import java.io.InputStreamReader;
  22. import java.io.OutputStream;
  23. import java.io.RandomAccessFile;
  24. import java.io.UnsupportedEncodingException;
  25. import java.net.URLEncoder;
  26. import java.text.MessageFormat;
  27. import java.util.ArrayList;
  28. import java.util.HashMap;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Map.Entry;
  32. import java.util.Vector;
  33. import java.util.zip.ZipInputStream;
  34. import javax.annotation.Resource;
  35. import javax.sql.DataSource;
  36. import org.ala.layers.dto.GridClass;
  37. import org.ala.layers.dto.IntersectionFile;
  38. import org.ala.layers.dto.Objects;
  39. import org.ala.layers.intersect.Grid;
  40. import org.ala.layers.intersect.IntersectConfig;
  41. import org.ala.layers.util.LayerFilter;
  42. import org.ala.layers.util.SpatialConversionUtils;
  43. import org.ala.layers.util.SpatialUtil;
  44. import org.apache.commons.io.FileUtils;
  45. import org.apache.log4j.Logger;
  46. import org.geotools.data.DataUtilities;
  47. import org.geotools.feature.simple.SimpleFeatureBuilder;
  48. import org.geotools.geojson.feature.FeatureJSON;
  49. import org.geotools.kml.KML;
  50. import org.geotools.kml.KMLConfiguration;
  51. import org.geotools.xml.Encoder;
  52. import org.opengis.feature.simple.SimpleFeatureType;
  53. import org.springframework.dao.DataAccessException;
  54. import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
  55. import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
  56. import org.springframework.scheduling.annotation.Async;
  57. import org.springframework.stereotype.Service;
  58. import org.springframework.transaction.annotation.Transactional;
  59. import com.vividsolutions.jts.geom.Geometry;
  60. import com.vividsolutions.jts.io.WKTReader;
  61. /**
  62. *
  63. * @author ajay
  64. */
  65. @Service("objectDao")
  66. public class ObjectDAOImpl implements ObjectDAO {
  67. // sld substitution strings
  68. private static final String SUB_LAYERNAME = "*layername*";
  69. private static final String SUB_COLOUR = "0xff0000"; // "*colour*";
  70. private static final String SUB_MIN_MINUS_ONE = "*min_minus_one*";
  71. private static final String SUB_MIN = "*min*";
  72. private static final String SUB_MAX = "*max*";
  73. private static final String SUB_MAX_PLUS_ONE = "*max_plus_one*";
  74. /** log4j logger */
  75. private static final Logger logger = Logger.getLogger(ObjectDAOImpl.class);
  76. private SimpleJdbcTemplate jdbcTemplate;
  77. @Resource(name = "layerIntersectDao")
  78. private LayerIntersectDAO layerIntersectDao;
  79. @Resource(name = "dataSource")
  80. public void setDataSource(DataSource dataSource) {
  81. this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
  82. }
  83. static final String objectWmsUrl = "/wms?service=WMS&version=1.1.0&request=GetMap&layers=ALA:Objects&format=image/png&viewparams=s:<pid>";
  84. static final String gridPolygonWmsUrl = "/wms?service=WMS&version=1.1.0&request=GetMap&layers=ALA:" + SUB_LAYERNAME + "&format=image/png&sld_body=";
  85. static final String gridPolygonSld;
  86. static final String gridClassSld;
  87. static {
  88. String polygonSld = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\">" + "<NamedLayer><Name>ALA:" + SUB_LAYERNAME + "</Name>"
  89. + "<UserStyle><FeatureTypeStyle><Rule><RasterSymbolizer><Geometry></Geometry>" + "<ColorMap>" + "<ColorMapEntry color=\"" + SUB_COLOUR + "\" opacity=\"0\" quantity=\""
  90. + SUB_MIN_MINUS_ONE + "\"/>" + "<ColorMapEntry color=\"" + SUB_COLOUR + "\" opacity=\"1\" quantity=\"" + SUB_MIN + "\"/>" + "<ColorMapEntry color=\"" + SUB_COLOUR
  91. + "\" opacity=\"0\" quantity=\"" + SUB_MAX_PLUS_ONE + "\"/>" + "</ColorMap></RasterSymbolizer></Rule></FeatureTypeStyle></UserStyle></NamedLayer></StyledLayerDescriptor>";
  92. String classSld = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\">" + "<NamedLayer><Name>ALA:" + SUB_LAYERNAME + "</Name>"
  93. + "<UserStyle><FeatureTypeStyle><Rule><RasterSymbolizer><Geometry></Geometry>" + "<ColorMap>" + "<ColorMapEntry color=\"" + SUB_COLOUR + "\" opacity=\"0\" quantity=\""
  94. + SUB_MIN_MINUS_ONE + "\"/>" + "<ColorMapEntry color=\"" + SUB_COLOUR + "\" opacity=\"1\" quantity=\"" + SUB_MIN + "\"/>" + "<ColorMapEntry color=\"" + SUB_COLOUR
  95. + "\" opacity=\"1\" quantity=\"" + SUB_MAX + "\"/>" + "<ColorMapEntry color=\"" + SUB_COLOUR + "\" opacity=\"0\" quantity=\"" + SUB_MAX_PLUS_ONE + "\"/>"
  96. + "</ColorMap></RasterSymbolizer></Rule></FeatureTypeStyle></UserStyle></NamedLayer></StyledLayerDescriptor>";
  97. try {
  98. polygonSld = URLEncoder.encode(polygonSld, "UTF-8");
  99. } catch (UnsupportedEncodingException ex) {
  100. logger.fatal("Invalid polygon sld string defined in ObjectDAOImpl.");
  101. }
  102. try {
  103. classSld = URLEncoder.encode(classSld, "UTF-8");
  104. } catch (UnsupportedEncodingException ex) {
  105. logger.fatal("Invalid class sld string defined in ObjectDAOImpl.");
  106. }
  107. gridPolygonSld = polygonSld;
  108. gridClassSld = classSld;
  109. }
  110. @Override
  111. public List<Objects> getObjects() {
  112. // return hibernateTemplate.find("from Objects");
  113. logger.info("Getting a list of all objects");
  114. String sql = "select o.pid as pid, o.id as id, o.name as name, o.desc as description, o.fid as fid, f.name as fieldname from objects o, fields f where o.fid = f.id";
  115. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class));
  116. updateObjectWms(objects);
  117. return objects;
  118. }
  119. @Override
  120. public List<Objects> getObjectsById(String id) {
  121. // return hibernateTemplate.find("from Objects where id = ?", id);
  122. logger.info("Getting object info for fid = " + id);
  123. // String sql = "select * from objects where fid = ?";
  124. String sql = "select o.pid as pid, o.id as id, o.name as name, o.desc as description, o.fid as fid, f.name as fieldname, o.bbox, o.area_km from objects o, fields f where o.fid = ? and o.fid = f.id";
  125. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), id);
  126. updateObjectWms(objects);
  127. // get grid classes
  128. if (objects == null || objects.isEmpty()) {
  129. objects = new ArrayList<Objects>();
  130. IntersectionFile f = layerIntersectDao.getConfig().getIntersectionFile(id);
  131. if (f != null && f.getClasses() != null) {
  132. for (Entry<Integer, GridClass> c : f.getClasses().entrySet()) {
  133. if (f.getType().equals("a")) { // class pid
  134. Objects o = new Objects();
  135. o.setPid(f.getLayerPid() + ":" + c.getKey());
  136. o.setId(f.getLayerPid() + ":" + c.getKey());
  137. o.setName(c.getValue().getName());
  138. o.setFid(f.getFieldId());
  139. o.setFieldname(f.getFieldName());
  140. o.setBbox(c.getValue().getBbox());
  141. o.setArea_km(c.getValue().getArea_km());
  142. o.setWmsurl(getGridClassWms(f.getLayerName(), c.getValue()));
  143. objects.add(o);
  144. } else { // polygon pid
  145. try {
  146. // BufferedReader br = new BufferedReader(new
  147. // FileReader(f.getFilePath() + File.separator +
  148. // c.getKey() + ".wkt.index"));
  149. // String line;
  150. // while((line = br.readLine()) != null) {
  151. // if(line.length() > 0) {
  152. // String [] cells = line.split(",");
  153. // Objects o = new Objects();
  154. // o.setPid(f.getLayerPid() + ":" + c.getKey() + ":"
  155. // + cells[0]);
  156. // o.setId(f.getLayerPid() + ":" + c.getKey() + ":"
  157. // + cells[0]);
  158. // o.setName(c.getValue().getName());
  159. // o.setFid(f.getFieldId());
  160. // o.setFieldname(f.getFieldName());
  161. //
  162. // //Too costly to calculate on the fly, and not
  163. // pre-calculated.
  164. // // o.setBbox(c.getValue().getBbox());
  165. // // o.setArea_km(c.getValue().getArea_km());
  166. // objects.add(o);
  167. // }
  168. // }
  169. // br.close();
  170. RandomAccessFile raf = new RandomAccessFile(f.getFilePath() + File.separator + c.getKey() + ".wkt.index.dat", "r");
  171. long len = raf.length() / (4 + 4 + 4 * 4 + 4); // group
  172. // number,
  173. // character
  174. // offset,
  175. // minx,
  176. // miny,
  177. // maxx,
  178. // maxy,
  179. // area
  180. // sq
  181. // km
  182. for (int i = 0; i < len; i++) {
  183. int n = raf.readInt();
  184. /* int charoffset = */raf.readInt();
  185. float minx = raf.readFloat();
  186. float miny = raf.readFloat();
  187. float maxx = raf.readFloat();
  188. float maxy = raf.readFloat();
  189. float area = raf.readFloat();
  190. Objects o = new Objects();
  191. o.setPid(f.getLayerPid() + ":" + c.getKey() + ":" + n);
  192. o.setId(f.getLayerPid() + ":" + c.getKey() + ":" + n);
  193. o.setName(c.getValue().getName());
  194. o.setFid(f.getFieldId());
  195. o.setFieldname(f.getFieldName());
  196. o.setBbox("POLYGON((" + minx + " " + miny + "," + minx + " " + maxy + "," + +maxx + " " + maxy + "," + +maxx + " " + miny + "," + +minx + " " + miny + "))");
  197. o.setArea_km(1.0 * area);
  198. o.setWmsurl(getGridPolygonWms(f.getLayerName(), n));
  199. objects.add(o);
  200. }
  201. raf.close();
  202. } catch (Exception e) {
  203. e.printStackTrace();
  204. }
  205. }
  206. }
  207. }
  208. }
  209. return objects;
  210. }
  211. @Override
  212. public String getObjectsGeometryById(String id, String geomtype) {
  213. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  214. try {
  215. streamObjectsGeometryById(baos, id, geomtype);
  216. } catch (IOException e) {
  217. e.printStackTrace();
  218. } finally {
  219. try {
  220. baos.close();
  221. } catch (IOException e) {
  222. e.printStackTrace();
  223. }
  224. }
  225. return new String(baos.toByteArray());
  226. }
  227. @Override
  228. public void streamObjectsGeometryById(OutputStream os, String id, String geomtype) throws IOException {
  229. logger.info("Getting object info for id = " + id + " and geometry as " + geomtype);
  230. String sql = "";
  231. if ("kml".equals(geomtype)) {
  232. sql = "SELECT ST_AsKml(the_geom) as geometry FROM objects WHERE pid=?;";
  233. } else if ("wkt".equals(geomtype)) {
  234. sql = "SELECT ST_AsText(the_geom) as geometry FROM objects WHERE pid=?;";
  235. } else if ("geojson".equals(geomtype)) {
  236. sql = "SELECT ST_AsGeoJSON(the_geom) as geometry FROM objects WHERE pid=?;";
  237. } else if ("shp".equals(geomtype)) {
  238. sql = "SELECT ST_AsText(the_geom) as geometry, name, \"desc\" as description FROM objects WHERE pid=?;";
  239. }
  240. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), id);
  241. if (l.size() > 0) {
  242. if ("shp".equals(geomtype)) {
  243. String wkt = l.get(0).getGeometry();
  244. File zippedShapeFile = SpatialConversionUtils.buildZippedShapeFile(wkt, id, l.get(0).getName(), l.get(0).getDescription());
  245. FileUtils.copyFile(zippedShapeFile, os);
  246. } else {
  247. os.write(l.get(0).getGeometry().getBytes());
  248. }
  249. } else {
  250. // get grid classes
  251. if (id.length() > 0) {
  252. // grid class pids are, 'layerPid:gridClassNumber'
  253. try {
  254. String[] s = id.split(":");
  255. if (s.length >= 2) {
  256. int n = Integer.parseInt(s[1]);
  257. IntersectionFile f = layerIntersectDao.getConfig().getIntersectionFile(s[0]);
  258. if (f != null && f.getClasses() != null) {
  259. GridClass gc = f.getClasses().get(n);
  260. if (gc != null && ("kml".equals(geomtype) || "wkt".equals(geomtype) || "geojson".equals(geomtype) || "shp".equals(geomtype))) {
  261. // TODO: enable for type 'a' after
  262. // implementation of fields table defaultLayer
  263. // field
  264. if (f.getType().equals("a") || s.length == 2) {
  265. // class
  266. File file = new File(f.getFilePath() + File.separator + s[1] + "." + geomtype + ".zip");
  267. if (file.exists()) {
  268. ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
  269. zis.getNextEntry();
  270. byte[] buffer = new byte[1024];
  271. int size;
  272. while ((size = zis.read(buffer)) > 0) {
  273. os.write(buffer, 0, size);
  274. }
  275. zis.close();
  276. }
  277. } else { // polygon
  278. BufferedInputStream bis = null;
  279. InputStreamReader isr = null;
  280. try {
  281. String[] cells = null;
  282. HashMap<String, Object> map = getGridIndexEntry(f.getFilePath() + File.separator + s[1], s[2]);
  283. cells = new String[] { s[2], String.valueOf(map.get("charoffset")) };
  284. if (cells != null) {
  285. // get polygon wkt string
  286. File file = new File(f.getFilePath() + File.separator + s[1] + ".wkt");
  287. bis = new BufferedInputStream(new FileInputStream(file));
  288. isr = new InputStreamReader(bis);
  289. isr.skip(Long.parseLong(cells[1]));
  290. char[] buffer = new char[1024];
  291. int size;
  292. StringBuilder sb = new StringBuilder();
  293. sb.append("POLYGON");
  294. int end = -1;
  295. while (end < 0 && (size = isr.read(buffer)) > 0) {
  296. sb.append(buffer, 0, size);
  297. end = sb.toString().indexOf("))");
  298. }
  299. end += 2;
  300. String wkt = sb.toString().substring(0, end);
  301. if (geomtype.equals("wkt")) {
  302. os.write(wkt.getBytes());
  303. } else {
  304. WKTReader r = new WKTReader();
  305. Geometry g = r.read(wkt);
  306. if (geomtype.equals("kml")) {
  307. Encoder encoder = new Encoder(new KMLConfiguration());
  308. encoder.setIndenting(true);
  309. encoder.encode(g, KML.Geometry, os);
  310. } else if (geomtype.equals("geojson")) {
  311. FeatureJSON fjson = new FeatureJSON();
  312. final SimpleFeatureType TYPE = DataUtilities.createType("class", "the_geom:MultiPolygon,name:String");
  313. SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
  314. featureBuilder.add(g);
  315. featureBuilder.add(gc.getName());
  316. fjson.writeFeature(featureBuilder.buildFeature(null), os);
  317. } else if (geomtype == "shp") {
  318. File zippedShapeFile = SpatialConversionUtils.buildZippedShapeFile(wkt, id, gc.getName(), null);
  319. FileUtils.copyFile(zippedShapeFile, os);
  320. }
  321. }
  322. }
  323. } catch (Exception e) {
  324. e.printStackTrace();
  325. } finally {
  326. if (bis != null) {
  327. try {
  328. bis.close();
  329. } catch (Exception e) {
  330. e.printStackTrace();
  331. }
  332. }
  333. if (isr != null) {
  334. try {
  335. isr.close();
  336. } catch (Exception e) {
  337. e.printStackTrace();
  338. }
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345. } catch (Exception e) {
  346. e.printStackTrace();
  347. }
  348. }
  349. }
  350. }
  351. @Override
  352. public Objects getObjectByPid(String pid) {
  353. // List<Objects> l =
  354. // hibernateTemplate.find("from Objects where pid = ?", pid);
  355. logger.info("Getting object info for pid = " + pid);
  356. String sql = "select o.pid, o.id, o.name, o.desc as description, o.fid as fid, f.name as fieldname, o.bbox, o.area_km from objects o, fields f where o.pid = ? and o.fid = f.id";
  357. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), pid);
  358. updateObjectWms(l);
  359. // get grid classes
  360. if ((l == null || l.isEmpty()) && pid.length() > 0) {
  361. // grid class pids are, 'layerPid:gridClassNumber'
  362. try {
  363. String[] s = pid.split(":");
  364. if (s.length >= 2) {
  365. int n = Integer.parseInt(s[1]);
  366. IntersectionFile f = layerIntersectDao.getConfig().getIntersectionFile(s[0]);
  367. if (f != null && f.getClasses() != null) {
  368. GridClass gc = f.getClasses().get(n);
  369. if (gc != null) {
  370. Objects o = new Objects();
  371. o.setPid(pid);
  372. o.setId(pid);
  373. o.setName(gc.getName());
  374. o.setFid(f.getFieldId());
  375. o.setFieldname(f.getFieldName());
  376. if (/* f.getType().equals("a") || */s.length == 2) {
  377. o.setBbox(gc.getBbox());
  378. o.setArea_km(gc.getArea_km());
  379. o.setWmsurl(getGridClassWms(f.getLayerName(), gc));
  380. } else {
  381. HashMap<String, Object> map = getGridIndexEntry(f.getFilePath() + File.separator + s[1], s[2]);
  382. if (!map.isEmpty()) {
  383. o.setBbox("POLYGON(" + map.get("minx") + " " + map.get("miny") + "," + map.get("minx") + " " + map.get("maxy") + "," + map.get("maxx") + " " + map.get("maxy")
  384. + "," + map.get("maxx") + " " + map.get("miny") + "," + map.get("minx") + " " + map.get("miny") + ")");
  385. o.setArea_km(((Float) map.get("area")).doubleValue());
  386. o.setWmsurl(getGridPolygonWms(f.getLayerName(), Integer.parseInt(s[2])));
  387. }
  388. }
  389. l.add(o);
  390. }
  391. }
  392. }
  393. } catch (Exception e) {
  394. e.printStackTrace();
  395. }
  396. }
  397. if (l.size() > 0) {
  398. return l.get(0);
  399. } else {
  400. return null;
  401. }
  402. }
  403. @Override
  404. public Objects getObjectByIdAndLocation(String fid, Double lng, Double lat) {
  405. logger.info("Getting object info for fid = " + fid + " at loc: (" + lng + ", " + lat + ") ");
  406. String sql = MessageFormat
  407. .format("select o.pid, o.id, o.name, o.desc as description, o.fid as fid, f.name as fieldname, o.bbox, o.area_km from search_objects_by_geometry_intersect(?, ST_GeomFromText(''POINT({0} {1})'', 4326)) o, fields f WHERE o.fid = f.id",
  408. lng, lat);
  409. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), new Object[] { fid });
  410. updateObjectWms(l);
  411. if (l == null || l.isEmpty()) {
  412. // get grid classes intersection
  413. l = new ArrayList<Objects>();
  414. IntersectionFile f = layerIntersectDao.getConfig().getIntersectionFile(fid);
  415. if (f != null && f.getClasses() != null) {
  416. Vector v = layerIntersectDao.samplingFull(fid, lng, lat);
  417. if (v != null && v.size() > 0 && v.get(0) != null) {
  418. Map m = (Map) v.get(0);
  419. int key = (int) Double.parseDouble(((String) m.get("pid")).split(":")[1]);
  420. GridClass gc = f.getClasses().get(key);
  421. if (f.getType().equals("a")) { // class pid
  422. Objects o = new Objects();
  423. o.setName(gc.getName());
  424. o.setFid(f.getFieldId());
  425. o.setFieldname(f.getFieldName());
  426. o.setPid(f.getLayerPid() + ":" + gc.getId());
  427. o.setId(f.getLayerPid() + ":" + gc.getId());
  428. o.setBbox(gc.getBbox());
  429. o.setArea_km(gc.getArea_km());
  430. o.setWmsurl(getGridClassWms(f.getLayerName(), gc));
  431. l.add(o);
  432. } else { // if(f.getType().equals("b")) {//polygon pid
  433. Grid g = new Grid(f.getFilePath() + File.separator + "polygons");
  434. if (g != null) {
  435. float[] vs = g.getValues(new double[][] { { lng, lat } });
  436. String pid = f.getLayerPid() + ":" + gc.getId() + ":" + ((int) vs[0]);
  437. l.add(getObjectByPid(pid));
  438. }
  439. }
  440. }
  441. }
  442. }
  443. if (l.size() > 0) {
  444. return l.get(0);
  445. } else {
  446. return null;
  447. }
  448. }
  449. @Override
  450. public List<Objects> getNearestObjectByIdAndLocation(String fid, int limit, Double lng, Double lat) {
  451. logger.info("Getting " + limit + " nearest objects in field fid = " + fid + " to loc: (" + lng + ", " + lat + ") ");
  452. String sql = "select fid, name, \"desc\", pid, id, ST_AsText(the_geom) as geometry, " + "st_Distance_Sphere(ST_SETSRID(ST_Point( ? , ? ),4326), the_geom) as distance, "
  453. + "degrees(Azimuth( ST_SETSRID(ST_Point( ? , ? ),4326), the_geom)) as degrees " + "from objects where fid= ? order by distance limit ? ";
  454. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), lng, lat, lng, lat, fid, new Integer(limit));
  455. updateObjectWms(objects);
  456. return objects;
  457. }
  458. @Override
  459. public List<Objects> getObjectByFidAndName(String fid, String name) {
  460. logger.info("Getting object info for fid = " + fid + " and name: (" + name + ") ");
  461. String sql = "select o.pid, o.id, o.name, o.desc as description, o.fid as fid, f.name as fieldname, o.bbox, o.area_km, ST_AsText(the_geom) as geometry from objects o, fields f where o.fid = ? and o.name like ? and o.fid = f.id";
  462. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), new Object[] { fid, name });
  463. updateObjectWms(objects);
  464. return objects;
  465. }
  466. private String getGridPolygonWms(String layername, int n) {
  467. return layerIntersectDao.getConfig().getGeoserverUrl() + gridPolygonWmsUrl.replace(SUB_LAYERNAME, layername)
  468. + formatSld(gridPolygonSld, layername, String.valueOf(n - 1), String.valueOf(n), String.valueOf(n), String.valueOf(n + 1));
  469. }
  470. private String getGridClassWms(String layername, GridClass gc) {
  471. return layerIntersectDao.getConfig().getGeoserverUrl()
  472. + gridPolygonWmsUrl.replace(SUB_LAYERNAME, layername)
  473. + formatSld(gridClassSld, layername, String.valueOf(gc.getMinShapeIdx() - 1), String.valueOf(gc.getMinShapeIdx()), String.valueOf(gc.getMaxShapeIdx()),
  474. String.valueOf(gc.getMaxShapeIdx() + 1));
  475. }
  476. private String formatSld(String sld, String layername, String min_minus_one, String min, String max, String max_plus_one) {
  477. return sld.replace(SUB_LAYERNAME, layername).replace(SUB_MIN_MINUS_ONE, min_minus_one).replace(SUB_MIN, min).replace(SUB_MAX, max).replace(SUB_MAX_PLUS_ONE, max_plus_one);
  478. }
  479. private void updateObjectWms(List<Objects> objects) {
  480. for (Objects o : objects) {
  481. o.setWmsurl(layerIntersectDao.getConfig().getGeoserverUrl() + objectWmsUrl.replace("<pid>", o.getPid()));
  482. }
  483. }
  484. private HashMap<String, Object> getGridIndexEntry(String path, String objectId) {
  485. HashMap<String, Object> map = new HashMap<String, Object>();
  486. RandomAccessFile raf = null;
  487. try {
  488. raf = new RandomAccessFile(path + ".wkt.index.dat", "r");
  489. int s2 = Integer.parseInt(objectId);
  490. // it is all in order, seek to the record
  491. int recordSize = 4 * 7; // 2 int + 5 float
  492. int start = raf.readInt();
  493. raf.seek(recordSize * (s2 - start));
  494. map.put("gn", raf.readInt());
  495. map.put("charoffset", raf.readInt());
  496. map.put("minx", raf.readFloat());
  497. map.put("miny", raf.readFloat());
  498. map.put("maxx", raf.readFloat());
  499. map.put("maxy", raf.readFloat());
  500. map.put("area", raf.readFloat());
  501. } catch (Exception e) {
  502. e.printStackTrace();
  503. } finally {
  504. try {
  505. if (raf != null) {
  506. raf.close();
  507. }
  508. } catch (Exception e) {
  509. e.printStackTrace();
  510. }
  511. }
  512. return map;
  513. }
  514. @Override
  515. public List<Objects> getObjectsByIdAndArea(String id, Integer limit, String wkt) {
  516. String sql = "select fid, name, \"desc\", pid, id, ST_AsText(the_geom) as geometry " + "from objects where fid= ? and " + "ST_Within(the_geom, ST_GeomFromText( ? , 4326)) " + "limit ? ";
  517. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), id, wkt, new Integer(limit));
  518. updateObjectWms(objects);
  519. return objects;
  520. }
  521. @Override
  522. public List<Objects> getObjectsByIdAndIntersection(String id, Integer limit, LayerFilter layerFilter) {
  523. String world = "POLYGON((-180 -90,-180 90,180 90,180 -90,-180 -90))";
  524. List<Objects> objects = getObjectsByIdAndArea(id, Integer.MAX_VALUE, world);
  525. double[][] points = new double[objects.size()][2];
  526. for (int i = 0; i < objects.size(); i++) {
  527. try {
  528. String[] s = objects.get(i).getGeometry().substring("POINT(".length(), objects.get(i).getGeometry().length() - 1).split(" ");
  529. points[i][0] = Double.parseDouble(s[0]);
  530. points[i][1] = Double.parseDouble(s[1]);
  531. } catch (Exception e) {
  532. // don't intersect this one
  533. points[i][0] = Integer.MIN_VALUE;
  534. points[i][1] = Integer.MIN_VALUE;
  535. }
  536. }
  537. // sampling
  538. ArrayList<String> sample = layerIntersectDao.sampling(new String[] { layerFilter.getLayername() }, points);
  539. // filter
  540. List<Objects> matched = new ArrayList<Objects>();
  541. String[] sampling = sample.get(0).split("\n");
  542. IntersectionFile f = layerIntersectDao.getConfig().getIntersectionFile(layerFilter.getLayername());
  543. if (f != null && (f.getType().equals("a") || f.getType().equals("b"))) {
  544. String target = f.getClasses().get((int) layerFilter.getMinimum_value()).getName();
  545. for (int i = 0; i < sampling.length; i++) {
  546. if (sampling[i].length() > 0) {
  547. if (sampling[i].equals(target)) {
  548. matched.add(objects.get(i));
  549. }
  550. }
  551. }
  552. } else {
  553. for (int i = 0; i < sampling.length; i++) {
  554. if (sampling[i].length() > 0) {
  555. double v = Double.parseDouble(sampling[i]);
  556. if (v >= layerFilter.getMinimum_value() && v <= layerFilter.getMaximum_value()) {
  557. matched.add(objects.get(i));
  558. }
  559. }
  560. }
  561. }
  562. updateObjectWms(matched);
  563. return matched;
  564. }
  565. @Override
  566. public List<Objects> getObjectsByIdAndIntersection(String id, Integer limit, String intersectingPid) {
  567. String sql = "select fid, name, \"desc\", pid, id, ST_AsText(the_geom) as geometry " + "from objects, " + "(select the_geom as g from Objects where pid = ? ) t " + "where fid= ? and "
  568. + "ST_Within(the_geom, g) " + "limit ? ";
  569. List<Objects> objects = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), intersectingPid, id, new Integer(limit));
  570. updateObjectWms(objects);
  571. return objects;
  572. }
  573. @Transactional
  574. @Override
  575. public String createUserUploadedObject(String wkt, String name, String description, String userid) {
  576. double area_km = SpatialUtil.calculateArea(wkt) / 1000.0 / 1000.0;
  577. try {
  578. // Insert shape into geometry table
  579. String sql = "INSERT INTO objects (pid, id, name, \"desc\", fid, the_geom, namesearch, bbox, area_km) values (nextval('objects_id_seq'::regclass), nextval('uploaded_objects_metadata_id_seq'::regclass), ?, ?, ?, ST_GeomFromText(?, 4326), true, ST_AsText(Box2D(ST_GeomFromText(?, 4326))), ?)";
  580. jdbcTemplate.update(sql, name, description, IntersectConfig.getUploadedShapesFieldId(), wkt, wkt, area_km);
  581. // Now write to metadata table
  582. String sql2 = "INSERT INTO uploaded_objects_metadata (pid, id, user_id, time_last_updated) values (currval('objects_id_seq'::regclass), currval('uploaded_objects_metadata_id_seq'::regclass), ?, now())";
  583. jdbcTemplate.update(sql2, userid);
  584. // get pid and id of new object
  585. String sql3 = "SELECT MAX(pid) from uploaded_objects_metadata";
  586. int pid = jdbcTemplate.queryForInt(sql3);
  587. return Integer.toString(pid);
  588. } catch (DataAccessException ex) {
  589. throw new IllegalArgumentException("Error writing to database. Check validity of wkt.", ex);
  590. }
  591. }
  592. @Override
  593. @Transactional
  594. public boolean updateUserUploadedObject(int pid, String wkt, String name, String description, String userid) {
  595. if (!shapePidIsForUploadedShape(pid)) {
  596. throw new IllegalArgumentException("Supplied pid does not match an uploaded shape.");
  597. }
  598. try {
  599. double area_km = SpatialUtil.calculateArea(wkt) / 1000.0 / 1000.0;
  600. // First update metadata table
  601. String sql = "UPDATE uploaded_objects_metadata SET user_id = ?, time_last_updated = now() WHERE pid = ?";
  602. jdbcTemplate.update(sql, userid, Integer.toString(pid));
  603. // Then update objects table
  604. String sql2 = "UPDATE objects SET the_geom = ST_GeomFromText(?, 4326), bbox = ST_AsText(Box2D(ST_GeomFromText(?, 4326))), name = ?, \"desc\" = ?, area_km = ? where pid = ?";
  605. int rowsUpdated = jdbcTemplate.update(sql2, wkt, wkt, name, description, area_km, Integer.toString(pid));
  606. return (rowsUpdated > 0);
  607. } catch (DataAccessException ex) {
  608. throw new IllegalArgumentException("Error writing to database. Check validity of wkt.", ex);
  609. }
  610. }
  611. @Override
  612. @Transactional
  613. public boolean deleteUserUploadedObject(int pid) {
  614. if (!shapePidIsForUploadedShape(pid)) {
  615. throw new IllegalArgumentException("Supplied pid does not match an uploaded shape.");
  616. }
  617. String sql = "DELETE FROM uploaded_objects_metadata WHERE pid = ?; DELETE FROM objects where pid = ?";
  618. int rowsAffected = jdbcTemplate.update(sql, Integer.toString(pid), Integer.toString(pid));
  619. return (rowsAffected > 0);
  620. }
  621. @Async
  622. public void updateObjectNames() {
  623. String sql = "INSERT INTO obj_names (name)" + " SELECT lower(objects.name) FROM fields, objects" + " LEFT OUTER JOIN obj_names ON lower(objects.name)=obj_names.name"
  624. + " WHERE obj_names.name IS NULL" + " AND fields.namesearch = true" + " AND fields.id = objects.fid" + " GROUP BY lower(objects.name);"
  625. + " UPDATE objects SET name_id=obj_names.id FROM obj_names WHERE name_id IS NULL AND lower(objects.name)=obj_names.name;";
  626. jdbcTemplate.update(sql);
  627. }
  628. private boolean shapePidIsForUploadedShape(int pid) {
  629. String sql = "SELECT * from uploaded_objects_metadata WHERE pid = ?";
  630. List<Map<String, Object>> queryResult = jdbcTemplate.queryForList(sql, Integer.toString(pid));
  631. if (queryResult == null || queryResult.isEmpty()) {
  632. return false;
  633. } else {
  634. return true;
  635. }
  636. }
  637. @Override
  638. public int createPointOfInterest(String objectId, String name, String type, Double latitude, Double longitude, Double bearing, String userId, String description, Double focalLength) {
  639. String sql = "INSERT INTO points_of_interest (id, object_id, name, type, latitude, longitude, bearing, user_id, description, focal_length_millimetres, the_geom) VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ST_SetSRID(ST_MakePoint(?, ?),4326))";
  640. jdbcTemplate.update(sql, objectId, name, type, latitude, longitude, bearing, userId, description, focalLength, longitude, latitude);
  641. // get pid and id of new object
  642. String sql2 = "SELECT MAX(id) from points_of_interest";
  643. int id = jdbcTemplate.queryForInt(sql2);
  644. return id;
  645. }
  646. @Override
  647. public boolean updatePointOfInterest(int id, String objectId, String name, String type, Double latitude, Double longitude, Double bearing, String userId, String description, Double focalLength) {
  648. String sql = "UPDATE points_of_interest SET object_id = ?, name = ?, type = ?, latitude = ?, longitude = ?, bearing = ?, user_id = ?, description = ?, focal_length_millimetres = ? WHERE id = ?; "
  649. + "UPDATE points_of_interest SET the_geom = ST_SetSRID(ST_MakePoint(longitude, latitude),4326) WHERE id = ?";
  650. int rowsUpdated = jdbcTemplate.update(sql, objectId, name, type, latitude, longitude, bearing, userId, description, focalLength, id, id);
  651. return (rowsUpdated > 0);
  652. }
  653. @Override
  654. public Map<String, Object> getPointOfInterestDetails(int id) {
  655. String sql = "SELECT id, object_id, name, type, latitude, longitude, bearing, user_id, description, focal_length_millimetres from points_of_interest WHERE id = ?";
  656. Map<String, Object> poiDetails = jdbcTemplate.queryForMap(sql, id);
  657. if (poiDetails.isEmpty()) {
  658. throw new IllegalArgumentException("Invalid point of interest id");
  659. }
  660. return poiDetails;
  661. }
  662. @Override
  663. public boolean deletePointOfInterest(int id) {
  664. String sql = "DELETE FROM points_of_interest WHERE id = ?;";
  665. int rowsAffected = jdbcTemplate.update(sql, id);
  666. return (rowsAffected > 0);
  667. }
  668. @Override
  669. public List<Objects> getObjectsWithinRadius(String fid, double latitude, double longitude, double radiusKm) {
  670. String sql = MessageFormat
  671. .format("SELECT o.pid, o.id, o.name, o.desc AS description, o.fid AS fid, f.name AS fieldname, o.bbox, o.area_km FROM objects o, fields f WHERE o.fid = ? AND o.fid = f.id AND ST_DWithin(ST_GeographyFromText(''POINT({0} {1})''), geography(the_geom), ?)",
  672. longitude, latitude);
  673. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), fid, radiusKm * 1000);
  674. updateObjectWms(l);
  675. return l;
  676. }
  677. @Override
  678. public List<Objects> getObjectsIntersectingWithGeometry(String fid, String wkt) {
  679. // String sql =
  680. // "SELECT o.pid, o.id, o.name, o.desc AS description, o.fid AS fid, f.name AS fieldname, o.bbox, o.area_km FROM objects o, fields f WHERE o.fid = ? AND o.fid = f.id AND ST_Intersects(ST_GeomFromText(?, 4326), the_geom)";
  681. String sql = "SELECT o.pid, o.id, o.name, o.desc AS description, o.fid AS fid, f.name AS fieldname, o.bbox, o.area_km from search_objects_by_geometry_intersect(?, ST_GeomFromText(?, 4326)) o, fields f WHERE o.fid = f.id";
  682. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), fid, wkt);
  683. updateObjectWms(l);
  684. return l;
  685. }
  686. @Override
  687. public List<Objects> getObjectsIntersectingWithObject(String fid, String objectPid) {
  688. // String sql =
  689. // "SELECT o.pid, o.id, o.name, o.desc AS description, o.fid AS fid, f.name AS fieldname, o.bbox, o.area_km FROM objects o, fields f WHERE o.fid = ? AND o.fid = f.id AND ST_Intersects((SELECT the_geom FROM objects WHERE pid = ?), the_geom)";
  690. String sql = "SELECT o.pid, o.id, o.name, o.desc AS description, o.fid AS fid, f.name AS fieldname, o.bbox, o.area_km FROM search_objects_by_geometry_intersect(?, (SELECT the_geom FROM objects WHERE pid = ?)) o, fields f WHERE o.fid = f.id";
  691. List<Objects> l = jdbcTemplate.query(sql, ParameterizedBeanPropertyRowMapper.newInstance(Objects.class), fid, objectPid);
  692. updateObjectWms(l);
  693. return l;
  694. }
  695. @Override
  696. public List<Map<String, Object>> getPointsOfInterestWithinRadius(double latitude, double longitude, double radiusKm) {
  697. String sql = MessageFormat
  698. .format("SELECT id, object_id, name, type, latitude, longitude, bearing, user_id, description, focal_length_millimetres from points_of_interest WHERE ST_DWithin(ST_GeographyFromText(''POINT({0} {1})''), geography(the_geom), ?)",
  699. longitude, latitude);
  700. List<Map<String, Object>> l = jdbcTemplate.queryForList(sql, radiusKm * 1000);
  701. return l;
  702. }
  703. @Override
  704. public List<Map<String, Object>> pointsOfInterestGeometryIntersect(String wkt) {
  705. String sql = "SELECT id, object_id, name, type, latitude, longitude, bearing, user_id, description, focal_length_millimetres from points_of_interest WHERE ST_Intersects(ST_GeomFromText(?, 4326), the_geom)";
  706. List<Map<String, Object>> l = jdbcTemplate.queryForList(sql, wkt);
  707. return l;
  708. }
  709. @Override
  710. public List<Map<String, Object>> pointsOfInterestObjectIntersect(String objectPid) {
  711. String sql = "SELECT id, object_id, name, type, latitude, longitude, bearing, user_id, description, focal_length_millimetres from points_of_interest WHERE ST_Intersects((SELECT the_geom FROM objects where pid = ?), the_geom)";
  712. List<Map<String, Object>> l = jdbcTemplate.queryForList(sql, objectPid);
  713. return l;
  714. }
  715. }